Summary of structures in abstract algebra consisting of:
- a Set S
- binary operation * that are total (so they form a Magma).
Algebraic structure | associativity | identity | invertibility | commutativity | idempotency |
---|---|---|---|---|---|
Semigroup | associativity | ||||
Commutative semigroup | associativity | commutativity | |||
Inverse semigroup | associativity | invertibility | |||
Monoid | associativity | identity | |||
Commutative Monoid | associativity | identity | commutativity | ||
Group | associativity | identity | invertibility | ||
Abelian Group | associativity | identity | invertibility | commutativity | |
Band | associativity | idempotency | |||
Semilattice | associativity | commutativity | idempotency | ||
Bounded semilattice | associativity | identity | commutativity | idempotency |
Properties of operation
property | definition |
---|---|
closure (totality) | x * y belongs to S |
associativity | x * (y * z) = (x * y) * z |
identity | x * id = id * x = x |
invertibility | x * x' = x' * x = id |
commutativity | x * y = y * x |
idempotency | x * x = x |
Abstract over associative operation combine
on some proper type A.
trait Semigroup[A] {
def combine(x: A, y: => A): A // |+| mappend <>
}
-
Semigroup Law - associativity:
((x |+| y) |+| z) == (x |+| (y |+| z))
-
Derived methods:
def combineN(a: A, n: Int): A // multiply1
def combineAllOption(as: TraversableOnce[A]): Option[A]
-
Semigroup can be defined for:
- containers like List, Vector, Nel with concatenation
- numeric types like Short/Int/Long/BigInteger with + or *
- Strings with string concatenation
-
Examples how to define alternative Semigroup instances for Option, Int with * and usage. Examples for usage of derived methods and combine (src)
-
Implementations: Cats Scalaz 7, Scalaz 8, twitter/algebird, zio-prelude, Haskell, Racket algebraic, Java
-
Resources:
- herding cats - Semigroup (blog post)
- Cats docs
- Scalaz example
Semigroup where operation is commutative
trait CommutativeSemigroup[A] extends Semigroup[A] {
def combine(x: A, y: => A): A // |+| mappend
}
- laws:
- associativity:
((x |+| y) |+| z) == (x |+| (y |+| z))
- commutativity:
(x |+| y) == (y |+| x)
- associativity:
Abstract over associative operation combine
that have default value empty
.
trait Monoid[A] extends Semigroup[A] {
def combine(x: A, y: => A): A // |+| mappend
def empty: A // mempty
}
-
Monoid Laws
- associativity:
((x |+| y) |+| z) == (x |+| (y |+| z))
- right identity:
(x |+| empty) == x
- left identity:
(empty |+| x) == x
- associativity:
-
Derived methods:
def combineAll(as: TraversableOnce[A]): A
-
Monoid can be defined for List (with list concatenation, Nil), Vector, Int with +, Strings with string concatenation. NEL is Semigroup but not a Monoid, same with non empty Strings :)
-
We can create Monoid for any Semigroup by wrapping it in Option (None is empty value) same with Map
-
It is possible to provide additional structure to Monoid (but not as much as in Group). Such monoids (ReductiveMonoid, CancellativeMonoid, GCDMonoid) are implemented in monoid-subclasses in Haskell described in paper Adding Structure to Monoids by Mario Blaževic
-
We can joint two monoids into tuple of monoids.
-
Implementations: Cats, Scalaz, Scalaz 8, Racket algebraic, Java functionaljava Java DataFixerUpper
-
Resources:
- FSiS 4 - Semigroup, Monoid, and Foldable type classes - Michael Pilquist video 23:02
- herding cats - Monoid (blog post)
- Cats docs
- twitter/algebird src docs
- (Haskell) base/Data-Monoid
- (Haskell) Monoids, theme and variations - Brent Yorgey (video) (paper)
- (Haskell) https://byorgey.wordpress.com/2011/04/18/monoids-for-maybe/
- (Haskell) http://blog.sigfpe.com/2009/01/haskell-monoids-and-their-uses.html
- (Haskell) https://apfelmus.nfshost.com/articles/monoid-fingertree.html
- On Monoids - Rúnar Bjarnason (blog post)
Function f between two monoids A, B that preserve the structure of monoid:
f(A.empty) == B.empty
f(A.combine(a1,a2)) == B.compine( f(a1), f(a2) )
For example size and Monoid - list with concatenation and integers with addition.
- Resources:
Monoid where operation is commutative
trait CommutativeMonoid[A] extends Monoid[A] with CommutativeSemigroup[A] {
def combine(x: A, y: => A): A // |+| mappend
def empty: A // mempty
}
-
laws:
- associativity:
((x |+| y) |+| z) == (x |+| (y |+| z))
- right identity:
(x |+| empty) == x
- left identity:
(empty |+| x) == x
- commutativity:
(x |+| y) == (y |+| x)
- associativity:
-
Resources
Semigroup where element with it's inverse don't produce neutral element but produce sth that behaves like one.
trait RegularSemigroup[A] extends Monoid[A] {
def combine(x: A, y: => A): A // |+| mappend <>
def inverse(a: A): A
}
-
laws:
- associativity:
((x |+| y) |+| z) == (x |+| (y |+| z))
- pseudoinverse 1:
x |+| -x |+| x == x
- pseudoinverse 2:
-x |+| x |+| -x == -x
- associativity:
-
there could be multiple inverse elements (in group there is only one inverse)
-
x |+| -x is idempotent, because (x |+| -x) |+| (x |+| -x) == (x |+| -x |+| x) |+| -x == x |+| -x
-
Resources:
- Haskell Live-Coding, Session 4.1, Regular and Inverse Semigroups - Edward Kmett video
Semigroup (or regular semigroup) in which every element has unique inverse. Other definition: Semigroup in which every element has at least one inverse and all indempotent elements commute.
trait InverseSemigroup[A] extends RegularSemigroup[A] {
def combine(x: A, y: => A): A // |+| mappend <>
def inverse(a: A): A
}
-
laws:
- associativity:
((x |+| y) |+| z) == (x |+| (y |+| z))
- pseudoinverse 1:
x |+| -x |+| x == x
- pseudoinverse 2:
-x |+| x |+| -x == -x
- pseudoinverse is unique
- associativity:
-
Resources:
- Haskell Live-Coding, Session 4.1, Regular and Inverse Semigroups - Edward Kmett video
Monoid where each element has an inverse
trait Group[A] extends Monoid[A] {
def combine(x: A, y: => A): A // |+| mappend <>
def empty: A // mempty
def inverse(a: A): A
}
-
laws:
- associativity:
((x |+| y) |+| z) == (x |+| (y |+| z))
- right identity:
(x |+| empty) == x
- left identity:
(empty |+| x) == x
- inverse:
(x |+| -x) == (-x |+| x) == empty
- associativity:
-
derived methods:
def remove(a: A, b: A): A = combine(a, inverse(b))
- Resources:
- (Cats Group src) (laws)
- twitter/algebird Group src docs
- (Haskell) monoids Data.Group
Group where operation |+| is commutative
trait CommutativeGroup[A] extends Group[A] with CommutativeMonoid[A] {
def combine(x: A, y: => A): A // |+| mappend
def empty: A // mempty
def inverse(a: A): A
}
-
laws:
- associativity:
((x |+| y) |+| z) == (x |+| (y |+| z))
- right identity:
(x |+| empty) == x
- left identity:
(empty |+| x) == x
- inverse:
(x |+| -x) == (-x |+| x) == empty
- commutativity:
(x |+| y) == (y |+| x)
- associativity:
-
Resources:
- Cats src laws
- (Haskell) algebra/Numeric.Additive Abelian
Semigroup whose operation is also idempotent
trait Band[A] extends Semigroup[A] {
def combine(x: A, y: => A): A // |+| mappend
}
-
laws:
- associativity:
((x |+| y) |+| z) == (x |+| (y |+| z))
- idempotent:
(x |+| x) == x
- associativity:
-
Resources:
type of band | additional law |
---|---|
left zero band | x + y == x |
right zero band | x + y == y |
rectangular band | x + y + x == x |
normal band | z + x + y + z == z + y + x + z |
left-regular band | x + y + x == x + y |
right-regular band | x + y + x == y + x |
regular bands | z + x + z + y + z == z + x + y + z |
Semilattice is commutative semigroup whose operation is also idempotent.
trait Semilattice[A] extends Band[A] with CommutativeSemigroup[A] {
def combine(x: A, y: => A): A // |+| mappend
}
- laws:
- associativity:
((x |+| y) |+| z) == (x |+| (y |+| z))
- commutativity:
(x |+| y) == (y |+| x)
- idempotent:
(x |+| x) == x
- associativity:
Sometimes (in typelevel/algebra) there are two definitions of Semilattice:
A meet-semilattice (or lower semilattice) is a semilattice whose operation is called "meet", and which can be thought of as a greatest lower bound.
trait MeetSemilattice[A] {
def meet(lhs: A, rhs: A): A
}
and a join-semilattice (or upper semilattice) is a semilattice whose operation is called "join", and which can be thought of as a least upper bound
trait JoinSemilattice[A] {
def join(lhs: A, rhs: A): A
}
- Resources:
Semilattice that has identity or Commutative Monoid that idempotent.
trait BoundedSemilattice[A] extends Semilattice[A] with CommutativeMonoid[A] {
def combine(x: A, y: => A): A // |+| mappend
def empty: A // mempty
}
- laws:
- associativity:
((x |+| y) |+| z) == (x |+| (y |+| z))
- right identity:
(x |+| empty) == x
- left identity:
(empty |+| x) == x
- commutativity:
(x |+| y) == (y |+| x)
- idempotent:
(x |+| x) == x
- associativity:
Similar as with Semilattice definition we can define Bounded Join Semilattice and Bounded Meet Semilattice
trait BoundedJoinSemilattice[A] extends JoinSemilattice[A] {
def join(lhs: A, rhs: A): A
def zero: A
}
trait BoundedMeetSemilattice[A] extends MeetSemilattice[A] {
def meet(lhs: A, rhs: A): A
def one: A
}
- Resources:
Has two associativity, commutativity and idempotent operations: join and meet that obey absorption law:
trait Lattice[A] extends JoinSemilattice[A] with MeetSemilattice[A] {
def join(lhs: A, rhs: A): A
def meet(lhs: A, rhs: A): A
}
-
laws:
- associativity:
(x join y) join z) == (x join (y join z))
- commutativity:
(x join y) == (y join x)
- idempotent:
(x join x) == x
- associativity:
(x meet y) meet z) == (x meet (y meet z))
- commutativity:
(x meet y) == (y meet x)
- idempotent:
(x meet x) == x
- absorption:
a meet (a join b) == a join (a meet b) == a
- associativity:
Lattice that obey distributive law
trait DistributiveLattice[A] extends Lattice[A] {
def join(lhs: A, rhs: A): A
def meet(lhs: A, rhs: A): A
}
-
laws:
- associativity:
(x join y) join z) == (x join (y join z))
- commutativity:
(x join y) == (y join x)
- idempotent:
(x join x) == x
- associativity:
(x meet y) meet z) == (x meet (y meet z))
- commutativity:
(x meet y) == (y meet x)
- idempotent:
(x meet x) == x
- absorption:
a meet (a join b) == a join (a meet b) == a
- distributive:
a meet (b join c) == (a meet b) join (a meet c)
- distributive:
a join (b meet c) == (a join b) meet (a join c)
- associativity:
trait BoundedLattice[A] extends Lattice[A] with BoundedMeetSemilattice[A] with BoundedJoinSemilattice[A] {
def join(lhs: A, rhs: A): A
def zero: A
def meet(lhs: A, rhs: A): A
def one: A
}
- laws:
- associativity:
(x join y) join z) == (x join (y join z))
- commutativity:
(x join y) == (y join x)
- idempotent:
(x join x) == x
- associativity:
(x meet y) meet z) == (x meet (y meet z))
- commutativity:
(x meet y) == (y meet x)
- idempotent:
(x meet x) == x
- absorption:
a meet (a join b) == a join (a meet b) == a
- identity of zero:
a join zero == a
- identity of one:
a meet one == a
- associativity:
trait BoundedDistributiveLattice[A] extends BoundedLattice[A] with DistributiveLattice[A] {
def join(lhs: A, rhs: A): A
def zero: A
def meet(lhs: A, rhs: A): A
def one: A
}
-
laws:
- associativity:
(x join y) join z) == (x join (y join z))
- commutativity:
(x join y) == (y join x)
- idempotent:
(x join x) == x
- associativity:
(x meet y) meet z) == (x meet (y meet z))
- commutativity:
(x meet y) == (y meet x)
- idempotent:
(x meet x) == x
- absorption:
a meet (a join b) == a join (a meet b) == a
- distributive:
a meet (b join c) == (a meet b) join (a meet c)
- distributive:
a join (b meet c) == (a join b) meet (a join c)
- identity of zero:
a join zero == a
- identity of one:
a meet one == a
- associativity:
Heyting algebra is bounded distributive lattices equipped with operation imp
(written as ->)
and complement
operation (written as -a)
trait Heyting[A] extends BoundedDistributiveLattice[A] {
def join(lhs: A, rhs: A): A
def zero: A
def meet(lhs: A, rhs: A): A
def one: A
def imp(a: A, b: A): A
def complement(a: A): A // a imp 0
}
-
laws:
- associativity:
(x join y) join z) == (x join (y join z))
- commutativity:
(x join y) == (y join x)
- idempotent:
(x join x) == x
- associativity:
(x meet y) meet z) == (x meet (y meet z))
- commutativity:
(x meet y) == (y meet x)
- idempotent:
(x meet x) == x
- absorption:
a meet (a join b) == a join (a meet b) == a
- distributive:
a meet (b join c) == (a meet b) join (a meet c)
- distributive:
a join (b meet c) == (a join b) meet (a join c)
- identity of zero:
a join zero == a
- identity of one:
a meet one == a
- complement law:
a meet -a == 0
- implication laws:
a -> a == 1
a ∧ (a -> b) == a meet b
b ∧ (a -> b) == b
a -> (b meet c) == (a -> b) meet (a -> c)
- associativity:
-
derived methods:
def or(a: A, b: A): A = join(a, b)
def and(a: A, b: A): A = meet(a, b)
def xor(a: A, b: A): A = or(and(a, complement(b)), and(complement(a), b))
def nand(a: A, b: A): A = complement(and(a, b))
def nor(a: A, b: A): A = complement(or(a, b))
def nxor(a: A, b: A): A = complement(xor(a, b))
Boolean algebra is Heyting algebras were law of the excluded middle is true
trait Bool[A] extends Heyting[A] {
def join(lhs: A, rhs: A): A
def zero: A
def meet(lhs: A, rhs: A): A
def one: A
def imp(a: A, b: A): A
def complement(a: A): A // a imp 0
}
- derived methods:
def without(a: A, b: A): A = and(a, complement(b))
-
laws:
- associativity:
(x join y) join z) == (x join (y join z))
- commutativity:
(x join y) == (y join x)
- idempotent:
(x join x) == x
- associativity:
(x meet y) meet z) == (x meet (y meet z))
- commutativity:
(x meet y) == (y meet x)
- idempotent:
(x meet x) == x
- absorption:
a meet (a join b) == a join (a meet b) == a
- distributive:
a meet (b join c) == (a meet b) join (a meet c)
- distributive:
a join (b meet c) == (a join b) meet (a join c)
- identity of zero:
a join zero == a
- identity of one:
a meet one == a
- complement law:
a meet -a == 0
- implication laws:
a -> a == 1
a ∧ (a -> b) == a meet b
b ∧ (a -> b) == b
a -> (b meet c) == (a -> b) meet (a -> c)
- excluded middle law:
(a join (a -> 0)) == 1
- associativity:
Ring without (n)egation
trait Ring[T] extends CommutativeGroup[T] {
def zero: T // empty mempty
def plus(l: T, r: T): T // combine mappend <> |+|
def negate(v: T): T // inverse
def one: T
def times(l: T, r: T): T
}
-
laws:
- associativity:
((x |+| y) |+| z) == (x |+| (y |+| z))
- identity:
(x |+| zero) == x == (zero |+| x)
- inverse:
(x |+| -x) == (-x |+| x) == zero
- commutativity:
(x |+| y) == (y |+| x)
- associativity:
((x * y) * z) == (x * (y * z))
- right identity:
(x * one) == x
- left identity:
(one * x) == x
- distributive:
a * (b |+| c) == (a * b) |+| (a * c)
- associativity:
-
Resources
- typelevel/algebra Rng
- (Haskell) algebra/Numeric.Rig
Ring without an identity
trait Rng[T] extends CommutativeGroup[T] {
def zero: T // empty mempty
def plus(l: T, r: T): T // combine mappend <> |+|
def negate(v: T): T // inverse
def times(l: T, r: T): T
}
-
laws:
- associativity:
((x |+| y) |+| z) == (x |+| (y |+| z))
- identity:
(x |+| zero) == x == (zero |+| x)
- inverse:
(x |+| -x) == (-x |+| x) == zero
- commutativity:
(x |+| y) == (y |+| x)
- associativity:
((x * y) * z) == (x * (y * z))
- distributive:
a * (b |+| c) == (a * b) |+| (a * c)
- associativity:
-
Resources
- typelevel/algebra Rng
- (Haskell) algebra/Numeric.Rng
Abelian group with a second binary operation that is associative, is distributive over the abelian group operation, and has an identity element.
trait Ring[T] extends CommutativeGroup[T] {
def zero: T // empty mempty
def plus(l: T, r: T): T // combine mappend <> |+|
def negate(v: T): T // inverse
def one: T
def times(l: T, r: T): T
}
-
laws:
- associativity:
((x |+| y) |+| z) == (x |+| (y |+| z))
- identity:
(x |+| zero) == x == (zero |+| x)
- inverse:
(x |+| -x) == (-x |+| x) == zero
- commutativity:
(x |+| y) == (y |+| x)
- associativity:
((x * y) * z) == (x * (y * z))
- right identity:
(x * one) == x
- left identity:
(one * x) == x
- distributive:
a * (b |+| c) == (a * b) |+| (a * c)
- associativity:
-
Resources
"Consider two monoids (S, +, 0) and (S, ⋅, 1), which operate on the same set S, such that + is commutative and ⋅ distributes over +.
We call these monoids united if 0 = 1."
- Resources
- United Monoids - Andrey Mokhov (blog post)
- twitter/algebird src
- Resources
- StarRig non/irreg
- Resources: