| @@ -3,6 +3,9 @@ Best viewed in emacs org mode. | |||
| This is the coursework for the graded part of the TDT4255 course at NTNU. | |||
| * 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 | |||
| [[./exercise.org][Exercise instructions]] | |||
| @@ -46,8 +46,6 @@ val defaultVersions = Map( | |||
| libraryDependencies ++= (Seq("chisel3","chisel-iotesters").map { | |||
| dep: String => "edu.berkeley.cs" %% dep % sys.props.getOrElse(dep + "Version", defaultVersions(dep)) }) | |||
| val versionOfScala = "2.12.4" | |||
| val fs2Version = "0.10.3" | |||
| val catsVersion = "1.1.0" | |||
| 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) { | |||
| 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) | |||
| } | |||
| } | |||