├── project ├── build.properties └── plugins.sbt ├── .gitignore ├── LICENSE ├── src ├── test │ └── scala │ │ ├── RealmTests.scala │ │ └── MSetTests.scala └── main │ └── scala │ └── mset │ ├── Realm.scala │ └── MSet.scala └── README.md /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.3.9 2 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.github.scalaprops" % "sbt-scalaprops" % "0.2.5") 2 | addSbtPlugin("com.dwijnand" % "sbt-dynver" % "3.0.0") 3 | addSbtPlugin("com.codecommit" % "sbt-github-packages" % "0.5.0") 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .idea_modules 3 | target 4 | project/boot 5 | *.swp 6 | project.vim 7 | tags 8 | .lib 9 | *~ 10 | *# 11 | .DS_Store 12 | .history 13 | .cache 14 | .classpath 15 | .project 16 | .settings 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Rúnar Bjarnason 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /src/test/scala/RealmTests.scala: -------------------------------------------------------------------------------- 1 | package mset 2 | 3 | import scalaprops._ 4 | import scalaprops.Gen._ 5 | import scalaprops.Property._ 6 | import spire.math.Natural 7 | 8 | object RealmTests extends Scalaprops { 9 | import Realm._ 10 | 11 | def realmLaws[A:Gen:Realm](s: String) = Properties.properties(s)( 12 | "commutativity" -> forAll(commutativeLaw[A] _), 13 | "absorption" -> forAll(absorptionLaw[A] _), 14 | "summation" -> forAll(summationLaw[A] _), 15 | "identity" -> forAll(identityLaw[A] _), 16 | "idempotence" -> forAll(idempotentLaw[A] _), 17 | "distributivity" -> forAll(distributiveLaw[A] _), 18 | "associativity" -> forAll(associativeLaw[A] _)) 19 | 20 | def leftMrealmLaws[A:Gen:MRealm](s: String) = Properties.properties(s)( 21 | "left adjoint" -> forAll(leftMonusLaw[A] _) 22 | ) product realmLaws[A](s) 23 | 24 | def rightMrealmLaws[A:Gen:MRealm](s: String) = Properties.properties(s)( 25 | "right adjoint" -> forAll(rightMonusLaw[A] _) 26 | ) product realmLaws[A](s) 27 | 28 | def cancellativeRealmLaws[A:Gen:Realm](s: String) = 29 | Properties.fromProps("cancellative realm", 30 | realmLaws[A](s), 31 | Properties.single("cancellativity", forAll(cancellationLaw[A] _))) 32 | 33 | implicit def genNatural: Gen[Natural] = nonNegativeInt.map(Natural(_)) 34 | 35 | val natural = leftMrealmLaws("natural")(genNatural, NaturalRealm) 36 | val boolean = realmLaws("boolean")(genBoolean, BooleanRealm) 37 | val trivial = realmLaws("trivial")(genUnit, trivialRealm) 38 | val product = realmLaws("product")( 39 | Gen[(Natural, Natural)], 40 | realmProduct[Natural,Natural](NaturalRealm, NaturalRealm)) 41 | 42 | val I = spire.std.int.IntAlgebra 43 | 44 | val gcd = leftMrealmLaws("euclidean")(choose(0,100), euclideanRealm[Int](I,I)) 45 | val set = leftMrealmLaws("set")(setGen[Int], setRealm[Int]) 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/test/scala/MSetTests.scala: -------------------------------------------------------------------------------- 1 | package mset 2 | 3 | import scalaprops._ 4 | import scalaprops.Gen._ 5 | import scalaprops.Property._ 6 | import spire.algebra.AdditiveMonoid 7 | import spire.algebra.Eq 8 | import spire.algebra.PartialOrder 9 | import spire.std.tuples._ 10 | import spire.syntax.all._ 11 | 12 | object MSetTests extends Scalaprops { 13 | 14 | import MSet._ 15 | import Realm._ 16 | 17 | implicit def genMSet[M:Gen:AdditiveMonoid:Eq,A:Gen]: Gen[MSet[M,A]] = 18 | Gen[List[(A,M)]].map(MSet.fromOccurList[M,A]) 19 | 20 | val equality = forAll { (m1: MSet[Int,Int], m2: MSet[Int,Int]) => 21 | (m1 === m2) == 22 | (m1.toSet.forall(x => m1(x) == m2(x)) && 23 | m2.toSet.forall(x => m1(x) == m2(x))) 24 | } 25 | 26 | val sumHomomorphism = forAll { (m1: MSet[Int,Int], m2: MSet[Int,Int]) => 27 | implicit val additive = implicitly[AdditiveMonoid[Int]].additive 28 | 29 | (m1 sum m2).fold(_ * _) == m1.fold(_ * _) + m2.fold(_ * _) 30 | } 31 | 32 | val size = forAll { (xs: List[(Int,Int)]) => 33 | fromOccurList(xs).size == xs.map(_._2).sum 34 | } 35 | 36 | val toList = forAll { (xs: List[Int]) => 37 | MSet.fromSeq[Nat,Int](xs).toList.sorted == xs.sorted 38 | } 39 | 40 | val product = forAll { (m1: MSet[Int,Int], m2: MSet[Int,Int]) => 41 | val p = (m1 product m2).occurList 42 | val as = m1.occurList.toMap 43 | val bs = m2.occurList.toMap 44 | p.forall { 45 | case ((a,b), m) => as(a) * bs(b) == m 46 | } 47 | } 48 | 49 | import RealmTests._ 50 | 51 | val msetRealmLaws = 52 | cancellativeRealmLaws[MSet[Nat,Nat]]("MSet Realm")( 53 | genMSet(genNatural, NaturalRealm, NaturalRealm, genNatural), 54 | msetRealm(NaturalRealm, NaturalRealm)) 55 | 56 | val poInt = PartialOrder[Int] 57 | 58 | val partialOrder = forAll { (m1: MSet[Int, Int], m2: MSet[Int, Int]) => 59 | msetPartialOrder[Int,Int].lteqv(m1, m2) == (m1.toSet ++ m2.toSet).forall { 60 | k => poInt.lteqv(m1(k), m2(k)) 61 | } 62 | } 63 | 64 | // |A + B| = |A| + |B| = |A ∪ B| + |A ∩ B| 65 | val sizeHomomorphism = forAll { (a: MSet[Int,Int], b: MSet[Int,Int]) => 66 | (a sum b).size == (a.size + b.size) && 67 | (a.size + b.size) == (a union b).size + (a intersect b).size && 68 | (a.size * b.size) == (a product b).size 69 | } 70 | 71 | implicit val E = MSet.msetEq[Nat,(Nat,Nat)] 72 | implicit def P[A:Realm,B:Realm] = realmProduct[A,B] 73 | 74 | // Product distributes over realm operations 75 | val productDistributive = forAll { 76 | (a: MSet[Nat,Nat], 77 | b: MSet[Nat,Nat], 78 | c: MSet[Nat,Nat]) => 79 | ((a product (b union c)) === ((a product b) union (a product c))) && 80 | ((a product (b intersect c)) === 81 | ((a product b) intersect (a product c))) && 82 | ((a product (b sum c)) === ((a product b) sum (a product c))) 83 | } 84 | 85 | val differenceHomomorphism = forAll { 86 | (a: MSet[Int,Int], b: MSet[Int,Int], x: Int) => 87 | (a difference b).apply(x) == (a(x) - b(x)) 88 | } 89 | 90 | // This law doesn't quite hold for finite signed integer domains, 91 | // as e.g. the negation of the smallest `Int` is the identity. 92 | val deMorgansLaws = forAll { (ax: MSet[Int,Int], bx: MSet[Int,Int]) => 93 | val a = ax.mapOccurs(_.toLong) 94 | val b = bx.mapOccurs(_.toLong) 95 | ((a.negate intersect b.negate) === (a union b).negate) && 96 | ((a.negate union b.negate) === (a intersect b).negate) 97 | } 98 | 99 | val isEmpty = forAll { (xs: List[Int]) => 100 | MSet.multisetFromSeq(xs).isEmpty == xs.isEmpty 101 | } 102 | 103 | val filter = forAll { (xs: MSet[Int,Int], n: Int) => 104 | !xs.filter(_ != n).contains(n) 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Multisets for Scala 2 | 3 | Based on [_A New Look at Multisets_ by Norman J Wildberger](https://www.researchgate.net/publication/251497534_A_new_look_at_multisets). 4 | 5 | The data structure provided by this library is `MSet`. An `MSet[M,A]` is a multiset of values of type A with multiplicities in M. 6 | 7 | For example, an `MSet[Natural,A]` is a multiset where values of type `A` can have zero or more occurrences. An `MSet[Boolean,A]` is an ordinary set. 8 | 9 | ## Using this library 10 | 11 | To get all the functionality of this library, add the following imports: 12 | 13 | ``` scala 14 | import spire.syntax.all._ 15 | import mset._ 16 | import Realm._ 17 | ``` 18 | 19 | 20 | ## Why this? 21 | 22 | 23 | This type differs from most implementations of multisets in that the multiplicities can be integers (for negative occurrences), rational numbers (for fractional occurrences), intervals and probability distributions (for non-deterministic or "fuzzy" occurrences), or any other type of value. The algebra on that type will determine what operations are available on the `MSet`. In particular, `MSet` provides operations for any type of measure that forms a `Realm`, a type this library also provides: 24 | 25 | ``` scala 26 | trait Realm[A] { 27 | def meet(x: A, y: A): A 28 | def join(x: A, y: A): A 29 | def sum(x: A, y: A): A 30 | def zero: A 31 | } 32 | ``` 33 | 34 | Notably, `MSet[M,A]` forms a `Realm` for any `Realm[M]`. 35 | 36 | A `Realm[A]` is a distributive lattice on `A` (through `meet` and `join`), and a commutative monoid (on `sum` and `zero`). Realms must obey the following laws (where `∧` is `meet`, `∨` is `join`, `+` is `sum` and `0` is `zero`): 37 | 38 | ### Commutative laws 39 | 40 | ``` scala 41 | m + n ≡ n + m 42 | m ∨ n ≡ n ∨ m 43 | m ∧ n ≡ n ∧ m 44 | ``` 45 | 46 | ### Associative laws 47 | 48 | ``` scala 49 | k + (m + n) ≡ (k + m) + n 50 | k ∨ (m ∨ n) ≡ (k ∨ m) ∨ n 51 | k ∧ (m ∧ n) ≡ (k ∧ m) ∧ n 52 | ``` 53 | 54 | ### Distributive laws 55 | 56 | ``` scala 57 | k + (m ∨ n) ≡ (k + m) ∨ (k + n) 58 | k + (m ∧ n) ≡ (k + m) ∧ (k + n) 59 | k ∧ (m ∨ n) ≡ (k ∧ m) ∨ (k ∧ n) 60 | k ∨ (m ∧ n) ≡ (k ∨ m) ∧ (k ∨ n) 61 | ``` 62 | 63 | ### Identity laws 64 | 65 | ``` 66 | 0 + m ≡ m 67 | 0 ∨ m ≡ m 68 | 0 ∧ m ≡ 0 69 | ``` 70 | 71 | ### Absorption laws 72 | 73 | ``` scala 74 | m ∨ (m ∧ n) ≡ m 75 | m ∧ (m ∨ n) ≡ m 76 | ``` 77 | 78 | ### Idempotent laws 79 | 80 | ``` scala 81 | m ∨ m ≡ m 82 | m ∧ m ≡ m 83 | ``` 84 | 85 | ### Summation law 86 | 87 | ``` scala 88 | (m ∨ n) + (m ∧ n) ≡ m + n 89 | ``` 90 | 91 | ### Partial order 92 | 93 | `Realm` extends `spire.algebra.Order` because any join semilattice 94 | defines an order: 95 | 96 | ``` scala 97 | m ≤ n ≡ m ∨ n = n 98 | ``` 99 | 100 | ### Cancellative law 101 | 102 | Some realms may additionally obey a cancellation law, and we call 103 | these _cancellative realms_: 104 | 105 | ``` scala 106 | (k + n = m + n) ⇒ (k = m) 107 | ``` 108 | 109 | ### Products and inverses 110 | 111 | Two `Realm` subtypes with products are also provided which are `RigRealm` (realms with products) and `RingRealm` (realms with products and additive inverses). 112 | 113 | A well-behaved realm with products requires products to distribute over the realm operations: 114 | 115 | ``` scala 116 | a * (b ∨ c) ≡ (a * b) ∨ (a * c) 117 | a * (b ∧ c) ≡ (a * b) ∧ (a * c) 118 | a * (b + c) ≡ (a * b) + (a * c) 119 | ``` 120 | 121 | A realm with inverses must obey a De Morgan law: 122 | 123 | ``` scala 124 | ¬(a ∨ b) ≡ (¬a) ∧ (¬b) 125 | ¬(a ∧ b) ≡ (¬a) ∨ (¬b) 126 | ``` 127 | 128 | ### M-Realms and monus 129 | 130 | An `MRealm` is a realm with a partial additive inverse called `monus` or `∸`. Every `RingRealm` is an `MRealm`, where the monus happens to be exact. A monus operation 131 | is a kind of _truncated_ or _residuated_ subtraction. 132 | 133 | The monus must be left adjoint to the addition: 134 | 135 | ``` scala 136 | a ∸ b ≤ c ≡ a ≤ b + c 137 | ``` 138 | 139 | In terms of the `meet` and `join`, that means: 140 | 141 | ``` scala 142 | a ∧ (b + (a ∸ b)) ≡ a 143 | ((b + c) ∸ b) ∨ c ≡ c 144 | ``` 145 | 146 | That is, `monus(a,b)` is the smallest object which when added to `b` is at 147 | least `a`. 148 | 149 | Examples of monus operations include truncated subtraction on natural numbers, the quotient operation on integers, and the difference operation on sets and multisets. 150 | 151 | -------------------------------------------------------------------------------- /src/main/scala/mset/Realm.scala: -------------------------------------------------------------------------------- 1 | package mset 2 | 3 | import spire.std.BooleanStructure 4 | import spire.std.IntAlgebra 5 | import spire.std.LongAlgebra 6 | import spire.std.boolean.BooleanStructure 7 | import spire.std.int.IntAlgebra 8 | import spire.std.long.LongAlgebra 9 | import algebra.lattice.DistributiveLattice 10 | import algebra.lattice.{JoinSemilatticeFunctions, MeetSemilatticeFunctions} 11 | import spire.algebra.Eq 12 | import spire.algebra.EuclideanRing 13 | import spire.algebra.Rig 14 | import spire.algebra.Ring 15 | import cats.kernel.PartialOrderFunctions 16 | import scala.language.higherKinds 17 | import spire.math.NaturalAlgebra 18 | import algebra.ring._ 19 | import algebra.Monoid 20 | import cats.kernel.PartialOrder 21 | import spire.syntax.all._ 22 | 23 | /** 24 | * A realm is an additive monoid and a distributive lattice, 25 | * satisfying the following: 26 | * 27 | * == Commutative laws == 28 | * 29 | * {{{ 30 | * m + n ≡ n + m 31 | * m ∨ n ≡ n ∨ m 32 | * m ∧ n ≡ n p m 33 | * }}} 34 | * 35 | * == Associative laws == 36 | * 37 | * {{{ 38 | * k + (m + n) ≡ (k + m) + n 39 | * k ∨ (m ∨ n) ≡ (k ∨ m) ∨ n 40 | * k ∧ (m ∧ n) ≡ (k ∧ m) ∧ n 41 | * }}} 42 | * 43 | * == Distributive laws == 44 | * 45 | * {{{ 46 | * k + (m ∨ n) ≡ (k + m) ∨ (k + n) 47 | * k + (m ∧ n) ≡ (k + m) ∧ (k + n) 48 | * k ∧ (m ∨ n) ≡ (k ∧ m) ∨ (k ∧ n) 49 | * k ∨ (m ∧ n) ≡ (k ∨ m) ∧ (k ∨ n) 50 | * }}} 51 | * 52 | * == Identity laws == 53 | * 54 | * {{{ 55 | * zero + m ≡ m 56 | * zero ∨ m ≡ m 57 | * zero ∧ m ≡ mempty 58 | * }}} 59 | * 60 | * == Absorption laws == 61 | * 62 | * {{{ 63 | * m ∨ (m ∧ n) ≡ m 64 | * m ∧ (m ∨ n) ≡ m 65 | * }}} 66 | * 67 | * Idempotent laws 68 | * 69 | * {{{ 70 | * m ∨ m ≡ m 71 | * m ∧ m ≡ m 72 | * }}} 73 | * 74 | * Summation law 75 | * 76 | * {{{ 77 | * (m ∨ n) + (m ∧ n) ≡ m + n 78 | * }}} 79 | * 80 | * Some realms may additionally obey a cancellation law, and we call 81 | * these cancellative realms: 82 | * 83 | * {{{ 84 | * (k + n = m + n) => (k = m) 85 | * }}} 86 | * 87 | * [[Realm]] extends `PartialOrder` because any join semilattice 88 | * defines a partial order: 89 | * 90 | * {{{ 91 | * m ≤ n ≡ m ∨ n = n 92 | * }}} 93 | * 94 | */ 95 | trait Realm[A] 96 | extends AdditiveCommutativeMonoid[A] 97 | with DistributiveLattice[A] 98 | with PartialOrder[A] { self: Eq[A] => 99 | private implicit val A: Eq[A] = self 100 | 101 | // a ≤ b ≡ a ∨ b = b 102 | def partialCompare(a: A, b: A) = { 103 | val j = join(a,b) 104 | if (j === b) 105 | if (j === a) 0 106 | else -1 107 | else if (j === a) 1 108 | else Double.NaN 109 | } 110 | 111 | /** The join semilattice of this realm, with identity. */ 112 | val joinMonoid: Monoid[A] = new Monoid[A] { 113 | def combine(x: A, y: A): A = join(x, y) 114 | def empty = zero 115 | } 116 | 117 | import Realm.Tropical 118 | 119 | val tropical: Tropical[A] = 120 | new AdditiveCommutativeSemigroup[A] 121 | with MultiplicativeCommutativeMonoid[A] { 122 | def plus(x: A, y: A): A = self.join(x, y) 123 | def times(x: A, y: A): A = self.plus(x, y) 124 | def one: A = self.zero 125 | } 126 | } 127 | 128 | /** 129 | * A well-behaved [[Realm]] that has products will allow such products to 130 | * distribute over the realm operations: 131 | * 132 | * {{{ 133 | * a * (b ∨ c) ≡ (a * b) ∨ (a * c) 134 | * a * (b ∧ c) ≡ (a * b) ∧ (a * c) 135 | * a * (b + c) ≡ (a * b) + (a * c) 136 | * }}} 137 | */ 138 | trait RigRealm[A] extends Realm[A] with Rig[A] 139 | with MultiplicativeMonoid[A] { self: Eq[A] => 140 | 141 | import Realm.Tropical 142 | 143 | override val tropical: Tropical[A] = 144 | new AdditiveCommutativeSemigroup[A] 145 | with MultiplicativeCommutativeMonoid[A] { 146 | def plus(x: A, y: A): A = self.join(x, y) 147 | def times(x: A, y: A): A = self.plus(x, y) 148 | def one: A = self.zero 149 | def pow(x: A, y: A): A = self.times(x, y) 150 | } 151 | } 152 | 153 | /** 154 | * A [[Realm]] with inverses will obey a De Morgan law: 155 | * 156 | * {{{ 157 | * -(a ∨ b) ≡ (-a) ∧ (-b) 158 | * -(a ∧ b) ≡ (-a) ∨ (-b) 159 | * }}} 160 | */ 161 | trait RingRealm[A] extends MRealm[A] with RigRealm[A] with Ring[A] 162 | with AdditiveCommutativeGroup[A] { self: Eq[A] => 163 | def monus(x: A, y: A): A = minus(x, y) 164 | 165 | import Realm.TropicalField 166 | 167 | val tropicalField: TropicalField[A] = 168 | new AdditiveCommutativeSemigroup[A] 169 | with MultiplicativeCommutativeGroup[A] { 170 | def plus(x: A, y: A): A = self.join(x, y) 171 | def times(x: A, y: A): A = self.plus(x, y) 172 | def one: A = self.zero 173 | def pow(x: A, y: A): A = self.times(x, y) 174 | def div(x: A, y: A): A = self.minus(x, y) 175 | } 176 | } 177 | 178 | /** 179 | * An [[MRealm]] is a realm equipped with a monus operator, sometimes written 180 | * with the symbol `∸`. 181 | * 182 | * The monus `a ∸ b` is the smallest `c` such that `a ≤ b + c`. In other words, 183 | * it is left adjoint to the commutative monoid operator `+`. 184 | */ 185 | trait MRealm[A] extends Realm[A] { self: Eq[A] => 186 | def monus(x: A, y: A): A 187 | } 188 | 189 | trait RealmFunctions[R[T] <: Realm[T]] extends PartialOrderFunctions[R] 190 | with AdditiveMonoidFunctions[R] 191 | with JoinSemilatticeFunctions[R] 192 | with MeetSemilatticeFunctions[R] { 193 | 194 | /** 195 | * A tropical calculus is an additive semigroup with a multiplicative monoid. 196 | * Tropical addition satisfies an idempotent property: 197 | * 198 | * {{{ 199 | * x + x ≡ x 200 | * }}} 201 | * 202 | * There is no operation of subtraction, but a value `x` is considered 203 | * "positive" if `x + 0 = x` and "negative" if `x + 0 = 0`. 204 | */ 205 | type Tropical[A] = 206 | AdditiveCommutativeSemigroup[A] with MultiplicativeCommutativeMonoid[A] 207 | 208 | type TropicalField[A] = 209 | AdditiveCommutativeSemigroup[A] with MultiplicativeCommutativeGroup[A] 210 | } 211 | 212 | trait RigRealmFunctions[R[T] <: RigRealm[T]] extends RealmFunctions[R] 213 | with MultiplicativeMonoidFunctions[R] { 214 | } 215 | 216 | trait RingRealmFunctions[R[T] <: RingRealm[T]] extends RigRealmFunctions[R] 217 | with AdditiveGroupFunctions[R] { 218 | } 219 | 220 | object RigRealm extends RigRealmFunctions[RigRealm] { 221 | @inline final def apply[A](implicit ev: RigRealm[A]): RigRealm[A] = ev 222 | } 223 | 224 | object RingRealm extends RingRealmFunctions[RingRealm] { 225 | @inline final def apply[A](implicit ev: RingRealm[A]): RingRealm[A] = ev 226 | } 227 | 228 | object Realm extends RealmFunctions[Realm] { 229 | 230 | @inline final def apply[A](implicit ev: Realm[A]): Realm[A] = ev 231 | 232 | def realm[A:AdditiveCommutativeMonoid:DistributiveLattice:Eq] = { 233 | val L = DistributiveLattice[A] 234 | val M = AdditiveMonoid[A] 235 | new Realm[A] { 236 | def meet(a: A, b: A) = L.meet(a,b) 237 | def join(a: A, b: A) = L.join(a,b) 238 | def plus(a: A, b: A) = { 239 | M.plus(a,b) 240 | } 241 | def zero = M.zero 242 | } 243 | } 244 | 245 | def rigRealm[A:AdditiveCommutativeMonoid 246 | :MultiplicativeMonoid 247 | :DistributiveLattice 248 | :Eq] = { 249 | val L = DistributiveLattice[A] 250 | val M = AdditiveMonoid[A] 251 | val S = MultiplicativeMonoid[A] 252 | new RigRealm[A] { 253 | def meet(a: A, b: A) = L.meet(a,b) 254 | def join(a: A, b: A) = L.join(a,b) 255 | def plus(a: A, b: A) = M.plus(a,b) 256 | def zero = M.zero 257 | def one = S.one 258 | def times(a: A, b: A) = S.times(a,b) 259 | } 260 | } 261 | 262 | def ringRealm[A:AdditiveGroup 263 | :MultiplicativeMonoid 264 | :DistributiveLattice 265 | :Eq] = { 266 | val L = DistributiveLattice[A] 267 | val M = AdditiveGroup[A] 268 | val S = MultiplicativeMonoid[A] 269 | new RingRealm[A] { 270 | def meet(a: A, b: A) = L.meet(a,b) 271 | def join(a: A, b: A) = L.join(a,b) 272 | def plus(a: A, b: A) = M.plus(a,b) 273 | def zero = M.zero 274 | def one = S.one 275 | def times(a: A, b: A) = S.times(a,b) 276 | def negate(a: A) = M.negate(a) 277 | } 278 | } 279 | 280 | type Nat = spire.math.Natural 281 | val natAlgebra = spire.math.Natural.NaturalAlgebra 282 | 283 | trait NaturalLattice extends DistributiveLattice[Nat] { 284 | def meet(a: Nat, b: Nat) = natAlgebra.min(a,b) 285 | def join(a: Nat, b: Nat) = natAlgebra.max(a,b) 286 | } 287 | 288 | /** Natural numbers with addition form a realm that has products. */ 289 | implicit object NaturalRealm extends NaturalAlgebra 290 | with MRealm[Nat] with RigRealm[Nat] with NaturalLattice { 291 | override def partialCompare(x: Nat, y: Nat) = 292 | natAlgebra.compare(x, y) 293 | def monus(x: Nat, y: Nat) = if (x <= y) zero else x - y 294 | } 295 | 296 | /** The Int min/max lattice. */ 297 | trait IntLattice extends DistributiveLattice[Int] { 298 | def meet(a: Int, b: Int) = (a:scala.runtime.RichInt) min b 299 | def join(a: Int, b: Int) = (a:scala.runtime.RichInt) max b 300 | } 301 | 302 | /** The Long integer min/max lattice. */ 303 | trait LongLattice extends DistributiveLattice[Long] { 304 | def meet(a: Long, b: Long) = (a:scala.runtime.RichLong) min b 305 | def join(a: Long, b: Long) = (a:scala.runtime.RichLong) max b 306 | } 307 | 308 | /** Integers with addition form a realm that has products and inverses. */ 309 | implicit object IntRealm extends IntAlgebra with RingRealm[Int] with IntLattice { 310 | override def partialCompare(x: Int, y: Int) = 311 | IntAlgebra.compare(x, y) 312 | } 313 | 314 | /** Integers with addition form a realm that has products and inverses. */ 315 | implicit object LongRealm extends LongAlgebra 316 | with RingRealm[Long] with LongLattice { 317 | override def partialCompare(x: Long, y: Long) = 318 | LongAlgebra.compare(x, y) 319 | } 320 | 321 | /** Booleans with disjunction form a realm with products and inverses. */ 322 | implicit object BooleanRealm extends BooleanStructure with RingRealm[Boolean] { 323 | override def partialCompare(x: Boolean, y: Boolean) = 324 | BooleanStructure.compare(x, y) 325 | def negate(x: Boolean): Boolean = !x 326 | } 327 | 328 | /** The trivial realm. */ 329 | implicit val trivialRealm: RingRealm[Unit] = 330 | new RingRealm[Unit] { 331 | def meet(a: Unit, b: Unit) = () 332 | def join(a: Unit, b: Unit) = () 333 | def plus(a: Unit, b: Unit) = () 334 | def zero = () 335 | def one = () 336 | def times(a: Unit, b: Unit) = () 337 | def negate(a: Unit) = () 338 | override def eqv(a: Unit, b: Unit) = true 339 | } 340 | 341 | /** Realms are closed under products. */ 342 | def realmProduct[A:Realm,B:Realm]: Realm[(A,B)] = new Realm[(A,B)] { 343 | def meet(a: (A,B), b: (A,B)) = 344 | (Realm[A].meet(a._1, b._1), Realm[B].meet(a._2, b._2)) 345 | def join(a: (A,B), b: (A,B)) = 346 | (Realm[A].join(a._1, b._1), Realm[B].join(a._2, b._2)) 347 | def plus(a: (A,B), b: (A,B)) = 348 | (Realm[A].plus(a._1, b._1), Realm[B].plus(a._2, b._2)) 349 | def zero = (Realm[A].zero, Realm[B].zero) 350 | override def eqv(a: (A,B), b: (A,B)) = a._1 === b._1 && a._2 === b._2 351 | } 352 | 353 | /** Realms are closed under products. */ 354 | def rigRealmProduct[A:RigRealm,B:RigRealm]: RigRealm[(A,B)] = { 355 | val R: Realm[(A,B)] = realmProduct[A,B] 356 | new RigRealm[(A,B)] { 357 | def meet(a: (A,B), b: (A,B)) = R.meet(a,b) 358 | def join(a: (A,B), b: (A,B)) = R.join(a,b) 359 | def plus(a: (A,B), b: (A,B)) = R.plus(a,b) 360 | def zero = R.zero 361 | def one = (RigRealm[A].one, RigRealm[B].one) 362 | def times(a: (A,B), b: (A,B)) = 363 | (RigRealm[A].times(a._1, b._1), RigRealm[B].times(a._2, b._2)) 364 | override def eqv(a: (A,B), b: (A,B)) = a._1 === b._1 && a._2 === b._2 365 | } 366 | } 367 | 368 | /** Realms are closed under products. */ 369 | def ringRealmProduct[A:RingRealm,B:RingRealm]: RingRealm[(A,B)] = { 370 | val R: RigRealm[(A,B)] = rigRealmProduct[A,B] 371 | new RingRealm[(A,B)] { 372 | def meet(a: (A,B), b: (A,B)) = R.meet(a,b) 373 | def join(a: (A,B), b: (A,B)) = R.join(a,b) 374 | def plus(a: (A,B), b: (A,B)) = R.plus(a,b) 375 | def zero = R.zero 376 | def one = R.one 377 | def times(a: (A,B), b: (A,B)) = R.times(a,b) 378 | def negate(a: (A,B)) = 379 | (RingRealm[A].negate(a._1), RingRealm[B].negate(a._2)) 380 | override def eqv(a: (A,B), b: (A,B)) = a._1 === b._1 && a._2 === b._2 381 | } 382 | } 383 | 384 | /** 385 | * Algebras with multiplication and division sometimes form a realm 386 | * with GCD and LCM as meet and join, respectively. E.g. the positive 387 | * rationals and probability distributions are realms in this way. 388 | * 389 | * The multiplication has a monus, which removes common prime factors. 390 | */ 391 | def euclideanRealm[A:EuclideanRing:Eq]: MRealm[A] = new MRealm[A] { 392 | val A = EuclideanRing[A] 393 | def meet(a: A, b: A) = A.gcd(a,b) 394 | def join(a: A, b: A) = A.lcm(a,b) 395 | def plus(a: A, b: A) = A.times(a,b) 396 | def zero = A.one 397 | def monus(a: A, b: A) = A.equot(a, A.gcd(a,b)) 398 | override def eqv(a: A, b: A) = Eq[A].eqv(a,b) 399 | } 400 | 401 | /** 402 | * The realm of sets is a specialization of the realm of MSets with 403 | * the measures fixed to `Boolean`. 404 | */ 405 | def setRealm[A]: MRealm[Set[A]] = new MRealm[Set[A]] { 406 | def meet(a: Set[A], b: Set[A]) = a intersect b 407 | def join(a: Set[A], b: Set[A]) = a union b 408 | def plus(a: Set[A], b: Set[A]) = a union b 409 | def zero = Set.empty[A] 410 | def monus(a: Set[A], b: Set[A]) = a diff b 411 | override def eqv(a: Set[A], b: Set[A]) = a == b 412 | } 413 | 414 | def commutativeLaw[A:Realm](a: A, b: A): Boolean = 415 | ((a + b) === (b + a)) && 416 | ((a ∧ b) === (b ∧ a)) && 417 | ((a ∨ b) === (b ∨ a)) 418 | 419 | def associativeLaw[A:Realm](a: A, b: A, c: A): Boolean = 420 | ((a + (b + c)) === ((a + b) + c)) && 421 | ((a ∨ (b ∨ c)) === ((a ∨ b) ∨ c)) && 422 | ((a ∧ (b ∧ c)) === ((a ∧ b) ∧ c)) 423 | 424 | def distributiveLaw[A:Realm](a: A, b: A, c: A): Boolean = 425 | ((a + (b ∨ c)) === ((a + b) ∨ (a + c))) && 426 | ((a + (b ∧ c)) === ((a + b) ∧ (a + c))) && 427 | ((a ∧ (b ∨ c)) === ((a ∧ b) ∨ (a ∧ c))) && 428 | ((a ∨ (b ∧ c)) === ((a ∨ b) ∧ (a ∨ c))) 429 | 430 | def identityLaw[A:Realm](a: A): Boolean = 431 | ((Realm[A].zero + a) === a) && 432 | ((Realm[A].zero ∧ a) === Realm[A].zero) && 433 | ((Realm[A].zero ∨ a) === a) 434 | 435 | def absorptionLaw[A:Realm](a: A, b: A): Boolean = 436 | (a ∨ (a ∧ b)) === a && (a ∧ (a ∨ b)) === a 437 | 438 | def idempotentLaw[A:Realm](a: A): Boolean = 439 | (a ∧ a) === a && (a ∨ a) === a 440 | 441 | def summationLaw[A:Realm](a: A, b: A): Boolean = 442 | (a ∨ b) + (a ∧ b) === a + b 443 | 444 | def cancellationLaw[A:Realm](a: A, b: A, c: A): Boolean = 445 | (a + c =!= b + c) || a === b 446 | 447 | def leftMonusLaw[A:MRealm](a: A, b: A, c: A): Boolean = 448 | implicitly[MRealm[A]].monus(a, b) <= c == (a <= b + c) 449 | 450 | def rightMonusLaw[A:MRealm](a: A, b: A, c: A): Boolean = 451 | implicitly[MRealm[A]].monus(a, b) >= c == (a >= b + c) 452 | } 453 | -------------------------------------------------------------------------------- /src/main/scala/mset/MSet.scala: -------------------------------------------------------------------------------- 1 | package mset 2 | 3 | import cats.Applicative 4 | import cats.Monad 5 | import spire.std.map._ 6 | import spire.algebra.AdditiveGroup 7 | import spire.algebra.AdditiveMonoid 8 | import spire.algebra.Eq 9 | import spire.algebra.Monoid 10 | import spire.algebra.MultiplicativeMonoid 11 | import spire.algebra.MultiplicativeSemigroup 12 | import spire.algebra.PartialOrder 13 | import spire.algebra.Ring 14 | import spire.algebra.lattice.JoinSemilattice 15 | import spire.algebra.lattice.MeetSemilattice 16 | import spire.math._ 17 | import spire.syntax.all._ 18 | import scala.language.higherKinds 19 | 20 | /** 21 | * An MSet[M,A] is a multiset of values of type A with multiplicities in M. 22 | * 23 | * Whereas in a regular Set a given element occurs either zero times or once, 24 | * in an MSet an element can have multiple occurrences, fractional occurrences, 25 | * or the occurrence can be a negative number, an interval, a probability 26 | * distribution, or any other type of value. 27 | * 28 | * Based on "A new look at multisets" by Norman J Wildberger. 29 | */ 30 | class MSet[M, A](private val rep: Map[A, M]) extends AnyVal { 31 | 32 | import MSet._ 33 | 34 | override def toString = "MSet(" + rep.toString + ")" 35 | 36 | /** 37 | * An mset `m1` is smaller than an mset `m2` if for every `x`, there are fewer 38 | * occurrences of `x` in `m1` than in `m2`. 39 | */ 40 | def <(other: MSet[M,A])(implicit O: PartialOrder[M], M: AdditiveMonoid[M]) = 41 | msetPartialOrder[M,A].lt(this, other) 42 | 43 | /** 44 | * An mset `m1` is "at most" `m2` if for every `x`, there are no more 45 | * occurrences of `x` in `m1` than there are in `m2`. 46 | */ 47 | def <=(other: MSet[M,A])(implicit O: PartialOrder[M], M: AdditiveMonoid[M]) = 48 | msetPartialOrder[M,A].lteqv(this, other) 49 | 50 | /** 51 | * An mset `m1` is greater than an mset `m2` if for every `x`, there are more 52 | * occurrences of `x` in `m1` than there are in `m2`. 53 | */ 54 | def >(other: MSet[M,A])(implicit O: PartialOrder[M], M: AdditiveMonoid[M]) = 55 | msetPartialOrder[M,A].gt(this, other) 56 | 57 | /** 58 | * An mset `m1` is "at least" `m2` if for every `x`, there are at least as 59 | * many occurrences of `x` in `m1` as there are in `m2`. 60 | */ 61 | def >=(other: MSet[M,A])(implicit O: PartialOrder[M], M: AdditiveMonoid[M]) = 62 | msetPartialOrder[M,A].gteqv(this, other) 63 | 64 | /** Get the occurrence list of this MSet */ 65 | def occurList(implicit M: AdditiveMonoid[M]): List[(A, M)] = rep.toList 66 | 67 | def toMap: Map[A, M] = rep 68 | 69 | /** Get the values of this MSet as a Set */ 70 | def toSet: Set[A] = rep.keySet 71 | 72 | /** 73 | * Get the list of values in this MSet. Only defined if the measure `M` is 74 | * isomorphic to the natural numbers. That is, if this mset is a Multiset. 75 | */ 76 | def toList(implicit E: MSet[M, A] =:= Multiset[A]): List[A] = 77 | E(this).foldLeft(List[A]()) { 78 | case (as, (a, m)) => List.fill(m.toInt)(a) ++ as 79 | } 80 | 81 | /** Check if the given predicate holds for all elements of this [[MSet]]. */ 82 | def forall(p: (A, M) => Boolean): Boolean = rep.forall(p.tupled) 83 | 84 | /** 85 | * Get the multiplicity of a given object in this [[MSet]]. 86 | * Alias for [[multiplicity]]. 87 | */ 88 | def apply(a: A)(implicit M: AdditiveMonoid[M]): M = 89 | rep get a getOrElse M.zero 90 | 91 | /** 92 | * Get the multiplicity of a given object in this [[MSet]]. 93 | * Alias for [[apply]]. 94 | */ 95 | def multiplicity(a: A)(implicit M: AdditiveMonoid[M]): M = apply(a) 96 | 97 | /** An object occurs in the MSet if its multiplicity is nonzero */ 98 | def contains(a: A)(implicit E: Eq[M], M: AdditiveMonoid[M]): Boolean = 99 | !apply(a).isZero 100 | 101 | /** 102 | * `a` is from `b` when every element of `a` also occurs in `b`. 103 | * This relation forms a partial order on `MSet`s. 104 | */ 105 | def isFrom(m: MSet[M, A])(implicit E: Eq[M], M: AdditiveMonoid[M]): Boolean = 106 | forall((a, _) => m contains a) 107 | 108 | /** Fold an `MSet` with a monoid */ 109 | def fold[B](f: (A, M) => B)(implicit B: Monoid[B]): B = 110 | foldLeft(B.empty) { case (b, (a, m)) => b |+| f(a, m) } 111 | 112 | def foldLeft[B](z: B)(f: (B, (A, M)) => B): B = 113 | rep.foldLeft(z)(f) 114 | 115 | def foldRight[B](z: B)(f: ((A, M), B) => B): B = 116 | rep.foldRight(z)(f) 117 | 118 | /** 119 | * Find all the elements that match a given predicate. 120 | */ 121 | def filter(f: A => Boolean)(implicit N: MRealm[M], E: Eq[M]): MSet[M, A] = 122 | foldRight(this) { 123 | case ((a, _), r) => if (f(a)) r else r deleteAll a 124 | } 125 | 126 | /** Insert one occurrence of an object into this MSet */ 127 | def insert(a: A)(implicit M: MultiplicativeMonoid[M], 128 | S: AdditiveMonoid[M], 129 | E: Eq[M]): MSet[M, A] = 130 | sum(singleton[M, A](a)) 131 | 132 | /** Insert n occurrences of an object into this MSet */ 133 | def insertN(a: A, n: M)(implicit S: AdditiveMonoid[M], E: Eq[M]): MSet[M, A] = 134 | if (n === S.zero) this 135 | else { 136 | implicit val additive = S.additive 137 | new MSet(MapMonoid[A, M].combine(rep, Map(a -> n))) 138 | } 139 | 140 | /** Delete an occurrence of an object from this MSet */ 141 | def delete(a: A)(implicit N: MRealm[M], 142 | M: MultiplicativeMonoid[M], 143 | E: Eq[M]): MSet[M, A] = 144 | difference(singleton[M, A](a)) 145 | 146 | /** Delete all occurrences of an object from this MSet */ 147 | def deleteAll(a: A)(implicit N: MRealm[M], E: Eq[M]): MSet[M, A] = 148 | difference(MSet.fromOccurList(List(a -> multiplicity(a)))) 149 | 150 | /** The size of an MSet is the sum of its multiplicities. */ 151 | def size(implicit M: AdditiveMonoid[M]): M = { 152 | implicit val additive = M.additive 153 | fold((_, m) => m) 154 | } 155 | 156 | /** Modify the occurrences of elements by a function. */ 157 | def mapOccurs[N: Eq](f: M => N)(implicit N: AdditiveMonoid[N]): MSet[N, A] = 158 | new MSet(rep.view.mapValues(f).toMap) 159 | 160 | /** Scale this MSet by a value. */ 161 | def scale(n: M)(implicit M: MultiplicativeSemigroup[M], 162 | N: AdditiveMonoid[M], 163 | E: Eq[M]): MSet[M, A] = mapOccurs(_ * n) 164 | 165 | /** 166 | * Pass the elements of this MSet to the given function and return the 167 | * results as an MSet. 168 | */ 169 | def map[B](f: A => B)(implicit S: MultiplicativeMonoid[M], 170 | M: AdditiveMonoid[M], 171 | E: Eq[M]): MSet[M, B] = { 172 | implicit val additive = M.additive 173 | fold((a, m) => MSet.singleton[M, B](f(a)).scale(m)) 174 | } 175 | 176 | /** 177 | * Pass the elements of this MSet to the given function and collect all 178 | * resulting MSets in one MSet. 179 | */ 180 | def flatMap[B](f: A => MSet[M, B])(implicit S: MultiplicativeSemigroup[M], 181 | M: AdditiveMonoid[M], 182 | E: Eq[M]): MSet[M, B] = { 183 | implicit val additive = M.additive 184 | fold((a, m) => f(a) scale m) 185 | } 186 | 187 | /** 188 | * Union one MSet with another. Also called the "direct sum" of the 189 | * two multisets. 190 | */ 191 | def sum(m: MSet[M, A])(implicit M: AdditiveMonoid[M], 192 | E: Eq[M]): MSet[M, A] = { 193 | implicit val additive = M.additive 194 | new MSet(rep |+| m.rep) 195 | } 196 | 197 | /** 198 | * Negate all the occurrences in this MSet. 199 | * This introduces the idea of a negative multiset. 200 | */ 201 | def negate(implicit M: AdditiveGroup[M], E: Eq[M]): MSet[M, A] = 202 | mapOccurs(M.negate) 203 | 204 | /** 205 | * Subtract one MSet from another. For any `x`, the multiplicity 206 | * `(a difference b)(x)` will be `a(x) - b(x)`. 207 | * 208 | * For example, if `A = [2 3 3 1 1]` and `B = [3 3 3 1]`, 209 | * then `A difference B = [2 1]`. 210 | */ 211 | def difference(m: MSet[M, A])(implicit M: MRealm[M], E: Eq[M]): MSet[M, A] = 212 | new MSet(m.foldLeft(rep) { 213 | case (r, (a, m)) => 214 | val newm = M.monus(multiplicity(a), m) 215 | if (newm === M.zero) r - a else r + (a -> newm) 216 | }) 217 | 218 | /** 219 | * Set theoretic difference. Intersects before subtracting. Not functoral, 220 | * and doesn't obey any interesting laws, but is included here as it's a 221 | * common operation on multisets. 222 | * 223 | * For example, if `A = [2 3 3 1 1]` and `B = [3 3 3 1]`, 224 | * then `A setDifference B = [1]`. 225 | */ 226 | def setDifference(m: MSet[M, A])(implicit M: MRealm[M], 227 | E: Eq[M]): MSet[M, A] = 228 | difference(intersect(m)) 229 | 230 | /** 231 | * The direct product of two MSets. The multiplicity of `(a,b)` in the 232 | * result will be the product of the multiplicities of `a` and `b` in 233 | * the inputs. 234 | * 235 | * For example, if `A = [1 3 1]` and `B = [2 3]`, 236 | * then `A product B = [(1,2) (1,2) (1,3) (1,3) (3,2) (3,3)]`. 237 | */ 238 | def product[B](m: MSet[M, B])(implicit M: AdditiveMonoid[M], 239 | S: MultiplicativeMonoid[M], 240 | E: Eq[M]): MSet[M, (A, B)] = 241 | productBy(m)((_, _)) 242 | 243 | /** 244 | * A product of two MSets. In the product of msets `m` and `n`, the 245 | * multiplicity of `f(m(a),n(b))` in the result will be the product of 246 | * `m(a)` and `n(b)`, the multiplicities of `a` and `b` in `m` and `n`, 247 | * respectively. 248 | * 249 | * For example, if `A = [1 3 1]` and `B = [2 3]`, 250 | * then `A.productBy(B)(_ + _) = [3 3 4 4 5 6]`. 251 | */ 252 | def productBy[B, C](m: MSet[M, B])(f: (A, B) => C)( 253 | implicit M: AdditiveMonoid[M], 254 | S: MultiplicativeMonoid[M], 255 | E: Eq[M]): MSet[M, C] = 256 | for { 257 | a <- this 258 | b <- m 259 | } yield f(a, b) 260 | 261 | /** 262 | * The union of two MSets. The multiplicity of an element in the result 263 | * will be the join (usually this means the max) of that element in the 264 | * two inputs. 265 | * 266 | * For example, if `A = [2 3 1 1]` and `B = [1 3 3 1 1]`, 267 | * then `A union B = [2 3 3 1 1 1]`. 268 | */ 269 | def union(m: MSet[M, A])(implicit L: JoinSemilattice[M], 270 | M: AdditiveMonoid[M], 271 | E: Eq[M]): MSet[M, A] = { 272 | val ks = toSet ++ m.toSet 273 | ks.foldLeft(empty[M, A]) { (nm, k) => 274 | nm.insertN(k, multiplicity(k) join m(k)) 275 | } 276 | } 277 | 278 | /** 279 | * The intersection of two `MSet`s. The multiplicity of an element in the 280 | * result will be the meet (usually this means the min) of that element in 281 | * the two inputs. 282 | * 283 | * For example, if `A = [2 3 1 1]` and `B = [1 3 3 1 1]`, 284 | * then `A intersect B = [3 1 1]`. 285 | */ 286 | def intersect(m: MSet[M, A])(implicit L: MeetSemilattice[M], 287 | M: AdditiveMonoid[M], 288 | E: Eq[M]): MSet[M, A] = { 289 | // This is not set-theoretic intersection. 290 | // We need to consider all the keys, as some multiplicities may be 291 | // negative. 292 | val ks = toSet ++ m.toSet 293 | ks.foldLeft(empty[M, A]) { (nm, k) => 294 | nm.insertN(k, multiplicity(k) meet m(k)) 295 | } 296 | } 297 | 298 | private def normal(implicit E: Eq[M], M: AdditiveMonoid[M]): MSet[M, A] = 299 | new MSet(rep.filter { case (_, m) => m =!= M.zero }) 300 | 301 | /** An mset is empty if for all m:M, multiplicity of m is zero. */ 302 | def isEmpty(implicit M: AdditiveMonoid[M], E: Eq[M]): Boolean = 303 | normal.rep.isEmpty 304 | 305 | /** 306 | * Given a function which has an effect, thread the effect through applying 307 | * this function on all the values in this mset, collecting the results in 308 | * an mset in the context of the effect. 309 | * 310 | * Only defined if the measure `M` is isomorphic to the natural numbers, 311 | * that is if this mset is a Multiset. 312 | */ 313 | def traverse[F[_]: Applicative, B](f: A => F[B])( 314 | implicit E: MSet[M, A] =:= Multiset[A]): F[Multiset[B]] = { 315 | def iterate[A](a: A, n: Int)(f: A => A): A = 316 | if (n < 1) a 317 | else { 318 | val x = f(a) 319 | iterate(x, n - 1)(f) 320 | } 321 | val F = Applicative[F] 322 | E(this).foldLeft(F.pure(empty[Natural, B])) { 323 | case (acc, (a, m)) => 324 | iterate(acc, m.toInt)( 325 | Applicative[F].map2(_, f(a))((x, y) => x insert y)) 326 | } 327 | } 328 | 329 | } 330 | 331 | object MSet { 332 | 333 | def apply[A,M](elements: (A, M)*): MSet[M,A] = new MSet(Map(elements :_*)) 334 | 335 | type Multiset[A] = MSet[Natural, A] 336 | type RatBag[A] = MSet[Rational, A] 337 | type IntBag[A] = MSet[Int, A] 338 | 339 | implicit def msetEq[M: Eq: AdditiveMonoid, A: Eq]: Eq[MSet[M, A]] = 340 | new Eq[MSet[M, A]] { 341 | def eqv(a: MSet[M, A], b: MSet[M, A]) = 342 | a.rep == b.rep 343 | } 344 | 345 | implicit def msetMonoid[M: AdditiveMonoid: Eq, A] 346 | : AdditiveMonoid[MSet[M, A]] = 347 | new AdditiveMonoid[MSet[M, A]] { 348 | def plus(a: MSet[M, A], b: MSet[M, A]) = a sum b 349 | val zero = MSet.empty[M, A] 350 | } 351 | 352 | implicit def msetAdditive[M: AdditiveMonoid: Eq, A]: Monoid[MSet[M, A]] = 353 | msetMonoid[M, A].additive 354 | 355 | implicit def msetMonad[M: MultiplicativeMonoid: AdditiveMonoid: Eq] = 356 | new Monad[MSet[M, ?]] { 357 | override def pure[A](a: A) = empty[M, A] insert a 358 | override def flatMap[A, B](m: MSet[M, A])(f: A => MSet[M, B]) = 359 | m flatMap f 360 | override def tailRecM[A, B](a: A)(f: A => MSet[M, Either[A, B]]) = { 361 | @annotation.tailrec 362 | def go(remain: List[(Either[A, B], M)], acc: MSet[M, B]): MSet[M, B] = 363 | remain match { 364 | case Nil => acc 365 | case (Right(b), m) :: t => go(t, acc.insertN(b, m)) 366 | case (Left(a), m) :: t => go(f(a).occurList, acc) 367 | } 368 | go(f(a).occurList, empty[M, B]) 369 | } 370 | } 371 | 372 | /** Turn an occurrence list into an MSet */ 373 | def fromOccurList[M, A](xs: List[(A, M)])(implicit M: AdditiveMonoid[M], 374 | E: Eq[M]): MSet[M, A] = { 375 | implicit val additive = M.additive 376 | new MSet(xs.foldLeft(Map.empty: Map[A, M]) { 377 | case (s, (a, m)) if (M.zero =!= m) => s |+| Map(a -> m) 378 | case (s, _) => s 379 | }) 380 | } 381 | 382 | def fromSeq[M: MultiplicativeMonoid: AdditiveMonoid: Eq, A]( 383 | s: Seq[A]): MSet[M, A] = 384 | s.foldLeft(empty[M, A])(_ insert _) 385 | 386 | /** Turn a sequence of elements into a multiset */ 387 | def multisetFromSeq[A](s: Seq[A]): Multiset[A] = fromSeq(s) 388 | 389 | /** The empty mset */ 390 | def empty[M, A]: MSet[M, A] = new MSet(Map.empty) 391 | 392 | /** The empty multiset */ 393 | def emptyMultiset[A]: Multiset[A] = empty[Natural, A] 394 | 395 | /** The empty rational multiset */ 396 | def emptyRatBag[A]: RatBag[A] = empty[Rational, A] 397 | 398 | /** Construct an mset where the given element occurs once */ 399 | def singleton[M, A](a: A)(implicit M: MultiplicativeMonoid[M]): MSet[M, A] = 400 | new MSet(Map(a -> M.one)) 401 | 402 | def msetRealm[M: Realm, A: Eq]: Realm[MSet[M, A]] = 403 | new Realm[MSet[M, A]] { 404 | def join(a: MSet[M, A], b: MSet[M, A]) = a union b 405 | def meet(a: MSet[M, A], b: MSet[M, A]) = a intersect b 406 | val zero = empty[M, A] 407 | def plus(a: MSet[M, A], b: MSet[M, A]) = a sum b 408 | override def eqv(a: MSet[M, A], b: MSet[M, A]) = a === b 409 | } 410 | 411 | def msetGroup[M: Ring: Eq, A]: AdditiveGroup[MSet[M, A]] = 412 | new AdditiveGroup[MSet[M, A]] { 413 | def plus(a: MSet[M, A], b: MSet[M, A]) = a sum b 414 | def zero = MSet.empty[M, A] 415 | def negate(a: MSet[M, A]) = a.negate 416 | } 417 | 418 | def msetPartialOrder[M: PartialOrder: AdditiveMonoid, A] 419 | : PartialOrder[MSet[M, A]] = 420 | new PartialOrder[MSet[M, A]] { 421 | val P = PartialOrder[M] 422 | def partialCompare(x: MSet[M, A], y: MSet[M, A]): Double = { 423 | // The atrocities we commit for performance 424 | var these = x.toSet ++ y.toSet 425 | var sofar = 0.0 426 | while (!these.isEmpty) { 427 | val k = these.head 428 | these = these.tail 429 | val p = P.partialCompare(x(k), y(k)) 430 | if (sofar == 0.0) sofar = p 431 | else if (p.isNaN || p.sign != sofar.sign) return Double.NaN 432 | } 433 | sofar 434 | } 435 | } 436 | 437 | } 438 | 439 | object Multiset { 440 | import MSet.Multiset 441 | def apply[A](as: A*): Multiset[A] = MSet.fromSeq(as) 442 | 443 | def empty[A]: Multiset[A] = MSet.empty[Natural, A] 444 | 445 | /** 446 | * The power-multiset containing all sub-msets of the given mset, equivalent 447 | * to the mset generated from the powerlist of the occurrence list. Contains 448 | * every combination of elements from this mset, where an object is counted 449 | * as an element as many times as it occurs in this mset. 450 | * 451 | * For example, the `powerMSet` of the mset `[1->2, 2->1]` is 452 | * 453 | * {{{ 454 | * [[]->1, [1->1]->2, [1->2]->1, [2->1]->1, [1->1,2->1]->2, [1->2,2->1]->1] 455 | * }}} 456 | */ 457 | def powerMSet[A](m: Multiset[A]): Multiset[Multiset[A]] = 458 | MSet.fromSeq( 459 | m.occurList 460 | .foldRight(List(List[(A, Natural)]())) { 461 | case ((x, n), ps) => 462 | ps ++ (for { 463 | m <- ps 464 | k <- List.range(Natural.one + 0, n + 1) 465 | p <- List 466 | .range(Natural.zero + 0, choose(n.longValue, k.toLong)) 467 | .map(_ => List(x -> Natural(k))) 468 | } yield p ++ m) 469 | } 470 | .map { case xs => MSet.fromOccurList(xs) }) 471 | 472 | } 473 | --------------------------------------------------------------------------------