├── .gitignore
├── run.js
├── application
├── manifest.mf
├── build.js
├── ivy.xml
└── pom.xml
├── readme.txt
├── scas
├── application
│ ├── resources
│ │ ├── META-INF
│ │ │ └── services
│ │ │ │ └── javax.script.ScriptEngineFactory
│ │ └── jscl
│ │ │ └── editor
│ │ │ └── Editor.properties
│ └── src
│ │ └── scas
│ │ ├── scripting
│ │ ├── OrderedRingParsers.scala
│ │ ├── OrderedFieldParsers.scala
│ │ ├── OrderedUFDParsers.scala
│ │ ├── RationalParsers.scala
│ │ ├── FactorParsers.scala
│ │ ├── FieldParsers.scala
│ │ ├── Var.scala
│ │ ├── Poly.scala
│ │ ├── StructureParsers.scala
│ │ ├── Parsers.scala
│ │ ├── UFDParsers.scala
│ │ ├── OrderingParsers.scala
│ │ ├── RFParsers.scala
│ │ ├── ComplexParsers.scala
│ │ ├── PolyParsers.scala
│ │ ├── BooleanParsers.scala
│ │ ├── Int.scala
│ │ ├── FS.scala
│ │ ├── BooleanAlgebra.scala
│ │ ├── BooleanRingParsers.scala
│ │ ├── BAParsers.scala
│ │ ├── RingParsers.scala
│ │ ├── DoubleParsers.scala
│ │ ├── Fn.scala
│ │ ├── NormalForm.scala
│ │ ├── Function.scala
│ │ ├── Engine.scala
│ │ └── Factors.scala
│ │ ├── rendering
│ │ ├── Graph.scala
│ │ └── MathObject.scala
│ │ ├── adapter
│ │ ├── jas
│ │ │ ├── Main.scala
│ │ │ ├── BigInteger.scala
│ │ │ ├── PolynomialRing.scala
│ │ │ ├── Ring.scala
│ │ │ └── PowerProduct.scala
│ │ ├── rings
│ │ │ ├── BigInteger.scala
│ │ │ ├── Ring.scala
│ │ │ └── MultivariatePolynomialRing.scala
│ │ └── math3
│ │ │ ├── Double.scala
│ │ │ └── Matrix.scala
│ │ └── test
│ │ └── Main.scala
├── src
│ └── scas
│ │ ├── structure
│ │ ├── Algebra.scala
│ │ ├── AlgebraOverRing.scala
│ │ ├── ordered
│ │ │ ├── Structure.scala
│ │ │ ├── Ring.scala
│ │ │ ├── Monoid.scala
│ │ │ └── AbelianGroup.scala
│ │ ├── commutative
│ │ │ ├── StarUFD.scala
│ │ │ ├── ordered
│ │ │ │ ├── EuclidianDomain.scala
│ │ │ │ ├── Field.scala
│ │ │ │ ├── UniqueFactorizationDomain.scala
│ │ │ │ ├── Quotient.scala
│ │ │ │ └── Residue.scala
│ │ │ ├── EuclidianDomain.scala
│ │ │ ├── Field.scala
│ │ │ ├── UniqueFactorizationDomain.scala
│ │ │ ├── Residue.scala
│ │ │ └── Quotient.scala
│ │ ├── Group.scala
│ │ ├── VectorSpace.scala
│ │ ├── Field.scala
│ │ ├── NotQuiteGroup.scala
│ │ ├── Structure.scala
│ │ ├── NotQuiteField.scala
│ │ ├── SemiGroup.scala
│ │ ├── Module.scala
│ │ ├── Ring.scala
│ │ ├── StarRing.scala
│ │ ├── AbelianGroup.scala
│ │ ├── BooleanRing.scala
│ │ ├── Monoid.scala
│ │ └── Product.scala
│ │ ├── power
│ │ ├── growable
│ │ │ ├── PowerProduct.scala
│ │ │ ├── Lexicographic.scala
│ │ │ ├── ArrayPowerProduct.scala
│ │ │ └── DegreeReverseLexicographic.scala
│ │ ├── degree
│ │ │ ├── DegreeReverseLexicographic.scala
│ │ │ └── ArrayPowerProduct.scala
│ │ ├── splitable
│ │ │ ├── PowerProduct.scala
│ │ │ ├── ArrayPowerProduct.scala
│ │ │ └── Lexicographic.scala
│ │ ├── offset
│ │ │ ├── ArrayPowerProduct.scala
│ │ │ └── Lexicographic.scala
│ │ ├── DegreeLexicographic.scala
│ │ ├── ModifiedPOT.scala
│ │ ├── DegreeReverseLexicographic.scala
│ │ ├── Lexicographic.scala
│ │ └── PowerProduct.scala
│ │ ├── variable
│ │ ├── Sqrt.scala
│ │ ├── Function.scala
│ │ ├── Constant.scala
│ │ └── Variable.scala
│ │ ├── polynomial
│ │ ├── gb
│ │ │ ├── GMEngine.scala
│ │ │ ├── SugarPair.scala
│ │ │ ├── GBEngine.scala
│ │ │ ├── Pair.scala
│ │ │ ├── GMSetting.scala
│ │ │ ├── SugarEngine.scala
│ │ │ └── Engine.scala
│ │ ├── SequentialStreamPolynomial.scala
│ │ ├── GrowablePolynomial.scala
│ │ ├── WeylAlgebra.scala
│ │ ├── tree
│ │ │ ├── WeylAlgebra.scala
│ │ │ ├── Polynomial.scala
│ │ │ ├── mutable
│ │ │ │ └── Polynomial.scala
│ │ │ ├── parallel
│ │ │ │ ├── Polynomial.scala
│ │ │ │ └── mutable
│ │ │ │ │ └── Polynomial.scala
│ │ │ ├── SolvablePolynomial.scala
│ │ │ ├── PolynomialOverField.scala
│ │ │ ├── PolynomialWithSimpleGCD.scala
│ │ │ ├── PolynomialWithSubresGCD.scala
│ │ │ ├── PolynomialWithPrimitiveGCD.scala
│ │ │ ├── MultivariatePolynomialOverField.scala
│ │ │ ├── PolynomialWithGB.scala
│ │ │ ├── PolynomialOverFieldWithGB.scala
│ │ │ ├── growable
│ │ │ │ ├── PolynomialWithGB.scala
│ │ │ │ └── PolynomialOverFieldWithGB.scala
│ │ │ ├── UnivariatePolynomial.scala
│ │ │ └── MultivariatePolynomial.scala
│ │ ├── ufd
│ │ │ ├── MultivariatePolynomialOverField.scala
│ │ │ ├── PolynomialWithSimpleGCD.scala
│ │ │ ├── PolynomialWithPrimitiveGCD.scala
│ │ │ ├── growable
│ │ │ │ ├── PolynomialWithGB.scala
│ │ │ │ ├── PolynomialOverUFD.scala
│ │ │ │ └── PolynomialOverFieldWithGB.scala
│ │ │ ├── PolynomialWithModInverse.scala
│ │ │ ├── PolynomialOverField.scala
│ │ │ ├── repr
│ │ │ │ └── UnivariatePolynomial.scala
│ │ │ ├── PolynomialOverFieldWithGB.scala
│ │ │ ├── PolynomialWithSubresGCD.scala
│ │ │ ├── UnivariatePolynomial.scala
│ │ │ ├── PolynomialWithGB.scala
│ │ │ ├── Module.scala
│ │ │ ├── MultivariatePolynomial.scala
│ │ │ └── PolynomialOverUFD.scala
│ │ ├── ParallelPolynomial.scala
│ │ ├── list
│ │ │ └── Polynomial.scala
│ │ ├── stream
│ │ │ ├── Polynomial.scala
│ │ │ ├── direct
│ │ │ │ └── Polynomial.scala
│ │ │ └── sequential
│ │ │ │ └── Polynomial.scala
│ │ ├── array
│ │ │ └── Polynomial.scala
│ │ ├── ParallelMutablePolynomial.scala
│ │ ├── PolynomialOverField.scala
│ │ ├── direct
│ │ │ └── StreamPolynomial.scala
│ │ ├── StreamPolynomial.scala
│ │ ├── PolynomialWithSugar.scala
│ │ ├── TreeMutablePolynomial.scala
│ │ ├── ListPolynomial.scala
│ │ ├── PolynomialWithRepr.scala
│ │ └── TreePolynomial.scala
│ │ ├── module
│ │ ├── Array.scala
│ │ └── ArrayModule.scala
│ │ ├── prettyprint
│ │ ├── Level.scala
│ │ └── Show.scala
│ │ ├── util
│ │ ├── Main.scala
│ │ ├── Fragable.scala
│ │ ├── Lazy.scala
│ │ └── Stream.scala
│ │ ├── residue
│ │ ├── growable
│ │ │ ├── Residue.scala
│ │ │ ├── ResidueOverField.scala
│ │ │ ├── BooleanAlgebra.scala
│ │ │ └── AlgebraicNumber.scala
│ │ ├── GaloisField.scala
│ │ ├── AlgebraicNumber.scala
│ │ ├── ResidueOverField.scala
│ │ ├── BooleanAlgebra.scala
│ │ └── Residue.scala
│ │ ├── math
│ │ ├── Equiv.scala
│ │ ├── PartialOrdering.scala
│ │ ├── Ordering.scala
│ │ └── Numeric.scala
│ │ ├── quotient
│ │ ├── growable
│ │ │ └── RationalFunction.scala
│ │ ├── QuotientOverInteger.scala
│ │ ├── Quotient.scala
│ │ ├── QuotientOverField.scala
│ │ ├── RationalFunctionOverField.scala
│ │ └── RationalFunction.scala
│ │ ├── group
│ │ └── FromAbelian.scala
│ │ └── base
│ │ ├── Complex.scala
│ │ ├── Boolean.scala
│ │ ├── Rational.scala
│ │ ├── ModInteger.scala
│ │ └── BigInteger.scala
└── resources
│ └── jscl
│ └── editor
│ └── Editor.properties
├── update.js
├── manifest.mf
├── examples
├── group.txt
├── jasbigint.txt
├── gf.txt
├── rfi.txt
├── pp1.txt
├── modint.txt
├── gcd_multivariate.txt
├── complex.txt
├── gb.txt
├── mod_polynomial.txt
├── gcd_subres.txt
├── pp2.txt
├── rf.txt
├── boolean.txt
├── rational_polynomial.txt
├── solvable_polynomial.txt
├── univariate_polynomial.txt
├── interface.txt
├── pp_jas.txt
├── primes1.txt
├── ringsbigint.txt
├── quotient.txt
├── gb_gcd.txt
├── math3.txt
├── primes2.txt
├── rational_module.txt
├── an.txt
├── rational.txt
├── residue.txt
├── poly.txt
├── poly_rings.txt
├── index.txt
├── polypower_rings.txt
├── polypower_scas.txt
├── bigint.txt
├── polypower.txt
├── module.txt
├── product.txt
└── polynomial.txt
├── ivy.xml
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | dist/
3 | out
4 |
--------------------------------------------------------------------------------
/run.js:
--------------------------------------------------------------------------------
1 | run("scas.test.Main", "build/classes", pathToFile("examples"))
2 |
--------------------------------------------------------------------------------
/application/manifest.mf:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Main-Class: scas.test.Main
3 |
--------------------------------------------------------------------------------
/readme.txt:
--------------------------------------------------------------------------------
1 |
2 | To run the test suite:
3 | ./mill -i -D dottyVersion=3.7.4-RC1 scas.application.run
4 |
5 |
--------------------------------------------------------------------------------
/scas/application/resources/META-INF/services/javax.script.ScriptEngineFactory:
--------------------------------------------------------------------------------
1 | scas.scripting.Engine$Factory
2 |
--------------------------------------------------------------------------------
/scas/application/resources/jscl/editor/Editor.properties:
--------------------------------------------------------------------------------
1 | language=scas
2 | scas.rendering=true
3 | scas.stylesheet=mmltxt.xsl
4 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/Algebra.scala:
--------------------------------------------------------------------------------
1 | package scas.structure
2 |
3 | trait Algebra[T, R] extends AlgebraOverRing[T, R] with VectorSpace[T, R]
4 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/AlgebraOverRing.scala:
--------------------------------------------------------------------------------
1 | package scas.structure
2 |
3 | trait AlgebraOverRing[T, R] extends Module[T, R] with SemiGroup[T]
4 |
--------------------------------------------------------------------------------
/update.js:
--------------------------------------------------------------------------------
1 | Packages.jscl.editor.Files.instance.dump("https://github.com/rjolly/meditor/raw/master/docs/examples/", pathToFile("examples"), "mmlscala.xsl");
2 |
--------------------------------------------------------------------------------
/scas/resources/jscl/editor/Editor.properties:
--------------------------------------------------------------------------------
1 | language=scala
2 | scala.rendering=true
3 | scala.renderer=scas.rendering.MathObject
4 | scala.stylesheet=mmlscala.xsl
5 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/ordered/Structure.scala:
--------------------------------------------------------------------------------
1 | package scas.structure.ordered
2 |
3 | trait Structure[T] extends scas.structure.Structure[T] with scas.math.Ordering[T]
4 |
--------------------------------------------------------------------------------
/scas/src/scas/power/growable/PowerProduct.scala:
--------------------------------------------------------------------------------
1 | package scas.power.growable
2 |
3 | import scas.variable.Variable
4 |
5 | trait PowerProduct[M] extends scas.power.PowerProduct[M] {
6 | def extend(variables: Variable*): Unit
7 | }
8 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/commutative/StarUFD.scala:
--------------------------------------------------------------------------------
1 | package scas.structure.commutative
2 |
3 | trait StarUFD[T] extends scas.structure.StarRing[T] with UniqueFactorizationDomain[T] {
4 | def conjugate(x: T) = magnitude2(x) / x
5 | }
6 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/commutative/ordered/EuclidianDomain.scala:
--------------------------------------------------------------------------------
1 | package scas.structure.commutative.ordered
2 |
3 | trait EuclidianDomain[T] extends scas.structure.commutative.EuclidianDomain[T] with UniqueFactorizationDomain[T]
4 |
--------------------------------------------------------------------------------
/scas/src/scas/variable/Sqrt.scala:
--------------------------------------------------------------------------------
1 | package scas.variable
2 |
3 | import scas.prettyprint.Show
4 |
5 | class Sqrt[T : Show](x: T) extends Function("sqrt", x) {
6 | override val toMathML = s"${x.toMathML}"
7 | }
8 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/gb/GMEngine.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.gb
2 |
3 | import scas.polynomial.Polynomial
4 |
5 | class GMEngine[T, C, M](using factory: Polynomial[T, C, M]) extends GBEngine[T, C, M] with GMSetting[T, C, M, Pair]
6 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/commutative/EuclidianDomain.scala:
--------------------------------------------------------------------------------
1 | package scas.structure.commutative
2 |
3 | trait EuclidianDomain[T] extends UniqueFactorizationDomain[T] {
4 | def gcd(x: T, y: T) = if y.isZero then x else gcd(y, x % y)
5 | }
6 |
--------------------------------------------------------------------------------
/manifest.mf:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Implementation-Vendor: Raphael Jolly
3 | Implementation-Title: ScAS
4 | Implementation-Version: 0
5 | Specification-Vendor: com.github.rjolly
6 | Specification-Title: scas
7 | Specification-Version: 3.1
8 |
--------------------------------------------------------------------------------
/examples/group.txt:
--------------------------------------------------------------------------------
1 | import scas.structure.Group
2 | import scas.base.BigInteger
3 | import BigInteger.given
4 |
5 | val a = BigInteger("1")
6 | val r = Group(BigInteger)
7 | import r.given
8 |
9 | assert (a * a >< 2)
10 | assert (a \ -1 >< -1)
11 |
--------------------------------------------------------------------------------
/examples/jasbigint.txt:
--------------------------------------------------------------------------------
1 | // Requires : de.uni-mannheim.rz.krum#jas;2.7.10
2 |
3 | import scas.adapter.jas.BigInteger
4 | import BigInteger.given
5 |
6 | assert(BigInteger("1") + 1 >< 1 + BigInteger("1"))
7 | assert(BigInteger("1") - BigInteger("1") >< 0)
8 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/SequentialStreamPolynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial
2 |
3 | import scas.util.Stream
4 |
5 | trait SequentialStreamPolynomial[C, M] extends StreamPolynomial[C, M] {
6 | override def apply(s: (M, C)*) = Stream.sequential(s*)
7 | }
8 |
--------------------------------------------------------------------------------
/scas/src/scas/module/Array.scala:
--------------------------------------------------------------------------------
1 | package scas.module
2 |
3 | import scas.util.{ToFrags, unary_~}
4 |
5 | object Array {
6 | def apply[R : ArrayModule as factory, S : ToFrags[R]](x: S) = factory(~x)
7 | def unapplySeq[T](x: Array[T]) = scala.Array.unapplySeq(x)
8 | }
9 |
--------------------------------------------------------------------------------
/examples/gf.txt:
--------------------------------------------------------------------------------
1 | import scas.residue.GaloisField
2 | import scas.base.BigInteger
3 | import BigInteger.given
4 |
5 | val r = GaloisField("2")("alpha")
6 | val List(alpha) = r.generators
7 | import r.given
8 | r.update(1+alpha+alpha\2)
9 |
10 | assert (alpha\2 >< 1+alpha)
11 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/OrderedRingParsers.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import scala.compiletime.deferred
4 |
5 | trait OrderedRingParsers[T] extends RingParsers[T] with OrderingParsers[T] {
6 | given structure: scas.structure.ordered.Ring[T] = deferred
7 | }
8 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/GrowablePolynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial
2 |
3 | import scala.compiletime.deferred
4 | import scas.power.growable.PowerProduct
5 |
6 | trait GrowablePolynomial[T, C, M] extends Polynomial[T, C, M] {
7 | given pp: PowerProduct[M] = deferred
8 | }
9 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/OrderedFieldParsers.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import scala.compiletime.deferred
4 |
5 | trait OrderedFieldParsers[T] extends UFDParsers[T] with OrderedUFDParsers[T] {
6 | given structure: scas.structure.commutative.ordered.Field[T] = deferred
7 | }
8 |
--------------------------------------------------------------------------------
/scas/application/src/scas/rendering/Graph.scala:
--------------------------------------------------------------------------------
1 | package scas.rendering
2 |
3 | class Graph(f: Double => Double) extends (Double => Double) with jscl.editor.rendering.Plot {
4 | def apply(x: Double) = f(x)
5 | }
6 |
7 | object Graph {
8 | def apply(f: Double => Double) = new Graph(f)
9 | }
10 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/Group.scala:
--------------------------------------------------------------------------------
1 | package scas.structure
2 |
3 | trait Group[T] extends NotQuiteGroup[T] {
4 | extension (x: T) {
5 | def isUnit = true
6 | }
7 | }
8 |
9 | object Group {
10 | def apply[T](group: AbelianGroup[T]) = new scas.group.FromAbelian.Conv(using group)
11 | }
12 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/ordered/Ring.scala:
--------------------------------------------------------------------------------
1 | package scas.structure.ordered
2 |
3 | trait Ring[T] extends scas.structure.Ring[T] with AbelianGroup[T] with Monoid[T]
4 |
5 | object Ring {
6 | trait Conv[T] extends Ring[T] with scas.structure.Ring.Conv[T] with AbelianGroup.Conv[T] with Monoid.Conv[T]
7 | }
8 |
--------------------------------------------------------------------------------
/examples/rfi.txt:
--------------------------------------------------------------------------------
1 | import scas.quotient.RationalFunction
2 | import scas.base.BigInteger
3 | import BigInteger.given
4 |
5 | val q = RationalFunction.integral("a", "b")
6 | val List(a, b) = q.generators
7 | import q.given
8 |
9 | assert ((a+b)\2 / (a\2-b\2) >< (a+b)/(a-b))
10 | assert (a / (2*a) >< 1%%2)
11 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/OrderedUFDParsers.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import scala.compiletime.deferred
4 |
5 | trait OrderedUFDParsers[T] extends UFDParsers[T] with OrderedRingParsers[T] {
6 | given structure: scas.structure.commutative.ordered.UniqueFactorizationDomain[T] = deferred
7 | }
8 |
--------------------------------------------------------------------------------
/examples/pp1.txt:
--------------------------------------------------------------------------------
1 | import scas.power.Lexicographic
2 | import scas.base.BigInteger
3 | import BigInteger.given
4 |
5 | val m = Lexicographic(0)("x")
6 | val List(x) = m.generators
7 | import m.given
8 |
9 | assert(x > 1)
10 | assert(1 < x)
11 | assert(1 | x)
12 | assert(x * 1 >< 1 * x)
13 | assert(x * x >< x\2)
14 |
--------------------------------------------------------------------------------
/examples/modint.txt:
--------------------------------------------------------------------------------
1 | import scas.base.{BigInteger, ModInteger}
2 | import BigInteger.given
3 |
4 | val r = ModInteger("7")
5 | import r.given
6 |
7 | assert (4 + 4 >< 1)
8 | assert (4 * 2 >< 1)
9 | assert (4 \ 2 >< 2)
10 | assert (r.toString == ModInteger("7").toString)
11 | assert (r == BigInteger(BigInteger("7")))
12 |
--------------------------------------------------------------------------------
/examples/gcd_multivariate.txt:
--------------------------------------------------------------------------------
1 | import scas.base.BigInteger
2 | import scas.polynomial.tree.MultivariatePolynomial
3 | import BigInteger.given
4 |
5 | val r = MultivariatePolynomial.withSubresGCD(BigInteger)("x", "y", "z")
6 | val List(x, y, z) = r.generators
7 | import r.{gcd, given}
8 |
9 | assert (gcd(x*y, x*z) >< x)
10 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/WeylAlgebra.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial
2 |
3 | trait WeylAlgebra[T, C, M] extends SolvablePolynomial[T, C, M] {
4 | val n = pp.length >> 1
5 | for i <- 0 until n; j = i + n do {
6 | val xi = generator(i)
7 | val xj = generator(j)
8 | update(xj, xi, xi * xj + one)
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/tree/WeylAlgebra.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.tree
2 |
3 | import scas.structure.Ring
4 | import scas.power.PowerProduct
5 | import scas.polynomial.TreePolynomial.Element
6 |
7 | class WeylAlgebra[C : Ring, M : PowerProduct] extends SolvablePolynomial[C, M] with scas.polynomial.WeylAlgebra[Element[C, M], C, M]
8 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/ufd/MultivariatePolynomialOverField.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.ufd
2 |
3 | import scala.annotation.tailrec
4 | import scas.base.BigInteger
5 | import BigInteger.given
6 |
7 | trait MultivariatePolynomialOverField[T[C, M], C, M] extends PolynomialWithSubresGCD[T, C, M] with PolynomialOverField[T[C, M], C, M]
8 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/ufd/PolynomialWithSimpleGCD.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.ufd
2 |
3 | import scala.annotation.tailrec
4 |
5 | trait PolynomialWithSimpleGCD[T[C, M], C, M] extends MultivariatePolynomial[T, C, M] {
6 | @tailrec final def gcd1(x: T[C, M], y: T[C, M]): T[C, M] = if y.isZero then x else gcd1(y, x.reduce(y))
7 | }
8 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/ordered/Monoid.scala:
--------------------------------------------------------------------------------
1 | package scas.structure.ordered
2 |
3 | import scas.math.PartialOrdering
4 |
5 | trait Monoid[T] extends scas.structure.Monoid[T] with Structure[T]
6 |
7 | object Monoid {
8 | trait Conv[T] extends Monoid[T] with scas.structure.Monoid.Conv[T] with PartialOrdering.Conv[T]
9 | }
10 |
--------------------------------------------------------------------------------
/scas/src/scas/prettyprint/Level.scala:
--------------------------------------------------------------------------------
1 | package scas.prettyprint
2 |
3 | import scas.math.Ordering
4 |
5 | enum Level {
6 | case Addition, Multiplication, Power
7 | }
8 |
9 | object Level {
10 | given Ordering[Level] {
11 | def compare(x: Level, y: Level) = java.lang.Integer.compare(x.ordinal, y.ordinal)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/commutative/ordered/Field.scala:
--------------------------------------------------------------------------------
1 | package scas.structure.commutative.ordered
2 |
3 | trait Field[T] extends scas.structure.commutative.Field[T] with EuclidianDomain[T]
4 |
5 | object Field {
6 | trait Conv[T] extends Field[T] with scas.structure.commutative.Field.Conv[T] with UniqueFactorizationDomain.Conv[T]
7 | }
8 |
--------------------------------------------------------------------------------
/examples/complex.txt:
--------------------------------------------------------------------------------
1 | import scas.base.{BigInteger, Rational, Complex}
2 | import BigInteger.given
3 | import Rational.given
4 | import Complex.{sqrt, conjugate, magnitude2, given}
5 |
6 | assert ((1+sqrt(-1))/(1-sqrt(-1)) >< sqrt(-1))
7 | assert (conjugate(sqrt(-1)) >< -sqrt(-1))
8 | assert (magnitude2(sqrt(-1)) >< 1)
9 | assert (sqrt(-1).isImag)
10 |
--------------------------------------------------------------------------------
/scas/src/scas/power/degree/DegreeReverseLexicographic.scala:
--------------------------------------------------------------------------------
1 | package scas.power.degree
2 |
3 | import scala.reflect.ClassTag
4 | import scas.math.Numeric
5 | import scas.variable.Variable
6 |
7 | class DegreeReverseLexicographic[N : {Numeric, ClassTag}](val variables: Variable*) extends scas.power.DegreeReverseLexicographic.Impl[N] with ArrayPowerProduct[N]
8 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/RationalParsers.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import Parsers.*
4 | import scas.base.Rational
5 |
6 | object RationalParsers extends OrderedFieldParsers[Rational] {
7 | override given structure: Rational.Impl = Rational
8 | def base: Parser[Rational] = Int.base ^^ { Rational(_) } | "(" ~> expr <~ ")"
9 | }
10 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/ufd/PolynomialWithPrimitiveGCD.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.ufd
2 |
3 | import scala.annotation.tailrec
4 |
5 | trait PolynomialWithPrimitiveGCD[T[C, M], C, M] extends MultivariatePolynomial[T, C, M] {
6 | @tailrec final def gcd1(x: T[C, M], y: T[C, M]): T[C, M] = if y.isZero then primitivePart(x) else gcd1(y, primitivePart(x.reduce(y)))
7 | }
8 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/ufd/growable/PolynomialWithGB.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.ufd.growable
2 |
3 | import scala.compiletime.deferred
4 | import scas.power.growable.ArrayPowerProduct
5 |
6 | trait PolynomialWithGB[T, C, N] extends PolynomialOverUFD[T, C, Array[N]] with scas.polynomial.ufd.PolynomialWithGB[T, C, N] {
7 | given pp: ArrayPowerProduct[N] = deferred
8 | }
9 |
--------------------------------------------------------------------------------
/examples/gb.txt:
--------------------------------------------------------------------------------
1 | import scas.polynomial.tree.PolynomialWithGB
2 | import scas.power.Lexicographic
3 | import scas.base.BigInteger
4 | import BigInteger.given
5 |
6 | val r = PolynomialWithGB(using BigInteger, Lexicographic.inlined(0)("x", "y"))
7 | val List(x, y) = r.generators
8 | import r.given
9 |
10 | assert(r.gb(4 - (x\2 + y\2), 1 - x*y) == List(4*x-x\3-y, 1-4*x\2+x\4))
11 |
--------------------------------------------------------------------------------
/examples/mod_polynomial.txt:
--------------------------------------------------------------------------------
1 | import scas.base.{BigInteger, ModInteger}
2 | import scas.power.Lexicographic
3 | import scas.polynomial.tree.Polynomial
4 | import BigInteger.given
5 |
6 | val r = Polynomial(using ModInteger("2"), Lexicographic.inlined(0)("x"))
7 | val List(x) = r.generators
8 | import r.given
9 |
10 | assert(1 + x + 1 >< x)
11 | assert(r == ModInteger("2")(x))
12 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/ParallelPolynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial
2 |
3 | import scala.collection.parallel.CollectionConverters.*
4 |
5 | trait ParallelPolynomial[T, C, M] extends Polynomial[T, C, M] {
6 | extension (x: T) override def multiply(y: T) = y.toSeq.par.aggregate(zero)({ (l, r) =>
7 | val (a, b) = r
8 | l.subtract(a, -b, x)
9 | }, _ + _)
10 | }
11 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/ufd/growable/PolynomialOverUFD.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.ufd.growable
2 |
3 | import scas.polynomial.GrowablePolynomial
4 | import scas.variable.Variable
5 |
6 | trait PolynomialOverUFD[T, C, M] extends GrowablePolynomial[T, C, M] with scas.polynomial.ufd.PolynomialOverUFD[T, C, M] {
7 | def extend(variables: Variable*): Unit = pp.extend(variables*)
8 | }
9 |
--------------------------------------------------------------------------------
/scas/src/scas/variable/Function.scala:
--------------------------------------------------------------------------------
1 | package scas.variable
2 |
3 | import scas.prettyprint.Show
4 | import Show.given
5 |
6 | open class Function[T : Show](name: String, parameter: T*) extends Variable {
7 | override val toString = s"$name(${parameter.toList.show(false)})"
8 | val toMathML = s"${name.toMathML}${parameter.toList.toMathML(false)}"
9 | }
10 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/list/Polynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.list
2 |
3 | import scas.structure.Ring
4 | import scas.power.PowerProduct
5 | import scas.polynomial.ListPolynomial
6 | import ListPolynomial.Element
7 |
8 | class Polynomial[C : Ring, M : PowerProduct] extends ListPolynomial[C, M] with Ring.Conv[Element[C, M]] {
9 | given instance: Polynomial[C, M] = this
10 | }
11 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/tree/Polynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.tree
2 |
3 | import scas.structure.Ring
4 | import scas.power.PowerProduct
5 | import scas.polynomial.TreePolynomial
6 | import TreePolynomial.Element
7 |
8 | class Polynomial[C : Ring, M : PowerProduct] extends TreePolynomial[C, M] with Ring.Conv[Element[C, M]] {
9 | given instance: Polynomial[C, M] = this
10 | }
11 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/VectorSpace.scala:
--------------------------------------------------------------------------------
1 | package scas.structure
2 |
3 | import scala.compiletime.deferred
4 | import scas.util.{Conversion, unary_~}
5 |
6 | trait VectorSpace[T, R] extends Module[T, R] {
7 | given ring: Field[R] = deferred
8 | extension (x: T) def divideRight(y: R) = x%* ring.inverse(y)
9 | extension (x: T) def %/ [U: Conversion[R]](y: U) = x.divideRight(~y)
10 | }
11 |
--------------------------------------------------------------------------------
/examples/gcd_subres.txt:
--------------------------------------------------------------------------------
1 | import scas.base.BigInteger
2 | import scas.polynomial.tree.MultivariatePolynomial
3 | import BigInteger.given
4 |
5 | val r = MultivariatePolynomial.withSubresGCD(BigInteger)("x")
6 | val List(x) = r.generators
7 | import r.{gcd, given}
8 |
9 | assert (gcd(0, 0) >< 0)
10 | assert (gcd(x, 0) >< x)
11 | assert (gcd(1, x) >< 1)
12 | assert (gcd((1+x)*(1+x), (1+x)*(1-x)) >< 1+x)
13 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/stream/Polynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.stream
2 |
3 | import scas.structure.Ring
4 | import scas.power.PowerProduct
5 | import scas.polynomial.StreamPolynomial
6 | import StreamPolynomial.Element
7 |
8 | class Polynomial[C : Ring, M : PowerProduct] extends StreamPolynomial[C, M] with Ring.Conv[Element[C, M]] {
9 | given instance: Polynomial[C, M] = this
10 | }
11 |
--------------------------------------------------------------------------------
/examples/pp2.txt:
--------------------------------------------------------------------------------
1 | import scas.power.Lexicographic
2 | import scas.variable.Variable
3 | import scas.prettyprint.Show.given
4 |
5 | val m = Lexicographic(0)((for (i <- 0 until 4; j <- 0 until 2) yield Variable("a", 0, Array(i, j)*))*)
6 | val a = m.generators.grouped(2).toList
7 | import m.given
8 |
9 | assert(m.toString == List(a(0)(0), a(0)(1), a(1)(0), a(1)(1), a(2)(0), a(2)(1), a(3)(0), a(3)(1)).show)
10 |
--------------------------------------------------------------------------------
/examples/rf.txt:
--------------------------------------------------------------------------------
1 | import scas.base.{BigInteger, Rational}
2 | import scas.quotient.RationalFunction
3 | import BigInteger.given
4 | import Rational.given
5 |
6 | val q = RationalFunction(Rational)("x")
7 | val List(x) = q.generators
8 | import q.given
9 |
10 | assert (x + 1%%2 >< 1%%2 + x)
11 | assert (x + 1 >< 1 + x)
12 | assert ((x\2-1)/(x-1) >< x+1)
13 | assert ((1-x\2)/(1-x) >< 1+x)
14 | assert (x / 2 >< 1%%2*x)
15 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/ufd/PolynomialWithModInverse.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.ufd
2 |
3 | import scas.structure.commutative.Field
4 |
5 | trait PolynomialWithModInverse[T, C, M] extends PolynomialOverField[T, C, M] {
6 | extension (x: T) def modInverse(mods: T*): T
7 | extension (ring: Field[C]) override def apply(s: T*): PolynomialWithModInverse[T, C, M] = {
8 | same(s*)
9 | this
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/FactorParsers.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import Parsers.*
4 | import scala.annotation.nowarn
5 |
6 | object FactorParsers extends RingParsers[FS] {
7 | override given structure: FS.type = FS
8 | @nowarn("msg=match may not be exhaustive")
9 | def base: Parser[FS] = ("factor") ~ ("(" ~> Int.expr) <~ ")" ^^ {
10 | case "factor" ~ x => structure(x)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/stream/direct/Polynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.stream.direct
2 |
3 | import scas.structure.Ring
4 | import scas.power.PowerProduct
5 | import scas.polynomial.direct.StreamPolynomial
6 | import StreamPolynomial.Element
7 |
8 | class Polynomial[C : Ring, M : PowerProduct] extends StreamPolynomial[C, M] with Ring.Conv[Element[C, M]] {
9 | given instance: Polynomial[C, M] = this
10 | }
11 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/Field.scala:
--------------------------------------------------------------------------------
1 | package scas.structure
2 |
3 | trait Field[T] extends NotQuiteField[T] with NotQuiteGroup[T] {
4 | extension (x: T) {
5 | override def isUnit = !x.isZero
6 | def divide(y: T) = x * inverse(y)
7 | }
8 | }
9 |
10 | object Field {
11 | def apply[T : Field] = summon[Field[T]]
12 |
13 | trait Conv[T] extends Field[T] with NotQuiteField.Conv[T] with Monoid.Conv[T]
14 | }
15 |
--------------------------------------------------------------------------------
/examples/boolean.txt:
--------------------------------------------------------------------------------
1 | import scas.base.{BigInteger, Boolean}
2 | import scas.residue.BooleanAlgebra
3 | import BigInteger.given
4 | import Boolean.given
5 |
6 | assert ((true ^ true) >< false)
7 |
8 | val r = BooleanAlgebra("x", "y")
9 | val List(x, y) = r.generators
10 | import r.given
11 |
12 | assert ((x ^ true) >< (true ^ x))
13 | assert ((x ^ y) >< ((x || y) ^ (x && y)))
14 | assert (r == Boolean(x, y)(x+x\2, y+y\2))
15 |
--------------------------------------------------------------------------------
/scas/src/scas/power/splitable/PowerProduct.scala:
--------------------------------------------------------------------------------
1 | package scas.power.splitable
2 |
3 | import scas.variable.Variable
4 |
5 | trait PowerProduct[M] extends scas.power.PowerProduct[M] {
6 | extension (x: M) def convert(from: PowerProduct[M]): M
7 | def take(n: Int) = newInstance(variables.take(n)*)
8 | def drop(n: Int) = newInstance(variables.drop(n)*)
9 | def newInstance(variables: Variable*): PowerProduct[M]
10 | }
11 |
--------------------------------------------------------------------------------
/examples/rational_polynomial.txt:
--------------------------------------------------------------------------------
1 | import scas.base.{BigInteger, Rational}
2 | import scas.power.Lexicographic
3 | import scas.polynomial.tree.Polynomial
4 | import BigInteger.given
5 | import Rational.given
6 |
7 | val r = Polynomial(using Rational, Lexicographic.inlined(0)("x"))
8 | val List(x) = r.generators
9 | import r.given
10 |
11 | assert (x + 1%%2 >< 1%%2 + x)
12 | assert (x + 1 >< 1 + x)
13 | assert (r == Rational(x))
14 |
--------------------------------------------------------------------------------
/examples/solvable_polynomial.txt:
--------------------------------------------------------------------------------
1 | import scas.base.BigInteger
2 | import scas.power.Lexicographic
3 | import scas.polynomial.tree.WeylAlgebra
4 | import BigInteger.given
5 |
6 | val r = WeylAlgebra(using BigInteger, Lexicographic.inlined(0)("a", "x", "b", "y"))
7 | val List(a, x, b, y) = r.generators
8 | import r.given
9 |
10 | assert (b * a + y * x >< 2+a*b+x*y)
11 | assert (r == BigInteger(a, x, b, y)(1+a*b-b*a, 1+x*y-y*x))
12 |
--------------------------------------------------------------------------------
/examples/univariate_polynomial.txt:
--------------------------------------------------------------------------------
1 | import scas.base.{BigInteger, Rational}
2 | import scas.polynomial.tree.UnivariatePolynomial
3 | import BigInteger.given
4 | import Rational.given
5 |
6 | val r = UnivariatePolynomial(Rational)("x")
7 | val List(x) = r.generators
8 | import r.{gcd, modInverse, given}
9 |
10 | assert (gcd((1+x) * (1+1%%2*x), (1+1%%2*x) * (1-x)) >< 2+x)
11 | assert ((1-x).modInverse((1+x) \ 2) >< 3%%4+1%%4*x)
12 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/gb/SugarPair.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.gb
2 |
3 | import scas.power.PowerProduct
4 | import scas.base.BigInteger
5 | import BigInteger.given
6 |
7 | class SugarPair[M](using pp: PowerProduct[M])(i: Int, j: Int, m: M, n: M, scm: M, s: BigInteger) extends Pair(i, j, m, n, scm) {
8 | def skey = (s, scm, j, i)
9 | override def toString = "{" + i + ", " + j + "}, " + s.show + ", " + reduction
10 | }
11 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/gb/GBEngine.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.gb
2 |
3 | import scas.polynomial.Polynomial
4 |
5 | open class GBEngine[T, C, M](using factory: Polynomial[T, C, M]) extends Engine[T, C, M, Pair] {
6 | import factory.pp
7 |
8 | def apply(i: Int, j: Int) = {
9 | val m = i.headPowerProduct
10 | val n = j.headPowerProduct
11 | val scm = pp.lcm(m, n)
12 | new Pair(i, j, m, n, scm)
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/tree/mutable/Polynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.tree.mutable
2 |
3 | import scas.structure.Ring
4 | import scas.power.PowerProduct
5 | import scas.polynomial.TreeMutablePolynomial
6 | import scas.polynomial.TreePolynomial.Element
7 |
8 | class Polynomial[C : Ring, M : PowerProduct] extends TreeMutablePolynomial[C, M] with Ring.Conv[Element[C, M]] {
9 | given instance: Polynomial[C, M] = this
10 | }
11 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/NotQuiteGroup.scala:
--------------------------------------------------------------------------------
1 | package scas.structure
2 |
3 | import scas.util.{Conversion, unary_~}
4 | import scas.base.BigInteger
5 | import BigInteger.given
6 |
7 | trait NotQuiteGroup[T] extends Monoid[T] {
8 | extension (a: T) override def pow(b: BigInteger) = if b.signum < 0 then inverse(a) \ -b else super.pow(a)(b)
9 | def inverse(x: T): T
10 | def inverse[U: Conversion[T]](x: U): T = inverse(~x)
11 | }
12 |
--------------------------------------------------------------------------------
/examples/interface.txt:
--------------------------------------------------------------------------------
1 | val manager = new javax.script.ScriptEngineManager
2 | val engine = manager.getEngineByName("scas")
3 | import engine.eval
4 | assert(eval("x+x").toString == "2*x")
5 | assert(eval("1").toString == "1")
6 | assert(eval("1+x").toString == "1+x")
7 | assert(eval("1/4").toString == "1%%4")
8 | assert(eval("mod(s=>m,s=>h,h=>m)").toString == "true")
9 | assert(eval("s=>h&h=>m").toString == "h >> m && s >> h && s >> m")
10 |
--------------------------------------------------------------------------------
/examples/pp_jas.txt:
--------------------------------------------------------------------------------
1 | // Requires : de.uni-mannheim.rz.krum#jas;2.7.10
2 |
3 | import edu.jas.poly.TermOrderByName
4 | import scas.adapter.jas.PowerProduct
5 | import scas.base.BigInteger
6 | import BigInteger.given
7 |
8 | val m = PowerProduct("x")(TermOrderByName.LEX)
9 | val List(x) = m.generators
10 | import m.given
11 |
12 | assert(x > 1)
13 | assert(1 < x)
14 | assert(1 | x)
15 | assert(x * 1 >< 1 * x)
16 | assert(x * x >< x \ 2)
17 |
--------------------------------------------------------------------------------
/examples/primes1.txt:
--------------------------------------------------------------------------------
1 | import scas.util.{Stream, given}
2 |
3 | val n = 20000
4 | def primes = sieve(Stream.sequential.from(2))
5 | def sieve(s: Stream[Int]): Stream[Int] = {
6 | val head = s.head
7 | head #: s.tail.map(s => sieve(s.filter(_ % head != 0)))
8 | }
9 | println("n: " + n)
10 | var t = System.currentTimeMillis();
11 | println("s: " + primes.takeWhile(_ < n).size)
12 | t = System.currentTimeMillis() - t;
13 | println("t: " + t)
14 |
--------------------------------------------------------------------------------
/examples/ringsbigint.txt:
--------------------------------------------------------------------------------
1 | // Requires : cc.redberry#rings;2.5.7
2 |
3 | import scas.adapter.rings.BigInteger
4 | import BigInteger.given
5 |
6 | assert(BigInteger("1") + 1 >< 1 + BigInteger("1"))
7 | assert(BigInteger("1") - BigInteger("1") >< 0)
8 | assert(BigInteger("2") \ 2 >< 4)
9 | assert(BigInteger("2") \:2 >< 4)
10 | assert(2 \ BigInteger("2") >< 4)
11 | assert(2 \:BigInteger("2") >< 4)
12 | assert(2 \ 2 >< 4)
13 | assert(2 \:2 >< 4)
14 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/ufd/growable/PolynomialOverFieldWithGB.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.ufd.growable
2 |
3 | import scas.structure.commutative.Field
4 |
5 | trait PolynomialOverFieldWithGB[T, C, N] extends PolynomialWithGB[T, C, N] with scas.polynomial.ufd.PolynomialOverFieldWithGB[T, C, N] {
6 | extension (ring: Field[C]) override def apply(s: T*): PolynomialOverFieldWithGB[T, C, N] = {
7 | same(s*)
8 | this
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/examples/quotient.txt:
--------------------------------------------------------------------------------
1 | import scas.base.{BigInteger, Rational}
2 | import scas.polynomial.tree.UnivariatePolynomial
3 | import scas.quotient.Quotient
4 | import BigInteger.given
5 | import Rational.given
6 |
7 | val r = UnivariatePolynomial(Rational)("x")
8 | val List(x) = r.generators
9 | import r.given
10 |
11 | val s = Quotient(Rational(x))
12 | import s.{ring => _, given}
13 |
14 | assert (x/(2*x) >< 1%%2)
15 | assert (s == Rational(x).quotient())
16 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/stream/sequential/Polynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.stream.sequential
2 |
3 | import scas.structure.Ring
4 | import scas.power.PowerProduct
5 | import scas.polynomial.SequentialStreamPolynomial
6 | import scas.polynomial.StreamPolynomial.Element
7 |
8 | class Polynomial[C : Ring, M : PowerProduct] extends SequentialStreamPolynomial[C, M] with Ring.Conv[Element[C, M]] {
9 | given instance: Polynomial[C, M] = this
10 | }
11 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/ordered/AbelianGroup.scala:
--------------------------------------------------------------------------------
1 | package scas.structure.ordered
2 |
3 | import scas.math.PartialOrdering
4 |
5 | trait AbelianGroup[T] extends scas.structure.AbelianGroup[T] with Structure[T] {
6 | extension (x: T) def signum = if x < zero then -1 else if x > zero then 1 else 0
7 | }
8 |
9 | object AbelianGroup {
10 | trait Conv[T] extends AbelianGroup[T] with scas.structure.AbelianGroup.Conv[T] with PartialOrdering.Conv[T]
11 | }
12 |
--------------------------------------------------------------------------------
/examples/gb_gcd.txt:
--------------------------------------------------------------------------------
1 | // See https://www.researchgate.net/publication/312962853_Polynomial_GCDs_by_Syzygies
2 |
3 | import scas.polynomial.tree.PolynomialWithGB
4 | import scas.power.DegreeReverseLexicographic
5 | import scas.base.BigInteger
6 | import BigInteger.given
7 |
8 | val r = PolynomialWithGB(using BigInteger, DegreeReverseLexicographic(0)("x", "y", "z"))
9 | val List(x, y, z) = r.generators
10 | import r.{gcd, given}
11 |
12 | assert (gcd(x*y, x*z) >< x)
13 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/gb/Pair.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.gb
2 |
3 | import scas.power.PowerProduct
4 |
5 | open class Pair[M : PowerProduct as pp](val i: Int, val j: Int, val m: M, val n: M, val scm: M) {
6 | def key = (scm, j, i)
7 | override def toString = "{" + i + ", " + j + "}, " + scm.show + ", " + reduction
8 | def reduction = if m < n then m | n else n | m
9 | def principal = if m < n then j else i
10 | def coprime = pp.coprime(m, n)
11 | }
12 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/commutative/ordered/UniqueFactorizationDomain.scala:
--------------------------------------------------------------------------------
1 | package scas.structure.commutative.ordered
2 |
3 | import scas.structure.ordered.Ring
4 |
5 | trait UniqueFactorizationDomain[T] extends scas.structure.commutative.UniqueFactorizationDomain[T] with Ring[T]
6 |
7 | object UniqueFactorizationDomain {
8 | trait Conv[T] extends UniqueFactorizationDomain[T] with scas.structure.commutative.UniqueFactorizationDomain.Conv[T] with Ring.Conv[T]
9 | }
10 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/tree/parallel/Polynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.tree.parallel
2 |
3 | import scas.structure.Ring
4 | import scas.power.PowerProduct
5 | import scas.polynomial.{TreePolynomial, ParallelPolynomial}
6 | import TreePolynomial.Element
7 |
8 | class Polynomial[C : Ring, M : PowerProduct] extends TreePolynomial[C, M] with ParallelPolynomial[Element[C, M], C, M] with Ring.Conv[Element[C, M]] {
9 | given instance: Polynomial[C, M] = this
10 | }
11 |
--------------------------------------------------------------------------------
/scas/src/scas/util/Main.scala:
--------------------------------------------------------------------------------
1 | package scas.util
2 |
3 | import scala.concurrent.{Await, ExecutionContext, Future}
4 | import scala.concurrent.duration.Duration
5 |
6 | extension [U](x: U)
7 | def unary_~[T](using c: U => T) = c(x)
8 |
9 | type Conversion[T] = [X] =>> X => T
10 |
11 | type ToFrags[T] = [X] =>> Fragable[X, T]
12 |
13 | given ExecutionContext = ExecutionContext.global
14 |
15 | extension[T](s: Future[T])
16 | def await = Await.result(s, Duration.Inf)
17 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/tree/SolvablePolynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.tree
2 |
3 | import scas.structure.Ring
4 | import scas.power.PowerProduct
5 | import scas.polynomial.TreePolynomial
6 | import TreePolynomial.Element
7 |
8 | open class SolvablePolynomial[C : Ring, M : PowerProduct] extends TreePolynomial[C, M] with scas.polynomial.SolvablePolynomial[Element[C, M], C, M] with Ring.Conv[Element[C, M]] {
9 | given instance: SolvablePolynomial[C, M] = this
10 | }
11 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/FieldParsers.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import Parsers.*
4 | import scala.compiletime.deferred
5 |
6 | trait FieldParsers[T] extends UFDParsers[T] {
7 | given structure: scas.structure.commutative.Field[T] = deferred
8 | override def unsignedFactor: Parser[T] = base ~ opt(("**" | "^") ~> Int.factor) ^^ {
9 | case x ~ option => option match {
10 | case Some(exp) => x \ exp
11 | case None => x
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/array/Polynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.array
2 |
3 | import scas.structure.Ring
4 | import scala.reflect.ClassTag
5 | import scas.power.offset.ArrayPowerProduct
6 | import scas.polynomial.ArrayPolynomial
7 | import ArrayPolynomial.Element
8 |
9 | class Polynomial[C, N](using Ring[C], ArrayPowerProduct[N])(using ClassTag[N], ClassTag[C]) extends ArrayPolynomial[C, N] with Ring.Conv[Element[C, N]] {
10 | given instance: Polynomial[C, N] = this
11 | }
12 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/tree/PolynomialOverField.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.tree
2 |
3 | import scas.structure.{Ring, Field}
4 | import scas.power.PowerProduct
5 | import scas.polynomial.TreePolynomial
6 | import TreePolynomial.Element
7 |
8 | class PolynomialOverField[C : Field, M : PowerProduct] extends TreePolynomial[C, M] with scas.polynomial.PolynomialOverField[Element[C, M], C, M] with Ring.Conv[Element[C, M]] {
9 | given instance: PolynomialOverField[C, M] = this
10 | }
11 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/Structure.scala:
--------------------------------------------------------------------------------
1 | package scas.structure
2 |
3 | import scas.math.Equiv
4 | import scas.prettyprint.Show
5 |
6 | trait Structure[T] extends Equiv[T] with Show[T] {
7 | def random(numbits: Int)(using rnd: java.util.Random): T = ???
8 | def fenced(s: String) = s"($s)"
9 | export scas.prettyprint.Level
10 | extension (x: T) {
11 | def toCode(level: Level): String
12 | def show = x.toCode(Level.Addition)
13 | }
14 | def toMathML: String
15 | }
16 |
--------------------------------------------------------------------------------
/examples/math3.txt:
--------------------------------------------------------------------------------
1 | // Requires : org.apache.commons#commons-math3;3.6.1
2 |
3 | import scas.adapter.math3.Matrix
4 | import scas.base.BigInteger
5 | import BigInteger.given
6 |
7 | val m = Matrix(3)
8 | import m.given
9 |
10 | val a = m(
11 | 0, 1, 0,
12 | 0, 0, 1,
13 | 1, 0, 0
14 | )
15 | val b = m(
16 | 0, 0, 1,
17 | 1, 0, 0,
18 | 0, 1, 0
19 | )
20 | assert(a + 1 >< 1 + a)
21 | assert(a%* 2 >< 2 *%a)
22 | assert(a%/ 2 >< .5*%a)
23 | assert(a \ -1 >< b)
24 | assert(a * b >< 1)
25 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/NotQuiteField.scala:
--------------------------------------------------------------------------------
1 | package scas.structure
2 |
3 | import scas.util.{Conversion, unary_~}
4 |
5 | trait NotQuiteField[T] extends Ring[T] {
6 | extension (x: T) {
7 | def divide(y: T): T
8 | inline def / [U: Conversion[T]](y: U) = x.divide(~y)
9 | }
10 | }
11 |
12 | object NotQuiteField {
13 | trait Conv[T] extends NotQuiteField[T] with Ring.Conv[T] {
14 | extension[U: Conversion[T]] (x: U) inline def / [V: Conversion[T]](y: V) = (~x).divide(~y)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/scas/application/src/scas/adapter/jas/Main.scala:
--------------------------------------------------------------------------------
1 | package scas.adapter.jas
2 |
3 | import edu.jas.poly.GenPolynomialRing
4 | import edu.jas.poly.GenPolynomial
5 | import edu.jas.structure.RingElem
6 | import scas.util.{Conversion, unary_~}
7 |
8 | given poly2scas: [C <: RingElem[C] : GenPolynomialRing] => PolynomialRing.Conv[C] = new PolynomialRing.Conv
9 |
10 | given coef2poly: [C <: RingElem[C] : GenPolynomialRing, D : Conversion[C]] => (D => GenPolynomial[C]) = x => summon[GenPolynomialRing[C]].valueOf(~x)
11 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/Var.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import Parsers.*
4 | import scas.variable.Variable
5 |
6 | object Var {
7 | def integer: Parser[Int] = """\d+""".r ^^ { _.toInt }
8 | def name: Parser[String] = """[a-zA-Z]+""".r
9 | def prime: Parser[Int] = """'*""".r ^^ { _.length }
10 | def subscript: Parser[Int] = "[" ~> integer <~ "]"
11 | def parser: Parser[Variable] = name ~ prime ~ rep(subscript) ^^ {
12 | case name ~ prime ~ list => Variable(name, prime, list*)
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/SemiGroup.scala:
--------------------------------------------------------------------------------
1 | package scas.structure
2 |
3 | import scas.math.Equiv
4 | import scas.util.{Conversion, unary_~}
5 |
6 | trait SemiGroup[T] extends Structure[T] {
7 | extension (x: T) {
8 | def multiply(y: T): T
9 | inline def * [U: Conversion[T]](y: U) = x.multiply(~y)
10 | }
11 | }
12 |
13 | object SemiGroup {
14 | trait Conv[T] extends SemiGroup[T] with Equiv.Conv[T] {
15 | extension[U: Conversion[T]] (x: U) inline def * [V: Conversion[T]](y: V) = (~x).multiply(~y)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/tree/parallel/mutable/Polynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.tree.parallel.mutable
2 |
3 | import scas.structure.Ring
4 | import scas.power.PowerProduct
5 | import scas.polynomial.{TreeMutablePolynomial, ParallelMutablePolynomial}
6 | import scas.polynomial.TreePolynomial.Element
7 |
8 | class Polynomial[C : Ring, M : PowerProduct] extends TreeMutablePolynomial[C, M] with ParallelMutablePolynomial[Element[C, M], C, M] with Ring.Conv[Element[C, M]] {
9 | given instance: Polynomial[C, M] = this
10 | }
11 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/ufd/PolynomialOverField.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.ufd
2 |
3 | import scala.compiletime.deferred
4 | import scas.structure.commutative.Field
5 |
6 | trait PolynomialOverField[T, C, M] extends scas.polynomial.PolynomialOverField[T, C, M] with PolynomialOverUFD[T, C, M] {
7 | given ring: Field[C] = deferred
8 | extension (x: T) override def divideRight(c: C) = super[PolynomialOverField].divideRight(x)(c)
9 | extension (ring: Field[C]) def apply(s: T*) = {
10 | same(s*)
11 | this
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/examples/primes2.txt:
--------------------------------------------------------------------------------
1 | import scas.util.{Stream, Lazy, await, given}
2 |
3 | val n = 20000
4 | val primes = 2 #: Lazy(sieve(Stream.sequential.from(3, 2)))
5 | def sieve(s: Stream[Int]): Stream[Int] = {
6 | val head = s.head
7 | if (primes.takeWhile(n => n * n <= head).exists(head % _ == 0)) s.tail.map(sieve(_)).await
8 | else head #: s.tail.map(sieve(_))
9 | }
10 | println("n: " + n)
11 | var t = System.currentTimeMillis();
12 | println("s: " + primes.takeWhile(_ < n).size)
13 | t = System.currentTimeMillis() - t;
14 | println("t: " + t)
15 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/Poly.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import scas.power.growable.Lexicographic
4 | import scas.polynomial.tree.growable.PolynomialWithGB
5 | import scas.polynomial.TreePolynomial.Element
6 | import scas.variable.Variable
7 | import scas.base.BigInteger
8 | import BigInteger.given
9 |
10 | type Poly = Element[BigInteger, Array[Int]]
11 |
12 | object Poly {
13 | def apply(variables: Variable*) = new scas.polynomial.tree.growable.PolynomialWithGB(using BigInteger, new Lexicographic[Int](variables*))
14 | }
15 |
--------------------------------------------------------------------------------
/scas/src/scas/power/growable/Lexicographic.scala:
--------------------------------------------------------------------------------
1 | package scas.power.growable
2 |
3 | import scala.reflect.ClassTag
4 | import scas.math.Numeric
5 | import scas.variable.Variable
6 | import scas.util.{Conversion, unary_~}
7 |
8 | class Lexicographic[N : {Numeric, ClassTag}](variables: Variable*) extends ArrayPowerProduct[N](variables*) with scas.power.Lexicographic.Impl[N]
9 |
10 | object Lexicographic {
11 | def apply[N : {Numeric, ClassTag}, S : Conversion[Variable]](degree: N)(variables: S*) = new Lexicographic[N](variables.map(~_)*)
12 | }
13 |
--------------------------------------------------------------------------------
/scas/src/scas/residue/growable/Residue.scala:
--------------------------------------------------------------------------------
1 | package scas.residue.growable
2 |
3 | import scala.compiletime.deferred
4 | import scas.variable.Variable
5 | import scas.polynomial.ufd.growable.PolynomialWithGB
6 |
7 | trait Residue[T, C, N] extends scas.residue.Residue[T, C, N] {
8 | given ring: PolynomialWithGB[T, C, N] = deferred
9 | def extend(variables: Variable*): Unit = {
10 | ring.extend(variables*)
11 | }
12 |
13 | extension (ring: PolynomialWithGB[T, C, N]) def apply(s: T*) = {
14 | same(s*)
15 | this
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/scas/src/scas/power/growable/ArrayPowerProduct.scala:
--------------------------------------------------------------------------------
1 | package scas.power.growable
2 |
3 | import scala.reflect.ClassTag
4 | import scas.math.Numeric
5 | import scas.variable.Variable
6 |
7 | abstract class ArrayPowerProduct[N : {Numeric as numeric, ClassTag}](var variables: Variable*) extends scas.power.ArrayPowerProduct[N] with PowerProduct[Array[N]] {
8 | def extend(variables: Variable*): Unit = this.variables ++= variables
9 | extension (x: Array[N]) override def get(i: Int) = {
10 | if i < x.length then x(i) else numeric.zero
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/Module.scala:
--------------------------------------------------------------------------------
1 | package scas.structure
2 |
3 | import scala.compiletime.deferred
4 | import scas.util.{Conversion, unary_~}
5 |
6 | trait Module[T, R] extends AbelianGroup[T] {
7 | given ring: Ring[R] = deferred
8 | extension (x: R) def multiplyLeft(y: T): T
9 | extension (x: T) def multiplyRight(y: R): T
10 | extension[U: Conversion[R]] (x: U) def *%(y: T) = (~x).multiplyLeft(y)
11 | extension (x: T) def %* [U: Conversion[R]](y: U) = x.multiplyRight(~y)
12 |
13 | extension (ring: Ring[R]) def pow(n: Int): Module[T, R]
14 | }
15 |
--------------------------------------------------------------------------------
/scas/src/scas/math/Equiv.scala:
--------------------------------------------------------------------------------
1 | package scas.math
2 |
3 | import scas.util.{Conversion, unary_~}
4 |
5 | trait Equiv[T] extends scala.math.Equiv[T] {
6 | extension (x: T) {
7 | inline def ><[U: Conversion[T]](y: U) = equiv(x, ~y)
8 | inline def <>[U: Conversion[T]](y: U) = !equiv(x, ~y)
9 | }
10 | }
11 |
12 | object Equiv {
13 | trait Conv[T] extends Equiv[T] {
14 | extension[U: Conversion[T]] (x: U) {
15 | inline def ><[V: Conversion[T]](y: V) = equiv(~x, ~y)
16 | inline def <>[V: Conversion[T]](y: V) = !equiv(~x, ~y)
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/scas/src/scas/quotient/growable/RationalFunction.scala:
--------------------------------------------------------------------------------
1 | package scas.quotient.growable
2 |
3 | import scas.polynomial.TreePolynomial.Element
4 | import scas.polynomial.ufd.growable.PolynomialOverUFD
5 | import scas.quotient.QuotientOverInteger
6 | import scas.base.BigInteger
7 |
8 | class RationalFunction(using PolynomialOverUFD[Element[BigInteger, Array[Int]], BigInteger, Array[Int]]) extends QuotientOverInteger[Element[BigInteger, Array[Int]], Array[Int]] {
9 | override given ring: PolynomialOverUFD[Element[BigInteger, Array[Int]], BigInteger, Array[Int]] = summon
10 | }
11 |
--------------------------------------------------------------------------------
/scas/src/scas/residue/growable/ResidueOverField.scala:
--------------------------------------------------------------------------------
1 | package scas.residue.growable
2 |
3 | import scala.reflect.ClassTag
4 | import scala.compiletime.deferred
5 | import scas.structure.commutative.Field
6 | import scas.polynomial.ufd.growable.PolynomialOverFieldWithGB
7 |
8 | trait ResidueOverField[T, C, N] extends Residue[T, C, N] with scas.residue.ResidueOverField[T, C, N] {
9 | given ring: PolynomialOverFieldWithGB[T, C, N] = deferred
10 |
11 | extension (ring: PolynomialOverFieldWithGB[T, C, N]) def apply(s: T*) = {
12 | same(s*)
13 | this
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/examples/rational_module.txt:
--------------------------------------------------------------------------------
1 | import scas.base.{BigInteger, Rational}
2 | import scas.module.{Array, ArrayModule}
3 | import BigInteger.given
4 | import Rational.given
5 |
6 | val s = ArrayModule(Rational)(2)
7 | val e = s.generators
8 | import s.given
9 |
10 | assert (Array(1, 1%%2) >< e(0) + 1%%2 *%e(1))
11 | assert (2 *%e(0) >< e(0)%* 2)
12 | assert (1%%2 *%e(0) >< e(0)%* (1%%2))
13 | assert (e(0) + e(1) >< e(0) + e(1))
14 | assert ((2 *%e(0) + e(1)).toList == Array(2, 1).toList)
15 | assert ((1%%2 *%e(0) + e(1)).toList == Array(1%%2, 1).toList)
16 | assert (s == Rational.pow(2))
17 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/commutative/ordered/Quotient.scala:
--------------------------------------------------------------------------------
1 | package scas.structure.commutative.ordered
2 |
3 | import scala.compiletime.deferred
4 | import scas.structure.commutative.Quotient.Element
5 |
6 | trait Quotient[T] extends scas.structure.commutative.Quotient[T] with Field[Element[T]] {
7 | given ring: UniqueFactorizationDomain[T] = deferred
8 | def compare(x: Element[T], y: Element[T]) = {
9 | val Element(a, b) = x
10 | val Element(c, d) = y
11 | ring.compare(a * d, c * b)
12 | }
13 | extension (x: Element[T]) override def signum = super.signum(x)
14 | }
15 |
--------------------------------------------------------------------------------
/scas/src/scas/prettyprint/Show.scala:
--------------------------------------------------------------------------------
1 | package scas.prettyprint
2 |
3 | trait Show[T] {
4 | extension (x: T) {
5 | def show: String
6 | def toMathML: String
7 | }
8 | }
9 |
10 | object Show {
11 | given listShow: [T : Show] => Show[List[T]] {
12 | extension (s: List[T]) {
13 | def show: String = s"List(${s.show(false)})"
14 | def show(fenced: Boolean): String = s.map(_.show).mkString(", ")
15 | def toMathML: String = s"${s.toMathML(false)}
"
16 | def toMathML(fenced: Boolean): String = s.map(_.toMathML).mkString
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/ParallelMutablePolynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial
2 |
3 | import scala.collection.parallel.CollectionConverters.*
4 |
5 | trait ParallelMutablePolynomial[T, C, M] extends Polynomial[T, C, M] {
6 | def unmodifiable(x: T): T
7 | def modifiable(x: T): T
8 | extension (x: T) override def multiply(y: T) = unmodifiable(y.toSeq.par.aggregate(() => modifiable(zero))({ (l, r) =>
9 | val (a, b) = r
10 | val k = l().subtract(a, -b, x)
11 | () => k
12 | }, { (a, b) =>
13 | val s = a().subtract(pp.one, -ring.one, b())
14 | () => s
15 | })())
16 | }
17 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/StructureParsers.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import Parsers.*
4 | import scala.annotation.nowarn
5 | import scala.compiletime.deferred
6 | import scas.rendering.MathObject
7 |
8 | trait StructureParsers[T] {
9 | given structure: scas.structure.Structure[T] = deferred
10 | def expr: Parser[T]
11 | def obj: Parser[MathObject] = expr ^^ { MathObject(_) }
12 | @nowarn("msg=match may not be exhaustive")
13 | def comparison: Parser[Boolean] = expr ~ ("=" | "<>") ~ expr ^^ {
14 | case x ~ "=" ~ y => x >< y
15 | case x ~ "<>" ~ y => x <> y
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/scas/src/scas/power/growable/DegreeReverseLexicographic.scala:
--------------------------------------------------------------------------------
1 | package scas.power.growable
2 |
3 | import scala.reflect.ClassTag
4 | import scas.math.Numeric
5 | import scas.variable.Variable
6 | import scas.util.{Conversion, unary_~}
7 |
8 | class DegreeReverseLexicographic[N : {Numeric, ClassTag}](variables: Variable*) extends ArrayPowerProduct[N](variables*) with scas.power.DegreeReverseLexicographic.Impl[N]
9 |
10 | object DegreeReverseLexicographic {
11 | def apply[N : {Numeric, ClassTag}, S : Conversion[Variable]](degree: N)(variables: S*) = new DegreeReverseLexicographic[N](variables.map(~_)*)
12 | }
13 |
--------------------------------------------------------------------------------
/examples/an.txt:
--------------------------------------------------------------------------------
1 | import scas.base.{BigInteger, Rational}
2 | import scas.residue.growable.AlgebraicNumber
3 | import scas.variable.Variable
4 | import BigInteger.given
5 | import Rational.{ring => _, given}
6 |
7 | val r = AlgebraicNumber(Rational)(Variable.sqrt(BigInteger("2")))
8 | import r.{sqrt, given}
9 | r.update(2-sqrt(2)\2)
10 |
11 | assert (2 >< sqrt(2)\2)
12 | assert(1/(1-sqrt(2)) >< -(1+sqrt(2)))
13 |
14 | r.extend(Variable.sqrt(1-sqrt(2)))
15 | r.update(1-sqrt(2)-sqrt(1-sqrt(2))\2)
16 |
17 | assert (1-sqrt(2) >< sqrt(1-sqrt(2))\2)
18 | assert (1/(1-sqrt(1-sqrt(2))) >< 1%%2*sqrt(2)*(1+sqrt(1-sqrt(2))))
19 |
--------------------------------------------------------------------------------
/examples/rational.txt:
--------------------------------------------------------------------------------
1 | import scas.base.{BigInteger, Rational}
2 | import BigInteger.given
3 | import Rational.given
4 |
5 | assert (Rational("1") >< 1)
6 | assert (Rational("1", "2") >< 1%%2)
7 | assert (BigInteger("1")%%BigInteger("2") >< 1%%2)
8 | assert (BigInteger("1")%%2 >< 1%%2)
9 | assert (1%%BigInteger("2") >< 1%%2)
10 | assert (1 + 1%%2 >< 1%%2 + 1)
11 | assert (1%%2 + 3%%4 >< 5%%4)
12 | assert (3%%2 * (2%%3) >< 1)
13 | assert (3%%2 / (2%%3) >< 9%%4)
14 | assert ((3%%2) \ 2 >< 9%%4)
15 | assert ((3%%2) \:2 >< 9%%4)
16 | assert ((3%%2) \ BigInteger("2") >< 9%%4)
17 | assert ((3%%2) \:BigInteger("2") >< 9%%4)
18 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/Parsers.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | object Parsers extends scala.util.parsing.combinator.RegexParsers {
4 | def obj: Parser[Object] = {
5 | Fn().graph | (Int.obj ||| FactorParsers.obj ||| RationalParsers.obj ||| ComplexParsers.obj ||| DoubleParsers.obj ||| RFParsers(false).obj ||| BAParsers(false).obj ||| BooleanParsers().obj)
6 | }
7 |
8 | def apply(input: String) = {
9 | val result = parseAll(obj, input) match {
10 | case Success(result, _) => Right(result)
11 | case NoSuccess.I(msg, _) => Left(msg)
12 | }
13 | result
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/PolynomialOverField.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial
2 |
3 | import scala.compiletime.deferred
4 | import scas.structure.{Field, Algebra}
5 |
6 | trait PolynomialOverField[T, C, M] extends Polynomial[T, C, M] with Algebra[T, C] {
7 | given ring: Field[C] = deferred
8 | override def normalize(x: T) = monic(x)
9 | def monic(x: T) = if x.isZero then zero else x%/ x.headCoefficient
10 | extension (x: T) override def reduce(m: M, a: C, y: T, b: C, strict: Boolean) = x.subtract(m, a / b, y)
11 | extension (ring: Field[C]) def apply(s: T*) = {
12 | same(s*)
13 | this
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/commutative/ordered/Residue.scala:
--------------------------------------------------------------------------------
1 | package scas.structure.commutative.ordered
2 |
3 | import scala.compiletime.deferred
4 |
5 | trait Residue[T, R] extends scas.structure.commutative.Residue[T, R] with UniqueFactorizationDomain[T] {
6 | given ring: UniqueFactorizationDomain[R] = deferred
7 | def compare(x: T, y: T) = {
8 | val self(a) = x.runtimeChecked
9 | val self(b) = y.runtimeChecked
10 | val self(c) = this(a).runtimeChecked
11 | val self(d) = this(b).runtimeChecked
12 | ring.compare(c, d)
13 | }
14 | extension (x: T) override def signum = super.signum(x)
15 | }
16 |
--------------------------------------------------------------------------------
/scas/src/scas/power/splitable/ArrayPowerProduct.scala:
--------------------------------------------------------------------------------
1 | package scas.power.splitable
2 |
3 | import scas.math.Numeric
4 |
5 | trait ArrayPowerProduct[N : Numeric as numeric] extends scas.power.ArrayPowerProduct[N] with PowerProduct[Array[N]] {
6 | extension (x: Array[N]) {
7 | def convert(from: PowerProduct[Array[N]]) = {
8 | val r = empty
9 | val index = from.variables.map(a => variables.indexOf(a))
10 | for i <- 0 until from.length do if x(i) > numeric.zero then {
11 | val c = index(i)
12 | assert (c > -1)
13 | r(c) = x(i)
14 | }
15 | r
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/commutative/Field.scala:
--------------------------------------------------------------------------------
1 | package scas.structure.commutative
2 |
3 | trait Field[T] extends scas.structure.Field[T] with EuclidianDomain[T] {
4 | override def gcd(x: T, y: T) = if y.isZero then x else y
5 | extension (x: T) {
6 | override def divide(y: T) = super[Field].divide(x)(y)
7 | override def remainder(y: T) = zero
8 | override def divideAndRemainder(y: T) = (x / y, x % y)
9 | }
10 | }
11 |
12 | object Field {
13 | def apply[T : Field] = summon[Field[T]]
14 |
15 | trait Conv[T] extends Field[T] with scas.structure.Field.Conv[T] with UniqueFactorizationDomain.Conv[T]
16 | }
17 |
--------------------------------------------------------------------------------
/examples/residue.txt:
--------------------------------------------------------------------------------
1 | import scas.base.{BigInteger, Rational}
2 | import scas.polynomial.tree.PolynomialOverFieldWithGB
3 | import scas.power.DegreeReverseLexicographic
4 | import scas.residue.Residue
5 | import BigInteger.given
6 | import Rational.given
7 |
8 | val r = PolynomialOverFieldWithGB(using Rational, DegreeReverseLexicographic(0)("x", "y"))
9 | val List(x, y) = r.generators
10 | import r.given
11 |
12 | val s = Residue(Rational(x, y))(2-x\2, 1-x-y\2)
13 | import s.{ring => _, given}
14 |
15 | assert (2 >< x\2)
16 | assert (1 >< x+y\2)
17 | assert (Rational("2") >< x\2)
18 | assert (s == Rational(x, y)(2-x\2, 1-x-y\2))
19 |
--------------------------------------------------------------------------------
/scas/src/scas/power/splitable/Lexicographic.scala:
--------------------------------------------------------------------------------
1 | package scas.power.splitable
2 |
3 | import scala.reflect.ClassTag
4 | import scas.math.Numeric
5 | import scas.variable.Variable
6 | import scas.util.{Conversion, unary_~}
7 |
8 | class Lexicographic[N : {Numeric, ClassTag}](val variables: Variable*) extends scas.power.Lexicographic.Impl[N] with ArrayPowerProduct[N] {
9 | def newInstance(variables: Variable*) = new Lexicographic[N](variables*)
10 | }
11 |
12 | object Lexicographic {
13 | def apply[N : {Numeric, ClassTag}, S : Conversion[Variable]](degree: N)(variables: S*) = new Lexicographic[N](variables.map(~_)*)
14 | }
15 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/Ring.scala:
--------------------------------------------------------------------------------
1 | package scas.structure
2 |
3 | import scas.util.{Conversion, unary_~}
4 | import scas.base.BigInteger
5 | import BigInteger.given
6 |
7 | trait Ring[T] extends AbelianGroup[T] with Monoid[T] {
8 | def characteristic: BigInteger
9 | def fromInt(n: BigInteger): T
10 | def fromInt[U: Conversion[BigInteger]](x: U): T = fromInt(~x)
11 | def zero = fromInt(0)
12 | def one = fromInt(1)
13 |
14 | given bigInt2ring: [U: Conversion[BigInteger]] => (U => T) = fromInt[U]
15 | }
16 |
17 | object Ring {
18 | trait Conv[T] extends Ring[T] with AbelianGroup.Conv[T] with Monoid.Conv[T]
19 | }
20 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/UFDParsers.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import Parsers.*
4 | import scala.annotation.nowarn
5 | import scala.compiletime.deferred
6 |
7 | trait UFDParsers[T] extends RingParsers[T] {
8 | given structure: scas.structure.commutative.UniqueFactorizationDomain[T] = deferred
9 | @nowarn("msg=match may not be exhaustive")
10 | override def unsignedTerm: Parser[T] = unsignedFactor ~ rep(("*" | "/" | "%") ~ factor) ^^ {
11 | case factor ~ list => list.foldLeft(factor) {
12 | case (x, "*" ~ y) => x * y
13 | case (x, "/" ~ y) => x / y
14 | case (x, "%" ~ y) => x % y
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/tree/PolynomialWithSimpleGCD.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.tree
2 |
3 | import scas.power.splitable.PowerProduct
4 | import scas.structure.commutative.UniqueFactorizationDomain
5 | import scas.variable.Variable
6 | import scas.polynomial.TreePolynomial.Element
7 |
8 | class PolynomialWithSimpleGCD[C](using UniqueFactorizationDomain[C])(val variables: Variable*) extends MultivariatePolynomial[C] with scas.polynomial.ufd.PolynomialWithSimpleGCD[Element, C, Array[Int]] {
9 | def newInstance = [C] => (ring: UniqueFactorizationDomain[C], pp: PowerProduct[Array[Int]]) => new PolynomialWithSimpleGCD(using ring)(pp.variables*)
10 | }
11 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/tree/PolynomialWithSubresGCD.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.tree
2 |
3 | import scas.power.splitable.PowerProduct
4 | import scas.structure.commutative.UniqueFactorizationDomain
5 | import scas.variable.Variable
6 | import scas.polynomial.TreePolynomial.Element
7 |
8 | class PolynomialWithSubresGCD[C](using UniqueFactorizationDomain[C])(val variables: Variable*) extends MultivariatePolynomial[C] with scas.polynomial.ufd.PolynomialWithSubresGCD[Element, C, Array[Int]] {
9 | def newInstance = [C] => (ring: UniqueFactorizationDomain[C], pp: PowerProduct[Array[Int]]) => new PolynomialWithSubresGCD(using ring)(pp.variables*)
10 | }
11 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/tree/PolynomialWithPrimitiveGCD.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.tree
2 |
3 | import scas.power.splitable.PowerProduct
4 | import scas.structure.commutative.UniqueFactorizationDomain
5 | import scas.variable.Variable
6 | import scas.polynomial.TreePolynomial.Element
7 |
8 | class PolynomialWithPrimitiveGCD[C](using UniqueFactorizationDomain[C])(val variables: Variable*) extends MultivariatePolynomial[C] with scas.polynomial.ufd.PolynomialWithPrimitiveGCD[Element, C, Array[Int]] {
9 | def newInstance = [C] => (ring: UniqueFactorizationDomain[C], pp: PowerProduct[Array[Int]]) => new PolynomialWithPrimitiveGCD(using ring)(pp.variables*)
10 | }
11 |
--------------------------------------------------------------------------------
/scas/src/scas/power/offset/ArrayPowerProduct.scala:
--------------------------------------------------------------------------------
1 | package scas.power.offset
2 |
3 | import scas.math.Numeric
4 |
5 | trait ArrayPowerProduct[N : Numeric] extends scas.power.ArrayPowerProduct[N] {
6 | override def compare(x: Array[N], y: Array[N]) = compare(x, 0, y, 0)
7 | def compare(x: Array[N], n: Int, y: Array[N], m: Int): Int
8 | override def multiply(x: Array[N], y: Array[N], z: Array[N]) = multiply(x, 0, y, z)
9 | def multiply(x: Array[N], n: Int, y: Array[N], z: Array[N]) = {
10 | val k = n * length
11 | var i = 0
12 | while i < length do {
13 | z(i + k) = x(i + k) + y(i)
14 | i += 1
15 | }
16 | z
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/examples/poly.txt:
--------------------------------------------------------------------------------
1 | import scas.base.BigInteger
2 | import scas.power.Lexicographic
3 | import scas.polynomial.tree.Polynomial
4 | import BigInteger.given
5 |
6 | val r = Polynomial(using BigInteger, Lexicographic.inlined(0)("x", "y", "z"))
7 | val List(x, y, z) = r.generators
8 | import r.given
9 |
10 | assert(x + 1 >< 1 + x)
11 | assert(x + BigInteger("1") >< BigInteger("1") + x)
12 |
13 | val s = Polynomial(using BigInteger(x, y, z), Lexicographic.inlined(0)("a"))
14 | val List(a) = s.generators
15 | import s.given
16 |
17 | assert(a + 1 >< 1 + a)
18 | assert(a + BigInteger("1") >< BigInteger("1") + a)
19 | assert(a + x >< x + a)
20 | assert((a + x).show == "x+a")
21 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/tree/MultivariatePolynomialOverField.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.tree
2 |
3 | import scas.power.splitable.PowerProduct
4 | import scas.structure.commutative.{UniqueFactorizationDomain, Field}
5 | import scas.variable.Variable
6 | import scas.polynomial.TreePolynomial.Element
7 |
8 | class MultivariatePolynomialOverField[C](using Field[C])(val variables: Variable*) extends MultivariatePolynomial[C] with scas.polynomial.ufd.MultivariatePolynomialOverField[Element, C, Array[Int]] {
9 | def newInstance = [C] => (ring: UniqueFactorizationDomain[C], pp: PowerProduct[Array[Int]]) => new PolynomialWithSubresGCD(using ring)(pp.variables*)
10 | }
11 |
--------------------------------------------------------------------------------
/scas/application/src/scas/rendering/MathObject.scala:
--------------------------------------------------------------------------------
1 | package scas.rendering
2 |
3 | import scas.util.{Conversion, unary_~}
4 | import scas.structure.Structure
5 | import scas.prettyprint.Show
6 |
7 | type MathObject = jscl.editor.rendering.MathObject
8 |
9 | object MathObject {
10 | def apply[U : Conversion[T], T : Show](x: U): MathObject = new MathObject {
11 | override def toString = (~x).show
12 | def toMathML = (~x).toMathML
13 | }
14 | def apply[T](x: Structure[T]): MathObject = new MathObject {
15 | override def toString = x.toString
16 | def toMathML = x.toMathML
17 | }
18 | def apply(f: Double => Double) = Graph(f)
19 | def apply(s: String) = s
20 | }
21 |
--------------------------------------------------------------------------------
/scas/src/scas/residue/GaloisField.scala:
--------------------------------------------------------------------------------
1 | package scas.residue
2 |
3 | import scas.structure.commutative.Field
4 | import scas.polynomial.TreePolynomial.Element
5 | import scas.util.{Conversion, unary_~}
6 | import scas.variable.Variable
7 | import scas.base.ModInteger
8 |
9 | class GaloisField(str: String)(variables: Variable*) extends AlgebraicNumber(ModInteger(str))(variables*)
10 |
11 | object GaloisField {
12 | def apply[S : Conversion[Variable]](str: String)(s: S*) = new Conv(str)(s.map(~_)*)
13 |
14 | class Conv(str: String)(variables: Variable*) extends GaloisField(str)(variables*) with Field.Conv[Element[Int, Array[Int]]] {
15 | given instance: Conv = this
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/poly_rings.txt:
--------------------------------------------------------------------------------
1 | // Requires : cc.redberry#rings;2.5.7
2 |
3 | import cc.redberry.rings.poly.multivar.MonomialOrder
4 | import scas.adapter.rings.{BigInteger, MultivariatePolynomialRing}
5 | import BigInteger.given
6 |
7 | val r = MultivariatePolynomialRing(MonomialOrder.LEX, "x", "y", "z")(using BigInteger)
8 | val List(x, y, z) = r.gens
9 | import r.given
10 |
11 | assert(x + 1 >< 1 + x)
12 | assert(x + BigInteger("1") >< BigInteger("1") + x)
13 |
14 | val s = MultivariatePolynomialRing(MonomialOrder.LEX, "a")(using r)
15 | val List(a) = s.gens
16 | import s.given
17 |
18 | assert(a + 1 >< 1 + a)
19 | assert(a + BigInteger("1") >< BigInteger("1") + a)
20 | assert(a + x >< x + a)
21 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/OrderingParsers.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import Parsers.*
4 | import scala.annotation.nowarn
5 | import scala.compiletime.deferred
6 |
7 | trait OrderingParsers[T] extends StructureParsers[T] {
8 | given structure: scas.structure.ordered.Structure[T] = deferred
9 | @nowarn("msg=match may not be exhaustive")
10 | override def comparison: Parser[Boolean] = expr ~ ("=" | "<>" | "<=" | "<" | ">=" | ">") ~ expr ^^ {
11 | case x ~ "=" ~ y => x >< y
12 | case x ~ "<>" ~ y => x <> y
13 | case x ~ "<=" ~ y => x <= y
14 | case x ~ "<" ~ y => x < y
15 | case x ~ ">=" ~ y => x >= y
16 | case x ~ ">" ~ y => x > y
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/StarRing.scala:
--------------------------------------------------------------------------------
1 | package scas.structure
2 |
3 | import scas.util.{Conversion, unary_~}
4 | import scas.base.BigInteger
5 | import BigInteger.given
6 |
7 | trait StarRing[T] extends Ring[T] {
8 | def real(x: T): T
9 | def imag(x: T): T
10 | extension (x: T) {
11 | def isReal = imag(x) >< zero
12 | def isImag = real(x) >< zero
13 | }
14 | def conjugate(x: T): T
15 | def magnitude2(x: T) = real(x)\2 + imag(x)\2
16 | def real[U: Conversion[T]](x: U): T = real(~x)
17 | def imag[U: Conversion[T]](x: U): T = imag(~x)
18 | def conjugate[U: Conversion[T]](x: U): T = conjugate(~x)
19 | def magnitude2[U: Conversion[T]](x: U): T = magnitude2(~x)
20 | }
21 |
--------------------------------------------------------------------------------
/scas/src/scas/util/Fragable.scala:
--------------------------------------------------------------------------------
1 | package scas.util
2 |
3 | import scala.reflect.ClassTag
4 |
5 | trait Fragable[S, T : ClassTag] extends (S => Array[T]):
6 | def apply(x: S) = x.toFrags
7 | extension (x: S)
8 | def toFrags: Array[T]
9 |
10 | object Fragable:
11 | given [U : Conversion[T], T : ClassTag] => Fragable[U, T]:
12 | extension (x: U)
13 | def toFrags = Array(~x)
14 | given [T : ClassTag] => Fragable[EmptyTuple, T]:
15 | extension (x: EmptyTuple)
16 | def toFrags = Array()
17 | given [A : ToFrags[T], B <: Tuple : ToFrags[T], T : ClassTag] => Fragable[A *: B, T]:
18 | extension (x: A *: B)
19 | def toFrags = x.head.toFrags ++ x.tail.toFrags
20 |
--------------------------------------------------------------------------------
/scas/application/src/scas/adapter/jas/BigInteger.scala:
--------------------------------------------------------------------------------
1 | package scas.adapter.jas
2 |
3 | import scas.util.{Conversion, unary_~}
4 |
5 | type BigInteger = edu.jas.arith.BigInteger
6 |
7 | object BigInteger extends BigInteger.Impl with Ring.Conv[BigInteger] {
8 | given instance: BigInteger.type = this
9 | abstract class Impl extends Ring[BigInteger] {
10 | val factory = new BigInteger()
11 | def apply(str: String) = new BigInteger(str)
12 | }
13 | given int2bigInt: (Int => BigInteger) = new BigInteger(_)
14 | given long2bigInt: (Long => BigInteger) = new BigInteger(_)
15 |
16 | given bigInt2scas: [U : Conversion[BigInteger]] => (U => scas.base.BigInteger) = x => (~x).`val`
17 | }
18 |
--------------------------------------------------------------------------------
/examples/index.txt:
--------------------------------------------------------------------------------
1 | (/*
2 | bigint.txt
3 | jasbigint.txt
4 | ringsbigint.txt
5 | mod_polynomial.txt
6 | modint.txt
7 | module.txt
8 | math3.txt
9 | poly.txt
10 | polynomial.txt
11 | poly_rings.txt
12 | polypower.txt
13 | polypower_scas.txt
14 | polypower_rings.txt
15 | boolean.txt
16 | group.txt
17 | an.txt
18 | gf.txt
19 | rf.txt
20 | rfi.txt
21 | residue.txt
22 | complex.txt
23 | quotient.txt
24 | gcd_subres.txt
25 | gcd_multivariate.txt
26 | gb_gcd.txt
27 | gb.txt
28 | interface.txt
29 | univariate_polynomial.txt
30 | solvable_polynomial.txt
31 | rational_polynomial.txt
32 | rational_module.txt
33 | rational.txt
34 | product.txt
35 | primes1.txt
36 | primes2.txt
37 | pp_jas.txt
38 | pp1.txt
39 | pp2.txt
40 | */)
41 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/ufd/repr/UnivariatePolynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.ufd.repr
2 |
3 | import scala.reflect.ClassTag
4 | import scas.polynomial.PolynomialWithRepr
5 | import scas.structure.commutative.Field
6 | import scas.power.PowerProduct
7 | import PolynomialWithRepr.Element
8 |
9 | class UnivariatePolynomial[T : ClassTag, C, M](using scas.polynomial.ufd.UnivariatePolynomial[T, C, M])(val dimension: Int) extends PolynomialWithRepr[T, C, M] with scas.polynomial.ufd.UnivariatePolynomial[Element[T], C, M] {
10 | override given factory: scas.polynomial.ufd.UnivariatePolynomial[T, C, M] = summon
11 | override given ring: Field[C] = factory.ring
12 | override given pp: PowerProduct[M] = factory.pp
13 | }
14 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/tree/PolynomialWithGB.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.tree
2 |
3 | import scala.reflect.ClassTag
4 | import scas.math.Numeric
5 | import scas.power.{ArrayPowerProduct, POT}
6 | import scas.structure.commutative.UniqueFactorizationDomain
7 | import scas.polynomial.TreePolynomial
8 | import TreePolynomial.Element
9 |
10 | class PolynomialWithGB[C, N](using UniqueFactorizationDomain[C], ArrayPowerProduct[N])(using ClassTag[N], Numeric[N]) extends TreePolynomial[C, Array[N]] with scas.polynomial.ufd.PolynomialWithGB[Element[C, Array[N]], C, N] with UniqueFactorizationDomain.Conv[Element[C, Array[N]]] {
11 | given instance: PolynomialWithGB[C, N] = this
12 | def newInstance(pp: POT[N]) = new PolynomialWithGB(using ring, pp)
13 | }
14 |
--------------------------------------------------------------------------------
/scas/src/scas/power/DegreeLexicographic.scala:
--------------------------------------------------------------------------------
1 | package scas.power
2 |
3 | import scala.reflect.ClassTag
4 | import scas.math.Numeric
5 | import scas.variable.Variable
6 |
7 | class DegreeLexicographic[N : {Numeric, ClassTag}](val variables: Variable*) extends DegreeLexicographic.Impl[N]
8 |
9 | object DegreeLexicographic {
10 | trait Impl[N : {Numeric, ClassTag}] extends ArrayPowerProduct[N] {
11 | def compare(x: Array[N], y: Array[N]) = {
12 | if x.deg < y.deg then return -1
13 | if x.deg > y.deg then return 1
14 | var i = length
15 | while i > 0 do {
16 | i -= 1
17 | if x.get(i) < y.get(i) then return -1
18 | if x.get(i) > y.get(i) then return 1
19 | }
20 | 0
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/scas/src/scas/quotient/QuotientOverInteger.scala:
--------------------------------------------------------------------------------
1 | package scas.quotient
2 |
3 | import scas.structure.commutative.Quotient.Element
4 | import scas.base.{BigInteger, Rational}
5 | import BigInteger.given
6 | import Rational.given
7 |
8 | trait QuotientOverInteger[T, M] extends Quotient[T, BigInteger, M] {
9 | extension (x: Element[T]) override def toCode(level: Level) = {
10 | val Element(n, d) = x
11 | if n.degree >< 0 && d.degree >< 0 then Rational(n.headCoefficient, d.headCoefficient).toCode(level) else super.toCode(x)(level)
12 | }
13 | extension (x: Element[T]) override def toMathML = {
14 | val Element(n, d) = x
15 | if n.degree >< 0 && d.degree >< 0 then Rational(n.headCoefficient, d.headCoefficient).toMathML else super.toMathML(x)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/RFParsers.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import Parsers.*
4 | import scas.quotient.growable.RationalFunction
5 | import scas.structure.commutative.Quotient.Element
6 | import scas.polynomial.ufd.growable.PolynomialOverUFD
7 | import scas.base.BigInteger
8 |
9 | type RF = Element[Poly]
10 |
11 | class RFParsers(using RationalFunction) extends FieldParsers[RF] {
12 | def this(ring: PolynomialOverUFD[Poly, BigInteger, Array[Int]]) = this(using new RationalFunction(using ring))
13 | def this(dummy: Boolean) = this(Poly())
14 | override given structure: RationalFunction = summon
15 | val poly = new PolyParsers(using structure.ring)
16 |
17 | def base: Parser[RF] = poly.base ^^ {
18 | case x => structure(x)
19 | } | "(" ~> expr <~ ")"
20 | }
21 |
--------------------------------------------------------------------------------
/scas/src/scas/power/ModifiedPOT.scala:
--------------------------------------------------------------------------------
1 | package scas.power
2 |
3 | import scala.reflect.ClassTag
4 | import scas.math.Numeric
5 |
6 | class ModifiedPOT[N : {Numeric, ClassTag}](factory: ArrayPowerProduct[N], name: String, dimension: Int) extends POT(factory, name, dimension) {
7 | override def compare(x: Array[N], y: Array[N]) = {
8 | if x(factory.len) < y(factory.len) then return -1
9 | if x(factory.len) > y(factory.len) then return 1
10 | val s = factory.compare(x, y)
11 | if s < 0 then return -1
12 | if s > 0 then return 1
13 | var i = 1
14 | while i < dimension do {
15 | if x(factory.len + i) < y(factory.len + i) then return -1
16 | if x(factory.len + i) > y(factory.len + i) then return 1
17 | i += 1
18 | }
19 | return 0
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/scas/src/scas/group/FromAbelian.scala:
--------------------------------------------------------------------------------
1 | package scas.group
2 |
3 | import scala.compiletime.deferred
4 | import scas.structure.{AbelianGroup, Group, Monoid}
5 |
6 | trait FromAbelian[T] extends Group[T] {
7 | given group: AbelianGroup[T] = deferred
8 | override def one = group.zero
9 | extension (x: T) {
10 | def multiply(y: T) = group.add(x)(y)
11 | }
12 | def inverse(x: T) = group.unary_-(x)
13 | def equiv(x: T, y: T) = group.equiv(x, y)
14 | extension (x: T) {
15 | def toCode(level: Level) = group.toCode(x)(level)
16 | def toMathML = group.toMathML(x)
17 | }
18 | def toMathML = group.toMathML
19 | }
20 |
21 | object FromAbelian {
22 | class Conv[T](using AbelianGroup[T]) extends FromAbelian[T] with Monoid.Conv[T] {
23 | given instance: Conv[T] = this
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/scas/application/src/scas/adapter/jas/PolynomialRing.scala:
--------------------------------------------------------------------------------
1 | package scas.adapter.jas
2 |
3 | import edu.jas.poly.GenPolynomialRing
4 | import edu.jas.poly.GenPolynomial
5 | import edu.jas.structure.RingElem
6 | import scas.util.Conversion
7 | import scala.jdk.CollectionConverters.ListHasAsScala
8 |
9 | class PolynomialRing[C <: RingElem[C] : GenPolynomialRing] extends Ring[GenPolynomial[C]] {
10 | val factory: GenPolynomialRing[C] = summon
11 | def gens = factory.getGenerators().asScala.toList
12 |
13 | given coef2poly: [D : Conversion[C]] => (D => GenPolynomial[C]) = scas.adapter.jas.coef2poly
14 | }
15 |
16 | object PolynomialRing {
17 | class Conv[C <: RingElem[C] : GenPolynomialRing] extends PolynomialRing[C] with Ring.Conv[GenPolynomial[C]] {
18 | given instance: Conv[C] = this
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/scas/application/src/scas/adapter/rings/BigInteger.scala:
--------------------------------------------------------------------------------
1 | package scas.adapter.rings
2 |
3 | import cc.redberry.rings.Rings
4 | import scas.util.{Conversion, unary_~}
5 | import cc.redberry.rings.bigint.BigInteger.valueOf
6 |
7 | type BigInteger = cc.redberry.rings.bigint.BigInteger
8 |
9 | object BigInteger extends BigInteger.Impl with Ring.Conv[BigInteger] {
10 | given instance: BigInteger.type = this
11 | abstract class Impl extends Ring[BigInteger] {
12 | def apply(str: String) = new BigInteger(str)
13 | val ring = Rings.Z
14 | }
15 | given int2bigInt: (Int => BigInteger) = valueOf(_)
16 | given long2bigInt: (Long => BigInteger) = valueOf(_)
17 |
18 | given bigInt2scas: [U : Conversion[BigInteger]] => (U => scas.base.BigInteger) = x => new scas.base.BigInteger((~x).toByteArray)
19 | }
20 |
--------------------------------------------------------------------------------
/examples/polypower_rings.txt:
--------------------------------------------------------------------------------
1 | // Requires : cc.redberry#rings;2.5.7
2 |
3 | import cc.redberry.rings.poly.multivar.MonomialOrder
4 | import scas.adapter.rings.{BigInteger, MultivariatePolynomialRing}
5 | import BigInteger.given
6 |
7 | val r = MultivariatePolynomialRing(MonomialOrder.LEX, "x", "y", "z")(using BigInteger)
8 | val List(x, y, z) = r.gens
9 | import r.given
10 |
11 | val p = 1 + x + y + z
12 | // val p = 1 + x \ 32767 + y \ 32767 + z \ 32767
13 | // val p = 10000000001l + 10000000001l * x + 10000000001l * y + 10000000001l * z
14 | println("p: " + p)
15 | val q = p \ 20
16 | println("q: " + q.size)
17 | val q1 = q + 1
18 | println("q1: " + q1.size)
19 | var t = System.currentTimeMillis();
20 | val q2 = q * q1
21 | println("q2: " + q2.size)
22 | t = System.currentTimeMillis() - t;
23 | println("t: " + t)
24 |
--------------------------------------------------------------------------------
/application/build.js:
--------------------------------------------------------------------------------
1 | mkdir("build");
2 | mkdir("build/classes");
3 | mkdir("build/sources");
4 | mkdir("build/javadoc");
5 |
6 | var name = "scas.application";
7 | dotc("../" + name.replace(".", "/") + "/src", "build/classes");
8 | copy("../" + name.replace(".", "/") + "/resources", "build/classes");
9 | copy("../" + name.replace(".", "/") + "/src", "build/sources");
10 | copy("../" + name.replace(".", "/") + "/resources", "build/sources");
11 | dottydoc("build/classes", "build/javadoc");
12 |
13 | mkdir("dist");
14 | var name_rev = name + "_3";
15 | jar("dist/" + name_rev + ".jar", "build/classes", ".*", "manifest.mf");
16 | jar("dist/" + name_rev + "-source.jar", "build/sources");
17 | jar("dist/" + name_rev + "-javadoc.jar", "build/javadoc");
18 | cp("pom.xml", "dist/" + name_rev + ".pom")
19 |
20 | publish("dist")
21 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/tree/PolynomialOverFieldWithGB.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.tree
2 |
3 | import scala.reflect.ClassTag
4 | import scas.math.Numeric
5 | import scas.power.{POT, ArrayPowerProduct}
6 | import scas.structure.commutative.{Field, UniqueFactorizationDomain}
7 | import scas.polynomial.TreePolynomial
8 | import scas.variable.Variable
9 | import TreePolynomial.Element
10 |
11 | class PolynomialOverFieldWithGB[C, N](using Field[C], ArrayPowerProduct[N])(using ClassTag[N], Numeric[N]) extends TreePolynomial[C, Array[N]] with scas.polynomial.ufd.PolynomialOverFieldWithGB[Element[C, Array[N]], C, N] with UniqueFactorizationDomain.Conv[Element[C, Array[N]]] {
12 | given instance: PolynomialOverFieldWithGB[C, N] = this
13 | def newInstance(pp: POT[N]) = new PolynomialOverFieldWithGB(using ring, pp)
14 | }
15 |
--------------------------------------------------------------------------------
/examples/polypower_scas.txt:
--------------------------------------------------------------------------------
1 | import scas.base.BigInteger
2 | import scas.power.Lexicographic
3 | import scas.polynomial.tree.mutable.Polynomial
4 | import BigInteger.given
5 |
6 | val r = Polynomial(using BigInteger, Lexicographic.inlined(0)("x", "y", "z"))
7 | // val r = Polynomial(using BigInteger, Lexicographic.inlined(0l)("x", "y", "z"))
8 | val List(x, y, z) = r.generators
9 | import r.given
10 |
11 | val p = 1+x+y+z
12 | // val p = 1+x\2147483647+y\2147483647+z\2147483647
13 | // val p = 10000000001l+10000000001l*x+10000000001l*y+10000000001l*z
14 | println("p: " + p.show)
15 | val q = p \ 20
16 | println("q: " + q.size)
17 | val q1 = q + 1
18 | println("q1: " + q1.size)
19 | var t = System.currentTimeMillis();
20 | val q2 = q * q1
21 | println("q2: " + q2.size)
22 | t = System.currentTimeMillis() - t;
23 | println("t: " + t)
24 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/tree/growable/PolynomialWithGB.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.tree.growable
2 |
3 | import scala.reflect.ClassTag
4 | import scas.math.Numeric
5 | import scas.power.POT
6 | import scas.power.growable.ArrayPowerProduct
7 | import scas.structure.commutative.UniqueFactorizationDomain
8 | import scas.polynomial.TreePolynomial
9 | import TreePolynomial.Element
10 |
11 | class PolynomialWithGB[C, N](using UniqueFactorizationDomain[C], ArrayPowerProduct[N])(using ClassTag[N], Numeric[N]) extends TreePolynomial[C, Array[N]] with scas.polynomial.ufd.growable.PolynomialWithGB[Element[C, Array[N]], C, N] with UniqueFactorizationDomain.Conv[Element[C, Array[N]]] {
12 | given instance: PolynomialWithGB[C, N] = this
13 | def newInstance(pp: POT[N]) = new scas.polynomial.tree.PolynomialWithGB(using ring, pp)
14 | }
15 |
--------------------------------------------------------------------------------
/scas/src/scas/quotient/Quotient.scala:
--------------------------------------------------------------------------------
1 | package scas.quotient
2 |
3 | import scala.compiletime.deferred
4 | import scas.structure.commutative.Quotient.Element
5 | import scas.polynomial.ufd.{PolynomialOverUFD, PolynomialOverField}
6 | import scas.util.Conversion
7 |
8 | trait Quotient[T, C, M] extends scas.structure.commutative.Quotient[T] {
9 | given ring: PolynomialOverUFD[T, C, M] = deferred
10 | def generator(n: Int) = this(ring.generator(n))
11 | def generators = ring.generators.map(apply)
12 | def toMathML = ring.toMathML(true)
13 | given coef2poly: [D: Conversion[C]] => (D => T) = ring.coef2poly
14 |
15 | extension (ring: PolynomialOverUFD[T, C, M]) def quotient() = this
16 | }
17 |
18 | object Quotient {
19 | def apply[T, C, M](ring: PolynomialOverField[T, C, M]) = new QuotientOverField.Conv(using ring)
20 | }
21 |
--------------------------------------------------------------------------------
/scas/src/scas/math/PartialOrdering.scala:
--------------------------------------------------------------------------------
1 | package scas.math
2 |
3 | import scas.util.{Conversion, unary_~}
4 |
5 | trait PartialOrdering[T] extends scala.math.PartialOrdering[T] with Equiv[T] {
6 | extension (x: T) {
7 | inline def <=[U: Conversion[T]](y: U) = lteq(x, ~y)
8 | inline def >=[U: Conversion[T]](y: U) = gteq(x, ~y)
9 | def < [U: Conversion[T]](y: U) = lt(x, ~y)
10 | def > [U: Conversion[T]](y: U) = gt(x, ~y)
11 | }
12 | }
13 |
14 | object PartialOrdering {
15 | trait Conv[T] extends PartialOrdering[T] with Equiv.Conv[T] {
16 | extension [U: Conversion[T]](x: U) {
17 | inline def <=[V: Conversion[T]](y: V) = lteq(~x, ~y)
18 | inline def >=[V: Conversion[T]](y: V) = gteq(~x, ~y)
19 | inline def < [V: Conversion[T]](y: V) = lt(~x, ~y)
20 | inline def > [V: Conversion[T]](y: V) = gt(~x, ~y)
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/examples/bigint.txt:
--------------------------------------------------------------------------------
1 | import scas.base.BigInteger
2 | import BigInteger.{abs, gcd, lcm, given}
3 |
4 | assert(BigInteger("1") + 1 >< 1 + BigInteger("1"))
5 | assert(BigInteger("1") - BigInteger("1") >< 0)
6 | assert(BigInteger("2") \ 2 >< BigInteger("4"))
7 | assert(BigInteger("2") \ 64 >< BigInteger("18446744073709551616"))
8 | assert(BigInteger("2") \ BigInteger("2") >< 4)
9 | assert(BigInteger("2") \:BigInteger("2") >< 4)
10 | assert(BigInteger("2") \ 2 >< 4)
11 | assert(BigInteger("2") \:2 >< 4)
12 | assert(2 \ BigInteger("2") >< 4)
13 | assert(2 \:BigInteger("2") >< 4)
14 | assert(2 \ 2 >< 4)
15 | assert(2 \:2 >< 4)
16 | assert(2 \:2 \:3 >< 256)
17 | assert((2 \:2) \ 3 >< 64)
18 | assert(abs(-1) >< -BigInteger("-1"))
19 | assert(gcd(3, 5) >< 1)
20 | assert(lcm(3, 5) >< 15)
21 | assert(gcd(BigInteger("3"), BigInteger("5")) >< 1)
22 | assert(lcm(BigInteger("3"), BigInteger("5")) >< 15)
23 |
--------------------------------------------------------------------------------
/scas/src/scas/base/Complex.scala:
--------------------------------------------------------------------------------
1 | package scas.base
2 |
3 | import scas.structure.commutative.{StarUFD, Field}
4 | import scas.polynomial.TreePolynomial.Element
5 | import scas.residue.AlgebraicNumber
6 | import scas.variable.Variable
7 | import BigInteger.given
8 | import Rational.{ring as _, given}
9 |
10 | type Complex = Element[Rational, Array[Int]]
11 |
12 | object Complex extends Complex.Impl with Field.Conv[Complex] {
13 | given instance: Complex.type = this
14 | class Impl extends AlgebraicNumber(Rational)(Variable.sqrt(BigInteger("-1"))) with StarUFD[Complex] {
15 | def real(x: Complex) = x.coefficient(one)
16 | def imag(x: Complex) = x.coefficient(generator(0))
17 | override def conjugate(x: Complex) = real(x) - sqrt(-1) * imag(x)
18 | override def toString = "Complex"
19 | override def toMathML = ""
20 | }
21 | update(1 + sqrt(-1)\2)
22 | }
23 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/ufd/PolynomialOverFieldWithGB.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.ufd
2 |
3 | import scala.reflect.ClassTag
4 | import scas.math.Numeric
5 | import scas.structure.commutative.Field
6 | import scas.module.Array
7 | import scas.base.BigInteger
8 | import BigInteger.given
9 |
10 | trait PolynomialOverFieldWithGB[T : ClassTag, C, N : {Numeric, ClassTag}] extends PolynomialWithGB[T, C, N] with PolynomialWithModInverse[T, C, Array[N]] {
11 | extension (x: T) def modInverse(mods: T*) = {
12 | given module: Module[T, C, N] = new Module(using this)("c", 2)
13 | val s = Seq(Array(x, 1)) ++ mods.map(Array(_, 0))
14 | val list = module.gb(s*)
15 | val Array(p, q) = list.head
16 | assert (p.isUnit)
17 | q / p
18 | }
19 | extension (ring: Field[C]) override def apply(s: T*): PolynomialOverFieldWithGB[T, C, N] = {
20 | same(s*)
21 | this
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/examples/polypower.txt:
--------------------------------------------------------------------------------
1 | // Requires : de.uni-mannheim.rz.krum#jas;2.7.10
2 |
3 | import edu.jas.poly.TermOrderByName
4 | import edu.jas.poly.GenPolynomialRing
5 | import scas.adapter.jas.{BigInteger, coef2poly, poly2scas}
6 | import BigInteger.{int2bigInt, long2bigInt, bigInt2scas}
7 |
8 | given GenPolynomialRing[BigInteger](BigInteger.factory, Array("x", "y", "z"), TermOrderByName.INVLEX)
9 | val List(one, x, y, z) = poly2scas.gens
10 |
11 | val p = 1 + x + y + z
12 | // val p = 1 + x \ 2147483647 + y \ 2147483647 + z \ 2147483647
13 | // val p = 10000000001l + 10000000001l * x + 10000000001l * y + 10000000001l * z
14 | println("p: " + p)
15 | val q = p \ 20
16 | println("q: " + q.length)
17 | val q1 = q + 1
18 | println("q1: " + q1.length)
19 | var t = System.currentTimeMillis();
20 | val q2 = q * q1
21 | println("q2: " + q2.length)
22 | t = System.currentTimeMillis() - t;
23 | println("t: " + t)
24 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/tree/growable/PolynomialOverFieldWithGB.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.tree.growable
2 |
3 | import scala.reflect.ClassTag
4 | import scas.math.Numeric
5 | import scas.power.POT
6 | import scas.power.growable.ArrayPowerProduct
7 | import scas.structure.commutative.{Field, UniqueFactorizationDomain}
8 | import scas.polynomial.TreePolynomial
9 | import scas.variable.Variable
10 | import TreePolynomial.Element
11 |
12 | class PolynomialOverFieldWithGB[C, N](using Field[C], ArrayPowerProduct[N])(using ClassTag[N], Numeric[N]) extends TreePolynomial[C, Array[N]] with scas.polynomial.ufd.growable.PolynomialOverFieldWithGB[Element[C, Array[N]], C, N] with UniqueFactorizationDomain.Conv[Element[C, Array[N]]] {
13 | given instance: PolynomialOverFieldWithGB[C, N] = this
14 | def newInstance(pp: POT[N]) = new scas.polynomial.tree.PolynomialOverFieldWithGB(using ring, pp)
15 | }
16 |
--------------------------------------------------------------------------------
/scas/src/scas/variable/Constant.scala:
--------------------------------------------------------------------------------
1 | package scas.variable
2 |
3 | class Constant(name: String, prime: Int, subscript: Int*) extends Variable {
4 | override def toString = name + (for i <- 0 until prime yield "_").mkString + subscript.map("(" + _ + ")").mkString
5 | def toMathML = s"${bodyToMathML}"
6 | def bodyToMathML = if subscript.isEmpty then {
7 | if prime == 0 then name.toMathML
8 | else s"${name.toMathML}${primeToMathML}"
9 | } else {
10 | if prime == 0 then s"${name.toMathML}${subscriptToMathML}"
11 | else s"${name.toMathML}${subscriptToMathML}${primeToMathML}"
12 | }
13 | def primeToMathML = (for i <- 0 until prime yield "′").mkString
14 | def subscriptToMathML = subscript.map(a => s"$a").mkString
15 | }
16 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/AbelianGroup.scala:
--------------------------------------------------------------------------------
1 | package scas.structure
2 |
3 | import scas.math.Equiv
4 | import scas.util.{Conversion, unary_~}
5 |
6 | trait AbelianGroup[T] extends Structure[T] {
7 | extension (x: T) {
8 | def add(y: T): T
9 | def subtract(y: T): T
10 | inline def + [U: Conversion[T]](y: U) = x.add(~y)
11 | inline def - [U: Conversion[T]](y: U) = x.subtract(~y)
12 | def unary_- = zero - x
13 | def isZero = x >< zero
14 | def signum: Int
15 | }
16 | def abs(x: T) = if x.signum < 0 then -x else x
17 | def abs[U: Conversion[T]](x: U): T = abs(~x)
18 | def zero: T
19 | }
20 |
21 | object AbelianGroup {
22 | trait Conv[T] extends AbelianGroup[T] with Equiv.Conv[T] {
23 | extension[U: Conversion[T]] (x: U) {
24 | inline def + [V: Conversion[T]](y: V) = (~x).add(~y)
25 | inline def - [V: Conversion[T]](y: V) = (~x).subtract(~y)
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/scas/application/src/scas/test/Main.scala:
--------------------------------------------------------------------------------
1 | package scas.test
2 |
3 | import java.io.File
4 | import scala.io.Source
5 |
6 | val manager = new javax.script.ScriptEngineManager
7 |
8 | @main def Main(names: String*) = {
9 | val file = new File(if names.length > 0 then names(0) else "examples")
10 | val list = if file.isDirectory then file.listFiles.toSeq else Seq(file)
11 | val n = (list.map { file =>
12 | println(file.getName)
13 | try {
14 | manager.getEngineByName("scala").eval(Source.fromFile(file).mkString)
15 | 1
16 | } catch {
17 | case e : Exception => {
18 | e.printStackTrace
19 | println(file.getName + " failure")
20 | 0
21 | }
22 | }
23 | }).foldLeft(0) { (l, r) =>
24 | l + r
25 | }
26 | val m = list.length - n
27 | println("success : " + n + ", failure : " + m)
28 | if m > 0 then throw new RuntimeException("tests failed")
29 | }
30 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/tree/UnivariatePolynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.tree
2 |
3 | import scas.power.{PowerProduct, Lexicographic}
4 | import scas.structure.commutative.{UniqueFactorizationDomain, Field}
5 | import scas.variable.Variable
6 | import scas.util.{Conversion, unary_~}
7 | import scas.polynomial.TreePolynomial
8 | import TreePolynomial.Element
9 |
10 | class UnivariatePolynomial[C](using Field[C])(variable: Variable) extends TreePolynomial[C, Array[Int]] with scas.polynomial.ufd.UnivariatePolynomial[Element[C, Array[Int]], C, Array[Int]] with UniqueFactorizationDomain.Conv[Element[C, Array[Int]]] {
11 | override given pp: PowerProduct[Array[Int]] = Lexicographic.inlined(0)(variable)
12 | given instance: UnivariatePolynomial[C] = this
13 | }
14 |
15 | object UnivariatePolynomial {
16 | def apply[C, S : Conversion[Variable]](ring: Field[C])(s: S) = new UnivariatePolynomial(using ring)(~s)
17 | }
18 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/ComplexParsers.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import Parsers.*
4 | import scala.annotation.nowarn
5 | import scas.base.{BigInteger, Rational, Complex}
6 | import BigInteger.given
7 | import Rational.given
8 | import Complex.{sqrt, real, imag, conjugate, coef2poly, ring}
9 |
10 | object ComplexParsers extends FieldParsers[Complex] {
11 | override given structure: Complex.Impl = Complex
12 | def number: Parser[Complex] = RationalParsers.base ^^ { ring(_) }
13 | @nowarn("msg=match may not be exhaustive")
14 | def function: Parser[Complex] = (literal("sqrt") | literal("real") | literal("imag") | literal("conjugate")) ~ ("(" ~> expr) <~ ")" ^^ {
15 | case "sqrt" ~ x if (x >< -1) => sqrt(x)
16 | case "real" ~ x => real(x)
17 | case "imag" ~ x => imag(x)
18 | case "conjugate" ~ x => conjugate(x)
19 | }
20 | def base: Parser[Complex] = number | function | "(" ~> expr <~ ")"
21 | }
22 |
--------------------------------------------------------------------------------
/scas/src/scas/util/Lazy.scala:
--------------------------------------------------------------------------------
1 | package scas.util
2 |
3 | import scala.concurrent.{ExecutionContext, CanAwait, Future}
4 | import scala.concurrent.duration.Duration
5 | import scala.util.{Try, Success}
6 |
7 | class Lazy[+T](body: => T) extends Future[T] {
8 | lazy val await = body
9 | def value = Some(Success(await))
10 | def isCompleted = true
11 | def onComplete[U](func: Try[T] => U)(using executor: ExecutionContext) = ()
12 | def ready(atMost: Duration)(using permit: CanAwait) = this
13 | def result(atMost: Duration)(using permit: CanAwait) = await
14 | override def map[S](f: T => S)(using executor: ExecutionContext) = Lazy(f(await))
15 | override def flatMap[S](f: T => Future[S])(using executor: ExecutionContext) = f(await)
16 | def transform[S](f: Try[T] => Try[S])(using executor: ExecutionContext): Future[S] = ???
17 | def transformWith[S](f: Try[T] => Future[S])(using executor: ExecutionContext): Future[S] = ???
18 | }
19 |
--------------------------------------------------------------------------------
/examples/module.txt:
--------------------------------------------------------------------------------
1 | import scas.base.{BigInteger, Rational}
2 | import scas.power.Lexicographic
3 | import scas.module.{Array, ArrayModule}
4 | import scas.polynomial.tree.Polynomial
5 | import BigInteger.given
6 | import Rational.given
7 |
8 | val r = Polynomial(using Rational, Lexicographic.inlined(0)("x"))
9 | val List(x) = r.generators
10 | import r.given
11 |
12 | val s = ArrayModule(Rational(x))(2)
13 | val e = s.generators
14 | import s.given
15 |
16 | assert (Array(1, 1%%2) >< e(0) + 1%%2 *%e(1))
17 | assert (Array(1, x) >< e(0) + x *%e(1))
18 | assert (2 *%e(0) >< e(0)%* 2)
19 | assert (1%%2 *%e(0) >< e(0)%* (1%%2))
20 | assert (x *%e(0) >< e(0)%* x)
21 | assert (2 * x *%e(0) >< e(0)%* (2 * x))
22 | assert (1%%2 * x *%e(0) >< e(0)%* (1%%2 * x))
23 | assert (e(0) + e(1) >< e(0) + e(1))
24 | assert ((2 *%e(0) + e(1)).toList == Array(2, 1).toList)
25 | assert ((1%%2 *%e(0) + e(1)).toList == Array(1%%2, 1).toList)
26 | assert (s == Rational(x).pow(2))
27 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/ufd/PolynomialWithSubresGCD.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.ufd
2 |
3 | import scala.annotation.tailrec
4 | import scas.base.BigInteger
5 | import BigInteger.given
6 |
7 | trait PolynomialWithSubresGCD[T[C, M], C, M] extends MultivariatePolynomial[T, C, M] {
8 | @tailrec final def gcd1(x: T[C, M], y: T[C, M]): T[C, M] = if x.degree < y.degree then gcd1(y, x) else gcd(x, y, ring.one, ring.one)
9 | @tailrec final def gcd(x: T[C, M], y: T[C, M], beta: C, phi: C): T[C, M] = if y.isZero then x else if x.isZero then y else {
10 | val d = x.degree - y.degree
11 | gcd(y, x.reduce(y)%/ beta, x.headCoefficient * phi\d, if d >< 0 then phi else if d >< 1 then y.headCoefficient else y.headCoefficient\d / phi\(d - 1))
12 | }
13 | extension (x: T[C, M]) {
14 | override def reduce(m: M, a: C, y: T[C, M], b: C, remainder: Boolean) = (x%* b).subtract(m, a, y)
15 | override def reduce(ys: T[C, M]*) = super.reduce(x)(ys*)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/scas/src/scas/quotient/QuotientOverField.scala:
--------------------------------------------------------------------------------
1 | package scas.quotient
2 |
3 | import scala.compiletime.deferred
4 | import scas.structure.commutative.Field
5 | import scas.structure.commutative.Quotient.Element
6 | import scas.polynomial.ufd.PolynomialOverField
7 | import scas.util.Conversion
8 |
9 | trait QuotientOverField[T, C, M] extends Quotient[T, C, M] {
10 | given ring: PolynomialOverField[T, C, M] = deferred
11 | given Field[C] = ring.ring
12 | override def apply(x: Element[T]) = {
13 | val Element(n, d) = x
14 | val c = ring.gcd(n, d)
15 | val gcd = c%/ (c.lastCoefficient / d.lastCoefficient)
16 | Element(n / gcd, d / gcd)
17 | }
18 |
19 | extension (ring: PolynomialOverField[T, C, M]) def quotient() = this
20 | }
21 |
22 | object QuotientOverField {
23 | class Conv[T, C, M](using PolynomialOverField[T, C, M]) extends QuotientOverField[T, C, M] with Field.Conv[Element[T]] {
24 | given instance: Conv[T, C, M] = this
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/scas/src/scas/quotient/RationalFunctionOverField.scala:
--------------------------------------------------------------------------------
1 | package scas.quotient
2 |
3 | import scas.structure.commutative.Field
4 | import scas.structure.commutative.Quotient.{Element as Quotient_Element}
5 | import scas.polynomial.tree.MultivariatePolynomialOverField
6 | import scas.polynomial.ufd.PolynomialOverField
7 | import scas.polynomial.TreePolynomial.Element
8 | import scas.variable.Variable
9 |
10 | class RationalFunctionOverField[C](using PolynomialOverField[Element[C, Array[Int]], C, Array[Int]]) extends QuotientOverField[Element[C, Array[Int]], C, Array[Int]] {
11 | def this(ring: Field[C])(variables: Variable*) = this(using new MultivariatePolynomialOverField(using ring)(variables*))
12 | }
13 |
14 | object RationalFunctionOverField {
15 | class Conv[C](ring: Field[C])(variables: Variable*) extends RationalFunctionOverField(ring)(variables*) with Field.Conv[Quotient_Element[Element[C, Array[Int]]]] {
16 | given instance: Conv[C] = this
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/PolyParsers.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import Parsers.*
4 | import scas.polynomial.ufd.growable.PolynomialOverUFD
5 | import scas.variable.Variable
6 | import scas.base.BigInteger
7 | import BigInteger.given
8 |
9 | class PolyParsers(using PolynomialOverUFD[Poly, BigInteger, Array[Int]]) extends UFDParsers[Poly] {
10 | def this(dummy: Boolean, variables: Variable*) = this(using Poly(variables*))
11 | override given structure: PolynomialOverUFD[Poly, BigInteger, Array[Int]] = summon
12 | def generator: Parser[Poly] = Var.parser ^^ { generator(_) }
13 | def generator(a: Variable) = {
14 | val variables = structure.pp.variables
15 | if variables.contains(a) then structure.generator(variables.indexOf(a))
16 | else {
17 | structure.extend(a)
18 | structure.generator(variables.length)
19 | }
20 | }
21 | def base: Parser[Poly] = Int.base ^^ { structure(_) } | generator | "(" ~> expr <~ ")"
22 | }
23 |
--------------------------------------------------------------------------------
/scas/src/scas/power/DegreeReverseLexicographic.scala:
--------------------------------------------------------------------------------
1 | package scas.power
2 |
3 | import scala.reflect.ClassTag
4 | import scas.math.Numeric
5 | import scas.variable.Variable
6 | import scas.util.{Conversion, unary_~}
7 |
8 | class DegreeReverseLexicographic[N : {Numeric, ClassTag}](val variables: Variable*) extends DegreeReverseLexicographic.Impl[N]
9 |
10 | object DegreeReverseLexicographic {
11 | def apply[N : {Numeric, ClassTag}, S : Conversion[Variable]](degree: N)(variables: S*) = new DegreeReverseLexicographic[N](variables.map(~_)*)
12 |
13 | trait Impl[N : {Numeric, ClassTag}] extends ArrayPowerProduct[N] {
14 | def compare(x: Array[N], y: Array[N]) = {
15 | if x.deg < y.deg then return -1
16 | if x.deg > y.deg then return 1
17 | var i = 0
18 | while i < length do {
19 | if x.get(i) > y.get(i) then return -1
20 | if x.get(i) < y.get(i) then return 1
21 | i += 1
22 | }
23 | 0
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/examples/product.txt:
--------------------------------------------------------------------------------
1 | import scas.base.{BigInteger, ModInteger}
2 | import scas.module.{Array, ArrayModule}
3 | import scas.structure.Product
4 | import BigInteger.self.given
5 |
6 | given r: Product[Int, Int](using ModInteger("3"), ModInteger("5"))
7 |
8 | assert (Product(1, 3) + Product(1, 3) >< Product(2, 1))
9 | assert (Product(1, 3) \ BigInteger("2") >< Product(1, 4))
10 | assert (Product(1, 3) \ 2 >< Product(1, 4))
11 | assert (r.toString == Product(ModInteger("3"), ModInteger("5")).toString)
12 | assert (r.characteristic >< 15)
13 |
14 | val s = ArrayModule(Product(ModInteger("3"), ModInteger("5")))(2)
15 | val e = s.generators
16 | import s.given
17 |
18 | assert (Array(Product(1, 3), Product(1, 3)) >< Product(1, 3) *%e(0) + Product(1, 3) *%e(1))
19 | assert (Product(1, 3) *%e(0) >< e(0)%* Product(1, 3))
20 | assert ((Product(1, 3) *%e(0) + Product(1, 3) *%e(1)).toList == Array(Product(1, 3), Product(1, 3)).toList)
21 | assert (s == Product(ModInteger("3"), ModInteger("5")).pow(2))
22 |
--------------------------------------------------------------------------------
/scas/src/scas/residue/growable/BooleanAlgebra.scala:
--------------------------------------------------------------------------------
1 | package scas.residue.growable
2 |
3 | import scas.polynomial.TreePolynomial.Element
4 | import scas.polynomial.ufd.growable.PolynomialWithGB
5 | import scas.power.growable.Lexicographic
6 | import scas.variable.Variable
7 | import scas.base.{BigInteger, Boolean}
8 | import BigInteger.given
9 |
10 | open class BooleanAlgebra(using PolynomialWithGB[Element[Boolean, Array[Int]], Boolean, Int]) extends BooleanAlgebra.Impl {
11 | def this(variables: Variable*) = this(using new scas.polynomial.tree.growable.PolynomialWithGB(using Boolean, new Lexicographic[Int](variables*)))
12 | }
13 |
14 | object BooleanAlgebra {
15 | trait Impl extends Residue[Element[Boolean, Array[Int]], Boolean, Int] with scas.residue.BooleanAlgebra.Impl {
16 | override def extend(variables: Variable*): Unit = {
17 | super.extend(variables*)
18 | update(generators.drop(ring.pp.variables.length - variables.length).map(x => x+x\2)*)
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/scas/application/src/scas/adapter/jas/Ring.scala:
--------------------------------------------------------------------------------
1 | package scas.adapter.jas
2 |
3 | import edu.jas.structure.RingElem
4 | import edu.jas.structure.RingFactory
5 | import scas.base.BigInteger
6 |
7 | trait Ring[T <: RingElem[T]] extends scas.structure.ordered.Ring[T] {
8 | def factory: RingFactory[T]
9 | def fromInt(n: BigInteger) = factory.fromInteger(n)
10 | override def zero = factory.getZERO()
11 | override def one = factory.getONE()
12 | extension (x: T) {
13 | def add(y: T) = x.sum(y)
14 | def subtract(y: T) = x.subtract(y)
15 | def multiply(y: T) = x.multiply(y)
16 | }
17 | def compare(x: T, y: T) = x.compareTo(y)
18 | extension (x: T) def isUnit = x.isUnit
19 | def characteristic = factory.characteristic
20 | extension (x: T) {
21 | def toCode(level: Level) = x.toString
22 | def toMathML = ???
23 | }
24 | def toMathML = ???
25 | }
26 |
27 | object Ring {
28 | trait Conv[T <: RingElem[T]] extends Ring[T] with scas.structure.ordered.Ring.Conv[T]
29 | }
30 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/BooleanParsers.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import Parsers.*
4 | import scala.annotation.nowarn
5 | import scas.base.Boolean
6 |
7 | class BooleanParsers extends BooleanRingParsers[Boolean] {
8 | override given structure: Boolean.Impl = Boolean
9 | def boolean: Parser[Boolean] = ("true" | "false") ^^ { _.toBoolean }
10 | def base: Parser[Boolean] = boolean | "(" ~> expr <~ ")"
11 | @nowarn("msg=match may not be exhaustive")
12 | override def comparison: Parser[Boolean] = term ~ rep(("=>" | "=" | "<>") ~ term) ^^ {
13 | case term ~ list => list.foldLeft(term) {
14 | case (x, "=>" ~ y) => x >> y
15 | case (x, "=" ~ y) => x >< y
16 | case (x, "<>" ~ y) => x <> y
17 | }
18 | }
19 | override def impl: Parser[Boolean] = Int.comparison | FactorParsers.comparison | RationalParsers.comparison | ComplexParsers.comparison | DoubleParsers.comparison | RFParsers(false).comparison | BAParsers(false).comparison | comparison
20 | }
21 |
--------------------------------------------------------------------------------
/examples/polynomial.txt:
--------------------------------------------------------------------------------
1 | // Requires : de.uni-mannheim.rz.krum#jas;2.7.10
2 |
3 | import edu.jas.poly.TermOrderByName
4 | import edu.jas.poly.{GenPolynomial, GenPolynomialRing}
5 | import scas.adapter.jas.{BigInteger, poly2scas}
6 | import BigInteger.given
7 |
8 | given GenPolynomialRing[BigInteger](BigInteger.factory, Array("x", "y", "z"), TermOrderByName.INVLEX)
9 | val r = poly2scas
10 | val List(one, x, y, z) = r.gens
11 | import r.given
12 |
13 | assert(x + 1 >< 1 + x)
14 | assert(x + BigInteger("1") >< BigInteger("1") + x)
15 | assert(x + BigInteger("18446744073709551616") >< BigInteger("18446744073709551616") + x)
16 | assert(x + one >< one + x)
17 | assert(x > one)
18 |
19 | given GenPolynomialRing[GenPolynomial[BigInteger]](r.factory, Array("a"), TermOrderByName.INVLEX)
20 | val s = poly2scas[GenPolynomial[BigInteger]]
21 | val List(_, a) = s.gens
22 | import s.given
23 |
24 | assert(a + 1 >< 1 + a)
25 | assert(a + BigInteger("1") >< BigInteger("1") + a)
26 | assert(a + x >< x + a)
27 | assert(a > x)
28 |
--------------------------------------------------------------------------------
/scas/src/scas/residue/AlgebraicNumber.scala:
--------------------------------------------------------------------------------
1 | package scas.residue
2 |
3 | import scas.polynomial.TreePolynomial.Element
4 | import scas.polynomial.ufd.PolynomialOverFieldWithGB
5 | import scas.power.degree.DegreeReverseLexicographic
6 | import scas.structure.commutative.Field
7 | import scas.util.{Conversion, unary_~}
8 | import scas.variable.Variable
9 |
10 | open class AlgebraicNumber[C](using PolynomialOverFieldWithGB[Element[C, Array[Int]], C, Int]) extends ResidueOverField[Element[C, Array[Int]], C, Int] {
11 | def this(ring: Field[C])(variables: Variable*) = this(using new scas.polynomial.tree.PolynomialOverFieldWithGB(using ring, new DegreeReverseLexicographic[Int](variables*)))
12 | }
13 |
14 | object AlgebraicNumber {
15 | def apply[C, S : Conversion[Variable]](ring: Field[C])(s: S*) = new Conv(ring)(s.map(~_)*)
16 |
17 | class Conv[C](ring: Field[C])(variables: Variable*) extends AlgebraicNumber(ring)(variables*) with Field.Conv[Element[C, Array[Int]]] {
18 | given instance: Conv[C] = this
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/BooleanRing.scala:
--------------------------------------------------------------------------------
1 | package scas.structure
2 |
3 | import scas.util.{Conversion, unary_~}
4 |
5 | trait BooleanRing[T] extends Ring[T] {
6 | extension (x: T) {
7 | def and(y: T) = x * y
8 | def or(y: T) = x ^ y ^ (x && y)
9 | def xor(y: T) = x + y
10 | def unary_! = x ^ one
11 | def implies(y: T) = y || !x
12 | inline def && [U: Conversion[T]](y: U) = x.and(~y)
13 | inline def || [U: Conversion[T]](y: U) = x.or(~y)
14 | inline def ^ [U: Conversion[T]](y: U) = x.xor(~y)
15 | inline def >> [U: Conversion[T]](y: U) = x.implies(~y)
16 | }
17 | }
18 |
19 | object BooleanRing {
20 | trait Conv[T] extends BooleanRing[T] with Ring.Conv[T] {
21 | extension[U: Conversion[T]] (x: U) {
22 | inline def && [V: Conversion[T]](y: V) = (~x).and(~y)
23 | inline def || [V: Conversion[T]](y: V) = (~x).or(~y)
24 | inline def ^ [V: Conversion[T]](y: V) = (~x).xor(~y)
25 | inline def >> [V: Conversion[T]](y: V) = (~x).implies(~y)
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/ufd/UnivariatePolynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.ufd
2 |
3 | import scala.reflect.ClassTag
4 | import scala.annotation.tailrec
5 | import scas.structure.commutative.EuclidianDomain
6 |
7 | trait UnivariatePolynomial[T : ClassTag, C, M] extends PolynomialWithModInverse[T, C, M] with EuclidianDomain[T] {
8 | assert (pp.length == 1)
9 | def derivative(x: T) = x.map((a, b) => (a / pp.generator(0), b * ring.fromInt(a.degree)))
10 | override def gcd(x: T, y: T) = gcd1(x, y)
11 | @tailrec final def gcd1(x: T, y: T): T = if y.isZero then x else gcd1(y, x.reduce(y))
12 | extension (x: T) {
13 | override def reduce(m: M, a: C, y: T, b: C, remainder: Boolean) = x.subtract(m, a / b, y)
14 | override def reduce(ys: T*) = super.reduce(x)(ys*)
15 | }
16 | extension (x: T) def modInverse(mods: T*) = {
17 | assert (mods.length == 1)
18 | val s = new scas.polynomial.ufd.repr.UnivariatePolynomial(using this)(1)
19 | val (p, e) = s.gcd(s(x, 0), s(mods(0)))
20 | assert (p.isUnit)
21 | e(0) / p
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/scas/src/scas/residue/growable/AlgebraicNumber.scala:
--------------------------------------------------------------------------------
1 | package scas.residue.growable
2 |
3 | import scas.polynomial.TreePolynomial.Element
4 | import scas.polynomial.ufd.growable.PolynomialOverFieldWithGB
5 | import scas.power.growable.DegreeReverseLexicographic
6 | import scas.structure.commutative.Field
7 | import scas.util.{Conversion, unary_~}
8 | import scas.variable.Variable
9 |
10 | class AlgebraicNumber[C](using PolynomialOverFieldWithGB[Element[C, Array[Int]], C, Int]) extends ResidueOverField[Element[C, Array[Int]], C, Int] {
11 | def this(ring: Field[C])(variables: Variable*) = this(using new scas.polynomial.tree.growable.PolynomialOverFieldWithGB(using ring, new DegreeReverseLexicographic[Int](variables*)))
12 | }
13 |
14 | object AlgebraicNumber {
15 | def apply[C, S : Conversion[Variable]](ring: Field[C])(s: S*) = new Conv(ring)(s.map(~_)*)
16 |
17 | class Conv[C](ring: Field[C])(variables: Variable*) extends AlgebraicNumber(ring)(variables*) with Field.Conv[Element[C, Array[Int]]] {
18 | given instance: Conv[C] = this
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/Monoid.scala:
--------------------------------------------------------------------------------
1 | package scas.structure
2 |
3 | import scas.util.{Conversion, unary_~}
4 | import scas.base.BigInteger
5 | import BigInteger.given
6 |
7 | trait Monoid[T] extends SemiGroup[T] {
8 | extension (a: T) {
9 | def pow(b: BigInteger): T = {
10 | assert (b.signum >= 0)
11 | if b.isZero then one else if (b % 2).isZero then {
12 | val c = a \ (b / 2)
13 | c * c
14 | } else {
15 | a * a \ (b - 1)
16 | }
17 | }
18 | def \ [U: Conversion[BigInteger]](b: U) = a.pow(~b)
19 | def \:[U: Conversion[BigInteger]](b: U) = a \ b
20 | }
21 | extension (x: T) {
22 | def isUnit: Boolean
23 | def isOne = x >< one
24 | }
25 | def one: T
26 | }
27 |
28 | object Monoid {
29 | trait Conv[T] extends Monoid[T] with SemiGroup.Conv[T] {
30 | extension[U: Conversion[T]] (a: U) {
31 | def \ [V: Conversion[BigInteger]](b: V) = (~a).pow(~b)
32 | }
33 | extension[U: Conversion[T], V: Conversion[BigInteger]] (a: U) {
34 | def \:(b: V) = a \ b
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/scas/src/scas/residue/ResidueOverField.scala:
--------------------------------------------------------------------------------
1 | package scas.residue
2 |
3 | import scala.reflect.ClassTag
4 | import scala.compiletime.deferred
5 | import scas.structure.commutative.Field
6 | import scas.polynomial.ufd.PolynomialOverFieldWithGB
7 | import scas.util.{Conversion, unary_~}
8 | import scas.variable.Variable
9 |
10 | trait ResidueOverField[T, C, N] extends Residue[T, C, N] with Field[T] {
11 | given ring: PolynomialOverFieldWithGB[T, C, N] = deferred
12 | def sqrt[U: Conversion[T]](x: U): T = sqrt(~x)
13 | def sqrt(x: T) = {
14 | val n = ring.pp.variables.indexOf(Variable.sqrt(x))
15 | assert (n > -1)
16 | generator(n)
17 | }
18 | def inverse(x: T) = x.modInverse(mods*)
19 |
20 | extension (ring: PolynomialOverFieldWithGB[T, C, N]) def apply(s: T*) = {
21 | same(s*)
22 | this
23 | }
24 | }
25 |
26 | object ResidueOverField {
27 | class Conv[T : ClassTag, C, N](using PolynomialOverFieldWithGB[T, C, N])(s: T*) extends ResidueOverField[T, C, N] with Field.Conv[T] {
28 | given instance: Conv[T, C, N] = this
29 | update(s*)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/scas/application/src/scas/adapter/rings/Ring.scala:
--------------------------------------------------------------------------------
1 | package scas.adapter.rings
2 |
3 | import cc.redberry.rings.io.Coder
4 | import scas.util.unary_~
5 | import BigInteger.given
6 |
7 | trait Ring[T] extends scas.structure.ordered.Ring[T] {
8 | def ring: cc.redberry.rings.Ring[T]
9 | def coder = Coder.mkCoder(ring)
10 | def fromInt(n: scas.base.BigInteger) = ring.valueOfBigInteger(new BigInteger(n))
11 | override def zero = ring.getZero()
12 | override def one = ring.getOne()
13 | extension (x: T) {
14 | def add(y: T) = ring.add(x, y)
15 | def subtract(y: T) = ring.subtract(x, y)
16 | def multiply(y: T) = ring.multiply(x, y)
17 | }
18 | def compare(x: T, y: T) = ring.compare(x, y)
19 | extension (x: T) def isUnit = ring.isUnit(x)
20 | def characteristic = ~ring.characteristic
21 | extension (x: T) {
22 | def toCode(level: Level) = coder.stringify(x)
23 | def toMathML = ???
24 | }
25 | def toMathML = ???
26 | }
27 |
28 | object Ring {
29 | def apply[T : Ring] = summon[Ring[T]]
30 |
31 | trait Conv[T] extends Ring[T] with scas.structure.ordered.Ring.Conv[T]
32 | }
33 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/Int.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import Parsers.*
4 | import scala.annotation.{nowarn, tailrec}
5 | import scas.base.BigInteger
6 | import BigInteger.int2bigInt
7 |
8 | object Int extends OrderedRingParsers[BigInteger] {
9 | override given structure: BigInteger.Impl = BigInteger
10 | def number: Parser[BigInteger] = """\d+""".r ^^ { BigInteger(_) }
11 | @nowarn("msg=match may not be exhaustive")
12 | def function1: Parser[BigInteger] = ("factorial") ~ ("(" ~> expr) <~ ")" ^^ {
13 | case "factorial" ~ x if (x > 0) => factorial(x)
14 | }
15 | @nowarn("msg=match may not be exhaustive")
16 | def function2: Parser[BigInteger] = ("div" | "mod") ~ ("(" ~> expr) ~ ("," ~> expr) <~ ")" ^^ {
17 | case "div" ~ x ~ y => x / y
18 | case "mod" ~ x ~ y => x % y
19 | }
20 | def function: Parser[BigInteger] = function1 | function2
21 | def base: Parser[BigInteger] = number | function | "(" ~> expr <~ ")"
22 |
23 | def factorial(x: BigInteger): BigInteger = factorial(BigInteger.one, x)
24 |
25 | @tailrec final def factorial(res: BigInteger, x: BigInteger): BigInteger = if x > 1 then factorial(x * res, x - 1) else res
26 | }
27 |
--------------------------------------------------------------------------------
/scas/application/src/scas/adapter/math3/Double.scala:
--------------------------------------------------------------------------------
1 | package scas.adapter.math3
2 |
3 | import java.lang.Math
4 | import scas.structure.commutative.Field
5 | import scas.base.BigInteger
6 |
7 | type Double = scala.Double
8 |
9 | object Double extends Double.Impl with Field.Conv[Double] {
10 | given instance: Double.type = this
11 | abstract class Impl extends Field[Double] {
12 | override def random(numbits: Int)(using rnd: java.util.Random) = rnd.nextDouble()
13 | def fromInt(n: BigInteger) = n.doubleValue()
14 | override val zero = 0
15 | override val one = 1
16 | extension (x: Double) {
17 | def add(y: Double) = x + y
18 | def subtract(y: Double) = x - y
19 | def multiply(y: Double) = x * y
20 | override def divide(y: Double) = x / y
21 | }
22 | def inverse(x: Double) = 1 / x
23 | def equiv(x: Double, y: Double) = x == y
24 | extension (x: Double) def signum = Math.signum(x).toInt
25 | def characteristic = BigInteger("0")
26 | extension (x: Double) {
27 | def toCode(level: Level) = x.toString
28 | def toMathML = s"$x"
29 | }
30 | override def toString = "Double"
31 | def toMathML = ""
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/scas/src/scas/base/Boolean.scala:
--------------------------------------------------------------------------------
1 | package scas.base
2 |
3 | import scala.compiletime.deferred
4 | import scas.structure.BooleanRing
5 | import scas.structure.commutative.Field
6 |
7 | type Boolean = scala.Boolean
8 |
9 | object Boolean extends Boolean.Impl with Field.Conv[Boolean] with BooleanRing.Conv[Boolean] {
10 | override given instance: Boolean.type = this
11 | trait Impl extends Field[Boolean] with BooleanRing[Boolean] {
12 | given instance: Boolean.Impl = deferred
13 | val self = this
14 | def fromInt(n: BigInteger) = n.signum != 0
15 | override val zero = false
16 | override val one = true
17 | extension (x: Boolean) {
18 | def add(y: Boolean) = x ^ y
19 | def subtract(y: Boolean) = x + y
20 | def multiply(y: Boolean) = x && y
21 | }
22 | def inverse(x: Boolean) = x
23 | val characteristic = BigInteger("2")
24 | def equiv(x: Boolean, y: Boolean) = x == y
25 | extension (x: Boolean) def signum = if x then 1 else 0
26 | extension (x: Boolean) def toCode(level: Level) = x.toString
27 | override def toString = "Boolean"
28 | extension (x: Boolean) def toMathML = if x then "" else ""
29 | def toMathML = "Boolean"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/ufd/PolynomialWithGB.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.ufd
2 |
3 | import scala.compiletime.deferred
4 | import scala.reflect.ClassTag
5 | import scas.math.Numeric
6 | import scas.power.{ArrayPowerProduct, POT, ModifiedPOT}
7 | import scas.polynomial.gb.GBEngine
8 | import scas.module.Array
9 | import scas.base.BigInteger
10 | import BigInteger.given
11 |
12 | trait PolynomialWithGB[T : ClassTag, C, N : {Numeric, ClassTag}] extends PolynomialOverUFD[T, C, Array[N]] {
13 | given pp: ArrayPowerProduct[N] = deferred
14 | extension (x: T) def convert(from: ArrayPowerProduct[N]) = x.map((s, a) => (s.convert(from), a)).sort
15 | def embedding(name: String, dimension: Int) = newInstance(new ModifiedPOT(pp, name, dimension))
16 | def newInstance(pp: POT[N]): PolynomialWithGB[T, C, N]
17 | def gcd(x: T, y: T) = {
18 | val (a, p) = contentAndPrimitivePart(x)
19 | val (b, q) = contentAndPrimitivePart(y)
20 | given module: Module[T, C, N] = new Module(using this)("c", 3)
21 | val list = module.gb(
22 | Array(p, 1, 0),
23 | Array(q, 0, 1)
24 | )
25 | val Array(_, u, v) = list.last
26 | (p / v)%* ring.gcd(a, b)
27 | }
28 | def gb(xs: T*) = new GBEngine(using this).gb(xs*)
29 | }
30 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/FS.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import scala.annotation.tailrec
4 | import scas.util.{Conversion, unary_~}
5 | import scala.collection.immutable.SortedMap
6 | import scas.base.BigInteger
7 | import BigInteger.given
8 | import Factors.Element
9 |
10 | type FS = Element[BigInteger, Int]
11 |
12 | object FS extends Factors[BigInteger, Int] {
13 | def empty = SortedMap.empty[BigInteger, Int]
14 |
15 | def apply[U: Conversion[BigInteger]](x: U) = super.apply(~x)
16 | override def apply(x: BigInteger) = if x.isZero then zero else factor(BigInteger.abs(x), one, primes)*this(BigInteger.signum(x))
17 |
18 | @tailrec final def factor(x: BigInteger, map: FS, primes: LazyList[BigInteger]): FS = {
19 | val y = primes.head
20 | if x >< 1 then map
21 | else if y * y > x then map + ((x, map.getOrElse(x, 0) + 1))
22 | else if y | x then factor(x / y, map + ((y, map.getOrElse(y, 0) + 1)), primes)
23 | else factor(x, map, primes.tail)
24 | }
25 |
26 | def sieve(n: BigInteger): LazyList[BigInteger] = {
27 | if primes.takeWhile(p => p * p <= n).exists(_ | n) then sieve(n + 2)
28 | else n #:: sieve(n + 2)
29 | }
30 |
31 | val primes: LazyList[BigInteger] = BigInteger("2") #:: sieve(BigInteger("3"))
32 | }
33 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/BooleanAlgebra.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import scas.variable.Variable
4 |
5 | class BooleanAlgebra(on: Boolean, recurse: Boolean, conj: Boolean, s: Variable*) extends BooleanAlgebra.WithNot(s*) {
6 | def this(conj: Boolean, s: Variable*) = this(true, true, conj, s*)
7 | def this(s: Variable*) = this(true, s*)
8 | override def extend(variables: Variable*): Unit = {
9 | super.extend(variables*)
10 | if (on) then a.extend(variables*)
11 | }
12 | given a: BooleanAlgebra = new BooleanAlgebra(recurse, false, !conj, s*)
13 | given nf: NormalForm = new NormalForm(conj)
14 | extension (x: BA) {
15 | override def toCode(level: Level) = if on then nf(x).toCode(level) else super.toCode(x)(level)
16 | override def toMathML = if on then nf(x).toMathML else super.toMathML(x)
17 | }
18 | }
19 |
20 | object BooleanAlgebra {
21 | class WithNot(s: Variable*) extends scas.residue.growable.BooleanAlgebra(s*) {
22 | extension (x: BA) {
23 | def isNot = x.coefOne.isOne && !x.isOne
24 | override def toCode(level: Level) = if !x.isNot then super.toCode(x)(level) else s"!${super.toCode(!x)(Level.Power)}"
25 | override def toMathML = if !x.isNot then super.toMathML(x) else s"${super.toMathML(!x)}"
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/scas/src/scas/quotient/RationalFunction.scala:
--------------------------------------------------------------------------------
1 | package scas.quotient
2 |
3 | import scas.structure.commutative.Field
4 | import scas.structure.commutative.Quotient.{Element as Quotient_Element}
5 | import scas.polynomial.tree.PolynomialWithSubresGCD
6 | import scas.polynomial.TreePolynomial.Element
7 | import scas.polynomial.ufd.PolynomialOverUFD
8 | import scas.util.{Conversion, unary_~}
9 | import scas.variable.Variable
10 | import scas.base.BigInteger
11 |
12 | class RationalFunction(using PolynomialOverUFD[Element[BigInteger, Array[Int]], BigInteger, Array[Int]]) extends QuotientOverInteger[Element[BigInteger, Array[Int]], Array[Int]] {
13 | def this(variables: Variable*) = this(using new PolynomialWithSubresGCD(using BigInteger)(variables*))
14 | }
15 |
16 | object RationalFunction {
17 | def apply[C, S : Conversion[Variable]](ring: Field[C])(s: S*) = new RationalFunctionOverField.Conv(ring)(s.map(~_)*)
18 | def integral[S : Conversion[Variable]](s: S*) = new Conv(s.map(~_)*)
19 |
20 | class Conv(variables: Variable*) extends RationalFunction(variables*) with Field.Conv[Quotient_Element[Element[BigInteger, Array[Int]]]] {
21 | given instance: Conv = this
22 | extension[U: Conversion[BigInteger]] (a: U) {
23 | def %%[V: Conversion[BigInteger]](b: V) = this(ring(~a), ring(~b))
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/BooleanRingParsers.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import Parsers.*
4 | import scala.annotation.nowarn
5 | import scala.compiletime.deferred
6 |
7 | trait BooleanRingParsers[T] extends RingParsers[T] {
8 | given structure: scas.structure.BooleanRing[T] = deferred
9 | override def term: Parser[T] = opt("!") ~ base ^^ {
10 | case option ~ base => option match {
11 | case Some(sign) => !base
12 | case None => base
13 | }
14 | }
15 | @nowarn("msg=match may not be exhaustive")
16 | def impl: Parser[T] = term ~ rep("=>" ~ term) ^^ {
17 | case term ~ list => list.foldLeft(term) {
18 | case (x, "=>" ~ y) => x >> y
19 | }
20 | }
21 | @nowarn("msg=match may not be exhaustive")
22 | def conj: Parser[T] = impl ~ rep("&" ~ impl) ^^ {
23 | case impl ~ list => list.foldLeft(impl) {
24 | case (x, "&" ~ y) => x && y
25 | }
26 | }
27 | @nowarn("msg=match may not be exhaustive")
28 | def disj: Parser[T] = conj ~ rep("^" ~ conj) ^^ {
29 | case conj ~ list => list.foldLeft(conj) {
30 | case (x, "^" ~ y) => x ^ y
31 | }
32 | }
33 | @nowarn("msg=match may not be exhaustive")
34 | override def expr: Parser[T] = disj ~ rep("|" ~ disj) ^^ {
35 | case disj ~ list => list.foldLeft(disj) {
36 | case (x, "|" ~ y) => x || y
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/direct/StreamPolynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.direct
2 |
3 | import scas.polynomial.Polynomial
4 | import scas.util.direct.Stream
5 | import StreamPolynomial.Element
6 |
7 | trait StreamPolynomial[C, M] extends Polynomial[Element[C, M], C, M] {
8 | def apply(s: (M, C)*) = Stream(s*)
9 |
10 | extension (x: Element[C, M]) {
11 | def add(y: Element[C, M]) = if !x.isEmpty then {
12 | if !y.isEmpty then {
13 | val (s, a) = x.head
14 | val (t, b) = y.head
15 | if s > t then (s, a)#::(x.tail + y)
16 | else if s < t then (t, b)#::(x + y.tail)
17 | else {
18 | val c = a + b
19 | val result = (s, c)#:(x.tail + y.tail)
20 | if !c.isZero then result else result.tail
21 | }
22 | } else x
23 | } else y
24 |
25 | override def isZero = x.isEmpty
26 |
27 | def iterator = x.iterator
28 |
29 | def size = x.toSeq.size
30 |
31 | def head = x.head
32 |
33 | def last = x.toSeq.last
34 |
35 | def map(f: (M, C) => (M, C)) = if !x.isEmpty then {
36 | val (s, a) = x.head
37 | val (m, c) = f(s, a)
38 | val result = (m, c)#::x.tail.map(f)
39 | if !c.isZero then result else result.tail
40 | } else Stream.Nil
41 | }
42 | }
43 |
44 | object StreamPolynomial {
45 | type Element[C, M] = Stream[(M, C)]
46 | }
47 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/BAParsers.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import Parsers.*
4 | import scala.annotation.nowarn
5 | import scala.compiletime.deferred
6 | import scas.polynomial.TreePolynomial.Element
7 | import scas.variable.Variable
8 |
9 | type BA = Element[Boolean, Array[Int]]
10 |
11 | class BAParsers(using BooleanAlgebra) extends BAParsers.Impl {
12 | def this(dummy: Boolean) = this(using BooleanAlgebra())
13 | @nowarn("msg=match may not be exhaustive")
14 | def function: Parser[BA] = ("mod") ~ ("(" ~> expr) ~ rep("," ~> expr) <~ ")" ^^ {
15 | case "mod" ~ expr ~ list => mod(expr, list*)
16 | }
17 | def generator: Parser[BA] = Var.parser ^^ { generator(_) }
18 | def generator(a: Variable) = {
19 | val variables = structure.ring.pp.variables
20 | if variables.contains(a) then structure.generator(variables.indexOf(a))
21 | else {
22 | structure.extend(a)
23 | structure.generator(variables.length)
24 | }
25 | }
26 | def base: Parser[BA] = BooleanParsers().base ^^ { structure(_) } | function | generator | "(" ~> expr <~ ")"
27 | }
28 |
29 | object BAParsers {
30 | trait Impl extends BooleanRingParsers[BA] {
31 | given structure: BooleanAlgebra = deferred
32 | def mod(expr: BA, list: BA*) = {
33 | structure.update(list.map(!_)*)
34 | !structure(!expr)
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/gb/GMSetting.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.gb
2 |
3 | import scala.collection.immutable.SortedSet
4 | import scala.collection.mutable.ArrayBuffer
5 | import scas.polynomial.Polynomial
6 | import scas.math.Ordering
7 |
8 | trait GMSetting[T, C, M, P[M] <: Pair[M]](using factory: Polynomial[T, C, M]) extends Engine[T, C, M, P] {
9 | import factory.pp
10 |
11 | override def b_criterion(pa: P[M]) = false
12 |
13 | extension (p1: P[M]) def | (p2: P[M]) = (p1.scm | p2.scm) && (p1.scm < p2.scm)
14 |
15 | override def make(index: Int): Unit = {
16 | val buffer = new ArrayBuffer[P[M]]
17 | for pair <- pairs do {
18 | val p1 = apply(pair.i, index)
19 | val p2 = apply(pair.j, index)
20 | if (p1 | pair) && (p2 | pair) then buffer += pair
21 | }
22 | for i <- 0 until buffer.size do remove(buffer(i))
23 | var s = SortedSet.empty(using natural)
24 | for i <- 0 until index do {
25 | val pair = apply(i, index)
26 | s += pair
27 | add(pair)
28 | }
29 | buffer.clear
30 | buffer ++= s
31 | for i <- 0 until buffer.size do {
32 | val p1 = buffer(i)
33 | for j <- i + 1 until buffer.size do {
34 | val p2 = buffer(j)
35 | if p1.scm | p2.scm then remove(p2)
36 | }
37 | }
38 | }
39 |
40 | def natural = Ordering by { (pair: P[M]) => pair.key }
41 | }
42 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/StreamPolynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial
2 |
3 | import scas.util.{Stream, await, given}
4 | import StreamPolynomial.Element
5 |
6 | trait StreamPolynomial[C, M] extends Polynomial[Element[C, M], C, M] {
7 | def apply(s: (M, C)*) = Stream(s*)
8 |
9 | extension (x: Element[C, M]) {
10 | def add(y: Element[C, M]) = if !x.isEmpty then {
11 | if !y.isEmpty then {
12 | val (s, a) = x.head
13 | val (t, b) = y.head
14 | if s > t then (s, a)#:x.tail.map(_ + y)
15 | else if s < t then (t, b)#:y.tail.map(x + _)
16 | else {
17 | val c = a + b
18 | val result = (s, c)#:(for sx <- x.tail; sy <- y.tail yield sx + sy)
19 | if !c.isZero then result else result.tail.await
20 | }
21 | } else x
22 | } else y
23 |
24 | override def isZero = x.isEmpty
25 |
26 | def iterator = x.iterator
27 |
28 | def size = x.toSeq.size
29 |
30 | def head = x.head
31 |
32 | def last = x.toSeq.last
33 |
34 | def map(f: (M, C) => (M, C)) = if !x.isEmpty then {
35 | val (s, a) = x.head
36 | val (m, c) = f(s, a)
37 | val result = (m, c)#:x.tail.map(_.map(f))
38 | if !c.isZero then result else result.tail.await
39 | } else Stream.Nil
40 | }
41 | }
42 |
43 | object StreamPolynomial {
44 | type Element[C, M] = Stream[(M, C)]
45 | }
46 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/tree/MultivariatePolynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.tree
2 |
3 | import scas.power.splitable.{PowerProduct, Lexicographic}
4 | import scas.structure.commutative.{UniqueFactorizationDomain, Field}
5 | import scas.variable.Variable
6 | import scas.util.{Conversion, unary_~}
7 | import scas.polynomial.TreePolynomial
8 | import TreePolynomial.Element
9 |
10 | trait MultivariatePolynomial[C] extends TreePolynomial[C, Array[Int]] with scas.polynomial.ufd.MultivariatePolynomial[Element, C, Array[Int]] with UniqueFactorizationDomain.Conv[Element[C, Array[Int]]] {
11 | def variables: Seq[Variable]
12 | override given pp: PowerProduct[Array[Int]] = new Lexicographic[Int](variables*)
13 | given instance: MultivariatePolynomial[C] = this
14 | }
15 |
16 | object MultivariatePolynomial {
17 | def withSimpleGCD[C, S : Conversion[Variable]](ring: UniqueFactorizationDomain[C])(s: S*) = new PolynomialWithSimpleGCD(using ring)(s.map(~_)*)
18 | def withPrimitiveGCD[C, S : Conversion[Variable]](ring: UniqueFactorizationDomain[C])(s: S*) = new PolynomialWithPrimitiveGCD(using ring)(s.map(~_)*)
19 | def withSubresGCD[C, S : Conversion[Variable]](ring: UniqueFactorizationDomain[C])(s: S*) = new PolynomialWithSubresGCD(using ring)(s.map(~_)*)
20 | def apply[C, S : Conversion[Variable]](ring: Field[C])(s: S*) = new MultivariatePolynomialOverField(using ring)(s.map(~_)*)
21 | }
22 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/commutative/UniqueFactorizationDomain.scala:
--------------------------------------------------------------------------------
1 | package scas.structure.commutative
2 |
3 | import scas.structure.NotQuiteField
4 | import scas.util.{Conversion, unary_~}
5 |
6 | trait UniqueFactorizationDomain[T] extends NotQuiteField[T] {
7 | def gcd(x: T, y: T): T
8 | def lcm(x: T, y: T) = (x * y) / gcd(x, y)
9 | def gcd[U: Conversion[T], V: Conversion[T]](x: U, y: V): T = gcd(~x, ~y)
10 | def lcm[U: Conversion[T], V: Conversion[T]](x: U, y: V): T = lcm(~x, ~y)
11 | extension (x: T) {
12 | def divide(y: T) = {
13 | val (q, _) = x /%y
14 | q
15 | }
16 | def remainder(y: T) = {
17 | val (_, r) = x /%y
18 | r
19 | }
20 | def divideAndRemainder(y: T): (T, T)
21 | def factorOf(y: T) = (y % x).isZero
22 | inline def % [U: Conversion[T]](y: U) = x.remainder(~y)
23 | inline def /%[U: Conversion[T]](y: U) = x.divideAndRemainder(~y)
24 | inline def | [U: Conversion[T]](y: U) = x.factorOf(~y)
25 | }
26 | }
27 |
28 | object UniqueFactorizationDomain {
29 | trait Conv[T] extends UniqueFactorizationDomain[T] with NotQuiteField.Conv[T] {
30 | extension[U: Conversion[T]] (x: U) {
31 | inline def % [V: Conversion[T]](y: V) = (~x).remainder(~y)
32 | inline def /%[V: Conversion[T]](y: V) = (~x).divideAndRemainder(~y)
33 | inline def | [V: Conversion[T]](y: V) = (~x).factorOf(~y)
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/scas/application/src/scas/adapter/rings/MultivariatePolynomialRing.scala:
--------------------------------------------------------------------------------
1 | package scas.adapter.rings
2 |
3 | import cc.redberry.rings.io.Coder
4 | import cc.redberry.rings.poly.MultivariateRing
5 | import cc.redberry.rings.poly.multivar.MultivariatePolynomial
6 | import cc.redberry.rings.poly.multivar.DegreeVector;
7 | import scas.util.{Conversion, unary_~}
8 | import java.util.Comparator
9 |
10 | trait MultivariatePolynomialRing[C : Ring](monomialOrder: Comparator[DegreeVector], variables: String*) extends Ring[MultivariatePolynomial[C]] {
11 | val ring: MultivariateRing[MultivariatePolynomial[C]] = MultivariateRing(MultivariatePolynomial.zero(variables.size, Ring[C].ring, monomialOrder))
12 | override def coder = Coder.mkMultivariateCoder(ring, Ring[C].coder, variables*)
13 | def gens = (for i <- 0 until ring.nVariables() yield ring.variable(i)).toList
14 |
15 | given coef2poly: [D : Conversion[C]] => (D => MultivariatePolynomial[C]) = x => ring.factory().createConstant(~x)
16 | }
17 |
18 | object MultivariatePolynomialRing {
19 | def apply[C : Ring](monomialOrder: Comparator[DegreeVector], variables: String*) = new Conv(monomialOrder, variables*)
20 |
21 | class Conv[C : Ring](monomialOrder: Comparator[DegreeVector], variables: String*) extends MultivariatePolynomialRing[C](monomialOrder, variables*) with Ring.Conv[MultivariatePolynomial[C]] {
22 | given instance: Conv[C] = this
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/RingParsers.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import Parsers.*
4 | import scala.annotation.nowarn
5 | import scala.compiletime.deferred
6 |
7 | trait RingParsers[T] extends StructureParsers[T] {
8 | given structure: scas.structure.Ring[T] = deferred
9 | def base: Parser[T]
10 | def unsignedFactor: Parser[T] = base ~ opt(("**" | "^") ~> Int.unsignedFactor) ^^ {
11 | case x ~ option => option match {
12 | case Some(exp) => x \ exp
13 | case None => x
14 | }
15 | }
16 | def factor: Parser[T] = opt("-") ~ unsignedFactor ^^ {
17 | case option ~ factor => option match {
18 | case Some(sign) => -factor
19 | case None => factor
20 | }
21 | }
22 | @nowarn("msg=match may not be exhaustive")
23 | def unsignedTerm: Parser[T] = unsignedFactor ~ rep("*" ~ factor) ^^ {
24 | case factor ~ list => list.foldLeft(factor) {
25 | case (x, "*" ~ y) => x * y
26 | }
27 | }
28 | def term: Parser[T] = opt("-") ~ unsignedTerm ^^ {
29 | case option ~ term => option match {
30 | case Some(sign) => -term
31 | case None => term
32 | }
33 | }
34 | @nowarn("msg=match may not be exhaustive")
35 | def expr: Parser[T] = term ~ rep(("+" | "-") ~ unsignedTerm) ^^ {
36 | case term ~ list => list.foldLeft(term) {
37 | case (x, "+" ~ y) => x + y
38 | case (x, "-" ~ y) => x - y
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/ivy.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/DoubleParsers.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import Parsers.{log as _, *}
4 | import scala.annotation.nowarn
5 | import scas.adapter.math3.Double
6 | import Math.{sinh, cosh, tanh, sin, cos, tan, asin, acos, atan, exp, log, pow, PI}
7 |
8 | object DoubleParsers extends FieldParsers[Double] {
9 | override given structure: Double.Impl = Double
10 | def number: Parser[Double] = """(\d+(\.\d*)?|\d*\.\d+)([eE][+-]?\d+)?""".r ^^ { _.toDouble }
11 | def constant: Parser[Double] = ("pi") ^^ {
12 | case "pi" => PI
13 | }
14 | @nowarn("msg=match may not be exhaustive")
15 | def function: Parser[Double] = ("sinh" | "cosh" | "tanh" | "sin" | "cos" | "tan" | "asin" | "acos" | "atan" | "exp" | "log") ~ ("(" ~> expr) <~ ")" ^^ {
16 | case "sinh" ~ x => sinh(x)
17 | case "cosh" ~ x => cosh(x)
18 | case "tanh" ~ x => tanh(x)
19 | case "sin" ~ x => sin(x)
20 | case "cos" ~ x => cos(x)
21 | case "tan" ~ x => tan(x)
22 | case "asin" ~ x => asin(x)
23 | case "acos" ~ x => acos(x)
24 | case "atan" ~ x => atan(x)
25 | case "exp" ~ x => exp(x)
26 | case "log" ~ x => log(x)
27 | }
28 | def base: Parser[Double] = number | constant | function | "(" ~> expr <~ ")"
29 | override def unsignedFactor: Parser[Double] = base ~ opt(("**" | "^") ~> factor) ^^ {
30 | case x ~ option => option match {
31 | case Some(y) => pow(x, y)
32 | case None => x
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/scas/src/scas/residue/BooleanAlgebra.scala:
--------------------------------------------------------------------------------
1 | package scas.residue
2 |
3 | import scas.structure.BooleanRing
4 | import scas.structure.commutative.UniqueFactorizationDomain
5 | import scas.polynomial.TreePolynomial.Element
6 | import scas.polynomial.ufd.PolynomialWithGB
7 | import scas.power.Lexicographic
8 | import scas.variable.Variable
9 | import scas.util.{Conversion, unary_~}
10 | import scas.base.{BigInteger, Boolean}
11 | import BigInteger.given
12 |
13 | class BooleanAlgebra(using PolynomialWithGB[Element[Boolean, Array[Int]], Boolean, Int]) extends BooleanAlgebra.Impl {
14 | def this(variables: Variable*) = this(using new scas.polynomial.tree.PolynomialWithGB(using Boolean, new Lexicographic[Int](variables*)))
15 | }
16 |
17 | object BooleanAlgebra {
18 | def apply[S : Conversion[Variable]](s: S*) = new Conv(s.map(~_)*)
19 |
20 | trait Impl extends Residue[Element[Boolean, Array[Int]], Boolean, Int] with BooleanRing[Element[Boolean, Array[Int]]] {
21 | update(generators.map(x => x+x\2)*)
22 | extension (x: Element[Boolean, Array[Int]]) {
23 | override def toCode(level: Level) = ring.toCode(x)(level, " ^ ", " && ")
24 | override def toMathML = ring.toMathML(x)("xor", "and")
25 | }
26 | }
27 |
28 | class Conv(variables: Variable*) extends BooleanAlgebra(variables*) with UniqueFactorizationDomain.Conv[Element[Boolean, Array[Int]]] with BooleanRing.Conv[Element[Boolean, Array[Int]]] {
29 | given instance: Conv = this
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/ufd/Module.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.ufd
2 |
3 | import scala.reflect.ClassTag
4 | import scas.module.ArrayModule
5 | import scas.power.ModifiedPOT
6 | import scas.math.Numeric
7 |
8 | class Module[T : ClassTag, C, N : {Numeric, ClassTag}](using ring: PolynomialWithGB[T, C, N])(name: String, dimension: Int) extends ArrayModule[T](dimension) {
9 | def gb(xs: Array[T]*) = {
10 | val s = ring.embedding(name, dimension)
11 | s.gb((xs.map(_.convertTo(using s)) ++ products(using s))*).map(_.convertFrom(s)).filter(!_.isZero)
12 | }
13 | def products(using s: PolynomialWithGB[T, C, N]) = {
14 | import s.pp
15 | for i <- 0 until dimension; j <- i until dimension yield s.generator(pp.length - dimension + i) * s.generator(pp.length - dimension + j)
16 | }
17 | extension (x: Array[T]) def convertTo(using s: PolynomialWithGB[T, C, N]): T = {
18 | x.zipWithIndex.foldLeft(s.zero)((l, r) => {
19 | import ring.pp
20 | val (p, n) = r
21 | l + p.convert(pp) * s.generator(pp.length + n)
22 | })
23 | }
24 | extension (x: T) def convertFrom(s: PolynomialWithGB[T, C, N]): Array[T] = s.iterator(x).foldLeft(zero) { (l, r) =>
25 | import s.pp
26 | val (m, c) = r
27 | val n = m.projection(pp.length - dimension, pp.length)
28 | l + (for i <- 0 until dimension yield {
29 | if n >< pp.generator(pp.length - dimension + i) then s(m / n, c).convert(ring.pp) else ring.zero
30 | }).toArray
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/gb/SugarEngine.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.gb
2 |
3 | import scala.annotation.targetName
4 | import scas.polynomial.{Polynomial, PolynomialWithSugar}
5 | import PolynomialWithSugar.Element
6 | import scas.base.{BigInteger, Boolean}
7 | import BigInteger.self.{max, given}
8 | import Boolean.self.given
9 | import scas.math.Ordering
10 |
11 | class SugarEngine[T, C, M](fussy: Boolean)(using factory: PolynomialWithSugar[T, C, M]) extends GMSetting[Element[T], C, M, SugarPair] {
12 | def this(fussy: Boolean)(factory: Polynomial[T, C, M]) = this(fussy)(using PolynomialWithSugar(using factory))
13 | def this(factory: Polynomial[T, C, M]) = this(false)(factory)
14 | import factory.pp
15 |
16 | override def ordering = Ordering by { (pair: SugarPair[M]) => pair.skey }
17 |
18 | override def natural = if fussy then ordering else super.natural
19 |
20 | extension (p1: SugarPair[M]) override def | (p2: SugarPair[M]) = super.|(p1)(p2) && (fussy >> (p1 < p2))
21 |
22 | override def apply(i: Int, j: Int) = {
23 | val m = i.headPowerProduct
24 | val n = j.headPowerProduct
25 | val scm = pp.lcm(m, n)
26 | val s = max(i.sugar - i.degree, j.sugar - j.degree)
27 | new SugarPair(i, j, m, n, scm, s + scm.degree)
28 | }
29 |
30 | extension (i: Int) def degree = i.headPowerProduct.degree
31 | extension (i: Int) def sugar = {
32 | val (_, e) = polys(i)
33 | e
34 | }
35 |
36 | @targetName("sugarGB") def gb(xs: T*): List[T] = gb(xs.map(factory(_))*).map(_._1)
37 | }
38 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | 4.0.0
6 | com.github.rjolly
7 | scas_3
8 | jar
9 | 3.1
10 | https://github.com/rjolly/scas
11 | Scala Algebra System
12 |
13 |
14 | GPL
15 | http://www.gnu.org/licenses/gpl.txt
16 |
17 |
18 | scas
19 |
20 | com.github.rjolly
21 |
22 |
23 | git@github.com:rjolly/scas.git
24 | scm:git:git@github.com:rjolly/scas.git
25 |
26 |
27 |
28 | rjolly
29 | Raphael Jolly
30 | https://github.com/rjolly
31 |
32 |
33 |
34 |
35 | org.scala-lang.modules
36 | scala-parallel-collections_3
37 | 1.0.4
38 |
39 |
40 | org.scala-lang
41 | scala3-library_3
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/scas/application/src/scas/adapter/jas/PowerProduct.scala:
--------------------------------------------------------------------------------
1 | package scas.adapter.jas
2 |
3 | import scas.variable.Variable
4 | import edu.jas.poly.{ExpVector, TermOrder}
5 | import scas.util.{Conversion, unary_~}
6 | import scas.base.BigInteger
7 | import BigInteger.given
8 |
9 | class PowerProduct(val variables: Variable*)(tord: TermOrder) extends scas.power.PowerProduct[ExpVector] {
10 | val comp = tord.getDescendComparator
11 | val one = ExpVector.create(length)
12 | def generator(n: Int) = ExpVector.create(length, n, 1)
13 | extension (x: ExpVector) def degree = BigInteger.fromInt(x.degree)
14 | def gcd(x: ExpVector, y: ExpVector) = x.gcd(y)
15 | def lcm(x: ExpVector, y: ExpVector) = x.lcm(y)
16 | extension (x: ExpVector) {
17 | def multiply(y: ExpVector) = x.sum(y)
18 | def divide(y: ExpVector) = x.subtract(y)
19 | def factorOf(y: ExpVector) = x.divides(y)
20 | }
21 | def compare(x: ExpVector, y: ExpVector) = comp.compare(x, y)
22 | extension (x: ExpVector) {
23 | def dependencyOnVariables = x.dependencyOnVariables
24 | def projection(n: Int, m: Int) = ???
25 | def size = x.dependentVariables
26 | def toCode(level: Level, times: String) = x.toString(variables.map(_.toString).toArray)
27 | def toMathML(times: String) = ???
28 | }
29 | }
30 |
31 | object PowerProduct {
32 | def apply[U: Conversion[Variable]](variables: U*)(tord: TermOrder) = new Conv(variables.map(~_)*)(tord)
33 |
34 | class Conv(variables: Variable*)(tord: TermOrder) extends PowerProduct(variables*)(tord) with scas.power.PowerProduct.Conv[ExpVector] {
35 | given instance: Conv = this
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/ufd/MultivariatePolynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.ufd
2 |
3 | import scala.compiletime.deferred
4 | import scas.power.splitable.PowerProduct
5 | import scas.structure.commutative.UniqueFactorizationDomain
6 |
7 | trait MultivariatePolynomial[T[C, M], C, M] extends PolynomialOverUFD[T[C, M], C, M] {
8 | given pp: PowerProduct[M] = deferred
9 | val take = pp.take(1)
10 | val drop = pp.drop(1)
11 | def newInstance: [C] => (UniqueFactorizationDomain[C], PowerProduct[M]) => MultivariatePolynomial[T, C, M]
12 | def gcd1(x: T[C, M], y: T[C, M]): T[C, M]
13 | def gcd(x: T[C, M], y: T[C, M]) = if pp.length > 1 then {
14 | val p = newInstance(ring, drop)
15 | val s = newInstance(p, take)
16 | s.gcd(x.convertTo(using p, s), y.convertTo(using p, s)).convertFrom(s)
17 | } else {
18 | val (a, p) = contentAndPrimitivePart(x)
19 | val (b, q) = contentAndPrimitivePart(y)
20 | primitivePart(gcd1(p, q))%* ring.gcd(a, b)
21 | }
22 | extension (x: T[C, M]) def convert(from: PowerProduct[M]) = x.map((s, a) => (s.convert(from), a)).sort
23 | extension (x: T[C, M]) def convertTo(using p: MultivariatePolynomial[T, C, M], s: MultivariatePolynomial[T, T[C, M], M]): T[T[C, M], M] = x.iterator.foldLeft(s.zero) { (l, r) =>
24 | val (m, c) = r
25 | val t = m.projection(0)
26 | l + s(take.convert(t)(pp), p(drop.convert(m / t)(pp), c))
27 | }
28 | extension (x: T[T[C, M], M]) def convertFrom(s: MultivariatePolynomial[T, T[C, M], M]): T[C, M] = s.iterator(x).foldLeft(zero) { (l, r) =>
29 | val (m, c) = r
30 | l + c.convert(drop)%* m.convert(take)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/scas/src/scas/base/Rational.scala:
--------------------------------------------------------------------------------
1 | package scas.base
2 |
3 | import scas.structure.commutative.ordered.{Quotient, Field}
4 | import scas.structure.commutative.Quotient.Element
5 | import scas.util.{Conversion, unary_~}
6 |
7 | type Rational = Element[BigInteger]
8 |
9 | object Rational extends Rational.Impl with Field.Conv[Rational] {
10 | given instance: Rational.type = this
11 | class Impl extends Quotient[BigInteger] {
12 | override given ring: BigInteger.Impl = BigInteger
13 | def apply(n: String): Rational = this(BigInteger(n))
14 | def apply(n: String, d: String): Rational = this(BigInteger(n), BigInteger(d))
15 | override val zero = this("0")
16 | override val one = this("1")
17 | extension (x: Rational) override def toCode(level: Level) = {
18 | import Level.given
19 | val Rational(n, d) = x
20 | if d.isOne then n.toCode(level) else {
21 | if n.bitLength < 64 && d.bitLength < 64 then {
22 | val s = n.toCode(Level.Multiplication) + "%%" + d.toCode(Level.Power)
23 | if level > Level.Multiplication then fenced(s) else s
24 | } else s"Rational(\"$n\", \"$d\")"
25 | }
26 | }
27 | override def toString = "Rational"
28 | extension (x: Rational) override def toMathML = {
29 | val Rational(n, d) = x
30 | if d.isOne then n.toMathML else s"""$n$d"""
31 | }
32 | def toMathML = ""
33 |
34 | extension (ring: BigInteger.Impl) def quotient() = this
35 | }
36 | extension[U: Conversion[BigInteger]] (a: U) {
37 | def %%[V: Conversion[BigInteger]](b: V) = this(~a, ~b)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/scas/src/scas/power/offset/Lexicographic.scala:
--------------------------------------------------------------------------------
1 | package scas.power.offset
2 |
3 | import scala.annotation.nowarn
4 | import scala.reflect.ClassTag
5 | import scas.math.Numeric
6 | import scas.variable.Variable
7 | import scas.util.{Conversion, unary_~}
8 |
9 | class Lexicographic[N : {Numeric, ClassTag}](val variables: Variable*) extends ArrayPowerProduct[N] {
10 | def compare(x: Array[N], n: Int, y: Array[N], m: Int) = {
11 | val k = n * length
12 | val l = m * length
13 | var i = length + k
14 | var j = length + l
15 | while i > k do {
16 | i -= 1
17 | j -= 1
18 | if x(i) < y(j) then return -1
19 | if x(i) > y(j) then return 1
20 | }
21 | 0
22 | }
23 | }
24 |
25 | object Lexicographic {
26 | @nowarn("msg=New anonymous class definition will be duplicated at each inline site") inline def inlined[N : {Numeric, ClassTag}, S : Conversion[Variable]](degree: N)(variables: S*): Lexicographic[N] = new Lexicographic[N](variables.map(~_)*) {
27 | override def compare(x: Array[N], n: Int, y: Array[N], m: Int) = {
28 | val k = n * length
29 | val l = m * length
30 | var i = length + k
31 | var j = length + l
32 | while i > k do {
33 | i -= 1
34 | j -= 1
35 | if x(i) < y(j) then return -1
36 | if x(i) > y(j) then return 1
37 | }
38 | 0
39 | }
40 | override def multiply(x: Array[N], n: Int, y: Array[N], z: Array[N]) = {
41 | val k = n * length
42 | var i = 0
43 | while i < length do {
44 | z(i + k) = x(i + k) + y(i)
45 | i += 1
46 | }
47 | z
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/PolynomialWithSugar.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial
2 |
3 | import scala.annotation.targetName
4 | import scas.power.PowerProduct
5 | import scas.structure.Ring
6 | import PolynomialWithSugar.Element
7 | import scas.base.BigInteger
8 | import BigInteger.{max, given}
9 |
10 | class PolynomialWithSugar[T, C, M](using factory: Polynomial[T, C, M]) extends Polynomial[Element[T], C, M] {
11 | override given ring: Ring[C] = factory.ring
12 | override given pp: PowerProduct[M] = factory.pp
13 | def apply(s: (M, C)*) = this(factory(s*))
14 | @targetName("fromPolynomial") def apply(p: T) = (p, p.degree)
15 | override def normalize(x: Element[T]) = {
16 | val (p, e) = x
17 | (factory.normalize(p), e)
18 | }
19 | extension (x: Element[T]) {
20 | def iterator = {
21 | val (p, _) = x
22 | p.iterator
23 | }
24 | def size = {
25 | val (p, _) = x
26 | p.size
27 | }
28 | def head = {
29 | val (p, _) = x
30 | p.head
31 | }
32 | def last = {
33 | val (p, _) = x
34 | p.last
35 | }
36 | def add(y: Element[T]) = {
37 | val (p, e) = x
38 | val (q, f) = y
39 | (p + q, max(e, f))
40 | }
41 | @targetName("ppMultiplyRight") override def %* (m: M) = {
42 | val (p, e) = x
43 | (p%* m, e + m.degree)
44 | }
45 | override def multiply(m: M, c: C) = {
46 | val (p, e) = x
47 | (p.multiply(m, c), e + m.degree)
48 | }
49 | def map(f: (M, C) => (M, C)) = {
50 | val (p, e) = x
51 | (p.map(f), e)
52 | }
53 | }
54 | }
55 |
56 | object PolynomialWithSugar {
57 | type Element[T] = (T, BigInteger)
58 | }
59 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/TreeMutablePolynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial
2 |
3 | import scala.jdk.CollectionConverters.MapHasAsScala
4 | import TreePolynomial.Element
5 |
6 | trait TreeMutablePolynomial[C, M] extends TreePolynomial[C, M] {
7 | extension (x: Element[C, M]) {
8 | override def subtract(y: Element[C, M]) = unmodifiable(super.subtract(modifiable(x))(y))
9 |
10 | override def multiply(y: Element[C, M]) = {
11 | val r = modifiable(zero)
12 | for (a, b) <- y.asScala do r.subtract(a, -b, x)
13 | unmodifiable(r)
14 | }
15 |
16 | override def reduce(ys: Element[C, M]*) = unmodifiable(super.reduce(modifiable(x))(ys*))
17 |
18 | override def reduce(strict: Boolean, tail: Boolean, ys: Element[C, M]*) = unmodifiable(super.reduce(modifiable(x))(strict, tail, ys*))
19 |
20 | override def subtract(m: M, c: C, y: Element[C, M]) = {
21 | val ys = y.entrySet.iterator
22 | while ys.hasNext do {
23 | val sa = ys.next
24 | val s = sa.getKey
25 | val a = sa.getValue
26 | val ac = a * c
27 | if !ac.isZero then {
28 | val sm = s * m
29 | val cc = x.getOrElse(sm, ring.zero) - ac
30 | if cc.isZero then x.remove(sm) else x.put(sm, cc)
31 | }
32 | }
33 | x
34 | }
35 |
36 | override def multiplyRight(c: C) = {
37 | val xs = x.entrySet.iterator
38 | while xs.hasNext do {
39 | val sa = xs.next
40 | val s = sa.getKey
41 | val a = sa.getValue
42 | val ac = a * c
43 | if !ac.isZero then sa.setValue(ac)
44 | else xs.remove
45 | }
46 | x
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/ListPolynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial
2 |
3 | import scala.collection.mutable.ListBuffer
4 | import ListPolynomial.Element
5 |
6 | trait ListPolynomial[C, M] extends Polynomial[Element[C, M], C, M] {
7 | def apply(s: (M, C)*) = List(s*)
8 |
9 | extension (x: Element[C, M]) {
10 | def add(y: Element[C, M]) = {
11 | val res = new ListBuffer[(M, C)]
12 | var leftx = x
13 | var lefty = y
14 | while !leftx.isEmpty && !lefty.isEmpty do {
15 | val (s, a) = leftx.head
16 | val (t, b) = lefty.head
17 | if s > t then {
18 | res += leftx.head
19 | leftx = leftx.tail
20 | } else if s < t then {
21 | res += lefty.head
22 | lefty = lefty.tail
23 | } else {
24 | val c = a + b
25 | if !c.isZero then res += ((s, c))
26 | leftx = leftx.tail
27 | lefty = lefty.tail
28 | }
29 | }
30 | res ++= leftx
31 | res ++= lefty
32 | res.toList
33 | }
34 |
35 | override def isZero = x.isEmpty
36 |
37 | def iterator = x.iterator
38 |
39 | override def toSeq = x
40 |
41 | def size = x.size
42 |
43 | def head = x.head
44 |
45 | def last = x.last
46 |
47 | def map(f: (M, C) => (M, C)) = {
48 | val res = new ListBuffer[(M, C)]
49 | var left = x
50 | while !left.isEmpty do {
51 | val (s, a) = left.head
52 | val (m, c) = f(s, a)
53 | if !c.isZero then res += ((m, c))
54 | left = left.tail
55 | }
56 | res.toList
57 | }
58 | }
59 | }
60 |
61 | object ListPolynomial {
62 | type Element[C, M] = List[(M, C)]
63 | }
64 |
--------------------------------------------------------------------------------
/scas/src/scas/residue/Residue.scala:
--------------------------------------------------------------------------------
1 | package scas.residue
2 |
3 | import scala.annotation.targetName
4 | import scala.compiletime.deferred
5 | import scala.reflect.ClassTag
6 | import scas.util.Conversion
7 | import scas.polynomial.ufd.{PolynomialWithGB, PolynomialOverFieldWithGB}
8 | import scas.module.ArrayModule
9 | import scas.prettyprint.Show.given
10 |
11 | trait Residue[T : ClassTag, C, N] extends scas.structure.commutative.Residue[T, T] {
12 | given ring: PolynomialWithGB[T, C, N] = deferred
13 | var mods = List.empty[T]
14 | def generator(n: Int) = ring.generator(n)
15 | def generators = ring.generators
16 | given coef2poly: [D: Conversion[C]] => (D => T) = ring.coef2poly
17 | def update(s: T*): Unit = {
18 | mods = gb(false, s*)
19 | }
20 | @targetName("fromCoefficient") def apply(x: C) = ring(x)
21 | def apply(x: T) = ring.remainder(x)(mods*)
22 | def unapply(x: T) = Some(x)
23 | def fromRing(x: T) = x
24 | def characteristic = ring.characteristic
25 | def gb(dummy: Boolean, xs: T*) = ring.gb((xs ++ mods)*)
26 | def gb(xs: T*): List[T] = gb(false, xs*).filter(!_.isZero)
27 | override def toString = s"${ring}(${mods.show(false)})"
28 | def toMathML = s"${ring.toMathML}${mods.toMathML(false)}"
29 |
30 | extension (ring: PolynomialWithGB[T, C, N]) def apply(s: T*) = {
31 | same(s*)
32 | this
33 | }
34 | def same(s: T*): Unit = {
35 | given ArrayModule[T] = ArrayModule(this)(mods.size)
36 | assert (s.toArray >< mods.toArray)
37 | }
38 | }
39 |
40 | object Residue {
41 | def apply[T : ClassTag, C, N](ring: PolynomialOverFieldWithGB[T, C, N])(s: T*) = new ResidueOverField.Conv(using ring)(s*)
42 | }
43 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/PolynomialWithRepr.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial
2 |
3 | import scala.annotation.targetName
4 | import scala.compiletime.deferred
5 | import scala.reflect.ClassTag
6 | import scas.module.ArrayModule
7 | import PolynomialWithRepr.Element
8 |
9 | trait PolynomialWithRepr[T, C, M] extends Polynomial[Element[T], C, M] {
10 | def dimension: Int
11 | given ClassTag[T] = deferred
12 | given factory: Polynomial[T, C, M] = deferred
13 | given module: ArrayModule[T] = ArrayModule(factory)(dimension)
14 | def apply(p: T, n: Int) = (p, module.generator(n))
15 | def apply(s: (M, C)*) = this(factory(s*))
16 | def apply(p: T) = (p, module.zero)
17 | extension (x: Element[T]) {
18 | def iterator = {
19 | val (p, _) = x
20 | p.iterator
21 | }
22 | def size = {
23 | val (p, _) = x
24 | p.size
25 | }
26 | def head = {
27 | val (p, _) = x
28 | p.head
29 | }
30 | def last = {
31 | val (p, _) = x
32 | p.last
33 | }
34 | def add(y: Element[T]) = {
35 | val (p, e) = x
36 | val (q, f) = y
37 | (p + q, e + f)
38 | }
39 | @targetName("ppMultiplyRight") override def %* (m: M) = {
40 | val (p, e) = x
41 | (p%* m, e%* factory(m))
42 | }
43 | override def multiply(m: M, c: C) = {
44 | val (p, e) = x
45 | (p.multiply(m, c), e%* factory(m, c))
46 | }
47 | override def multiplyRight(c: C) = {
48 | val (p, e) = x
49 | (p%* c, e%* factory(c))
50 | }
51 | def map(f: (M, C) => (M, C)) = {
52 | val (p, e) = x
53 | (p.map(f), e)
54 | }
55 | }
56 | }
57 |
58 | object PolynomialWithRepr {
59 | type Element[T] = (T, Array[T])
60 | }
61 |
--------------------------------------------------------------------------------
/scas/src/scas/power/Lexicographic.scala:
--------------------------------------------------------------------------------
1 | package scas.power
2 |
3 | import scala.annotation.nowarn
4 | import scala.reflect.ClassTag
5 | import scas.math.Numeric
6 | import scas.variable.Variable
7 | import scas.util.{Conversion, unary_~}
8 |
9 | class Lexicographic[N : {Numeric, ClassTag}](val variables: Variable*) extends Lexicographic.Impl[N]
10 |
11 | object Lexicographic {
12 | def apply[N : {Numeric, ClassTag}, S : Conversion[Variable]](degree: N)(variables: S*) = new Conv[N](variables.map(~_)*)
13 |
14 | @nowarn("msg=New anonymous class definition will be duplicated at each inline site") inline def inlined[N : {Numeric, ClassTag}, S : Conversion[Variable]](degree: N)(variables: S*): Lexicographic[N] = new Lexicographic[N](variables.map(~_)*) {
15 | override def compare(x: Array[N], y: Array[N]) = {
16 | var i = length
17 | while i > 0 do {
18 | i -= 1
19 | if x(i) < y(i) then return -1
20 | if x(i) > y(i) then return 1
21 | }
22 | 0
23 | }
24 | override def multiply(x: Array[N], y: Array[N], z: Array[N]) = {
25 | var i = 0
26 | while i < length do {
27 | z(i) = x(i) + y(i)
28 | i += 1
29 | }
30 | z
31 | }
32 | }
33 |
34 | trait Impl[N : {Numeric, ClassTag}] extends ArrayPowerProduct[N] {
35 | def compare(x: Array[N], y: Array[N]) = {
36 | var i = length
37 | while i > 0 do {
38 | i -= 1
39 | if x.get(i) < y.get(i) then return -1
40 | if x.get(i) > y.get(i) then return 1
41 | }
42 | 0
43 | }
44 | }
45 |
46 | class Conv[N : {Numeric, ClassTag}](val variables: Variable*) extends Impl[N] with PowerProduct.Conv[Array[N]] {
47 | given instance: Conv[N] = this
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/scas/src/scas/power/PowerProduct.scala:
--------------------------------------------------------------------------------
1 | package scas.power
2 |
3 | import scas.util.{Conversion, unary_~}
4 | import scas.structure.ordered.Monoid
5 | import scas.variable.Variable
6 | import scas.base.BigInteger
7 | import scas.prettyprint.Show.given
8 |
9 | trait PowerProduct[M] extends Monoid[M] {
10 | def variables: Seq[Variable]
11 | def length = variables.length
12 | def generator(variable: Variable): M = generator(variables.indexOf(variable))
13 | def generator(n: Int): M
14 | def generators = (for i <- 0 until length yield generator(i)).toList
15 | def apply(x: Int) = {
16 | assert (x == 1)
17 | one
18 | }
19 | def gcd(x: M, y: M): M
20 | def lcm(x: M, y: M): M
21 | def coprime(x: M, y: M) = gcd(x, y).isOne
22 | extension (x: M) {
23 | def degree: BigInteger
24 | def divide(y: M): M
25 | def factorOf(y: M): Boolean
26 | inline def / [U: Conversion[M]](y: U) = x.divide(~y)
27 | inline def | [U: Conversion[M]](y: U) = x.factorOf(~y)
28 | def isUnit = x.isOne
29 | def dependencyOnVariables: Array[Int]
30 | def projection(n: Int): M = projection(n, n + 1)
31 | def projection(n: Int, m: Int): M
32 | def size: Int
33 | def toCode(level: Level) = toCode(level, "*")
34 | def toCode(level: Level, times: String): String
35 | def toMathML = toMathML("times")
36 | def toMathML(times: String): String
37 | }
38 | override def toString = variables.toList.show
39 | def toMathML = variables.toList.toMathML
40 |
41 | given int2powerProduct: (Int => M) = this(_)
42 | }
43 |
44 | object PowerProduct {
45 | trait Conv[M] extends PowerProduct[M] with Monoid.Conv[M] {
46 | extension[U: Conversion[M]] (x: U) {
47 | inline def / (y: M) = (~x).divide(y)
48 | inline def | (y: M) = (~x).factorOf(y)
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/scas/src/scas/module/ArrayModule.scala:
--------------------------------------------------------------------------------
1 | package scas.module
2 |
3 | import scala.reflect.ClassTag
4 | import scas.structure.{Ring, Module}
5 | import scas.prettyprint.Show.given
6 |
7 | open class ArrayModule[R : ClassTag](using Ring[R])(val dimension: Int) extends Module[Array[R], R] {
8 | given instance: ArrayModule[R] = this
9 | def apply(x: Array[R]) = x
10 | def generator(n: Int) = (for i <- 0 until dimension yield if i == n then ring.one else ring.zero).toArray
11 | def generators = (for i <- 0 until dimension yield generator(i)).toList
12 | def equiv(x: Array[R], y: Array[R]): Boolean = {
13 | var i = 0
14 | while i < dimension do {
15 | if x(i) <> y(i) then return false
16 | i += 1
17 | }
18 | true
19 | }
20 | extension (x: R) def multiplyLeft(y: Array[R]) = (for i <- 0 until dimension yield x * y(i)).toArray
21 | extension (x: Array[R]) {
22 | def multiplyRight(y: R) = (for i <- 0 until dimension yield x(i) * y).toArray
23 | def add(y: Array[R]) = (for i <- 0 until dimension yield x(i) + y(i)).toArray
24 | def subtract(y: Array[R]) = (for i <- 0 until dimension yield x(i) - y(i)).toArray
25 | def signum = x.foldLeft(0)((l, r) => if l == 0 then r.signum else l)
26 | def toCode(level: Level) = s"Array(${x.toList.show(false)})"
27 | def toMathML = s"${x.toList.toMathML(false)}"
28 | }
29 | def zero = (for i <- 0 until dimension yield ring.zero).toArray
30 | override def toString = s"$ring.pow($dimension)"
31 | def toMathML = s"${ring.toMathML}${dimension}"
32 |
33 | extension (ring: Ring[R]) def pow(n: Int) = {
34 | assert (n == dimension)
35 | this
36 | }
37 | }
38 |
39 | object ArrayModule {
40 | def apply[R : ClassTag](ring: Ring[R])(dimension: Int) = new ArrayModule(using ring)(dimension)
41 | }
42 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/TreePolynomial.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial
2 |
3 | import java.util.{SortedMap, TreeMap, Collections}
4 | import scala.jdk.CollectionConverters.MapHasAsScala
5 | import TreePolynomial.Element
6 |
7 | trait TreePolynomial[C, M] extends Polynomial[Element[C, M], C, M] {
8 | def unmodifiable(x: Element[C, M]): Element[C, M] = Collections.unmodifiableSortedMap(x)
9 | def modifiable(x: Element[C, M]): Element[C, M] = new TreeMap(x)
10 | def apply(s: (M, C)*) = {
11 | val r = new TreeMap[M, C](pp.reverse)
12 | for (m, c) <- s do r.put(m, c)
13 | unmodifiable(r)
14 | }
15 |
16 | extension (x: Element[C, M]) def add(y: Element[C, M]) = {
17 | val r = modifiable(x)
18 | for (t, b) <- y.asScala do {
19 | val c = r.getOrElse(t, ring.zero) + b
20 | if c.isZero then r.remove(t) else r.put(t, c)
21 | }
22 | unmodifiable(r)
23 | }
24 |
25 | extension (x: Element[C, M]) {
26 | override def isZero = x.isEmpty
27 |
28 | def iterator = x.asScala.iterator
29 |
30 | override def iterator(m: M) = x.tailMap(m).asScala.iterator
31 |
32 | override def toSeq = x.asScala.toSeq
33 |
34 | def size = x.size
35 |
36 | def head = x.asScala.head
37 |
38 | def last = x.asScala.last
39 |
40 | override def coefficient(m: M) = x.getOrElse(m, ring.zero)
41 |
42 | def getOrElse(m: M, c: C) = {
43 | val a = x.get(m)
44 | if a == null then c else a
45 | }
46 |
47 | def map(f: (M, C) => (M, C)) = {
48 | val r = modifiable(zero)
49 | for (s, a) <- x.asScala do {
50 | val (m, c) = f(s, a)
51 | if !c.isZero then r.put(m, c)
52 | }
53 | unmodifiable(r)
54 | }
55 |
56 | override def sort = x
57 | }
58 | }
59 |
60 | object TreePolynomial {
61 | type Element[C, M] = SortedMap[M, C]
62 | }
63 |
--------------------------------------------------------------------------------
/scas/src/scas/base/ModInteger.scala:
--------------------------------------------------------------------------------
1 | package scas.base
2 |
3 | import scas.structure.commutative.ordered.{Residue, Field}
4 | import scas.module.ArrayModule
5 | import BigInteger.given
6 |
7 | class ModInteger(mod: BigInteger) extends Residue[Int, BigInteger] with Field[Int] {
8 | assert (mod.isProbablePrime(100))
9 | override given ring: BigInteger.type = BigInteger
10 | def apply(x: BigInteger) = this(x.longValue)
11 | def unapply(x: Int) = Some(int2bigInt(x))
12 | def fromRing(x: BigInteger) = this(x)
13 | def characteristic = mod
14 | val m = mod.intValue
15 | def apply(x: Long) = {
16 | val c = (x % m).toInt
17 | if c < 0 then c + m else c
18 | }
19 | extension (x: Int) {
20 | override def signum = java.lang.Integer.signum(x)
21 | override def add(y: Int) = this(x.toLong + y)
22 | override def subtract(y: Int) = this(x.toLong - y)
23 | override def multiply(y: Int) = this(x.toLong * y)
24 | override def isZero = x.signum == 0
25 | }
26 | extension (a: Int) override def pow(b: BigInteger) = int2bigInt(a).modPow(b, mod).intValue
27 | def inverse(x: Int) = int2bigInt(x).modInverse(mod).intValue
28 | override def toString = s"ModInteger(\"${mod}\")"
29 | def toMathML = s"${BigInteger.toMathML}${mod.toMathML}"
30 |
31 | extension (ring: BigInteger.Impl) def apply(s: BigInteger*) = {
32 | same(s*)
33 | this
34 | }
35 | def same(s: BigInteger*): Unit = {
36 | given ArrayModule[BigInteger] = ArrayModule(BigInteger)(1)
37 | assert (s.toArray >< List(mod).toArray)
38 | }
39 | override val zero = 0
40 | override val one = 1
41 | }
42 |
43 | object ModInteger {
44 | def apply(str: String) = new Conv(BigInteger(str))
45 | class Conv(mod: BigInteger) extends ModInteger(mod) with Field.Conv[Int] {
46 | given instance: Conv = this
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/Fn.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import Parsers.{log as _, *}
4 | import scala.annotation.nowarn
5 | import scas.rendering.Graph
6 | import scas.variable.Variable
7 | import Function.{sinh, cosh, tanh, sin, cos, tan, asin, acos, atan, exp, log, sqrt, abs, pow, identity}
8 |
9 | class Fn(var n: Variable*) extends FieldParsers[Double => Double] {
10 | override given structure: Function.type = Function
11 |
12 | @nowarn("msg=match may not be exhaustive")
13 | def function: Parser[Double => Double] = ("sinh" | "cosh" | "tanh" | "sin" | "cos" | "tan" | "asin" | "acos" | "atan" | "exp" | "log" | "sqrt" | "abs") ~ ("(" ~> expr) <~ ")" ^^ {
14 | case "sinh" ~ x => sinh(x)
15 | case "cosh" ~ x => cosh(x)
16 | case "tanh" ~ x => tanh(x)
17 | case "sin" ~ x => sin(x)
18 | case "cos" ~ x => cos(x)
19 | case "tan" ~ x => tan(x)
20 | case "asin" ~ x => asin(x)
21 | case "acos" ~ x => acos(x)
22 | case "atan" ~ x => atan(x)
23 | case "exp" ~ x => exp(x)
24 | case "log" ~ x => log(x)
25 | case "sqrt" ~ x => sqrt(x)
26 | case "abs" ~ x => abs(x)
27 | }
28 | def generator: Parser[Double => Double] = Var.parser ^^ {
29 | case variable if (contains(variable)) => identity
30 | }
31 | def base: Parser[Double => Double] = DoubleParsers.base ^^ { Function(_) } | function | generator | "(" ~> expr <~ ")"
32 | override def unsignedFactor: Parser[Double => Double] = base ~ opt(("**" | "^") ~> factor) ^^ {
33 | case x ~ option => option match {
34 | case Some(y) => pow(x, y)
35 | case None => x
36 | }
37 | }
38 | @nowarn("msg=match may not be exhaustive")
39 | def graph: Parser[Graph] = "graph" ~> ("(" ~> expr) ~ ("," ~> Var.parser) <~ ")" ^^ {
40 | case expr ~ variable if (contains(variable)) => Graph(expr)
41 | }
42 | def contains(variable: Variable) = {
43 | if n.isEmpty then n = List(variable)
44 | n.contains(variable)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/scas/application/src/scas/adapter/math3/Matrix.scala:
--------------------------------------------------------------------------------
1 | package scas.adapter.math3
2 |
3 | import org.apache.commons.math3.linear.Array2DRowRealMatrix
4 | import org.apache.commons.math3.linear.MatrixUtils
5 | import org.apache.commons.math3.linear.RealMatrix
6 | import scas.structure.{Algebra, Ring, Field}
7 | import scas.base.BigInteger
8 | import Matrix.Element
9 | import Double.given
10 |
11 | trait Matrix extends Algebra[Element, Double] with Field[Element] {
12 | override given ring: Field[Double] = Double
13 | def size: Int
14 | def fromInt(n: BigInteger) = one%* Double.fromInt(n)
15 | override def zero = MatrixUtils.createRealMatrix(size, size)
16 | override def one = MatrixUtils.createRealIdentityMatrix(size)
17 | def apply(ds: Double*): Element = Array2DRowRealMatrix(ds.grouped(size).map(_.toArray).toArray)
18 | extension (x: Element) {
19 | def add(y: Element) = x.add(y)
20 | def subtract(y: Element) = x.subtract(y)
21 | def multiply(y: Element) = x.multiply(y)
22 | }
23 | def inverse(x: Element) = MatrixUtils.inverse(x)
24 | def equiv(x: Element, y: Element) = x == y
25 | extension (x: Element) def signum = if size > 0 then x.getEntry(0, 0).sign.toInt else 0
26 | extension (x: Double) def multiplyLeft(y: Element) = y%* x
27 | extension (x: Element) def multiplyRight(y: Double) = x.scalarMultiply(y)
28 | def characteristic = BigInteger("0")
29 | extension (x: Element) {
30 | def toCode(level: Level) = x.toString
31 | def toMathML = ???
32 | }
33 | def toMathML = ???
34 |
35 | extension (ring: Ring[Double]) def pow(n: Int) = {
36 | assert (n == size * size)
37 | this
38 | }
39 |
40 | given int2matrix: (Int => Element) = one%* _
41 | given double2matrix: (Double => Element) = one%* _
42 | }
43 |
44 | object Matrix {
45 | type Element = RealMatrix
46 | def apply(size: Int) = new Conv(size)
47 |
48 | class Conv(val size: Int) extends Matrix with Field.Conv[Element] {
49 | given instance: Conv = this
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/scas/src/scas/math/Ordering.scala:
--------------------------------------------------------------------------------
1 | package scas.math
2 |
3 | import scas.util.{Conversion, unary_~}
4 |
5 | trait Ordering[T] extends scala.math.Ordering[T] with PartialOrdering[T]
6 |
7 | object Ordering {
8 | def by[T, S : scala.math.Ordering as ord](f: T => S): Ordering[T] = new Ordering[T] {
9 | def compare(x: T, y: T) = ord.compare(f(x), f(y))
10 | override def lt(x: T, y: T): Boolean = ord.lt(f(x), f(y))
11 | override def gt(x: T, y: T): Boolean = ord.gt(f(x), f(y))
12 | override def gteq(x: T, y: T): Boolean = ord.gteq(f(x), f(y))
13 | override def lteq(x: T, y: T): Boolean = ord.lteq(f(x), f(y))
14 | }
15 | trait ByteOrdering extends Ordering[Byte] {
16 | def compare(x: Byte, y: Byte) = java.lang.Byte.compare(x, y)
17 | extension (x: Byte) {
18 | inline override def < [U: Conversion[Byte]](y: U) = x < (~y)
19 | inline override def > [U: Conversion[Byte]](y: U) = x > (~y)
20 | }
21 | }
22 | given Byte: ByteOrdering()
23 | trait ShortOrdering extends Ordering[Short] {
24 | def compare(x: Short, y: Short) = java.lang.Short.compare(x, y)
25 | extension (x: Short) {
26 | inline override def < [U: Conversion[Short]](y: U) = x < (~y)
27 | inline override def > [U: Conversion[Short]](y: U) = x > (~y)
28 | }
29 | }
30 | given Short: ShortOrdering()
31 | trait IntOrdering extends Ordering[Int] {
32 | def compare(x: Int, y: Int) = java.lang.Integer.compare(x, y)
33 | extension (x: Int) {
34 | inline override def < [U: Conversion[Int]](y: U) = x < (~y)
35 | inline override def > [U: Conversion[Int]](y: U) = x > (~y)
36 | }
37 | }
38 | given Int: IntOrdering()
39 | trait LongOrdering extends Ordering[Long] {
40 | def compare(x: Long, y: Long) = java.lang.Long.compare(x, y)
41 | extension (x: Long) {
42 | inline override def < [U: Conversion[Long]](y: U) = x < (~y)
43 | inline override def > [U: Conversion[Long]](y: U) = x > (~y)
44 | }
45 | }
46 | given Long: LongOrdering()
47 | }
48 |
--------------------------------------------------------------------------------
/scas/src/scas/power/degree/ArrayPowerProduct.scala:
--------------------------------------------------------------------------------
1 | package scas.power.degree
2 |
3 | import scala.reflect.ClassTag
4 | import scas.math.Numeric
5 | import scas.power.PowerProduct
6 |
7 | trait ArrayPowerProduct[N : {Numeric as numeric, ClassTag}] extends scas.power.ArrayPowerProduct[N] {
8 | override def len = length + 1
9 | override def generator(n: Int, z: Array[N]) = {
10 | z(n) = numeric.fromInt(1)
11 | z(length) = numeric.fromInt(1)
12 | z
13 | }
14 | override def gcd(x: Array[N], y: Array[N], z: Array[N]) = {
15 | for i <- 0 until length do {
16 | z(i) = numeric.min(x.get(i), y.get(i))
17 | z(length) += z(i)
18 | }
19 | z
20 | }
21 | override def lcm(x: Array[N], y: Array[N], z: Array[N]) = {
22 | for i <- 0 until length do {
23 | z(i) = numeric.max(x.get(i), y.get(i))
24 | z(length) += z(i)
25 | }
26 | z
27 | }
28 | override def multiply(x: Array[N], y: Array[N], z: Array[N]) = {
29 | var i = 0
30 | while i <= length do {
31 | z(i) = x.get(i) + y.get(i)
32 | i += 1
33 | }
34 | z
35 | }
36 | override def divide(x: Array[N], y: Array[N], z: Array[N]) = {
37 | for i <- 0 to length do {
38 | assert (x.get(i) >= y.get(i))
39 | z(i) = x.get(i) - y.get(i)
40 | }
41 | z
42 | }
43 | override def projection(x: Array[N], n: Int, m: Int, z: Array[N]) = {
44 | for i <- 0 until length do if i >= n && i < m then {
45 | z(i) = x.get(i)
46 | z(length) += x.get(i)
47 | }
48 | z
49 | }
50 | override def convert(x: Array[N], from: scas.power.ArrayPowerProduct[N], z: Array[N]) = {
51 | val index = from.variables.map(a => variables.indexOf(a))
52 | for i <- 0 until from.length do if from.get(x)(i) > numeric.zero then {
53 | val c = index(i)
54 | assert (c > -1)
55 | z(c) = from.get(x)(i)
56 | }
57 | z(length) = from.deg(x)
58 | z
59 | }
60 | extension (x: Array[N]) {
61 | inline override def deg = x.get(length)
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/commutative/Residue.scala:
--------------------------------------------------------------------------------
1 | package scas.structure.commutative
2 |
3 | import scala.compiletime.deferred
4 | import scas.base.BigInteger
5 |
6 | trait Residue[T, R] extends UniqueFactorizationDomain[T] {
7 | given ring: UniqueFactorizationDomain[R] = deferred
8 | def apply(x: R): T
9 | val self = this
10 | def unapply(x: T): Option[R]
11 | def fromInt(n: BigInteger) = this(ring.fromInt(n))
12 | def fromRing(x: R): T
13 | extension (x: T) {
14 | def signum = {
15 | val self(a) = x.runtimeChecked
16 | ring.signum(a)
17 | }
18 | def add(y: T) = {
19 | val self(a) = x.runtimeChecked
20 | val self(b) = y.runtimeChecked
21 | this(a + b)
22 | }
23 | def subtract(y: T) = {
24 | val self(a) = x.runtimeChecked
25 | val self(b) = y.runtimeChecked
26 | this(a - b)
27 | }
28 | def multiply(y: T) = {
29 | val self(a) = x.runtimeChecked
30 | val self(b) = y.runtimeChecked
31 | this(a * b)
32 | }
33 | def isUnit = {
34 | val self(a) = x.runtimeChecked
35 | ring.isUnit(a)
36 | }
37 | override def divide(y: T) = {
38 | val self(a) = x.runtimeChecked
39 | val self(b) = y.runtimeChecked
40 | this(a / b)
41 | }
42 | override def remainder(y: T) = {
43 | val self(a) = x.runtimeChecked
44 | val self(b) = y.runtimeChecked
45 | this(a % b)
46 | }
47 | def divideAndRemainder(y: T) = (x / y, x % y)
48 | }
49 | def gcd(x: T, y: T) = {
50 | val self(a) = x.runtimeChecked
51 | val self(b) = y.runtimeChecked
52 | this(ring.gcd(a, b))
53 | }
54 | def equiv(x: T, y: T) = {
55 | val self(a) = x.runtimeChecked
56 | val self(b) = y.runtimeChecked
57 | val self(c) = this(a).runtimeChecked
58 | val self(d) = this(b).runtimeChecked
59 | c >< d
60 | }
61 | extension (x: T) {
62 | def toCode(level: Level) = {
63 | val self(a) = x.runtimeChecked
64 | a.toCode(level)
65 | }
66 | def toMathML = {
67 | val self(a) = x.runtimeChecked
68 | a.toMathML
69 | }
70 | }
71 |
72 | extension (ring: UniqueFactorizationDomain[R]) def apply(s: R*) = {
73 | same(s*)
74 | this
75 | }
76 | def same(s: R*): Unit
77 | }
78 |
--------------------------------------------------------------------------------
/scas/src/scas/base/BigInteger.scala:
--------------------------------------------------------------------------------
1 | package scas.base
2 |
3 | import scala.compiletime.deferred
4 | import scas.structure.commutative.ordered.{UniqueFactorizationDomain, EuclidianDomain}
5 | import java.math.BigInteger.valueOf
6 |
7 | type BigInteger = java.math.BigInteger
8 |
9 | object BigInteger extends BigInteger.Impl with UniqueFactorizationDomain.Conv[BigInteger] {
10 | override given instance: BigInteger.type = this
11 | trait Impl extends EuclidianDomain[BigInteger] {
12 | given instance: BigInteger.Impl = deferred
13 | val self = this
14 | def fromInt(n: BigInteger) = n
15 | override val zero = this("0")
16 | override val one = this("1")
17 | def apply(str: String): BigInteger = new BigInteger(str)
18 | extension (x: BigInteger) {
19 | def add(y: BigInteger) = x.add(y)
20 | def subtract(y: BigInteger) = x.subtract(y)
21 | def multiply(y: BigInteger) = x.multiply(y)
22 | }
23 | def compare(x: BigInteger, y: BigInteger) = x.compareTo(y)
24 | override def gcd(x: BigInteger, y: BigInteger) = x.gcd(y)
25 | extension (x: BigInteger) {
26 | override def divide(y: BigInteger) = x.divide(y)
27 | override def remainder(y: BigInteger) = x.remainder(y)
28 | def divideAndRemainder(y: BigInteger) = {
29 | val Array(q, r) = x.divideAndRemainder(y)
30 | (q, r)
31 | }
32 | }
33 | def characteristic = zero
34 | extension (x: BigInteger) def isUnit = abs(x).isOne
35 | extension (x: BigInteger) override def isZero = x.signum == 0
36 | extension (a: BigInteger) override def pow(b: BigInteger) = a.pow(b.intValue)
37 | extension (x: BigInteger) override def unary_- = x.negate
38 | override def abs(x: BigInteger) = x.abs
39 | extension (x: BigInteger) override def signum = x.signum
40 | extension (x: BigInteger) def toCode(level: Level) = {
41 | if x.bitLength < 32 then x.toString
42 | else if x.bitLength < 64 then x.toString + "l"
43 | else s"BigInteger(\"$x\")"
44 | }
45 | override def toString = "BigInteger"
46 | extension (x: BigInteger) def toMathML = s"$x"
47 | def toMathML = ""
48 |
49 | given int2bigInt: (Int => BigInteger) = valueOf(_)
50 | given long2bigInt: (Long => BigInteger) = valueOf(_)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/Product.scala:
--------------------------------------------------------------------------------
1 | package scas.structure
2 |
3 | import scas.util.{Conversion, unary_~}
4 | import scas.base.BigInteger
5 | import BigInteger.lcm
6 |
7 | class Product[R1 : Ring as ring1, R2 : Ring as ring2] extends Ring[(R1, R2)] {
8 | def apply(a: R1, b: R2) = (a, b)
9 | def fromInt(n: BigInteger) = (ring1.fromInt(n), ring2.fromInt(n))
10 | extension (x: (R1, R2)) {
11 | def add(y: (R1, R2)) = {
12 | val (a, b) = x
13 | val (c, d) = y
14 | (a + c, b + d)
15 | }
16 | def subtract(y: (R1, R2)) = {
17 | val (a, b) = x
18 | val (c, d) = y
19 | (a - c, b - d)
20 | }
21 | def multiply(y: (R1, R2)) = {
22 | val (a, b) = x
23 | val (c, d) = y
24 | (a * c, b * d)
25 | }
26 | override def unary_- = {
27 | val (a, b) = x
28 | (-a, -b)
29 | }
30 | override def pow(b: BigInteger) = {
31 | val (c, d) = x
32 | (c \ b, d \ b)
33 | }
34 | def isUnit = {
35 | val (a, b) = x
36 | a.isUnit && b.isUnit
37 | }
38 | def signum = {
39 | val (a, b) = x
40 | if a.signum == 0 then b.signum else a.signum
41 | }
42 | }
43 | override def abs(x: (R1, R2)) = {
44 | val (a, b) = x
45 | (ring1.abs(a), ring2.abs(b))
46 | }
47 | def characteristic = lcm(ring1.characteristic, ring2.characteristic)
48 | def equiv(x: (R1, R2), y: (R1, R2)) = {
49 | val (a, b) = x
50 | val (c, d) = y
51 | a >< c && b >< d
52 | }
53 | extension (x: (R1, R2)) def toCode(level: Level) = {
54 | val (a, b) = x
55 | s"Product(${a.show}, ${b.show})"
56 | }
57 | override def toString = s"Product($ring1, $ring2)"
58 | extension (x: (R1, R2)) def toMathML = {
59 | val (a, b) = x
60 | s"${a.toMathML}${b.toMathML}"
61 | }
62 | def toMathML = s"${ring1.toMathML}${ring2.toMathML}"
63 | }
64 |
65 | object Product {
66 | def apply[R1, R2, U : Conversion[R1], V : Conversion[R2]](using factory: Product[R1, R2])(a: U, b: V) = factory(~a, ~b)
67 |
68 | def apply[R1, R2](ring1: Ring[R1], ring2: Ring[R2]) = new Conv(using ring1, ring2)
69 |
70 | class Conv[R1 : Ring, R2 : Ring] extends Product[R1, R2] with Ring.Conv[(R1, R2)] {
71 | given instance: Conv[R1, R2] = this
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/ufd/PolynomialOverUFD.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.ufd
2 |
3 | import scala.annotation.tailrec
4 | import scala.compiletime.deferred
5 | import scas.polynomial.Polynomial
6 | import scas.structure.commutative.UniqueFactorizationDomain
7 | import scas.base.Boolean.given
8 |
9 | trait PolynomialOverUFD[T, C, M] extends Polynomial[T, C, M] with UniqueFactorizationDomain[T] {
10 | given ring: UniqueFactorizationDomain[C] = deferred
11 | override def normalize(x: T) = primitivePart(x)
12 | extension (x: T) {
13 | def divideAndRemainder(y: T) = {
14 | if y.isZero then throw new ArithmeticException("Polynomial divide by zero")
15 | else if x.isZero then (zero, zero)
16 | else {
17 | val (s, a) = x.head
18 | if y.factorOf(s, a, true) then {
19 | val (t, b) = y.head
20 | val c = this(s / t, a / b)
21 | val (q, r) = (x - c * y).divideAndRemainder(y)
22 | (c + q, r)
23 | } else (zero, x)
24 | }
25 | }
26 | def remainder(ys: T*): T = x.reduce(true, false, ys*)
27 | override def factorOf(s: M, a: C, strict: Boolean) = {
28 | val (t, b) = x.head
29 | (t | s) && (strict >> (b | a))
30 | }
31 | override def reduce(strict: Boolean, tail: Boolean, ys: T*) = super.reduce(x)(strict, tail, ys*)
32 | override def reduce(m: M, a: C, y: T, b: C, strict: Boolean) = {
33 | if strict then x.subtract(m, a / b, y) else {
34 | val c = ring.gcd(a, b)
35 | val gcd = if b.signum == -c.signum then -c else c
36 | val (a0, b0) = (a / gcd, b / gcd)
37 | (x%* b0).subtract(m, a0, y)
38 | }
39 | }
40 | def divideRight(c: C) = x.map((s, a) => (s, a / c))
41 | def %/ (c: C) = x.divideRight(c)
42 | }
43 | def content(x: T) = {
44 | val c = x.iterator.foldLeft(ring.zero) { (l, r) =>
45 | val (_, a) = r
46 | ring.gcd(l, a)
47 | }
48 | val d = ring.abs(c)
49 | if x.signum < 0 then -d else d
50 | }
51 | def contentAndPrimitivePart(x: T) = {
52 | if x.isZero then (ring.zero, zero) else {
53 | val c = content(x)
54 | (c, x%/ c)
55 | }
56 | }
57 | def primitivePart(x: T) = { val (c, p) = contentAndPrimitivePart(x) ; p }
58 |
59 | extension (ring: UniqueFactorizationDomain[C]) def apply(s: T*) = {
60 | same(s*)
61 | this
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/NormalForm.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import scala.compiletime.deferred
4 | import Factors.Element
5 |
6 | class NormalForm(conj: Boolean)(using BooleanAlgebra) extends NormalForm.Impl(conj) {
7 | extension (x: Element[BA, Int]) {
8 | def isImpl = !conj && x.size == 2 && x.head._1.isNot && !x.last._1.isNot
9 | def isRevImpl = !conj && x.size == 2 && x.last._1.isNot && !x.head._1.isNot
10 | override def toCode(level: Level) = if x.isImpl then {
11 | (!x.head._1).toCode(Level.Power) + " >> " + x.last._1.toCode(Level.Power)
12 | } else if x.isRevImpl then {
13 | (!x.last._1).toCode(Level.Power) + " >> " + x.head._1.toCode(Level.Power)
14 | } else super.toCode(x)(level)
15 | override def toMathML = if x.isImpl then {
16 | s"${(!x.head._1).toMathML}${x.last._1.toMathML}"
17 | } else if x.isRevImpl then {
18 | s"${(!x.last._1).toMathML}${x.head._1.toMathML}"
19 | } else super.toMathML(x)
20 | }
21 | }
22 |
23 | object NormalForm {
24 | trait Impl(conj: Boolean) extends Factors[BA, Int] {
25 | given ring: BooleanAlgebra = deferred
26 | def empty = Map.empty[BA, Int]
27 | override def apply(x: BA) = if x.isZero then zero else {
28 | val s = ring.gb(flip(x)).foldLeft(one)((l, a) => l * super.apply(flip(a)))
29 | if s.contains(x) then super.apply(x) else s
30 | }
31 | def flip(x: BA) = if conj then !x else x
32 | extension (x: Element[BA, Int]) {
33 | override def toCode(level: Level) = {
34 | val p = if x.size == 1 then level else if conj then Level.Multiplication else Level.Addition
35 | var s = ring.one.show
36 | var m = 0
37 | for (a, b) <- x do {
38 | val t = a.toCode(p)
39 | val times = if conj then " && " else " || "
40 | s = if m == 0 then t else s + times + t
41 | m += 1
42 | }
43 | if level > p then fenced(s) else s
44 | }
45 | override def toMathML = {
46 | var s = ring.one.toMathML
47 | var m = 0
48 | for (a, b) <- x do {
49 | val t = a.toMathML
50 | val times = if conj then "and" else "or"
51 | s = if m == 0 then t else s"<${times}/>$s$t"
52 | m += 1
53 | }
54 | s
55 | }
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/Function.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import java.lang.Math
4 | import scas.structure.commutative.Field
5 | import scas.base.BigInteger
6 |
7 | object Function extends Field[Double => Double] {
8 | override def random(numbits: Int)(using rnd: java.util.Random) = { a => rnd.nextDouble() }
9 | def apply(value: Double): Double => Double = { a => value }
10 | def fromInt(n: BigInteger) = { a => n.doubleValue() }
11 | override def zero = { a => 0 }
12 | override def one = { a => 1 }
13 | extension (x: Double => Double) {
14 | def add(y: Double => Double) = { a => x(a) + y(a) }
15 | def subtract(y: Double => Double) = { a => x(a) - y(a) }
16 | def multiply(y: Double => Double) = { a => x(a) * y(a) }
17 | override def divide(y: Double => Double) = { a => x(a) / y(a) }
18 | override def pow(b: BigInteger) = this.pow(x, { a => b.doubleValue() })
19 | }
20 | def inverse(x: Double => Double) = { a => 1 / x(a) }
21 | def identity = { (a: Double) => a }
22 | def sin(x: Double => Double) = { (a: Double) => Math.sin(x(a)) }
23 | def cos(x: Double => Double) = { (a: Double) => Math.cos(x(a)) }
24 | def tan(x: Double => Double) = { (a: Double) => Math.tan(x(a)) }
25 | def asin(x: Double => Double) = { (a: Double) => Math.asin(x(a)) }
26 | def acos(x: Double => Double) = { (a: Double) => Math.acos(x(a)) }
27 | def atan(x: Double => Double) = { (a: Double) => Math.atan(x(a)) }
28 | def sinh(x: Double => Double) = { (a: Double) => Math.sinh(x(a)) }
29 | def cosh(x: Double => Double) = { (a: Double) => Math.cosh(x(a)) }
30 | def tanh(x: Double => Double) = { (a: Double) => Math.tanh(x(a)) }
31 | def exp(x: Double => Double) = { (a: Double) => Math.exp(x(a)) }
32 | def log(x: Double => Double) = { (a: Double) => Math.log(x(a)) }
33 | def sqrt(x: Double => Double) = { (a: Double) => Math.sqrt(x(a)) }
34 | def pow(x: Double => Double, y: Double => Double) = { (a: Double) => Math.pow(x(a), y(a)) }
35 | def equiv(x: Double => Double, y: Double => Double) = x == y
36 | extension (x: Double => Double) def signum = 0
37 | override def abs(x: Double => Double) = { a => Math.abs(a) }
38 | def characteristic = BigInteger("0")
39 | extension (x: Double => Double) {
40 | def toCode(level: Level) = x.toString
41 | def toMathML = s"$x"
42 | }
43 | override def toString = "Double => Double"
44 | def toMathML = "↦"
45 | }
46 |
--------------------------------------------------------------------------------
/scas/src/scas/variable/Variable.scala:
--------------------------------------------------------------------------------
1 | package scas.variable
2 |
3 | import scas.prettyprint.Show
4 |
5 | abstract class Variable {
6 | def toMathML: String
7 | override def hashCode = toString.hashCode
8 | override def equals(that: Any) = toString.equals(that.toString)
9 | extension (name: String) def toMathML = Map(
10 | "Alpha" -> "Α",
11 | "Beta" -> "Β",
12 | "Gamma" -> "Γ",
13 | "Delta" -> "Δ",
14 | "Epsilon" -> "Ε",
15 | "Zeta" -> "Ζ",
16 | "Eta" -> "Η",
17 | "Theta" -> "Θ",
18 | "Iota" -> "Ι",
19 | "Kappa" -> "Κ",
20 | "Lambda" -> "Λ",
21 | "Mu" -> "Μ",
22 | "Nu" -> "Ν",
23 | "Xi" -> "Ξ",
24 | "Pi" -> "Π",
25 | "Rho" -> "Ρ",
26 | "Sigma" -> "Σ",
27 | "Tau" -> "Τ",
28 | "Upsilon" -> "Υ",
29 | "Phi" -> "Φ",
30 | "Chi" -> "Χ",
31 | "Psi" -> "Ψ",
32 | "Omega" -> "Ω",
33 | "alpha" -> "α",
34 | "beta" -> "β",
35 | "gamma" -> "γ",
36 | "delta" -> "δ",
37 | "epsilon" -> "ε",
38 | "zeta" -> "ζ",
39 | "eta" -> "η",
40 | "theta" -> "θ",
41 | "iota" -> "ι",
42 | "kappa" -> "κ",
43 | "lambda" -> "λ",
44 | "mu" -> "μ",
45 | "nu" -> "ν",
46 | "xi" -> "ξ",
47 | "pi" -> "π",
48 | "rho" -> "ρ",
49 | "sigma" -> "σ",
50 | "tau" -> "τ",
51 | "upsilon" -> "υ",
52 | "phi" -> "φ",
53 | "chi" -> "χ",
54 | "psi" -> "ψ",
55 | "omega" -> "ω"
56 | ).getOrElse(name, name)
57 | }
58 |
59 | object Variable {
60 | given string2variable: (String => Variable) = apply(_)
61 | given Show[Variable] {
62 | extension (x: Variable) {
63 | def show = x.toString
64 | def toMathML = x.toMathML
65 | }
66 | }
67 |
68 | def apply(name: String): Variable = new Constant(name, 0)
69 | def apply(name: String, prime: Int, subscript: Int*): Variable = new Constant(name, prime, subscript*)
70 |
71 | def function[T : Show](name: String, parameter: T*): Variable = new Function(name, parameter*)
72 | def sqrt[T : Show](x: T): Variable = new Sqrt(x)
73 | }
74 |
--------------------------------------------------------------------------------
/application/ivy.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/scas/src/scas/math/Numeric.scala:
--------------------------------------------------------------------------------
1 | package scas.math
2 |
3 | trait Numeric[T] extends Ordering[T] {
4 | extension (x: T) {
5 | def + (y: T): T
6 | def - (y: T): T
7 | def * (y: T): T
8 | def unary_- : T
9 | }
10 | def fromInt(x: Int): T
11 | extension (x: T) {
12 | def toInt: Int
13 | def toLong: Long
14 | }
15 |
16 | def zero = fromInt(0)
17 | def one = fromInt(1)
18 |
19 | def abs(x: T) = if x.signum < 0 then -x else x
20 |
21 | extension (x: T) def signum =
22 | if x < zero then -1
23 | else if x > zero then 1
24 | else 0
25 | }
26 |
27 | object Numeric {
28 | trait ByteIsIntegral extends Numeric[Byte] {
29 | extension (x: Byte) {
30 | def + (y: Byte) = (x + y).toByte
31 | def - (y: Byte) = (x - y).toByte
32 | def * (y: Byte) = (x * y).toByte
33 | def unary_- = (-x).toByte
34 | }
35 | def fromInt(x: Int) = x.toByte
36 | extension (x: Byte) {
37 | def toInt = x.toInt
38 | def toLong = x.toLong
39 | override def signum = java.lang.Integer.signum(x)
40 | }
41 | }
42 | given ByteIsIntegral: ByteIsIntegral with Ordering.ByteOrdering
43 | trait ShortIsIntegral extends Numeric[Short] {
44 | extension (x: Short) {
45 | def + (y: Short) = (x + y).toShort
46 | def - (y: Short) = (x - y).toShort
47 | def * (y: Short) = (x * y).toShort
48 | def unary_- = (-x).toShort
49 | }
50 | def fromInt(x: Int) = x.toShort
51 | extension (x: Short) {
52 | def toInt = x.toInt
53 | def toLong = x.toLong
54 | override def signum = java.lang.Integer.signum(x)
55 | }
56 | }
57 | given ShortIsIntegral: ShortIsIntegral with Ordering.ShortOrdering
58 | trait IntIsIntegral extends Numeric[Int] {
59 | extension (x: Int) {
60 | def + (y: Int) = x + y
61 | def - (y: Int) = x - y
62 | def * (y: Int) = x * y
63 | def unary_- = -x
64 | }
65 | def fromInt(x: Int) = x
66 | extension (x: Int) {
67 | def toInt = x
68 | def toLong = x.toLong
69 | override def signum = java.lang.Integer.signum(x)
70 | }
71 | }
72 | given IntIsIntegral: IntIsIntegral with Ordering.IntOrdering
73 | trait LongIsIntegral extends Numeric[Long] {
74 | extension (x: Long) {
75 | def + (y: Long) = x + y
76 | def - (y: Long) = x - y
77 | def * (y: Long) = x * y
78 | def unary_- = -x
79 | }
80 | def fromInt(x: Int) = x.toLong
81 | extension (x: Long) {
82 | def toInt = x.toInt
83 | def toLong = x
84 | override def signum = java.lang.Long.signum(x)
85 | }
86 | }
87 | given LongIsIntegral: LongIsIntegral with Ordering.LongOrdering
88 | }
89 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/Engine.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import scala.beans.BeanProperty
4 | import javax.script.{AbstractScriptEngine, Bindings, ScriptContext, ScriptEngine, ScriptEngineFactory, ScriptException, SimpleBindings}
5 | import java.io.{StringWriter, Reader}
6 | import java.util.{Arrays, List}
7 |
8 | class Engine(@BeanProperty val factory: ScriptEngineFactory) extends AbstractScriptEngine(new SimpleBindings) {
9 | def createBindings: Bindings = new SimpleBindings
10 |
11 | var code = ""
12 |
13 | @throws(classOf[ScriptException])
14 | def eval(script: String, context: ScriptContext): Object = {
15 | val cat = code + script
16 | Parsers(cat) match {
17 | case Right(result) => {
18 | code = ""
19 | result
20 | }
21 | case Left(msg) if (msg.endsWith("end of source found")) => {
22 | code = cat + "\n"
23 | null
24 | }
25 | case Left(msg) => {
26 | code = ""
27 | throw new ScriptException(msg)
28 | }
29 | }
30 | }
31 |
32 | @throws(classOf[ScriptException])
33 | def eval(reader: Reader, context: ScriptContext): Object = {
34 | val writer = new StringWriter()
35 | var c = reader.read()
36 | while c != -1 do {
37 | writer.write(c)
38 | c = reader.read()
39 | }
40 | reader.close()
41 | eval(writer.toString(), context)
42 | }
43 | }
44 |
45 | object Engine {
46 | class Factory extends ScriptEngineFactory {
47 | @BeanProperty
48 | val engineName = "ScAS Interface"
49 |
50 | @BeanProperty
51 | val engineVersion = "1.0"
52 |
53 | @BeanProperty
54 | val extensions: List[String] = Arrays.asList("txt", "TXT")
55 |
56 | @BeanProperty
57 | val languageName = "ScAS"
58 |
59 | @BeanProperty
60 | val languageVersion = "3.0"
61 |
62 | def getMethodCallSyntax(obj: String, m: String, args: String*): String = null
63 |
64 | @BeanProperty
65 | val mimeTypes: List[String] = Arrays.asList("text/plain")
66 |
67 | @BeanProperty
68 | val names: List[String] = Arrays.asList("scas")
69 |
70 | def getOutputStatement(toDisplay: String): String = null
71 |
72 | def getParameter(key: String): Object = key match {
73 | case ScriptEngine.ENGINE => engineName
74 | case ScriptEngine.ENGINE_VERSION => engineVersion
75 | case ScriptEngine.LANGUAGE => languageName
76 | case ScriptEngine.LANGUAGE_VERSION => languageVersion
77 | case ScriptEngine.NAME => names.get(0)
78 | case _ => null
79 | }
80 |
81 | def getProgram(statements: String*): String = null
82 |
83 | def getScriptEngine: ScriptEngine = new Engine(this)
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/scas/src/scas/util/Stream.scala:
--------------------------------------------------------------------------------
1 | package scas.util
2 |
3 | import scala.concurrent.Future
4 |
5 | trait Stream[+A] {
6 | def isEmpty: Boolean
7 | def head: A
8 | def tail: Future[Stream[A]]
9 |
10 | def force: Stream[A] =
11 | var these = this
12 | while !these.isEmpty do these = these.tail.await
13 | this
14 |
15 | def filter(p: A => Boolean): Stream[A] = {
16 | var rest = this
17 | while !rest.isEmpty && !p(rest.head) do rest = rest.tail.await
18 | if !rest.isEmpty then {
19 | rest.head #: rest.tail.map(_.filter(p))
20 | } else Stream.Nil
21 | }
22 |
23 | def take(n: Int): Stream[A] = if !isEmpty && n > 0 then {
24 | head #: tail.map(_.take(n - 1))
25 | } else Stream.Nil
26 |
27 | def takeWhile(p: A => Boolean): Stream[A] = if !isEmpty && p(head) then {
28 | head #: tail.map(_.takeWhile(p))
29 | } else Stream.Nil
30 |
31 | def exists(p: A => Boolean): Boolean = {
32 | var these = this
33 | while !these.isEmpty do {
34 | if p(these.head) then return true
35 | these = these.tail.await
36 | }
37 | false
38 | }
39 |
40 | def size = iterator.size
41 |
42 | def iterator: Iterator[A] = new Stream.Iterator(this)
43 | }
44 |
45 | object Stream {
46 | object Nil extends Stream[Nothing] {
47 | def isEmpty = true
48 | def head = ???
49 | def tail = ???
50 | }
51 |
52 | final class Cons[+A](hd: A, tl: Future[Stream[A]]) extends Stream[A] {
53 | def isEmpty = false
54 | def head = hd
55 | def tail = tl
56 | }
57 |
58 | extension [A](x: A)
59 | def #:(xs1: Future[Stream[A]]): Stream[A] =
60 | Cons(x, xs1)
61 |
62 | def apply[A](s: A*): Stream[A] = if !s.isEmpty then s.head #: Future(apply(s.tail*)) else Nil
63 |
64 | def range[T : Integral as num](start: T, end: T, step: T): Stream[T] = {
65 | import num.*
66 | if if step < zero then start <= end else end <= start then Nil
67 | else start #: Future(range(start + step, end, step))
68 | }
69 |
70 | def range[T : Integral as num](start: T, end: T): Stream[T] = range(start, end, num.one)
71 |
72 | object sequential {
73 | def apply[A](s: A*): Stream[A] = if !s.isEmpty then s.head #: Lazy(apply(s.tail*)) else Nil
74 |
75 | def from(start: Int, step: Int): Stream[Int] = start #: Lazy(from(start + step, step))
76 |
77 | def from(start: Int): Stream[Int] = from(start, 1)
78 | }
79 |
80 | private class Iterator[+A](private var stream: Stream[A]) extends scala.collection.Iterator[A] {
81 | override def hasNext: Boolean = !stream.isEmpty
82 |
83 | override def next(): A =
84 | if stream.isEmpty then Iterator.empty.next()
85 | else {
86 | val res = stream.head
87 | stream = stream.tail.await
88 | res
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/scas/application/src/scas/scripting/Factors.scala:
--------------------------------------------------------------------------------
1 | package scas.scripting
2 |
3 | import scala.compiletime.deferred
4 | import scas.structure.Ring
5 | import scas.math.Numeric
6 | import scas.base.BigInteger
7 | import BigInteger.given
8 | import Factors.Element
9 |
10 | trait Factors[T, N : Numeric as numeric] extends Ring[Element[T, N]] {
11 | given ring: Ring[T] = deferred
12 | def empty: Element[T, N]
13 | override val zero = empty + ((ring.zero, numeric.one))
14 | override val one = empty
15 | def fromInt(n: BigInteger) = apply(ring.fromInt(n))
16 | def apply(x: T): Element[T, N] = if x.isOne then empty else if x.signum < 0 then apply(-x) + ((-ring.one, numeric.one)) else empty + ((x, numeric.one))
17 | extension (x: Element[T, N]) {
18 | override def isZero = x.getOrElse(ring.zero, numeric.zero) >< numeric.one
19 | override def isOne = x.isEmpty
20 | def add(y: Element[T, N]) = {
21 | val (a, b) = x.partition((c, _) => y.contains(c))
22 | val (_, d) = y.partition((c, _) => a.contains(c))
23 | a * this(b.expand + d.expand)
24 | }
25 | def expand = x.foldLeft(ring.one) { (l, r) =>
26 | val (a, b) = r
27 | l * a \ b.toLong
28 | }
29 | def subtract(y: Element[T, N]) = x + (-y)
30 | def multiply(y: Element[T, N]) = if x.isZero || y.isZero then zero else y.foldLeft(x)((l, r) => {
31 | val (a, b) = r
32 | val c = l.getOrElse(a, numeric.zero)
33 | if a >< -ring.one && b >< numeric.one && c >< numeric.one then l - a else l + ((a, c + b))
34 | })
35 | def isUnit = abs(x).isOne
36 | override def unary_- = x * this(-ring.one)
37 | def signum = if x.isZero then 0 else if x.getOrElse(-ring.one, numeric.zero) >< numeric.one then -1 else 1
38 | }
39 | def characteristic = ring.characteristic
40 | def equiv(x: Element[T, N], y: Element[T, N]) = {
41 | val xs = x.iterator
42 | val ys = y.iterator
43 | while xs.hasNext && ys.hasNext do {
44 | val (a, b) = xs.next
45 | val (c, d) = ys.next
46 | if a <> c then return false
47 | else if b <> d then return false
48 | }
49 | !xs.hasNext && !ys.hasNext
50 | }
51 | extension (x: Element[T, N]) def toCode(level: Level) = {
52 | var s = ring.one.show
53 | val p = if x.size == 1 then level else Level.Multiplication
54 | var m = 0
55 | for (a, b) <- x do {
56 | val t = if b >< numeric.one then a.toCode(p) else s"${a.toCode(Level.Power)}\\$b"
57 | s = if m == 0 then t else s + "*" + t
58 | m += 1
59 | }
60 | s
61 | }
62 | override def toString = s"Product($ring)"
63 | extension (x: Element[T, N]) def toMathML = {
64 | var s = ring.one.toMathML
65 | var m = 0
66 | for (a, b) <- x do {
67 | val t = if b >< numeric.one then a.toMathML else s"${a.toMathML}$b"
68 | s = if m == 0 then t else s"$s$t"
69 | m += 1
70 | }
71 | s
72 | }
73 | def toMathML = s"${ring.toMathML}"
74 | }
75 |
76 | object Factors {
77 | type Element[T, N] = Map[T, N]
78 | }
79 |
--------------------------------------------------------------------------------
/scas/src/scas/structure/commutative/Quotient.scala:
--------------------------------------------------------------------------------
1 | package scas.structure.commutative
2 |
3 | import Quotient.Element
4 | import scala.compiletime.deferred
5 | import scas.util.{Conversion, unary_~}
6 | import scas.base.BigInteger
7 | import BigInteger.given
8 |
9 | trait Quotient[T] extends Field[Element[T]] {
10 | given ring: UniqueFactorizationDomain[T] = deferred
11 | def apply(n: T) = Element(n, ring.one)
12 | def fromInt(n: BigInteger) = this(ring.fromInt(n))
13 | def apply(n: T, d: T): Element[T] = this(Element(n, d))
14 | def apply(x: Element[T]) = {
15 | val Element(n, d) = x
16 | val c = ring.gcd(n, d)
17 | val gcd = if d.signum == -c.signum then -c else c
18 | Element(n / gcd, d / gcd)
19 | }
20 | extension (x: Element[T]) {
21 | def add(y: Element[T]) = {
22 | val Element(a, b) = x
23 | val Element(c, d) = y
24 | val Element(b0, d0) = this(b, d)
25 | this(a * d0 + c * b0, b0 * d)
26 | }
27 | def subtract(y: Element[T]) = {
28 | val Element(a, b) = x
29 | val Element(c, d) = y
30 | val Element(b0, d0) = this(b, d)
31 | this(a * d0 - c * b0, b0 * d)
32 | }
33 | def multiply(y: Element[T]) = {
34 | val Element(a, b) = x
35 | val Element(c, d) = y
36 | val Element(a0, d0) = this(a, d)
37 | val Element(c0, b0) = this(c, b)
38 | Element(a0 * c0, b0 * d0)
39 | }
40 | override def unary_- = {
41 | val Element(n, d) = x
42 | Element(-n, d)
43 | }
44 | override def pow(b: BigInteger) = if b.signum < 0 then inverse(x) \ -b else {
45 | val Element(n, d) = x
46 | Element(n \ b, d \ b)
47 | }
48 | def signum = {
49 | val Element(n, _) = x
50 | n.signum
51 | }
52 | }
53 | def equiv(x: Element[T], y: Element[T]) = {
54 | val Element(a, b) = x
55 | val Element(c, d) = y
56 | a >< c && b >< d
57 | }
58 | def inverse(x: Element[T]) = {
59 | val Element(n, d) = x
60 | Element(d, n)
61 | }
62 | override def gcd(x: Element[T], y: Element[T]) = {
63 | val Element(a, b) = x
64 | val Element(c, d) = y
65 | Element(ring.gcd(a, c), ring.lcm(b, d))
66 | }
67 | override def abs(x: Element[T]) = {
68 | val Element(n, d) = x
69 | Element(ring.abs(n), d)
70 | }
71 | def characteristic = ring.characteristic
72 | extension (x: Element[T]) def toCode(level: Level) = {
73 | import Level.given
74 | val Element(n, d) = x
75 | if d.isOne then n.toCode(level) else {
76 | val s = n.toCode(Level.Multiplication) + "/" + d.toCode(Level.Power)
77 | if level > Level.Multiplication then fenced(s) else s
78 | }
79 | }
80 | override def toString = s"$ring.quotient()"
81 | extension (x: Element[T]) def toMathML = {
82 | val Element(n, d) = x
83 | if d.isOne then n.toMathML else s"${n.toMathML}${d.toMathML}"
84 | }
85 |
86 | extension (ring: UniqueFactorizationDomain[T]) def quotient() = this
87 |
88 | given ring2quotient: [U: Conversion[T]] => (U => Element[T]) = x => this(~x)
89 | }
90 |
91 | object Quotient {
92 | case class Element[T](numerator: T, denominator: T)
93 | }
94 |
--------------------------------------------------------------------------------
/scas/src/scas/polynomial/gb/Engine.scala:
--------------------------------------------------------------------------------
1 | package scas.polynomial.gb
2 |
3 | import scala.collection.immutable.SortedSet
4 | import scala.collection.mutable.ListBuffer
5 | import scas.polynomial.Polynomial
6 | import scas.math.Ordering
7 | import scas.prettyprint.Show.given
8 | import java.util.logging.Logger
9 |
10 | trait Engine[T, C, M, P[M] <: Pair[M]](using factory: Polynomial[T, C, M]) {
11 | import factory.{normalize, s_polynomial, pp}
12 | val logger = Logger.getLogger(getClass().getName());
13 |
14 | def process(pa: P[M]): Unit = {
15 | if !b_criterion(pa) then {
16 | logger.config(pa.toString)
17 | val p = normalize(s_polynomial(polys(pa.i), polys(pa.j)).reduce(polys.toSeq*))
18 | if !p.isZero then update(p)
19 | npairs += 1
20 | }
21 | remove(pa)
22 | }
23 | def b_criterion(pa: P[M]): Boolean = {
24 | var k = 0
25 | while k < polys.size do {
26 | if (k.headPowerProduct | pa.scm) && considered(pa.i, k) && considered(pa.j, k) then return true
27 | k += 1
28 | }
29 | false
30 | }
31 | def remove(pa: P[M]): Unit = {
32 | pairs -= pa
33 | if pa.reduction then removed(pa.principal) = true
34 | }
35 | def add(pa: P[M]): Unit = {
36 | pairs += pa
37 | if pa.coprime then remove(pa)
38 | }
39 |
40 | def apply(i: Int, j: Int): P[M]
41 | def sorted(i: Int, j: Int) = if i > j then apply(j, i) else apply(i, j)
42 | def make(index: Int): Unit = for i <- 0 until index do add(apply(i, index))
43 | def considered(i: Int, j: Int) = !pairs.contains(sorted(i, j))
44 |
45 | def ordering = Ordering by { (pair: P[M]) => pair.key }
46 | given Ordering[P[M]] = ordering
47 |
48 | var pairs = SortedSet.empty[P[M]]
49 | val removed = ListBuffer.empty[Boolean]
50 | val polys = ListBuffer.empty[T]
51 | var npairs = 0
52 | var npolys = 0
53 |
54 | extension (i: Int) def headPowerProduct = polys(i).headPowerProduct
55 |
56 | def gb(xs: T*) = {
57 | update(xs)
58 | process
59 | reduce
60 | toList
61 | }
62 |
63 | def update(s: Seq[T]): Unit = {
64 | logger.config(s.toList.show)
65 | s.foreach { p =>
66 | if !p.isZero then update(p)
67 | }
68 | npairs = 0
69 | npolys = 0
70 | }
71 |
72 | def update(poly: T): Unit = {
73 | polys += poly
74 | removed += false
75 | val index = polys.size - 1
76 | logger.config("(" + index.headPowerProduct.show + ", " + index + ")")
77 | make(index)
78 | npolys += 1
79 | }
80 |
81 | def process: Unit = {
82 | logger.config("process")
83 | while !pairs.isEmpty do process(pairs.head)
84 | }
85 |
86 | def reduce: Unit = {
87 | logger.config("reduce")
88 | for i <- polys.size - 1 to 0 by -1 if removed(i) do {
89 | removed.remove(i)
90 | polys.remove(i)
91 | }
92 | for i <- 0 until polys.size do {
93 | polys(i) = normalize(polys(i).reduce(false, true, polys.toSeq*))
94 | logger.config("(" + i.headPowerProduct.show + ")")
95 | }
96 | }
97 |
98 | def toList = {
99 | logger.config("statistic = (" + npairs + ", " + npolys + ", " + polys.size + ")")
100 | polys.toList
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/application/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | 4.0.0
6 | com.github.rjolly
7 | scas.application_3
8 | jar
9 | 3.1
10 | https://github.com/rjolly/scas
11 | Scala Algebra System - Application
12 |
13 |
14 | GPL
15 | http://www.gnu.org/licenses/gpl.txt
16 |
17 |
18 | scas.application
19 |
20 | com.github.rjolly
21 |
22 |
23 | git@github.com:rjolly/scas.git
24 | scm:git:git@github.com:rjolly/scas.git
25 |
26 |
27 |
28 | rjolly
29 | Raphael Jolly
30 | https://github.com/rjolly
31 |
32 |
33 |
34 |
35 | com.github.rjolly
36 | scas_3
37 | 3.1
38 |
39 |
40 | de.uni-mannheim.rz.krum
41 | jas
42 | 2.7.200
43 |
44 |
45 | org.apache.logging.log4j
46 | log4j-core
47 |
48 |
49 | org.apache.logging.log4j
50 | log4j-api
51 |
52 |
53 |
54 |
55 | org.apache.logging.log4j
56 | log4j-core
57 | 2.24.3
58 |
59 |
60 | org.apache.logging.log4j
61 | log4j-api
62 | 2.24.3
63 |
64 |
65 | cc.redberry
66 | rings
67 | 2.5.7
68 |
69 |
70 | org.apache.commons
71 | commons-math3
72 |
73 |
74 |
75 |
76 | org.apache.commons
77 | commons-math3
78 | 3.6.1
79 |
80 |
81 | net.sourceforge.jscl-meditor
82 | jscl
83 | 2.4.18
84 |
85 |
86 | org.scala-lang.modules
87 | scala-parser-combinators_3
88 | 2.4.0
89 |
90 |
91 | org.scala-lang
92 | scala3-library_3
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------