Comments (14)
Personally, I would prefer Abelian.
Commutes is very colloquial within the math circles & that's fine too.
So have a marker trait Abelian. ( no val's etc. just a trait )
All cyclic groups will necessarily extend Abelian.
By default, groups aren't going to be abelian, so they won't extend it. No need for this isCommutative, isNotCommutative, CommutativeStatus etc.
from algebird.
I think @krishnanraman is right here. add trait Abelian
and mix it in to the appropriate monoids. This works, for example:
trait Abelian
trait Monoid[T] {
def zero: T
def plus(l: T, r: T): T
}
class StringMonoid extends Monoid[String] {
def zero = ""
def plus(l: String, r: String) = l + r
}
class IntMonoid extends Monoid[Int] with Abelian {
def zero = 0
def plus(l: Int, r: Int) = l + r
}
object Monoid {
implicit val int: Monoid[Int] = new IntMonoid
implicit val string: Monoid[String] = new StringMonoid
def commutes[T](implicit m: Monoid[T]) =
m match {
case _: Abelian => true
case _ => false
}
def plus[T](l: T, r: T)(implicit m: Monoid[T]) = {
if (commutes[T])
m.plus(r, l)
else
m.plus(l, r)
}
}
from algebird.
Perhaps now is a good time to add Oscar's Movember challenge problem into Algebird. https://gist.github.com/krishnanraman/4166029
That code defines "a" cyclic group of order n ( all cyclic groups are abelian ), with a specified zero.
( Note: Abelian groups aren't unique, which is why the "a", not "the". As I recall, there was some $50 movember bet about coding up Cayley tables for a cyclic group.)
from algebird.
I strongly prefer "Commutative" rather than "Abelian". The term "Abelian" is ordinarily reserved for groups - commutative semigroups and monoids are just called "Commutative Semigroups" and "Commutative Monoids". (e.g., Grillet: http://www.amazon.com/Commutative-Semigroups-Advances-Mathematics-Grillet/dp/1441948570/ref=sr_1_1?ie=UTF8&qid=1361313759&sr=8-1&keywords=grillet+semigroups)
To me, it would seem incredibly odd to say "extends Monoid[T] with Abelian". I think the most natural approach is something like the following:
class MyMonoid extends Monoid[T] with CommutativeSemigroup { /* ... */ }
where CommutativeSemigroup is a marker trait:
trait CommutativeSemigroup
the reason for calling it CommutativeSemigroup rather than Commutative is that we also (presumably) want commutative ring support. Thus Ring becomes
trait Ring[T] extends Group[T] with CommutativeSemigroup
(the additive group of a ring is always Abelian)
and another marker trait
trait CommutativeRing
identifies commutative multiplication operations. (and of course Fields are always CommutativeRings.)
Here's another proposal, which I think has a lot to recommend it: a whole range of marker traits in the expected hierarchy:
trait CommutativeSemigroup[T] extends Semigroup[T]
trait CommutativeMonoid[T] extends Monoid[T] with CommutativeSemigroup[T]
trait AbelianGroup[T] extends Group[T] with CommutativeMonoid[T]
trait Ring[T] extends AbelianGroup[T] { /* Ring body is just as before */ }
trait CommutativeRing[T] extends Ring[T]
trait Field[T] extends CommutativeRing[T] { /* Field body is just as before */ }
Then I can write
class MyMonoid[T] extends CommutativeMonoid[T] { /* My implementation */ }
which is quite natural.
I like the other ideas in Sam's comment, which are interchangeable with either proposal suggested here.
from algebird.
Btw, I should add that the proposed IsNotCommutative trait doesn't sit well with me at all. Monoids that lack inverses for their elements aren't (and shouldn't be) tagged with an IsNotGroup trait... and in general it seems cumbersome to annotate structures with tags for properties that they lack. The benefit of IsNotCommutative is to facility the CommutativeStatus pattern, which I don't like either - I really think tagging traits are the way to go.
The only disadvantage (relative to CommutativeStatus) is that we lose the ability to define structures that have some (but not all) commutative instances. But I think such cases are best handled hierarchically anyway... in my view we should take advantage of the fact that scala makes it easy to do this the right way.
from algebird.
case class Zn(order:Int, zero:Int) extends Abelian {
def identity = zero
def size = order
def elements = (1 to order).toSeq
def cayley = {
Vector.tabulate(order,order)((x,y)=> {
val idx = math.abs(zero - (x+1)) // difference between x & zero
val timesToShift = if ((x+1)>=zero) idx else (order-idx)
val row = shift(elements, timesToShift )
row(y)
})
}
private def shift(s:Seq[Int], pos:Int) = {
val n = 1+s.indexOf(pos)
s.slice(n,s.size)++s.slice(0,n)
}
def plus(x:Int, y:Int) = cayley(x-1)(y-1)
def inverse(x:Int) = cayley(x-1).indexOf(zero)+1
}
Works as advertised. Please cut-n-paste in repl & play with it. eg. On group of order 7 with 5 as zero, 1+1 = 4, and the inverse of 1 is 2.
scala> Zn(7,5)
res9: Zn = Zn(7,5)
scala> res9.plus(1,1)
res10: Int = 4
scala> res9.inverse(1)
res11: Int = 2
from algebird.
Regarding type-class vs. marker trait, I vote for the marker trait. Here's the pros and cons of using the marker trait as I see it:
pros: simple and our usage is consistent with marker-trait pattern
cons: it's not a type class, so if someone hasn't already defined FooMonoid as Commutative it could be pain. But our type hierarchy is shallow and we could add the marker trait throughout Algebird all at once pretty easily. Also, all checking for commutative must be done statically via type system (although, that could be considered a pro...)
Also, what do Albanians have to do with Monoids?
from algebird.
This is coming up in summingbird and I think we need to get something done.
The problem with a trait is that it doesn't recurse. For instance, Semigroup[Map[K, V]]
is Commutative if Semigroup[V]
is. With the typeclass approach, we can capture this, without, I don't know how to.
from algebird.
We have the money, we have the technology. Let's do this.
What are the reservations with the typeclass approach? More boilerplate? It seems like it more cleanly encapsulates the idea without baking things in, though @mikegagnon is correct in that the type hierarchy isn't so deep.
from algebird.
We should pick this up. I think @asiegel34's approach is the best one here (though I still think might suggest just CommutativeGroup instead of Abelian for consistency).
While we are at it, I'd go ahead and add Rng
and Rig
for the cases without identity and negation respectively. Then
trait Rng[T] extends Group[T] {
def times(l: T, r: T): T
}
trait Rig[T] extends Monoid[T] {
def times(l: T, r: T)
def one: T
}
trait Ring[T] extends Rng[T] with Rig[T] with CommutativeGroup[T]
// useful in concurrent/distributed settings:
// http://en.wikipedia.org/wiki/Semilattice
// idempotent commutative semigroup is a semilattice (e.g. max, min)
trait Semilattice[T] extends CommutativeSemigroup[T]
// zero is either the smallest or largest item depending on if this is a meet or join semilattice.
trait BoundedSemilattice[T] extends CommutativeMonoid[T]
from algebird.
+1 to @asiegel34's approach, as well as Rng, Rig, etc. We might as well express as much as we can in the type hierarchy.
from algebird.
https://github.com/non/algebra is strugging with this same issue right now, we might want to make sure to coordinate. (Sounds like they're ending up with isCommutative
instead).
from algebird.
Actually Avi, I think algebra has both runtime and compile time info. Which is good I think (you can always check the type so runtime is always open to you).
I am 90% in favor of using algebra, but I would like to see a more rigorous policy for how code gets in.
from algebird.
@johnynek , I propose that we close this since we're adopting shared typeclasses soon.
from algebird.
Related Issues (20)
- Release cadance of algebrid, next planned release? HOT 5
- Scala 3 support? HOT 7
- microsite is failing CI because it depends on a very old ruby
- Release v.0.13.10 HOT 1
- SketchMap is not commutative
- `MinHasher32` tests are flaky
- Idea: BloomFilterAggregator can directly rely on a BitSet instead of a BFMonoid
- use fast immutable bitset for better bloom filter HOT 6
- The GeneratedTupleAggregator is not recognized HOT 2
- Add combinators on Semigroup, Monoid, Aggregator to reverse order. HOT 1
- flakey test: downsiding HLL to 4 bits HOT 1
- investigate flaky test on AdaptiveVector
- Latest version published with `-optimize` HOT 1
- configure mergify.io HOT 1
- H
- Investigate flaky `com.twitter.algebird.CollectionSpecification` test HOT 8
- Possible buffer overflow for lengths over 127. Why are you doing .toByte in order to represent an integer size of 4 bytes? For example item length of 184 will result in -72 and thus in NegativeArraySize Exception when deserializing in fromBytes : 94. HOT 1
- Possible buffer overflow for lengths over 127. HOT 4
- SparseVector monoid flake
- New release? HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from algebird.