Skip to content

Commit

Permalink
More laws for Signed
Browse files Browse the repository at this point in the history
  • Loading branch information
armanbilge committed May 29, 2021
1 parent 7ab3d90 commit b0c1ced
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 4 deletions.
4 changes: 2 additions & 2 deletions algebra-core/src/main/scala/cats/algebra/ring/Signed.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import scala.{specialized => sp}
*
* (3) `abs(x) = -x` if `x < 0`, or `x` otherwise,
*
* Laws (1) and (2) lead to the triange inequality:
* Laws (1) and (2) lead to the triangle inequality:
*
* (4) `abs(a + b) <= abs(a) + abs(b)`
*
Expand All @@ -27,7 +27,7 @@ import scala.{specialized => sp}
* It's better to have the Signed hierarchy separate from the Ring/Order hierarchy, so that
* we do not end up with duplicate implicits.
*/
trait Signed[@sp(Byte, Short, Int, Long, Float, Double) A] extends Any {
trait Signed[@sp(Byte, Short, Int, Long, Float, Double) A] extends Any with Serializable {

def additiveCommutativeMonoid: AdditiveCommutativeMonoid[A]
def order: Order[A]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package cats.algebra.laws

import cats.algebra.ring.{CommutativeRing, Signed, TruncatedDivision}
import cats.algebra.ring.{
AdditiveCommutativeGroup,
CommutativeRing,
GCDRing,
Signed,
TruncatedDivision
}
import cats.kernel._
import org.scalacheck.{Arbitrary, Cogen, Prop}
import org.scalacheck.Prop._
Expand Down Expand Up @@ -30,7 +36,37 @@ trait SignedTests[A] extends OrderTests[A] {
"abs non-negative" -> forAll((x: A) => A.sign(A.abs(x)) != Signed.Negative),
"abs never less than" -> forAll((x: A) => A.order.gteqv(A.abs(x), x)),
"signum returns -1/0/1" -> forAll((x: A) => A.signum(A.abs(x)) <= 1),
"signum is sign.toInt" -> forAll((x: A) => A.signum(x) == A.sign(x).toInt)
"signum is sign.toInt" -> forAll((x: A) => A.signum(x) == A.sign(x).toInt),
"linear order" -> forAll { (x: A, y: A, z: A) =>
A.order.lteqv(x, y) ==> A.order.lteqv(A.additiveCommutativeMonoid.plus(x, z),
A.additiveCommutativeMonoid.plus(y, z)
)
},
"triangle inequality" -> forAll { (x: A, y: A) =>
A.order.lteqv(A.abs(A.additiveCommutativeMonoid.plus(x, y)), A.additiveCommutativeMonoid.plus(A.abs(x), A.abs(y)))
}
)

def signedAdditiveCommutativeGroup(implicit signedA: Signed[A], A: AdditiveCommutativeGroup[A]) = new DefaultRuleSet(
name = "signedAdditiveAbGroup",
parent = Some(signed),
"abs(x) equals abs(-x)" -> forAll { (x: A) =>
signedA.abs(x) ?== signedA.abs(A.negate(x))
}
)

// more a convention: as GCD is defined up to a unit, so up to a sign,
// on an ordered GCD ring we require gcd(x, y) >= 0, which is the common
// behavior of computer algebra systems
def signedGCDRing(implicit signedA: Signed[A], A: GCDRing[A]) = new DefaultRuleSet(
name = "signedGCDRing",
parent = Some(signedAdditiveCommutativeGroup),
"gcd(x, y) >= 0" -> forAll { (x: A, y: A) =>
signedA.isSignNonNegative(A.gcd(x, y))
},
"gcd(x, 0) === abs(x)" -> forAll { (x: A) =>
A.gcd(x, A.zero) ?== signedA.abs(x)
}
)

def truncatedDivision(implicit ring: CommutativeRing[A], A: TruncatedDivision[A]) = new DefaultRuleSet(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class LawTests extends munit.DisciplineSuite {

checkAll("BigInt", RingTests[BigInt].euclideanRing)
checkAll("BigInt", SignedTests[BigInt].truncatedDivision)
checkAll("BigInt", SignedTests[BigInt].signedGCDRing)

checkAll("FPApprox[Float]", RingTests[FPApprox[Float]].approxField)
checkAll("FPApprox[Double]", RingTests[FPApprox[Double]].approxField)
Expand Down

0 comments on commit b0c1ced

Please sign in to comment.