Skip to content

Commit

Permalink
Lint.
Browse files Browse the repository at this point in the history
  • Loading branch information
Mikael Vejdemo-Johansson committed Apr 26, 2024
1 parent 8b1dce3 commit 40070e1
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 55 deletions.
4 changes: 2 additions & 2 deletions src/main/scala/org/appliedtopology/tda4j/Chain.scala
Expand Up @@ -266,14 +266,14 @@ package org.appliedtopology.tda4j {
*/
def collapseHead(): ChainElement[CellT, CoefficientT] = chainHeap.minimumO match {
case None => this
case Some((headCell,headCoeff)) =>
case Some((headCell, headCoeff)) =>
var acc = headCoeff
var tmpHeap = chainHeap.deleteMin
while (tmpHeap.minimumO.map(_._1) == Some(headCell)) {
acc += tmpHeap.minimum._2
tmpHeap = tmpHeap.deleteMin
}
if(acc != fr.zero) {
if (acc != fr.zero) {
chainHeap = tmpHeap.insert((headCell, acc))
this
} else {
Expand Down
51 changes: 25 additions & 26 deletions src/main/scala/org/appliedtopology/tda4j/Homology.scala
Expand Up @@ -4,7 +4,7 @@ import org.appliedtopology.tda4j.barcode.PersistenceBar

import collection.mutable
import scala.annotation.tailrec
import scalaz.{Ordering => _,_}, Scalaz._
import scalaz.{Ordering => _, _}, Scalaz._

given [T: Ordering]: Ordering[AbstractSimplex[T]] = (new SimplexContext[T] {}).simplexOrdering

Expand All @@ -18,10 +18,10 @@ class SimplicialHomologyContext[VertexT: Ordering, CoefficientT: Fractional]()

case class HomologyState(
cycles: mutable.Map[Simplex, ChainElement[Simplex, CoefficientT]],
cyclesBornBy: mutable.Map[Simplex,Simplex],
cyclesBornBy: mutable.Map[Simplex, Simplex],
boundaries: mutable.Map[Simplex, ChainElement[Simplex, CoefficientT]],
boundariesBornBy: mutable.Map[Simplex, Simplex],
coboundaries: mutable.Map[Simplex, ChainElement[Simplex,CoefficientT]],
coboundaries: mutable.Map[Simplex, ChainElement[Simplex, CoefficientT]],
stream: SimplexStream[VertexT, FiltrationT],
var current: FiltrationT,
barcode: mutable.ArrayDeque[
Expand All @@ -30,28 +30,28 @@ class SimplicialHomologyContext[VertexT: Ordering, CoefficientT: Fractional]()
) {
given Ordering[Simplex] = stream.filtrationOrdering
given Order[Simplex] = Order.fromScalaOrdering(stream.filtrationOrdering)
given Order[(Simplex,CoefficientT)] = Order.orderBy(_._1)
given Order[(Simplex, CoefficientT)] = Order.orderBy(_._1)

val simplexIterator = stream.iterator.buffered
boundaries(Simplex()) = ChainElement(Simplex())

def diagramAt(
f: FiltrationT
): List[(Int, FiltrationT | NegativeInfinity[FiltrationT], FiltrationT | PositiveInfinity[FiltrationT])] = {
f: FiltrationT
): List[(Int, FiltrationT | NegativeInfinity[FiltrationT], FiltrationT | PositiveInfinity[FiltrationT])] = {
advanceTo(f)
(for
(dim, lowerQ, oldUpperQ): (
Int,
FiltrationT | NegativeInfinity[FiltrationT],
FiltrationT | PositiveInfinity[FiltrationT]
) <- barcode.toList
FiltrationT | NegativeInfinity[FiltrationT],
FiltrationT | PositiveInfinity[FiltrationT]
) <- barcode.toList
lower = lowerQ match {
case NegativeInfinity() => Double.NegativeInfinity
case l: Double => l
case l: Double => l
}
oldUpper = oldUpperQ match {
case NegativeInfinity() => Double.NegativeInfinity
case l: Double => l
case l: Double => l
}
if lower <= f
upper = oldUpper.min(f)
Expand All @@ -61,36 +61,35 @@ class SimplicialHomologyContext[VertexT: Ordering, CoefficientT: Fractional]()
dim = sigma.size - 1
lower = stream.filtrationValue(sigma)
yield (dim, lower, Double.PositiveInfinity)
)
)
}

def barcodeAt(f: FiltrationT): List[PersistenceBar[FiltrationT, Nothing]] =
diagramAt(f).map { (dim, l, u) =>
val lower: BarcodeEndpoint[FiltrationT] = l match {
case NegativeInfinity() => NegativeInfinity()
case f: FiltrationT => ClosedEndpoint(f)
case f: FiltrationT => ClosedEndpoint(f)
}
val upper: BarcodeEndpoint[FiltrationT] = u match {
case PositiveInfinity() => PositiveInfinity()
case f: FiltrationT => OpenEndpoint(f)
case f: FiltrationT => OpenEndpoint(f)
}
new PersistenceBar(dim, lower, upper, None)
}

@tailrec
private def reduceBy(
z: ChainElement[Simplex, CoefficientT],
basis: mutable.Map[Simplex, ChainElement[Simplex, CoefficientT]],
reductionLog: ChainElement[Simplex,CoefficientT] = ChainElement()
)(using fr: Fractional[CoefficientT]): (ChainElement[Simplex, CoefficientT], ChainElement[Simplex, CoefficientT]) =
z: ChainElement[Simplex, CoefficientT],
basis: mutable.Map[Simplex, ChainElement[Simplex, CoefficientT]],
reductionLog: ChainElement[Simplex, CoefficientT] = ChainElement()
)(using fr: Fractional[CoefficientT]): (ChainElement[Simplex, CoefficientT], ChainElement[Simplex, CoefficientT]) =
z.leadingCell match {
case None => (z,reductionLog)
case Some(sigma) => {
if(basis.contains(sigma)) {
case None => (z, reductionLog)
case Some(sigma) =>
if (basis.contains(sigma)) {
val redCoeff = fr.div(z.leadingCoefficient, basis(sigma).leadingCoefficient)
reduceBy(z - redCoeff ⊠ basis(sigma), basis, reductionLog + redCoeff ⊠ ChainElement(sigma))
} else (z, reductionLog)
}
}

def advanceOne(): Unit =
Expand All @@ -100,9 +99,9 @@ class SimplicialHomologyContext[VertexT: Ordering, CoefficientT: Fractional]()
val dsigma: ChainElement[Simplex, CoefficientT] =
sigma.boundary[CoefficientT]: ChainElement[Simplex, CoefficientT]
val (dsigmaReduced, reduction) = reduceBy(dsigma, boundaries)
val coboundary = reduction.chainHeap.foldRight(fr.negate(fr.one) ⊠ ChainElement(sigma)) { (next,acc) =>
val (spx,coeff) = next
if(coboundaries.contains(spx))
val coboundary = reduction.chainHeap.foldRight(fr.negate(fr.one) ⊠ ChainElement(sigma)) { (next, acc) =>
val (spx, coeff) = next
if (coboundaries.contains(spx))
acc + coeff ⊠ coboundaries(spx)
else
acc
Expand All @@ -119,7 +118,7 @@ class SimplicialHomologyContext[VertexT: Ordering, CoefficientT: Fractional]()

val (_, cycleBasis) = reduceBy(dsigmaReduced, cycles)
cycleBasis.leadingCell match {
case None => ()
case None => ()
case Some(cell) => cycles.remove(cell)
}

Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/org/appliedtopology/tda4j/RingModule.scala
Expand Up @@ -29,17 +29,17 @@ trait RingModule[T, R] {
def -(rhs: T): T = minus(t, rhs)
@targetName("scalarMultiplyRight")
def <*(rhs: R): T = rmod.scale(rhs, t)
infix def mul(rhs: R): T = rmod.scale(rhs,t)
infix def mul(rhs: R): T = rmod.scale(rhs, t)
def unary_- : T = negate(t)
}

extension (r: R) {
@targetName("scalarMultiplyLeft")
def *>(t: T): T = rmod.scale(r, t)
@targetName("scalarMultiplyLeft2")
def (t:T): T = rmod.scale(r,t) // unicode ⊠ for boxed times
def (t: T): T = rmod.scale(r, t) // unicode ⊠ for boxed times
@targetName("infixScale")
infix def scale(t:T):T = rmod.scale(r,t)
infix def scale(t: T): T = rmod.scale(r, t)
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/org/appliedtopology/tda4j/Simplex.scala
Expand Up @@ -9,7 +9,7 @@ import math.Ordering.Implicits.sortedSetOrdering
trait SimplexContext[VertexT: Ordering] {
type Simplex = AbstractSimplex[VertexT]

given simplexOrdering : Ordering[Simplex] = sortedSetOrdering[AbstractSimplex, VertexT]
given simplexOrdering: Ordering[Simplex] = sortedSetOrdering[AbstractSimplex, VertexT]

object Simplex {
def apply(vertices: VertexT*): Simplex =
Expand Down
16 changes: 8 additions & 8 deletions src/main/scala/org/appliedtopology/tda4j/SimplexStream.scala
Expand Up @@ -19,16 +19,16 @@ trait Filtration[VertexT, FiltrationT: Ordering] {
* We may want to change this to inherit instead from `IterableOnce[AbstractSimplex[VertexT]]`, so that a lazy
* computed simplex stream can be created and fit in the type hierarchy.
*/
trait SimplexStream[VertexT:Ordering, FiltrationT:Ordering]
trait SimplexStream[VertexT: Ordering, FiltrationT: Ordering]
extends Filtration[VertexT, FiltrationT]
with IterableOnce[AbstractSimplex[VertexT]] {
val filtrationOrdering =
FilteredSimplexOrdering[VertexT,FiltrationT](this)(
using vertexOrdering=summon[Ordering[VertexT]])(
using filtrationOrdering=summon[Ordering[FiltrationT]].reverse)
FilteredSimplexOrdering[VertexT, FiltrationT](this)(using vertexOrdering = summon[Ordering[VertexT]])(using
filtrationOrdering = summon[Ordering[FiltrationT]].reverse
)
}

class ExplicitStream[VertexT:Ordering, FiltrationT](
class ExplicitStream[VertexT: Ordering, FiltrationT](
protected val filtrationValues: Map[AbstractSimplex[VertexT], FiltrationT],
protected val simplices: Seq[AbstractSimplex[VertexT]]
)(using ordering: Ordering[FiltrationT])
Expand Down Expand Up @@ -96,7 +96,7 @@ class FilteredSimplexOrdering[VertexT, FiltrationT](
filtrationOrdering: Ordering[FiltrationT]
) extends Ordering[AbstractSimplex[VertexT]] {
def compare(x: AbstractSimplex[VertexT], y: AbstractSimplex[VertexT]): Int = (x, y) match {
case (x, y) if (filtration.filtrationValue.isDefinedAt(x) && filtration.filtrationValue.isDefinedAt(y)) =>
case (x, y) if filtration.filtrationValue.isDefinedAt(x) && filtration.filtrationValue.isDefinedAt(y) =>
filtrationOrdering.compare(filtration.filtrationValue(x), filtration.filtrationValue(y)) match {
case 0 =>
if (Ordering.Int.compare(x.size, y.size) == 0)
Expand All @@ -105,7 +105,7 @@ class FilteredSimplexOrdering[VertexT, FiltrationT](
.compare(x.to(Seq), y.to(Seq))
else
Ordering.Int.compare(x.size, y.size)
case cmp if (cmp != 0) => cmp
case cmp if cmp != 0 => cmp
}
case (x, y) => // at least one does not have a filtration value defined; just go by dimension and lexicographic
if (Ordering.Int.compare(x.size, y.size) == 0)
Expand All @@ -115,4 +115,4 @@ class FilteredSimplexOrdering[VertexT, FiltrationT](
else
Ordering.Int.compare(x.size, y.size)
}
}
}
6 changes: 3 additions & 3 deletions src/test/scala/org/appliedtopology/tda4j/ChainSpec.scala
Expand Up @@ -199,9 +199,9 @@ class HeapChainSpec extends mutable.Specification {
given Conversion[Simplex, HeapChain[Simplex, Double]] = HeapChain.apply
given rm: RingModule[HeapChain[Simplex, Double], Double] = HeapChainOps()
import rm.{given, *}
val z1 : HeapChain[Simplex,Double] = 1.0 ⊠ s(1, 2) + (s(1, 3) mul 2.0) - 1.0 *> s(2, 3) + (5.2 scale s(1,4))
val z2 : HeapChain[Simplex,Double] = 1.0 ⊠ s(1, 2) + 1.0 ⊠ s(2, 3)
val z3 : HeapChain[Simplex,Double] = z2 + (-1.0 ⊠ z2)
val z1: HeapChain[Simplex, Double] = 1.0 ⊠ s(1, 2) + (s(1, 3).mul(2.0)) - 1.0 *> s(2, 3) + (5.2.scale(s(1, 4)))
val z2: HeapChain[Simplex, Double] = 1.0 ⊠ s(1, 2) + 1.0 ⊠ s(2, 3)
val z3: HeapChain[Simplex, Double] = z2 + (-1.0 ⊠ z2)

"subtracts to zero" ==>
(z3.isZero must beTrue)
Expand Down
26 changes: 14 additions & 12 deletions src/test/scala/org/appliedtopology/tda4j/HomologySpec.scala
Expand Up @@ -4,20 +4,22 @@ import org.specs2.mutable
import org.specs2.ScalaCheck

class HomologySpec extends mutable.Specification with ScalaCheck {
given shc : SimplicialHomologyContext[Int,Double]()
import shc.{given,*}
given shc: SimplicialHomologyContext[Int, Double]()
import shc.{given, *}

"Homology of a triangle" >> {
val streamBuilder = ExplicitStreamBuilder[Int,Double]()
streamBuilder.addAll(List(1,2,3).map{i => (0.0,s(i))})
streamBuilder.addAll(List((1.0,s(1,2)),(2.0,s(1,3)),(3.0,s(2,3)),(4.0,s(1,2,3))))
val streamBuilder = ExplicitStreamBuilder[Int, Double]()
streamBuilder.addAll(List(1, 2, 3).map(i => (0.0, s(i))))
streamBuilder.addAll(List((1.0, s(1, 2)), (2.0, s(1, 3)), (3.0, s(2, 3)), (4.0, s(1, 2, 3))))
val stream = streamBuilder.result()
val homology = persistentHomology(stream)
homology.diagramAt(5.0) must containTheSameElementsAs(List(
(0, 0.0, 1.0), // one 0-component dies when 1-2 shows up
(0, 0.0, 2.0), // one 0-component dies when 1-3 shows up
(0, 0.0, Double.PositiveInfinity), // one 0-component lives forever
(1, 3.0, 4.0) // one 1-component created from 2-3 and killed by 1-2-3.
))
homology.diagramAt(5.0) must containTheSameElementsAs(
List(
(0, 0.0, 1.0), // one 0-component dies when 1-2 shows up
(0, 0.0, 2.0), // one 0-component dies when 1-3 shows up
(0, 0.0, Double.PositiveInfinity), // one 0-component lives forever
(1, 3.0, 4.0) // one 1-component created from 2-3 and killed by 1-2-3.
)
)
}
}

0 comments on commit 40070e1

Please sign in to comment.