| @@ -3,6 +3,9 @@ Best viewed in emacs org mode. | |||||
| This is the coursework for the graded part of the TDT4255 course at NTNU. | This is the coursework for the graded part of the TDT4255 course at NTNU. | ||||
| * Instructions | * Instructions | ||||
| #+ATTR_HTML: title="Join the chat at https://gitter.im/RISCV-FiveStage/community" | |||||
| [[https://gitter.im/RISCV-FiveStage/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge][file:https://badges.gitter.im/RISCV-FiveStage/community.svg]] | |||||
| To get started with designing your 5-stage RISC-V pipeline you should follow the | To get started with designing your 5-stage RISC-V pipeline you should follow the | ||||
| [[./exercise.org][Exercise instructions]] | [[./exercise.org][Exercise instructions]] | ||||
| @@ -46,8 +46,6 @@ val defaultVersions = Map( | |||||
| libraryDependencies ++= (Seq("chisel3","chisel-iotesters").map { | libraryDependencies ++= (Seq("chisel3","chisel-iotesters").map { | ||||
| dep: String => "edu.berkeley.cs" %% dep % sys.props.getOrElse(dep + "Version", defaultVersions(dep)) }) | dep: String => "edu.berkeley.cs" %% dep % sys.props.getOrElse(dep + "Version", defaultVersions(dep)) }) | ||||
| val versionOfScala = "2.12.4" | |||||
| val fs2Version = "0.10.3" | val fs2Version = "0.10.3" | ||||
| val catsVersion = "1.1.0" | val catsVersion = "1.1.0" | ||||
| val catsEffectVersion = "0.10" | val catsEffectVersion = "0.10" | ||||
| @@ -49,11 +49,18 @@ class InstructionFetch extends MultiIOModule { | |||||
| /** | /** | ||||
| * Setup. You should not change this code | |||||
| * Setup. | |||||
| * | |||||
| * When you have added an instruction signal to this module you | |||||
| * should ensure that it is set to NOP during program loading. | |||||
| * | |||||
| * If not you will end up issuing instructions during program load | |||||
| * which will start executing before memory, registers and programs | |||||
| * are fully loaded. | |||||
| */ | */ | ||||
| when(testHarness.IMEMsetup.setup) { | when(testHarness.IMEMsetup.setup) { | ||||
| PC := 0.U | PC := 0.U | ||||
| // TODO: You must set the instruction to Instruction.NOP here. | |||||
| // throw new Exception("Just making sure you're seeing the line above") | |||||
| // TODO: You should probably set the instruction to Instruction.NOP here. | |||||
| throw new Exception("Just making sure you're seeing the line above.\nYou can delete this exception now, it's found at line 64 at IF.scala") | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,178 +0,0 @@ | |||||
| package FiveStage | |||||
| import cats.data.Writer | |||||
| import cats._ | |||||
| import cats.data.{ Op => _ } | |||||
| import cats.implicits._ | |||||
| object DTree { | |||||
| // opaques WHEN | |||||
| type Feature = String | |||||
| type Value = String | |||||
| type Cls = String | |||||
| case class TrainingData(values: Map[Feature, Value], cls: Cls) | |||||
| type TestData = Map[Feature, Value] | |||||
| // Base | |||||
| // def predict(data: TestData): Cls = "Died" | |||||
| // Gendered | |||||
| def predictStatic(data: TestData): Cls = | |||||
| if(data("gender") == "female") | |||||
| "survived" | |||||
| else "died" | |||||
| sealed trait Tree | |||||
| case class Node(feature: Feature, children: Map[Value, Tree]) extends Tree | |||||
| case class Leaf(cls: Cls) extends Tree | |||||
| val genderBased: Tree = Node( | |||||
| "gender", Map( | |||||
| "female" -> Leaf("survived"), | |||||
| "male" -> Leaf("died"), | |||||
| )) | |||||
| def predict(data: TestData)(tree: Tree): Cls = | |||||
| tree match { | |||||
| case Leaf(cls) => cls | |||||
| case Node(feature, children) => predict(data)(children(data(feature))) | |||||
| } | |||||
| val data = Map("gender" -> "female", "family size" -> "0", "ticket" -> "1") | |||||
| predict(data)(genderBased) // true | |||||
| def entropy(classes: List[Cls]): Double = { | |||||
| val total = classes.size | |||||
| classes.groupBy(identity) | |||||
| .mapValues { group => | |||||
| val prop = group.size / total | |||||
| prop * math.log(1.0 / prop) | |||||
| }.values.sum | |||||
| } | |||||
| def bucketedEntropy(data: List[TrainingData], feature: Feature): Double = { | |||||
| val total = data.size | |||||
| val bucketed = data.groupBy(_.values(feature)) | |||||
| .mapValues(_.map(_.cls)) | |||||
| .toMap | |||||
| bucketed.values.map { classes => | |||||
| val prop = classes.size / total | |||||
| prop * entropy(classes) | |||||
| }.sum | |||||
| } | |||||
| def best(data: List[TrainingData], features: Set[Feature]): Feature = features.minBy(bucketedEntropy(data, _)) | |||||
| def mostCommonCls(data: List[TrainingData]): Cls = ??? | |||||
| def build(data: List[TrainingData], features: Set[Feature]): Tree = { | |||||
| if(features.nonEmpty) { | |||||
| val feature = best(data, features) | |||||
| val buckets = data.groupBy(_.values(feature)) | |||||
| Node(feature, buckets.mapValues(build(_, features - feature))) | |||||
| } else { | |||||
| Leaf(mostCommonCls(data)) | |||||
| } | |||||
| } | |||||
| def withHKT { | |||||
| sealed trait Tree[A] | |||||
| case class Node[A](feature: Feature, children: Map[Value, A]) extends Tree[A] | |||||
| case class Leaf[A](cls: Cls) extends Tree[A] | |||||
| // import matryoshka._ | |||||
| // import matryoshka.data.Fix | |||||
| // import matryoshka.implicits._ | |||||
| case class Fix[F[_]](unfix: F[Fix[F]]) | |||||
| case class Cofree[F[_], A](head: A, tail: F[Cofree[F, A]]){ | |||||
| def counit: A = head | |||||
| def map[B](f: A => B)(implicit ev: Functor[F]): Cofree[F, B] = Cofree(f(head), tail.map(_.map(f))) | |||||
| /** | |||||
| * Coflatmap alters the value of the node based on its context, then recursively | |||||
| * alters its tail independently (which makes sense as it's the only thing Cofree[F, A] => B can do. | |||||
| */ | |||||
| def coflatMap[B](fa: Cofree[F, A] => B)(implicit ev: Functor[F]): Cofree[F, B] = { | |||||
| val b = fa(this) | |||||
| val fb = tail.map(_.coflatMap(fa)) | |||||
| Cofree(b, fb) | |||||
| } | |||||
| } | |||||
| implicit val treeFunctor: Functor[Tree] = new Functor[Tree] { | |||||
| def map[A, B](fa: Tree[A])(f: A => B): Tree[B] = fa match { | |||||
| case Node(name, children) => Node(name, children.mapValues(f)) | |||||
| case Leaf(cls) => Leaf(cls) | |||||
| } | |||||
| } | |||||
| val genderBased: Fix[Tree] = | |||||
| Fix(Node( | |||||
| "gender", | |||||
| Map( | |||||
| "female" -> Fix(Leaf[Fix[Tree]]("survived")), | |||||
| "male" -> Fix(Leaf[Fix[Tree]]("died")) | |||||
| ))) | |||||
| def build: ((List[TrainingData], Set[Feature])) => Tree[(List[TrainingData], Set[Feature])] = { | |||||
| case (data, features) => | |||||
| if(features.nonEmpty) { | |||||
| val feature = best(data, features) | |||||
| val buckets = data.groupBy(_.values(feature)) | |||||
| val next = buckets.mapValues { subset => (subset, features - feature) } | |||||
| Node(feature, next) | |||||
| } else { | |||||
| Leaf(mostCommonCls(data)) | |||||
| } | |||||
| } | |||||
| def explore(testData: TestData): Fix[Tree] => Cls Either Fix[Tree] = | |||||
| fix => fix.unfix match { | |||||
| case Leaf(cls) => Left(cls) | |||||
| case Node(feature, children) => Right(children.get(testData(feature)).get) | |||||
| } | |||||
| // Anamorphism: Generalized unfold, builds structures | |||||
| def ana[F[_]: Functor, A](f: A => F[A])(a: A): Fix[F] = | |||||
| Fix( (f(a)).map(ana(f)) ) | |||||
| // Catamorphism: Generalized fold, tears structures down. | |||||
| def cata[F[_]: Functor, A](fa: F[A] => A)(f: Fix[F]): A = { | |||||
| fa(f.unfix.map(cata(fa))) | |||||
| } | |||||
| // def hyloSimple[F[_] : Functor, A, B](f: F[B] => B)(g: A => F[A]): A => B | |||||
| def hyloSimple[F[_]: Functor, A, B](f: F[B] => B)(g: A => F[A])(a: A): B = | |||||
| cata(f)(ana(g)(a)) | |||||
| // A more powerful cata | |||||
| def para[F[_]: Functor, A](f: F[(Fix[F], A)] => A)(fa: Fix[F]): A = | |||||
| f(fa.unfix.map(x => (x, para(f)(x)))) | |||||
| // A more powerful ana | |||||
| def apo[F[_]: Functor, A](f: A => F[Either[Fix[F], A]])(a: A): Fix[F] = { | |||||
| Fix(f(a).map{ | |||||
| case Right(a) => apo(f)(a) | |||||
| case Left(fix) => fix | |||||
| }) | |||||
| } | |||||
| // When we have cofree | |||||
| def histo[F[_]: Functor, A](f: F[Cofree[F, A]] => A)(fix: Fix[F]): A = { | |||||
| def toCofree(fix: Fix[F]): Cofree[F, A] = | |||||
| Cofree(histo(f)(fix), fix.unfix.map(toCofree)) | |||||
| f(fix.unfix.map(toCofree)) | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,164 +0,0 @@ | |||||
| package FiveStage | |||||
| import cats.data.Writer | |||||
| import cats._ | |||||
| import cats.data.{ Op => _ } | |||||
| import cats.implicits._ | |||||
| import fileUtils.say | |||||
| object DeletDis { | |||||
| def delet = { | |||||
| case class Fix[F[_]](unfix: F[Fix[F]]) | |||||
| case class Cofree[F[_], A](head: A, tail: F[Cofree[F, A]]){ | |||||
| def counit: A = head | |||||
| def map[B](f: A => B)(implicit ev: Functor[F]): Cofree[F, B] = Cofree(f(head), tail.map(_.map(f))) | |||||
| /** | |||||
| * Coflatmap alters the value of the node based on its context, then recursively | |||||
| * alters its tail independently (which makes sense as it's the only thing Cofree[F, A] => B can do. | |||||
| */ | |||||
| def coflatMap[B](fa: Cofree[F, A] => B)(implicit ev: Functor[F]): Cofree[F, B] = { | |||||
| val b = fa(this) | |||||
| val fb = tail.map(_.coflatMap(fa)) | |||||
| Cofree(b, fb) | |||||
| } | |||||
| } | |||||
| // Anamorphism: Generalized unfold, builds structures | |||||
| def ana[F[_]: Functor, A](f: A => F[A])(a: A): Fix[F] = | |||||
| Fix( (f(a)).map(ana(f)) ) | |||||
| // Catamorphism: Generalized fold, tears structures down. | |||||
| def cata[F[_]: Functor, A](fa: F[A] => A)(f: Fix[F]): A = { | |||||
| fa(f.unfix.map(cata(fa))) | |||||
| } | |||||
| // def hyloSimple[F[_] : Functor, A, B](f: F[B] => B)(g: A => F[A]): A => B | |||||
| def hylo[F[_]: Functor, A, B](f: F[B] => B)(g: A => F[A])(a: A): B = | |||||
| cata(f)(ana(g)(a)) | |||||
| // A more powerful cata | |||||
| def para[F[_]: Functor, A](f: F[(Fix[F], A)] => A)(fa: Fix[F]): A = | |||||
| f(fa.unfix.map(x => (x, para(f)(x)))) | |||||
| // A more powerful ana | |||||
| def apo[F[_]: Functor, A](f: A => F[Either[Fix[F], A]])(a: A): Fix[F] = { | |||||
| Fix(f(a).map{ | |||||
| case Right(a) => apo(f)(a) | |||||
| case Left(fix) => fix | |||||
| }) | |||||
| } | |||||
| // When we have cofree | |||||
| def histo[F[_]: Functor, A](f: F[Cofree[F, A]] => A)(fix: Fix[F]): A = { | |||||
| def toCofree(fix: Fix[F]): Cofree[F, A] = | |||||
| Cofree(histo(f)(fix), fix.unfix.map(toCofree)) | |||||
| f(fix.unfix.map(toCofree)) | |||||
| } | |||||
| sealed trait StackR | |||||
| final case class DoneR(result: Int = 1) extends StackR | |||||
| final case class MoreR(stack: StackR, next: Int) extends StackR | |||||
| def unfoldStackR(n: Int): StackR = | |||||
| if(n > 0) MoreR(unfoldStackR(n-1), n) else DoneR() | |||||
| say(unfoldStackR(5)) | |||||
| sealed trait Stack[A] | |||||
| final case class Done[A](result: Int) extends Stack[A] | |||||
| final case class More[A](a: A, next: Int) extends Stack[A] | |||||
| object Stack { | |||||
| implicit val stackFunctor: Functor[Stack] = new Functor[Stack] { | |||||
| def map[A, B](fa: Stack[A])(f: A => B): Stack[B] = fa match { | |||||
| case Done(result) => Done(result) | |||||
| case More(a, next) => More(f(a), next) | |||||
| } | |||||
| } | |||||
| def done[A](result: Int = 1): Stack[A] = Done(result) | |||||
| def more[A](a: A, next: Int): Stack[A] = More(a, next) | |||||
| } | |||||
| import Stack._ | |||||
| val stackCoalgebra: Int => Stack[Int] = | |||||
| n => if(n > 0) more(n - 1, n) else done() | |||||
| say(ana(stackCoalgebra)(5)) | |||||
| val stackAlgebra: Stack[Int] => Int = { | |||||
| case Done(result) => result | |||||
| case More(acc, next) => acc * next | |||||
| } | |||||
| say(cata(stackAlgebra)(ana(stackCoalgebra)(5))) | |||||
| say(hylo(stackAlgebra)(stackCoalgebra)(5)) | |||||
| sealed trait Nat[A] | |||||
| final case class Zero[A]() extends Nat[A] | |||||
| final case class Succ[A](prev: A) extends Nat[A] | |||||
| object Nat { | |||||
| implicit val natFunctor: Functor[Nat] = new Functor[Nat] { | |||||
| override def map[A, B](na: Nat[A])(f: A => B): Nat[B] = | |||||
| na match { | |||||
| case Zero() => Zero() | |||||
| case Succ(a) => Succ(f(a)) | |||||
| } | |||||
| } | |||||
| } | |||||
| val natAlgebra: Nat[Int] => Int = { | |||||
| case Zero() => 1 | |||||
| case Succ(n) => { | |||||
| say(s"nat alg succ $n") | |||||
| n + 1 | |||||
| } | |||||
| } | |||||
| val natAlgebraS: Nat[String] => String = { | |||||
| case Zero() => "N" | |||||
| case Succ(n) => n match { | |||||
| case "N" => "NI" | |||||
| case "NI" => "NIG" | |||||
| case "NIG" => "NIGG" | |||||
| case "NIGG" => "NIGGE" | |||||
| case "NIGGE" => "NIGGER :-" | |||||
| case s => s + "D" | |||||
| } | |||||
| } | |||||
| val natCoalgebra: Int => Nat[Int] = | |||||
| n => if (n == 0) Zero() else Succ(n - 1) | |||||
| val b = ana(natCoalgebra)(9) | |||||
| val c = cata(natAlgebraS)(b) | |||||
| say(c) | |||||
| val natAlgebraPara: Nat[(Fix[Nat], Int)] => Int = { | |||||
| case Zero() => 1 | |||||
| case Succ((fix, acc)) => { | |||||
| say(s"nat para alg succ $fix, $acc") | |||||
| cata(natAlgebra)(fix) * acc | |||||
| } | |||||
| } | |||||
| val build = ana(natCoalgebra)(_) | |||||
| say("built") | |||||
| val tear = para(natAlgebraPara)(_) | |||||
| say(tear(build(5))) | |||||
| // say(ana(natCoalgebra)(5)) | |||||
| val lastThreeSteps: Fix[Stack] = Fix(More(Fix(More(Fix(More(Fix(Done(1)),1)),2)),3)) | |||||
| val stackCoalgebraApo: Int => Stack[Either[Fix[Stack], Int]] = | |||||
| n => if(n > 3) more(n - 1, n).map(_.asRight) else lastThreeSteps.unfix.map(_.asLeft) | |||||
| } | |||||
| } | |||||