├── .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 | --------------------------------------------------------------------------------