From 6fbedec5ca557b57d0930c3cf7359adcf7203a9d Mon Sep 17 00:00:00 2001 From: Mikael Vejdemo-Johansson Date: Fri, 12 Apr 2024 10:51:31 +0100 Subject: [PATCH] Lint. --- build.sbt | 2 +- project/plugins.sbt | 18 +- .../org/appliedtopology/tda4j/Chain.scala | 259 +++++++++--------- .../org/appliedtopology/tda4j/package.scala | 3 +- .../org/appliedtopology/tda4j/ChainSpec.scala | 7 +- .../appliedtopology/tda4j/ProfilingSpec.scala | 7 +- 6 files changed, 155 insertions(+), 141 deletions(-) diff --git a/build.sbt b/build.sbt index 3972779f..7c012658 100644 --- a/build.sbt +++ b/build.sbt @@ -60,7 +60,7 @@ lazy val root = (project in file(".")) // Workaround for XML versioning issues // See: https://github.com/scala/bug/issues/12632 libraryDependencySchemes ++= Seq( - "org.scala-lang.modules" %% "scala-xml" % VersionScheme.Always, + "org.scala-lang.modules" %% "scala-xml" % VersionScheme.Always ) Compile / doc / scalacOptions := Seq("-diagrams") diff --git a/project/plugins.sbt b/project/plugins.sbt index c079bcc8..42026139 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,9 +1,9 @@ -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6") -addSbtPlugin("com.github.sbt" % "sbt-site-paradox" % "1.6.0") -addSbtPlugin("com.github.sbt" % "sbt-paradox-material-theme" % "0.7.0") -addSbtPlugin("io.kevinlee" % "sbt-github-pages" % "0.14.0") -addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.9.2") -addSbtPlugin("com.wanari" % "sbt-paradox-diagrams" % "0.1.4") -addSbtPlugin("com.github.sbt" % "sbt-release" % "1.3.0") -addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.10.0") -addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.2") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6") +addSbtPlugin("com.github.sbt" % "sbt-site-paradox" % "1.6.0") +addSbtPlugin("com.github.sbt" % "sbt-paradox-material-theme" % "0.7.0") +addSbtPlugin("io.kevinlee" % "sbt-github-pages" % "0.14.0") +addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.9.2") +addSbtPlugin("com.wanari" % "sbt-paradox-diagrams" % "0.1.4") +addSbtPlugin("com.github.sbt" % "sbt-release" % "1.3.0") +addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.10.0") +addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.2") diff --git a/src/main/scala/org/appliedtopology/tda4j/Chain.scala b/src/main/scala/org/appliedtopology/tda4j/Chain.scala index ecf81892..a25d7f46 100644 --- a/src/main/scala/org/appliedtopology/tda4j/Chain.scala +++ b/src/main/scala/org/appliedtopology/tda4j/Chain.scala @@ -6,8 +6,8 @@ package org.appliedtopology.tda4j { import scala.collection.mutable /** Trait that defines what it means to be a "Chain". - */ - trait Chain[CellT <: Cell[CellT] : Ordering, CoefficientT: Fractional] { + */ + trait Chain[CellT <: Cell[CellT]: Ordering, CoefficientT: Fractional] { def leadingCell: CellT = leadingTerm._1 def leadingCoefficient: CoefficientT = leadingTerm._2 @@ -16,29 +16,29 @@ package org.appliedtopology.tda4j { } /** Lightweight trait to define what it means to be a topological "Cell". - * - * Using F-bounded types to ensure reflective typing. See - * https://tpolecat.github.io/2015/04/29/f-bounds.html See - * https://dotty.epfl.ch/3.0.0/docs/reference/contextual/type-classes.html - */ + * + * Using F-bounded types to ensure reflective typing. See + * https://tpolecat.github.io/2015/04/29/f-bounds.html See + * https://dotty.epfl.ch/3.0.0/docs/reference/contextual/type-classes.html + */ trait Cell[CellT <: Cell[CellT]] { this: CellT => /** The boundary map of the cell. - * - * @return - * A sequence of boundary cells. - * @todo - * When a `Chain` trait or class has been created, this should change to - * return an appropriate `Chain` instead of the current `List`. - */ + * + * @return + * A sequence of boundary cells. + * @todo + * When a `Chain` trait or class has been created, this should change to + * return an appropriate `Chain` instead of the current `List`. + */ def boundary[CoefficientT: Fractional]: Chain[CellT, CoefficientT] } // Here we choose the underlying chain implementation to use - export mapchain.{ChainElement, ChainOps, Chain} + export mapchain.{Chain, ChainElement, ChainOps} /* Implementation of the Chain trait using maps for internal storage. @@ -46,38 +46,38 @@ package org.appliedtopology.tda4j { package mapchain { object Chain { - def apply[CellT <: Cell[CellT] : Ordering, CoefficientT: Fractional]( - cc: (CellT, CoefficientT)* - ): Chain[CellT, CoefficientT] = ChainElement(cc: _*) + def apply[CellT <: Cell[CellT]: Ordering, CoefficientT: Fractional]( + cc: (CellT, CoefficientT)* + ): Chain[CellT, CoefficientT] = ChainElement(cc: _*) - def apply[CellT <: Cell[CellT] : Ordering, CoefficientT: Fractional]( - c: CellT - ): Chain[CellT, CoefficientT] = ChainElement(c) + def apply[CellT <: Cell[CellT]: Ordering, CoefficientT: Fractional]( + c: CellT + ): Chain[CellT, CoefficientT] = ChainElement(c) } - /** The Chain class is a representation of a formal linear combination of the n - * cells in a cell complex. Note that CellT is a type parameter subtype of - * Cell, a trait in this library. We have Scala look for a type parameter of - * cellOrdering that matches as best as possible an Ordering on CellT. - * - * (Note: write a fully fleshed out explanation in comments after code def. - * write up) - * - * @tparam CellT - * Type of the cells in the chain complex. For example `AbstractSimplex[Int]` - * etc. - * @tparam CoefficientT - * Type of the coefficients of the chain complex. For example `Double` or an - * implicit 'FiniteField : Fractional[Int]' - * @param chainMap - * Internal storage of the sorted map of the elements - */ - class ChainElement[CellT <: Cell[CellT] : Ordering, CoefficientT: Fractional] + /** The Chain class is a representation of a formal linear combination of + * the n cells in a cell complex. Note that CellT is a type parameter + * subtype of Cell, a trait in this library. We have Scala look for a type + * parameter of cellOrdering that matches as best as possible an Ordering + * on CellT. + * + * (Note: write a fully fleshed out explanation in comments after code def. + * write up) + * + * @tparam CellT + * Type of the cells in the chain complex. For example + * `AbstractSimplex[Int]` etc. + * @tparam CoefficientT + * Type of the coefficients of the chain complex. For example `Double` or + * an implicit 'FiniteField : Fractional[Int]' + * @param chainMap + * Internal storage of the sorted map of the elements + */ + class ChainElement[CellT <: Cell[CellT]: Ordering, CoefficientT: Fractional] /** chainMap is an immutable variable and constructor that uses Scala's SortedMap to make a key-value pairing of an CellT as the key and a - * CoefficientT type as the value. Here, we'll use the Using keyword to check for any relevant types for CoefficientT. - */ - (val chainMap: SortedMap[CellT, CoefficientT]) - extends Chain[CellT, CoefficientT] { + * CoefficientT type as the value. Here, we'll use the Using keyword to check for any relevant types for CoefficientT. + */ (val chainMap: SortedMap[CellT, CoefficientT]) + extends Chain[CellT, CoefficientT] { // Currently will throw errors around if `chainMap` is empty // TODO: should probably fail more gracefully @@ -85,7 +85,9 @@ package org.appliedtopology.tda4j { chainMap.head override def toString: String = - chainMap.map((k, v) => s"${v.toString} *: ${k.toString}").mkString(" + ") + chainMap + .map((k, v) => s"${v.toString} *: ${k.toString}") + .mkString(" + ") // Define equality between chains. // an override of the equals method from the Any class. @@ -108,24 +110,25 @@ package org.appliedtopology.tda4j { // for first apply: he first `apply` takes a sequence of coefficient/cell pairs and creates a sorted map that fits the constructor to let us create chains that way. /** Both apply() functions assist in constructor execution. - * - * The 1st apply() is used to take Cell/Coefficient pairs, and converts them - * to a sorted map using the Chain chainMap constructor. Why? So it works - * with the constructor, so we can create chains. - * - * Here,the 2nd apply() works as a implicit cast function. Simply, it is used - * to take a cell and transform it to a chain. In depth, the Chain chainMap - * constructor is called to create a new Chain object, as indicated by 'new' - * followed by Chain. The constructor then requires a Cell/Coefficient pair. - * The "List(cell -> fr.one)" creates a list with at least a single key-value - * of a Cell/Coefficient pair ready to be inserted into the chainMap. The key - * will then product the value 1. Why 1? The Chain has to produce at least a - * value of 1. Think of this as the 'base case' for Chain values. - */ - - def apply[CellT <: Cell[CellT] : Ordering, CoefficientT: Fractional]( - items: (CellT, CoefficientT)* - ): ChainElement[CellT, CoefficientT] = + * + * The 1st apply() is used to take Cell/Coefficient pairs, and converts + * them to a sorted map using the Chain chainMap constructor. Why? So it + * works with the constructor, so we can create chains. + * + * Here,the 2nd apply() works as a implicit cast function. Simply, it is + * used to take a cell and transform it to a chain. In depth, the Chain + * chainMap constructor is called to create a new Chain object, as + * indicated by 'new' followed by Chain. The constructor then requires a + * Cell/Coefficient pair. The "List(cell -> fr.one)" creates a list with + * at least a single key-value of a Cell/Coefficient pair ready to be + * inserted into the chainMap. The key will then product the value 1. Why + * 1? The Chain has to produce at least a value of 1. Think of this as + * the 'base case' for Chain values. + */ + + def apply[CellT <: Cell[CellT]: Ordering, CoefficientT: Fractional]( + items: (CellT, CoefficientT)* + ): ChainElement[CellT, CoefficientT] = // Filter out terms with zero coefficients during construction val filteredItems = items.filter { case (_, coefficient) => @@ -136,42 +139,44 @@ package org.appliedtopology.tda4j { // Original apply innards // new Chain[CellT, CoefficientT](SortedMap.from(items)) - def apply[CellT <: Cell[CellT] : Ordering, CoefficientT](cell: CellT)(using - fr: Fractional[CoefficientT] + def apply[CellT <: Cell[CellT]: Ordering, CoefficientT](cell: CellT)(using + fr: Fractional[CoefficientT] ): ChainElement[CellT, CoefficientT] = - new ChainElement[CellT, CoefficientT](SortedMap.from(List(cell -> fr.one))) + new ChainElement[CellT, CoefficientT]( + SortedMap.from(List(cell -> fr.one)) + ) } - class ChainOps[CellT <: Cell[CellT] : Ordering, CoefficientT: Fractional] - extends RingModule[ChainElement[CellT, CoefficientT], CoefficientT] { + class ChainOps[CellT <: Cell[CellT]: Ordering, CoefficientT: Fractional] + extends RingModule[ChainElement[CellT, CoefficientT], CoefficientT] { import Numeric.Implicits._ val zero: ChainElement[CellT, CoefficientT] = ChainElement() def plus( - x: ChainElement[CellT, CoefficientT], - y: ChainElement[CellT, CoefficientT] - ): ChainElement[CellT, CoefficientT] = + x: ChainElement[CellT, CoefficientT], + y: ChainElement[CellT, CoefficientT] + ): ChainElement[CellT, CoefficientT] = ChainElement( (for k <- (x.chainMap.keySet | y.chainMap.keySet) - yield { - val fr = summon[Fractional[CoefficientT]] - val xv: CoefficientT = x.chainMap.getOrElse(k, fr.zero) - val yv: CoefficientT = y.chainMap.getOrElse(k, fr.zero) - k -> fr.plus(xv, yv) - }).toSeq: _* + yield { + val fr = summon[Fractional[CoefficientT]] + val xv: CoefficientT = x.chainMap.getOrElse(k, fr.zero) + val yv: CoefficientT = y.chainMap.getOrElse(k, fr.zero) + k -> fr.plus(xv, yv) + }).toSeq: _* ) def scale( - x: CoefficientT, - y: ChainElement[CellT, CoefficientT] - ): ChainElement[CellT, CoefficientT] = + x: CoefficientT, + y: ChainElement[CellT, CoefficientT] + ): ChainElement[CellT, CoefficientT] = new ChainElement(y.chainMap.transform((k, v) => x * v)) override def negate( - x: ChainElement[CellT, CoefficientT] - ): ChainElement[CellT, CoefficientT] = + x: ChainElement[CellT, CoefficientT] + ): ChainElement[CellT, CoefficientT] = new ChainElement(x.chainMap.transform((k, v) => -v)) } } @@ -183,18 +188,21 @@ package org.appliedtopology.tda4j { import org.appliedtopology.tda4j.mapchain.ChainElement - /** A heap-based chain class. Will delay accumulating and evaluating any actual - * arithmetic for as long as possible. - * - * NOTA BENE: both checking for equality and converting to string will force - * the entire heap while extracting leading terms and cells will only force the - * leading terms and cells. Algebraic operations force nothing: entries are - * just added to the heap without checking for any computations that they - * imply. - */ - class ChainElement[CellT <: Cell[CellT] : Ordering, CoefficientT: Fractional]( - cc: IterableOnce[(CellT, CoefficientT)] - ) extends Chain[CellT, CoefficientT] { + /** A heap-based chain class. Will delay accumulating and evaluating any + * actual arithmetic for as long as possible. + * + * NOTA BENE: both checking for equality and converting to string will + * force the entire heap while extracting leading terms and cells will only + * force the leading terms and cells. Algebraic operations force nothing: + * entries are just added to the heap without checking for any computations + * that they imply. + */ + class ChainElement[ + CellT <: Cell[CellT]: Ordering, + CoefficientT: Fractional + ]( + cc: IterableOnce[(CellT, CoefficientT)] + ) extends Chain[CellT, CoefficientT] { import Numeric.Implicits._ @@ -232,8 +240,8 @@ package org.appliedtopology.tda4j { ) // sum coefficients def mapInPlace( - f: ((CellT, CoefficientT)) => (CellT, CoefficientT) - ): this.type = { + f: ((CellT, CoefficientT)) => (CellT, CoefficientT) + ): this.type = { chainHeap.mapInPlace(f) this } @@ -255,60 +263,61 @@ package org.appliedtopology.tda4j { } object ChainElement { - def from[CellT <: Cell[CellT] : Ordering, CoefficientT: Fractional]( - cc: IterableOnce[(CellT, CoefficientT)] - ) = + def from[CellT <: Cell[CellT]: Ordering, CoefficientT: Fractional]( + cc: IterableOnce[(CellT, CoefficientT)] + ) = new ChainElement(cc) - def apply[CellT <: Cell[CellT] : Ordering, CoefficientT: Fractional]( - cc: IterableOnce[(CellT, CoefficientT)] - ): ChainElement[CellT, CoefficientT] = from(cc) + def apply[CellT <: Cell[CellT]: Ordering, CoefficientT: Fractional]( + cc: IterableOnce[(CellT, CoefficientT)] + ): ChainElement[CellT, CoefficientT] = from(cc) - def apply[CellT <: Cell[CellT] : Ordering, CoefficientT: Fractional]( - cc: (CellT, CoefficientT)* - ): ChainElement[CellT, CoefficientT] = from(cc) + def apply[CellT <: Cell[CellT]: Ordering, CoefficientT: Fractional]( + cc: (CellT, CoefficientT)* + ): ChainElement[CellT, CoefficientT] = from(cc) - def apply[CellT <: Cell[CellT] : Ordering, CoefficientT](c: CellT)(using - fr: Fractional[CoefficientT] + def apply[CellT <: Cell[CellT]: Ordering, CoefficientT](c: CellT)(using + fr: Fractional[CoefficientT] ): ChainElement[CellT, CoefficientT] = from(Seq((c, fr.one))) } - object Chain { - def apply[CellT <: Cell[CellT] : Ordering, CoefficientT: Fractional]( - cc: (CellT, CoefficientT)* - ): Chain[CellT, CoefficientT] = ChainElement(cc: _*) + def apply[CellT <: Cell[CellT]: Ordering, CoefficientT: Fractional]( + cc: (CellT, CoefficientT)* + ): Chain[CellT, CoefficientT] = ChainElement(cc: _*) - def apply[CellT <: Cell[CellT] : Ordering, CoefficientT: Fractional]( - c: CellT - ): Chain[CellT, CoefficientT] = ChainElement(c) + def apply[CellT <: Cell[CellT]: Ordering, CoefficientT: Fractional]( + c: CellT + ): Chain[CellT, CoefficientT] = ChainElement(c) } - class ChainOps[CellT <: Cell[CellT] : Ordering, CoefficientT: Fractional] - extends RingModule[ChainElement[CellT, CoefficientT], CoefficientT] { + class ChainOps[CellT <: Cell[CellT]: Ordering, CoefficientT: Fractional] + extends RingModule[ChainElement[CellT, CoefficientT], CoefficientT] { import Numeric.Implicits._ - override val zero: ChainElement[CellT, CoefficientT] = new ChainElement(Seq()) + override val zero: ChainElement[CellT, CoefficientT] = new ChainElement( + Seq() + ) override def plus( - x: ChainElement[CellT, CoefficientT], - y: ChainElement[CellT, CoefficientT] - ): ChainElement[CellT, CoefficientT] = + x: ChainElement[CellT, CoefficientT], + y: ChainElement[CellT, CoefficientT] + ): ChainElement[CellT, CoefficientT] = ChainElement.from(Iterator.concat(x.chainHeap, y.chainHeap)) override def scale( - x: CoefficientT, - y: ChainElement[CellT, CoefficientT] - ): ChainElement[CellT, CoefficientT] = + x: CoefficientT, + y: ChainElement[CellT, CoefficientT] + ): ChainElement[CellT, CoefficientT] = y.clone().mapInPlace((cell, coeff) => (cell, coeff * x)) override def negate( - x: ChainElement[CellT, CoefficientT] - ): ChainElement[CellT, CoefficientT] = { + x: ChainElement[CellT, CoefficientT] + ): ChainElement[CellT, CoefficientT] = { val fr = summon[Fractional[CoefficientT]] scale(fr.negate(fr.one), x) } } } -} \ No newline at end of file +} diff --git a/src/main/scala/org/appliedtopology/tda4j/package.scala b/src/main/scala/org/appliedtopology/tda4j/package.scala index edcfe997..82d62234 100644 --- a/src/main/scala/org/appliedtopology/tda4j/package.scala +++ b/src/main/scala/org/appliedtopology/tda4j/package.scala @@ -17,6 +17,7 @@ package object tda4j { class TDAContext[VertexT: Ordering, CoefficientT: Fractional] extends ChainOps[AbstractSimplex[VertexT], CoefficientT], SimplexContext[VertexT] { - given Conversion[Simplex, ChainElement[Simplex, CoefficientT]] = ChainElement.apply + given Conversion[Simplex, ChainElement[Simplex, CoefficientT]] = + ChainElement.apply } } diff --git a/src/test/scala/org/appliedtopology/tda4j/ChainSpec.scala b/src/test/scala/org/appliedtopology/tda4j/ChainSpec.scala index 36ad0c78..697ca17c 100644 --- a/src/test/scala/org/appliedtopology/tda4j/ChainSpec.scala +++ b/src/test/scala/org/appliedtopology/tda4j/ChainSpec.scala @@ -173,8 +173,11 @@ class ChainSpec extends mutable.Specification { class HeapChainSpec extends mutable.Specification { given sc: SimplexContext[Int]() import sc.{given, *} - import org.appliedtopology.tda4j.heapchain.{ChainElement as HeapChain, ChainOps as HeapChainOps} - + import org.appliedtopology.tda4j.heapchain.{ + ChainElement as HeapChain, + ChainOps as HeapChainOps + } + "Heap-based chains should" >> { "be created from a sequence" >> { val elts = Seq((s(1, 2), 1.0), (s(1, 3), -1.0)) diff --git a/src/test/scala/org/appliedtopology/tda4j/ProfilingSpec.scala b/src/test/scala/org/appliedtopology/tda4j/ProfilingSpec.scala index 1b276696..0d685c0d 100644 --- a/src/test/scala/org/appliedtopology/tda4j/ProfilingSpec.scala +++ b/src/test/scala/org/appliedtopology/tda4j/ProfilingSpec.scala @@ -13,7 +13,7 @@ class ProfilingSpec(args: Arguments) extends mutable.Specification { val bitlength: Int = args.commandLine.intOr("bitlength", 3) val maxFVal: Double = args.commandLine.doubleOr("maxFVal", 7.0) val maxDim: Int = args.commandLine.intOr("maxDim", 7) - + val symmetry: HyperCubeSymmetry = HyperCubeSymmetry(bitlength) class HyperCubeProfiling( @@ -24,7 +24,8 @@ class ProfilingSpec(args: Arguments) extends mutable.Specification { ) { pp(s"Measuring ${vr.className}") var now: Long = System.currentTimeMillis() - val sstream: Seq[AbstractSimplex[Int]] = vr(symmetry.hypercube, maxFVal, maxDim) + val sstream: Seq[AbstractSimplex[Int]] = + vr(symmetry.hypercube, maxFVal, maxDim) var duration: Long = System.currentTimeMillis() - now pp(s"${tag}\tInitialization: $duration ms") pp(s"${tag}\tSimplex Stream Size: ${sstream.size}") @@ -47,7 +48,7 @@ class ProfilingSpec(args: Arguments) extends mutable.Specification { HyperCubeProfiling(BronKerbosch[Int](), symmetry, bitlength, "BK") }) section("bron-kerbosch") - + section("zomorodian-incremental") ("Zomorodian Incremental" >> { val zi: HyperCubeProfiling =