summaryrefslogtreecommitdiff
path: root/macros/luatex/latex/luacas/tex
diff options
context:
space:
mode:
Diffstat (limited to 'macros/luatex/latex/luacas/tex')
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-absexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-algebra_init.lua24
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-equation.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-euclideandomain.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-factorialexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-field.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-integer.lua17
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-integerquotientring.lua11
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-logarithm.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-polynomialring.lua21
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-rational.lua22
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-ring.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-rootexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-sqrtexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-trigexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/calculus/luacas-calculus_init.lua6
-rw-r--r--macros/luatex/latex/luacas/tex/calculus/luacas-derivativeexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/calculus/luacas-diffexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/calculus/luacas-integralexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/core/luacas-atomicexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/core/luacas-binaryoperation.lua4
-rw-r--r--macros/luatex/latex/luacas/tex/core/luacas-compoundexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/core/luacas-constantexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/core/luacas-core_init.lua16
-rw-r--r--macros/luatex/latex/luacas/tex/core/luacas-functionexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/core/luacas-symbolexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/luacas.sty2
-rw-r--r--macros/luatex/latex/luacas/tex/luacas_init.lua304
-rw-r--r--macros/luatex/latex/luacas/tex/test/luacas-main.lua17
-rw-r--r--macros/luatex/latex/luacas/tex/test/luacas-parser.lua24
-rw-r--r--macros/luatex/latex/luacas/tex/test/rings/luacas-conversion.lua20
31 files changed, 412 insertions, 112 deletions
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-absexpression.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-absexpression.lua
index 2bf0b6a7ef..264730cbbe 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-absexpression.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-absexpression.lua
@@ -2,7 +2,7 @@
--- The absolute value of an expression.
--- @field expression Expression
AbsExpression = {}
-__AbsExpression = {}
+local __AbsExpression = {}
----------------------------
-- Instance functionality --
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-algebra_init.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-algebra_init.lua
deleted file mode 100644
index ac37c56a5b..0000000000
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-algebra_init.lua
+++ /dev/null
@@ -1,24 +0,0 @@
--- Loads algebra files in the correct order.
-require("_lib.luacas-table")
-
-require("core.luacas-core_init")
-
-require("algebra.luacas-ring")
-require("algebra.luacas-euclideandomain")
-require("algebra.luacas-field")
-require("algebra.luacas-polynomialring")
-require("algebra.luacas-integer")
-require("algebra.luacas-rational")
-require("algebra.luacas-integerquotientring")
-require("algebra.luacas-sqrtexpression")
-
-require("algebra.luacas-absexpression")
-require("algebra.luacas-equation")
-require("algebra.luacas-factorialexpression")
-require("algebra.luacas-logarithm")
-require("algebra.luacas-rootexpression")
-require("algebra.luacas-trigexpression")
-
-require("algebra.polynomialring.luacas-berlekampfactoring")
-require("algebra.polynomialring.luacas-zassenhausfactoring")
-require("algebra.polynomialring.luacas-decomposition") \ No newline at end of file
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-equation.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-equation.lua
index 4e81d5ca95..18d6a9c091 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-equation.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-equation.lua
@@ -3,7 +3,7 @@
--- @field lhs Expression
--- @field rhs Expression
Equation = {}
-__Equation = {}
+local __Equation = {}
--------------------------
-- Static functionality --
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-euclideandomain.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-euclideandomain.lua
index fab2c5c7c2..fec52d5d81 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-euclideandomain.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-euclideandomain.lua
@@ -1,7 +1,7 @@
--- @class EuclideanDomain
--- Interface for an element of a euclidean domain.
EuclideanDomain = {}
-__EuclideanDomain = {}
+local __EuclideanDomain = {}
----------------------
-- Required methods --
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-factorialexpression.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-factorialexpression.lua
index 1c5b824ff7..5920d22733 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-factorialexpression.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-factorialexpression.lua
@@ -2,7 +2,7 @@
--- The factorial of an expression.
--- @field expression Expression
FactorialExpression = {}
-__FactorialExpression = {}
+local __FactorialExpression = {}
----------------------------
-- Instance functionality --
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-field.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-field.lua
index c845e94c55..0846a90ec9 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-field.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-field.lua
@@ -1,7 +1,7 @@
--- @class Field
--- Interface for an element of a field.
Field = {}
-__Field = {}
+local __Field = {}
----------------------
-- Required methods --
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-integer.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-integer.lua
index a3c54f498c..6a81be295b 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-integer.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-integer.lua
@@ -3,7 +3,7 @@
--- @field self table<number, number>
--- @field sign number
Integer = {}
-__Integer = {}
+local __Integer = {}
--------------------------
-- Static functionality --
@@ -90,6 +90,9 @@ end
--- @return Integer
function Integer.ceillog(a, base)
base = base or Integer(10)
+ if a == Integer.one() then
+ return Integer.one()
+ end
local k = Integer.zero()
while (base ^ k) < a do
@@ -138,9 +141,9 @@ end
----------------------------
-- So we don't have to copy the Euclidean operations each time we create an integer.
-local __o = Copy(__EuclideanOperations)
-__o.__index = Integer
-__o.__tostring = function(a) -- Only works if the digit size is a power of 10
+__IntegerOperations = Copy(__EuclideanOperations)
+__IntegerOperations.__index = Integer
+__IntegerOperations.__tostring = function(a) -- Only works if the digit size is a power of 10
local out = ""
for i, digit in ipairs(a) do
local pre = tostring(math.floor(digit))
@@ -156,7 +159,7 @@ __o.__tostring = function(a) -- Only works if the digit size is a power of 10
end
return out
end
-__o.__div = function(a, b) -- Constructor for a rational number disguised as division
+__IntegerOperations.__div = function(a, b) -- Constructor for a rational number disguised as division
if not b.getring then
return BinaryOperation.DIVEXP({a, b})
end
@@ -165,7 +168,7 @@ __o.__div = function(a, b) -- Constructor for a rational number disguised as d
end
return __FieldOperations.__div(a, b)
end
-__o.__concat = function(a, b) -- Like a decimal, but fancier. Used mainly for the parser with decimal numbers.
+__IntegerOperations.__concat = function(a, b) -- Like a decimal, but fancier. Used mainly for the parser with decimal numbers.
return a + b / (Integer(10) ^ Integer.ceillog(b))
end
@@ -174,7 +177,7 @@ end
--- @return Integer
function Integer:new(n)
local o = {}
- o = setmetatable(o, __o)
+ o = setmetatable(o, __IntegerOperations)
if not n then
o[1] = 0
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-integerquotientring.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-integerquotientring.lua
index 4c2188c9e5..6fe0ce1cdf 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-integerquotientring.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-integerquotientring.lua
@@ -4,7 +4,7 @@
--- @field modulus Integer
IntegerModN = {}
-__IntegerModN = {}
+local __IntegerModN = {}
-- Metatable for ring objects.
local __obj = {__index = IntegerModN, __eq = function(a, b)
@@ -37,11 +37,10 @@ end
----------------------------
-- So we don't have to copy the field operations each time
-local __o
-__o = Copy(__FieldOperations)
+__IntegerModNOperations = Copy(__FieldOperations)
-__o.__index = IntegerModN
-__o.__tostring = function(a)
+__IntegerModNOperations.__index = IntegerModN
+__IntegerModNOperations.__tostring = function(a)
return tostring(a.element)
end
@@ -56,7 +55,7 @@ function IntegerModN:new(i, n)
error("Argument error: modulus must be an integer greater than 0.")
end
- o = setmetatable(o, __o)
+ o = setmetatable(o, __IntegerModNOperations)
if i < Integer.zero() or i >= n then
i = i % n
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-logarithm.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-logarithm.lua
index 07a9db84d1..135a74f326 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-logarithm.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-logarithm.lua
@@ -4,7 +4,7 @@
--- @field base Expression
--- @field expression Expression
Logarithm = {}
-__Logarithm = {}
+local __Logarithm = {}
----------------------------
-- Instance functionality --
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-polynomialring.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-polynomialring.lua
index 568c21c921..2a76bda265 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-polynomialring.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-polynomialring.lua
@@ -4,7 +4,7 @@
--- @field symbol SymbolExpression
--- @field ring RingIdentifier
PolynomialRing = {}
-__PolynomialRing = {}
+local __PolynomialRing = {}
-- Metatable for ring objects.
local __obj = {__index = PolynomialRing, __eq = function(a, b)
@@ -214,9 +214,9 @@ end
----------------------------
-- So we don't have to copy the Euclidean operations each time
-local __o = Copy(__EuclideanOperations)
-__o.__index = PolynomialRing
-__o.__tostring = function(a)
+__PolynomialOperations = Copy(__EuclideanOperations)
+__PolynomialOperations.__index = PolynomialRing
+__PolynomialOperations.__tostring = function(a)
local out = ""
local loc = a.degree:asnumber()
while loc >= 0 do
@@ -229,7 +229,7 @@ __o.__tostring = function(a)
end
return string.sub(out, 1, string.len(out) - 1)
end
-__o.__div = function(a, b)
+__PolynomialOperations.__div = function(a, b)
if not b.getring then
return BinaryOperation.DIVEXP({a, b})
end
@@ -258,13 +258,20 @@ function PolynomialRing:tolatex()
end
if self.ring == Rational.getring() or self.ring == Integer.getring() or self.ring == IntegerModN.getring() then
if self.coefficients[loc] ~= Integer.one() then
- out = out .. self.coefficients[loc]:tolatex() .. self.symbol
+ if self.coefficients[loc] == Integer(-1) then
+ out = out .. "-" .. self.symbol
+ elseif self.coefficients[loc] == Integer.zero() then
+ goto lead
+ else
+ out = out .. self.coefficients[loc]:tolatex() .. self.symbol
+ end
else
out = out .. self.symbol
end
if loc ~=1 then
out = out .. "^{" .. loc .. "}"
end
+ ::lead::
loc = loc -1
while loc >=0 do
local coeff = self.coefficients[loc]
@@ -330,7 +337,7 @@ end
-- Creates a new polynomial ring given an array of coefficients and a symbol
function PolynomialRing:new(coefficients, symbol, degree)
local o = {}
- o = setmetatable(o, __o)
+ o = setmetatable(o, __PolynomialOperations)
if type(coefficients) ~= "table" then
error("Sent parameter of wrong type: Coefficients must be in an array")
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-rational.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-rational.lua
index 811909a948..0802eb5172 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-rational.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-rational.lua
@@ -4,7 +4,7 @@
--- @field denominator Ring
--- @field ring RingIdentifier
Rational = {}
-__Rational = {}
+local __Rational = {}
--------------------------
@@ -54,9 +54,9 @@ end
----------------------------
-- So we don't have to copy the field operations each time.
-local __o = Copy(__FieldOperations)
-__o.__index = Rational
-__o.__tostring = function(a)
+__RationalOperations = Copy(__FieldOperations)
+__RationalOperations.__index = Rational
+__RationalOperations.__tostring = function(a)
if a.ring.symbol then
return "(" .. tostring(a.numerator)..")/("..tostring(a.denominator) .. ")"
end
@@ -70,7 +70,7 @@ end
--- @param keep boolean
function Rational:new(n, d, keep)
local o = {}
- o = setmetatable(o, __o)
+ o = setmetatable(o, __RationalOperations)
if n:getring() == PolynomialRing.getring() then
o.symbol = n.symbol
@@ -88,7 +88,15 @@ function Rational:new(n, d, keep)
d = d or Integer.one()
o.numerator = n
o.denominator = d
- o:reduce()
+ if not keep then
+ o:reduce()
+ end
+
+ if o.numerator:getring() == Integer.getring() then
+ o.ring = Integer.getring()
+ elseif o.numerator:getring() == PolynomialRing.getring() then
+ o.ring = Ring.resultantring(o.numerator:getring(), o.denominator:getring())
+ end
if (not keep) and o.denominator == Integer.one() or (not keep) and o.numerator == Integer.zero() then
return o.numerator
@@ -107,7 +115,6 @@ function Rational:reduce()
local gcd = Integer.gcd(self.numerator, self.denominator)
self.numerator = self.numerator//gcd
self.denominator = self.denominator//gcd
- self.ring = Integer.getring()
elseif self.numerator:getring() == PolynomialRing.getring() then
local lc = self.denominator:lc()
self.denominator = self.denominator/lc
@@ -115,7 +122,6 @@ function Rational:reduce()
local gcd = PolynomialRing.gcd(self.numerator, self.denominator)
self.numerator = self.numerator//gcd
self.denominator = self.denominator//gcd
- self.ring = Ring.resultantring(self.numerator:getring(), self.denominator:getring())
end
end
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-ring.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-ring.lua
index 4903b9c912..81df15d18c 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-ring.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-ring.lua
@@ -1,7 +1,7 @@
--- @class Ring
--- Interface for an element of a ring with unity.
Ring = {}
-__Ring = {}
+local __Ring = {}
--------------------------
-- Static functionality --
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-rootexpression.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-rootexpression.lua
index a66182579a..6f9a492591 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-rootexpression.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-rootexpression.lua
@@ -2,7 +2,7 @@
--- An expression that represents the solutions to expression = 0.
--- @field expression Expression
RootExpression = {}
-__RootExpression = {}
+local __RootExpression = {}
----------------------------
-- Instance functionality --
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-sqrtexpression.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-sqrtexpression.lua
index bc96f4e1d8..641198fd65 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-sqrtexpression.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-sqrtexpression.lua
@@ -2,7 +2,7 @@
--- An expression that represents the positive real solution to x^n = a where n is a positive integer and a is constant.
--- @field expression Expression
SqrtExpression = {}
-__SqrtExpression = {}
+local __SqrtExpression = {}
----------------------------
-- Instance functionality --
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-trigexpression.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-trigexpression.lua
index 307bfe1737..6f09e39f57 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-trigexpression.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-trigexpression.lua
@@ -3,7 +3,7 @@
--- @field name string
--- @field expression Expression
TrigExpression = {}
-__TrigExpression = {}
+local __TrigExpression = {}
----------------------------
-- Instance functionality --
diff --git a/macros/luatex/latex/luacas/tex/calculus/luacas-calculus_init.lua b/macros/luatex/latex/luacas/tex/calculus/luacas-calculus_init.lua
deleted file mode 100644
index 89b38b650e..0000000000
--- a/macros/luatex/latex/luacas/tex/calculus/luacas-calculus_init.lua
+++ /dev/null
@@ -1,6 +0,0 @@
--- Loads calculus files in the correct order.
-require("algebra.luacas-algebra_init")
-
-require("calculus.luacas-derivativeexpression")
-require("calculus.luacas-integralexpression")
-require("calculus.luacas-diffexpression")
diff --git a/macros/luatex/latex/luacas/tex/calculus/luacas-derivativeexpression.lua b/macros/luatex/latex/luacas/tex/calculus/luacas-derivativeexpression.lua
index b757759c4c..2ef4c43125 100644
--- a/macros/luatex/latex/luacas/tex/calculus/luacas-derivativeexpression.lua
+++ b/macros/luatex/latex/luacas/tex/calculus/luacas-derivativeexpression.lua
@@ -3,7 +3,7 @@
--- @field symbol SymbolExpression
--- @field expression Expression
DerivativeExpression = {}
-__DerivativeExpression = {}
+local __DerivativeExpression = {}
----------------------------
-- Instance functionality --
diff --git a/macros/luatex/latex/luacas/tex/calculus/luacas-diffexpression.lua b/macros/luatex/latex/luacas/tex/calculus/luacas-diffexpression.lua
index df1dc90f33..bf15c56b6f 100644
--- a/macros/luatex/latex/luacas/tex/calculus/luacas-diffexpression.lua
+++ b/macros/luatex/latex/luacas/tex/calculus/luacas-diffexpression.lua
@@ -4,7 +4,7 @@
--- @field expression Expression
DiffExpression = {}
-__DiffExpression = {}
+local __DiffExpression = {}
----------------------------
-- Instance functionality --
diff --git a/macros/luatex/latex/luacas/tex/calculus/luacas-integralexpression.lua b/macros/luatex/latex/luacas/tex/calculus/luacas-integralexpression.lua
index 5267127264..bddc179fa4 100644
--- a/macros/luatex/latex/luacas/tex/calculus/luacas-integralexpression.lua
+++ b/macros/luatex/latex/luacas/tex/calculus/luacas-integralexpression.lua
@@ -10,7 +10,7 @@
--- @field recursive boolean
IntegralExpression = {}
-__IntegralExpression = {}
+local __IntegralExpression = {}
--------------------------
diff --git a/macros/luatex/latex/luacas/tex/core/luacas-atomicexpression.lua b/macros/luatex/latex/luacas/tex/core/luacas-atomicexpression.lua
index 6cc6e4f58e..4eed1592f4 100644
--- a/macros/luatex/latex/luacas/tex/core/luacas-atomicexpression.lua
+++ b/macros/luatex/latex/luacas/tex/core/luacas-atomicexpression.lua
@@ -1,7 +1,7 @@
--- @class AtomicExpression
--- Interface for an atomic mathematical expression that has no sub-expressions.
AtomicExpression = {}
-__AtomicExpression = {}
+local __AtomicExpression = {}
----------------------
diff --git a/macros/luatex/latex/luacas/tex/core/luacas-binaryoperation.lua b/macros/luatex/latex/luacas/tex/core/luacas-binaryoperation.lua
index 708a6c1540..f2998436eb 100644
--- a/macros/luatex/latex/luacas/tex/core/luacas-binaryoperation.lua
+++ b/macros/luatex/latex/luacas/tex/core/luacas-binaryoperation.lua
@@ -5,7 +5,7 @@
--- @field operation function
--- @field expressions table<number, Expression>
BinaryOperation = {}
-__BinaryOperation = {}
+local __BinaryOperation = {}
----------------------------
-- Instance functionality --
@@ -621,6 +621,8 @@ function BinaryOperation:tolatex()
for index, expression in ipairs(self.expressions) do
if index == 1 then
out = out .. expression:tolatex()
+ elseif expression:isconstant() and expression < Integer.zero() then
+ out = out .. "\\cdot (" .. expression:tolatex() .. ")"
else
out = out .. "\\cdot " .. expression:tolatex()
end
diff --git a/macros/luatex/latex/luacas/tex/core/luacas-compoundexpression.lua b/macros/luatex/latex/luacas/tex/core/luacas-compoundexpression.lua
index 792c36cfc2..cae82719ac 100644
--- a/macros/luatex/latex/luacas/tex/core/luacas-compoundexpression.lua
+++ b/macros/luatex/latex/luacas/tex/core/luacas-compoundexpression.lua
@@ -1,7 +1,7 @@
--- @class CompoundExpression
--- Interface for an expression consisting of one or more subexpressions.
CompoundExpression = {}
-__CompoundExpression = {}
+local __CompoundExpression = {}
----------------------
-- Instance methods --
diff --git a/macros/luatex/latex/luacas/tex/core/luacas-constantexpression.lua b/macros/luatex/latex/luacas/tex/core/luacas-constantexpression.lua
index 0f91a037a9..6d9f8e96d2 100644
--- a/macros/luatex/latex/luacas/tex/core/luacas-constantexpression.lua
+++ b/macros/luatex/latex/luacas/tex/core/luacas-constantexpression.lua
@@ -3,7 +3,7 @@
--- Interface for a mathematical expression without any symbols.
--- ConstantExpressions are AtomicExpressions by default, but individual classes may overwrite that inheritance.
ConstantExpression = {}
-__ConstantExpression = {}
+local __ConstantExpression = {}
----------------------
-- Instance methods --
diff --git a/macros/luatex/latex/luacas/tex/core/luacas-core_init.lua b/macros/luatex/latex/luacas/tex/core/luacas-core_init.lua
deleted file mode 100644
index c9c3b89126..0000000000
--- a/macros/luatex/latex/luacas/tex/core/luacas-core_init.lua
+++ /dev/null
@@ -1,16 +0,0 @@
--- Loads core files in the correct order.
-
-require("core.luacas-expression")
-require("core.luacas-atomicexpression")
-require("core.luacas-compoundexpression")
-require("core.luacas-constantexpression")
-require("core.luacas-symbolexpression")
-require("core.luacas-binaryoperation")
-require("core.luacas-functionexpression")
-
-
-require("core.binaryoperation.luacas-power")
-require("core.binaryoperation.luacas-product")
-require("core.binaryoperation.luacas-sum")
-require("core.binaryoperation.luacas-quotient")
-require("core.binaryoperation.luacas-difference") \ No newline at end of file
diff --git a/macros/luatex/latex/luacas/tex/core/luacas-functionexpression.lua b/macros/luatex/latex/luacas/tex/core/luacas-functionexpression.lua
index dc94790b81..f6f3a99720 100644
--- a/macros/luatex/latex/luacas/tex/core/luacas-functionexpression.lua
+++ b/macros/luatex/latex/luacas/tex/core/luacas-functionexpression.lua
@@ -6,7 +6,7 @@
--- @field variables table<number,SymbolExpression>
--- @alias Function FunctionExpression
FunctionExpression = {}
-__FunctionExpression = {}
+local __FunctionExpression = {}
----------------------------
-- Instance functionality --
diff --git a/macros/luatex/latex/luacas/tex/core/luacas-symbolexpression.lua b/macros/luatex/latex/luacas/tex/core/luacas-symbolexpression.lua
index 0d9192c084..068ab71dcc 100644
--- a/macros/luatex/latex/luacas/tex/core/luacas-symbolexpression.lua
+++ b/macros/luatex/latex/luacas/tex/core/luacas-symbolexpression.lua
@@ -3,7 +3,7 @@
--- @field symbol string
--- @alias Symbol SymbolExpression
SymbolExpression = {}
-__SymbolExpression = {}
+local __SymbolExpression = {}
----------------------
-- Instance methods --
diff --git a/macros/luatex/latex/luacas/tex/luacas.sty b/macros/luatex/latex/luacas/tex/luacas.sty
index d46ee847fc..939bd9d392 100644
--- a/macros/luatex/latex/luacas/tex/luacas.sty
+++ b/macros/luatex/latex/luacas/tex/luacas.sty
@@ -9,7 +9,7 @@
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{luacas}
- [2022/11/15 v1.0.1 CAS written in Lua for LaTeX]
+ [2023/05/26 v1.0.2 CAS written in Lua for LaTeX]
\RequirePackage{iftex}
\ifluatex
diff --git a/macros/luatex/latex/luacas/tex/luacas_init.lua b/macros/luatex/latex/luacas/tex/luacas_init.lua
new file mode 100644
index 0000000000..8d58e259e7
--- /dev/null
+++ b/macros/luatex/latex/luacas/tex/luacas_init.lua
@@ -0,0 +1,304 @@
+--- @class LuaCAS
+--- @class Module
+--- A table that initalizes and stores luacas modules.
+--- @field moduleinfo table<string, table>
+--- @field core Module
+--- @field algebra Module
+--- @field calculus Module
+local luacas = {}
+
+
+-- a table containing a list of module names, descriptions, class names, variables, required files, and dependent modules
+luacas.moduleinfo = {
+ ["core"]=
+ {
+ "Classes needed for creating basic expressions such as symbols, binary operations, and functions.",
+ {
+ "Expression",
+ "AtomicExpression",
+ "CompoundExpression",
+ "ConstantExpression",
+ "SymbolExpression",
+ "BinaryOperation",
+ "FunctionExpression",
+
+ "__ExpressionOperations"
+ },
+ {"E", "I", "PI"},
+ {
+ "_lib.luacas-table",
+ "core.luacas-expression",
+ "core.luacas-atomicexpression",
+ "core.luacas-compoundexpression",
+ "core.luacas-constantexpression",
+ "core.luacas-symbolexpression",
+ "core.luacas-binaryoperation",
+ "core.luacas-functionexpression",
+ "core.binaryoperation.luacas-power",
+ "core.binaryoperation.luacas-product",
+ "core.binaryoperation.luacas-sum",
+ "core.binaryoperation.luacas-quotient",
+ "core.binaryoperation.luacas-difference",
+ },
+ {}
+ },
+
+ ["algebra"]=
+ {
+ "Classes for elements of rings (integers, rationals, polynomials, etc., and operations on those elements (polynomial factoring). Also includes some elementary functions like logs and trig functions.",
+ {
+ "Ring",
+ "EuclideanDomain",
+ "Field",
+ "PolynomialRing",
+ "Integer",
+ "Rational",
+ "IntegerModN",
+ "SqrtExpression",
+ "AbsExpression",
+ "Equation",
+ "FactorialExpression",
+ "Logarithm",
+ "RootExpression",
+ "TrigExpression",
+
+ "__RingOperations", -- Not classes, but we need to set the environment for this
+ "__EuclideanOperations",
+ "__FieldOperations",
+ "__PolynomialOperations",
+ "__IntegerOperations",
+ "__IntegerModNOperations",
+ "__RationalOperations"
+ },
+ {"ABS", "ARCCOS", "ARCCOT", "ARCCSC", "ARCSEC", "ARCSIN", "ARCTAN", "COS", "COT", "CSC", "FACT", "LN", "LOG", "SEC", "SIN", "TAN"},
+ {
+ "algebra.luacas-ring",
+ "algebra.luacas-euclideandomain",
+ "algebra.luacas-field",
+ "algebra.luacas-polynomialring",
+ "algebra.luacas-integer",
+ "algebra.luacas-rational",
+ "algebra.luacas-integerquotientring",
+ "algebra.luacas-sqrtexpression",
+ "algebra.luacas-absexpression",
+ "algebra.luacas-equation",
+ "algebra.luacas-factorialexpression",
+ "algebra.luacas-logarithm",
+ "algebra.luacas-rootexpression",
+ "algebra.luacas-trigexpression",
+ "algebra.polynomialring.luacas-berlekampfactoring",
+ "algebra.polynomialring.luacas-zassenhausfactoring",
+ "algebra.polynomialring.luacas-decomposition"
+ },
+ {"core"}
+ },
+
+ ["calculus"]=
+ {
+ "Classes for symbolic differentation and integration.",
+ {
+ "DerivativeExpression",
+ "IntegralExpression",
+ "DiffExpression"
+ },
+ {"DD", "INT"},
+ {
+ "calculus.luacas-derivativeexpression",
+ "calculus.luacas-integralexpression",
+ "calculus.luacas-diffexpression"
+ },
+ {"algebra"}
+ }
+}
+
+--- Retrieves a short description for a module.
+--- @param mod string
+--- @return string
+function luacas:moduledesc(mod)
+ if self.moduleinfo[mod] then
+ return self.moduleinfo[mod][1]
+ end
+ return "Module not found."
+end
+
+--- Retrieves a list of class names included in a module.
+--- @param mod string
+--- @return table<number,string>
+function luacas:moduleclasses(mod)
+ if self.moduleinfo[mod] then
+ return self.moduleinfo[mod][2]
+ end
+ return {}
+end
+
+--- Retrieves a list of fields included in a module.
+--- @param mod string
+--- @return table<number,string>
+function luacas:modulefields(mod)
+ if self.moduleinfo[mod] then
+ return self.moduleinfo[mod][3]
+ end
+ return {}
+end
+
+--- Retrieves a list of files included in a module.
+--- @param mod string
+--- @return table<number,string>
+function luacas:modulefiles(mod)
+ if self.moduleinfo[mod] then
+ return self.moduleinfo[mod][4]
+ end
+ return {}
+end
+
+--- Retrieves a list of a module's immediate dependencies.
+--- @param mod string
+--- @return table<number,string>
+function luacas:moduledependencies(mod)
+ if self.moduleinfo[mod] then
+ return self.moduleinfo[mod][5]
+ end
+ return {}
+end
+
+--- Initalizes a LuaCAS module and returns it.
+--- Since this creates temporary global variables, it should be treated as atomic to avoid collisions.
+--- @param mod string
+--- @return Module|nil
+function luacas:initmodule(mod)
+ if not self.moduleinfo[mod] then
+ return nil
+ end
+
+ -- TODO: This is a special case, since the algebra module is dependent on the core module and vice versa,
+ -- but our initialization scheme does not allow for circular dependencies.
+ if mod == "core" then
+ self:initmodule("algebra")
+ end
+
+ -- Since other modules require globals from their dependencies, we only remove global variables after all modules have been initalized
+ local G = self:saveglobalstate()
+ self:_initmodulerec(mod)
+ self:restoreglobalstate(G)
+
+ return self[mod]
+end
+
+--- Recursive part of initalizing modules.
+--- @param mod string
+function luacas:_initmodulerec(mod)
+
+ for _, dep in ipairs(self:moduledependencies(mod)) do
+ self:_initmodulerec(dep)
+ end
+
+ if self[mod] then
+ -- Since globals from a dependency might be needed to initialize a module, we create globals even if a module has already been initalized.
+ for class, _ in self[mod] do
+ _G[class] = self[mod][class]
+ end
+ else
+ -- Creates globals needed for modules dependent on this one.
+ self:initglobalmodule(mod)
+
+ -- Adds classes to module table.
+ self[mod] = {}
+ for _, class in ipairs(self:moduleclasses(mod)) do
+ self[mod][class] = _G[class]
+ end
+
+ -- Sets the environment for each method of each class to include all dependent classes of this class.
+ self:setmoduleenvironment(mod)
+ -- TODO: This is a special case, since the algebra module is dependent on the core module and vice versa,
+ -- but our initialization scheme does not allow for circular dependencies.
+ if mod == "algebra" then
+ self:setmoduleenvironment("core")
+ end
+
+ -- Adds fields to module tables
+ for _, class in ipairs(self:modulefields(mod)) do
+ self[mod][class] = _G[class]
+ end
+ end
+end
+
+--- Sets the environment for each method of each class in a module to the current global environment, so it can keep using global variables when reset.
+--- @param mod string
+function luacas:setmoduleenvironment(mod)
+ local realenv = self:saveglobalstate()
+ for _, class in pairs(self[mod]) do
+ -- print(_)
+ for _, func in pairs(class) do
+ -- print(" ", _)
+ if type(func) == "function" then
+ --- Functions only have an _ENV upvalue if they have a global variable, so this should work
+ local _envloc = debug.findupvalue(func, "_ENV")
+ if _envloc then
+ debug.upvaluejoin(func, debug.findupvalue(func, "_ENV"), function () return realenv end, 1)
+ end
+ end
+ end
+
+ -- local meta = getmetatable(class)
+ -- if meta then
+ -- for _, func in pairs(meta) do
+ -- print(" ", _)
+ -- if type(func) == "function" then
+ -- --- Functions only have an _ENV upvalue if they have a global variable, so this should work
+ -- local _envloc = debug.findupvalue(func, "_ENV")
+ -- if _envloc then
+ -- debug.upvaluejoin(func, debug.findupvalue(func, "_ENV"), function () return realenv end, 1)
+ -- end
+ -- end
+ -- end
+ -- end
+ end
+end
+
+--- Saves the current global state as a table and returns it.
+--- @return table
+function luacas:saveglobalstate()
+ local G = {}
+ for key, value in pairs(_G) do
+ G[key] = value
+ end
+ return G
+end
+
+--- Saves the current global state as a table and returns it.
+--- @param G table
+function luacas:restoreglobalstate(G)
+ for key, _ in pairs(_G) do
+ if key ~= "_G" and key ~= "pairs" then
+ _G[key] = nil
+ end
+ end
+ for key, value in pairs(G) do
+ _G[key] = value
+ end
+end
+
+--- Initalizes a LuaCAS module and creates global variables for all classes in that module.
+--- DOES NOT HANDLE DEPENDENCIES, so dependent modules must be globally initalized first.
+--- @param mod string
+--- @return Module|nil
+function luacas:initglobalmodule(mod)
+ for _, filename in ipairs(self:modulefiles(mod)) do
+ require(filename)
+ end
+end
+
+--- Why is Lua like this?
+function debug.findupvalue(fn, search_name)
+ local i = 1
+ while true do
+ local name, val = debug.getupvalue(fn, i)
+ if not name then break end
+ if name == search_name then
+ return i, val
+ end
+ i = i + 1
+ end
+end
+
+return luacas \ No newline at end of file
diff --git a/macros/luatex/latex/luacas/tex/test/luacas-main.lua b/macros/luatex/latex/luacas/tex/test/luacas-main.lua
index 95f77885e4..78b25aa587 100644
--- a/macros/luatex/latex/luacas/tex/test/luacas-main.lua
+++ b/macros/luatex/latex/luacas/tex/test/luacas-main.lua
@@ -1,8 +1,23 @@
---@diagnostic disable: lowercase-global
-- Runs test code from test files.
-require("calculus.luacas-calculus_init")
require("_lib.luacas-pepperfish")
+require("_lib.luacas-table")
+
+local luacas = require("luacas_init")
+luacas:initmodule("calculus")
+
+for name, class in pairs(luacas.core) do
+ _G[name] = class
+end
+
+for name, class in pairs(luacas.algebra) do
+ _G[name] = class
+end
+
+for name, class in pairs(luacas.calculus) do
+ _G[name] = class
+end
-- Stuff required for the basic parser.
local constants = {e="E", pi = "PI", ln = "LN", log = "LOG", Integer = "Integer", DD = "DD", int = "INT", abs = "ABS", fact="FACT"}
diff --git a/macros/luatex/latex/luacas/tex/test/luacas-parser.lua b/macros/luatex/latex/luacas/tex/test/luacas-parser.lua
index 3380549620..47f0640c3f 100644
--- a/macros/luatex/latex/luacas/tex/test/luacas-parser.lua
+++ b/macros/luatex/latex/luacas/tex/test/luacas-parser.lua
@@ -1,8 +1,10 @@
-- Rudimentary parser for making the CAS easier to use. Essentially just wraps SymbolExpression() around symbols and Integer() around integers.
-
-require("calculus.luacas-calculus_init")
+local luacas = require("luacas_init")
+luacas:initglobalmodule("core")
+luacas:initglobalmodule("algebra")
+luacas:initglobalmodule("calculus")
-- Splits a string on a seperator.
function split(str, sep)
@@ -284,8 +286,16 @@ end
--- @param input string
function CASparse(input)
- -- First, we replace any occurance of a number with an integer or rational version of itself.
- local str = string.gsub(input, ".?[0-9]+", function (s)
+ -- First, we replace any occurrence of a decimal with the appropriate fraction.
+
+ local str = string.gsub(input,"%d+%.%d+", function(s)
+ local ints = split(s,"%.")
+ return "("..ints[1]..ints[2].." / 10^" .. tostring(string.len(ints[2])) .. ")"
+ end)
+
+ -- Next, we replace any occurance of a number with an integer or rational version of itself.
+
+ str = string.gsub(str, ".?[0-9]+", function (s)
-- Here, we are part of an identifier, so we don't replace anything
if string.match(string.sub(s, 1, 1), "[A-Z]") or string.match(string.sub(s, 1, 1), "[a-z]") or string.match(string.sub(s, 1, 1), "_") then
return
@@ -301,11 +311,11 @@ function CASparse(input)
--------------------------
-- HERE COMES THE JANK. --
--------------------------
-
+ -- The JANK may not actually be doing anything now. But for the sake of posterity...
-- Replaces each instance of a decimal with .., so we can use integer metatables to convert it into a rational properly.
str = string.gsub(str, "Integer%('[0-9]+'%)%.Integer%('[0-9]+'%)", function (s)
local ints = split(s, "%.")
- return ints[1] .. ".." .. ints[2]
+ return "("..ints[1] .. ".." .. ints[2] .. ")"
end)
str = string.gsub(str, ".?%.Integer%('[0-9]+'%)", function (s)
if string.sub(s, 1, 2) == ".." then
@@ -320,4 +330,4 @@ function CASparse(input)
else
print(err)
end
-end \ No newline at end of file
+end
diff --git a/macros/luatex/latex/luacas/tex/test/rings/luacas-conversion.lua b/macros/luatex/latex/luacas/tex/test/rings/luacas-conversion.lua
index b9eb523c7a..6a53dacd17 100644
--- a/macros/luatex/latex/luacas/tex/test/rings/luacas-conversion.lua
+++ b/macros/luatex/latex/luacas/tex/test/rings/luacas-conversion.lua
@@ -120,9 +120,9 @@ testringconvert(a, fring, "12/1x^0", "QQ[x]")
testringconvert(a, gring, "((12x^0)y^0)z^0", "ZZ[x][y][z]")
testringconvert(a, hring, "((12/1z^0)y^0)x^0", "QQ[z][y][x]")
testringconvert(a, iring, "(12x^0)/(1x^0)", "ZZ(x)")
-testringconvert(a, jring, "(12x^0)/(1x^0)", "ZZ(x)")
+testringconvert(a, jring, "(12/1x^0)/(1/1x^0)", "QQ(x)")
testringconvert(a, kring, "2x^0", "Z/Z5[x]")
-testringconvert(a, lring, "((12x^0)/(1x^0))y^0", "ZZ(x)[y]")
+testringconvert(a, lring, "((12/1x^0)/(1/1x^0))y^0", "QQ(x)[y]")
-- testringconvert(b, aring, "3/2", "ZZ")
testringconvert(b, bring, "3/2", "QQ")
@@ -133,9 +133,9 @@ testringconvert(b, fring, "3/2x^0", "QQ[x]")
-- testringconvert(b, gring, "3/2", "ZZ[x][y][z]")
testringconvert(b, hring, "((3/2z^0)y^0)x^0", "QQ[z][y][x]")
-- testringconvert(b, iring, "3/2", "ZZ(x)")
-testringconvert(b, jring, "(3/2x^0)/(1x^0)", "QQ(x)")
+testringconvert(b, jring, "(3/2x^0)/(1/1x^0)", "QQ(x)")
-- testringconvert(b, kring, "3/2", "Z/Z5[x]")
-testringconvert(b, lring, "((3/2x^0)/(1x^0))y^0", "QQ(x)[y]")
+testringconvert(b, lring, "((3/2x^0)/(1/1x^0))y^0", "QQ(x)[y]")
testringconvert(c, aring, "4", "ZZ")
-- testringconvert(c, bring, "4", "QQ")
@@ -172,9 +172,9 @@ testringconvert(e, fring, "3/1x^2+0/1x^1+6/1x^0", "QQ[x]")
testringconvert(e, gring, "((3x^2+0x^1+6x^0)y^0)z^0", "ZZ[x][y][z]")
testringconvert(e, hring, "((3/1z^0)y^0)x^2+((0/1z^0)y^0)x^1+((6/1z^0)y^0)x^0", "QQ[z][y][x]")
testringconvert(e, iring, "(3x^2+0x^1+6x^0)/(1x^0)", "ZZ(x)")
-testringconvert(e, jring, "(3x^2+0x^1+6x^0)/(1x^0)", "ZZ(x)")
+testringconvert(e, jring, "(3/1x^2+0/1x^1+6/1x^0)/(1/1x^0)", "QQ(x)")
testringconvert(e, kring, "3x^2+0x^1+1x^0", "Z/Z5[x]")
-testringconvert(e, lring, "((3x^2+0x^1+6x^0)/(1x^0))y^0", "ZZ(x)[y]")
+testringconvert(e, lring, "((3/1x^2+0/1x^1+6/1x^0)/(1/1x^0))y^0", "QQ(x)[y]")
-- testringconvert(f, aring, "12x^1+4/5x^0", "ZZ")
-- testringconvert(f, bring, "12x^1+4/5x^0", "QQ")
@@ -185,9 +185,9 @@ testringconvert(f, fring, "12x^1+4/5x^0", "QQ[x]")
-- testringconvert(f, gring, "12x^1+4/5x^0", "ZZ[x][y][z]")
testringconvert(f, hring, "((12/1z^0)y^0)x^1+((4/5z^0)y^0)x^0", "QQ[z][y][x]")
-- testringconvert(f, iring, "12x^1+4/5x^0", "ZZ(x)")
-testringconvert(f, jring, "(12x^1+4/5x^0)/(1x^0)", "QQ(x)")
+testringconvert(f, jring, "(12x^1+4/5x^0)/(1/1x^0)", "QQ(x)")
-- testringconvert(f, kring, "12x^1+4/5x^0", "Z/Z5[x]")
-testringconvert(f, lring, "((12x^1+4/5x^0)/(1x^0))y^0", "QQ(x)[y]")
+testringconvert(f, lring, "((12x^1+4/5x^0)/(1/1x^0))y^0", "QQ(x)[y]")
-- testringconvert(g, aring, "", "ZZ")
-- testringconvert(g, bring, "", "QQ")
@@ -224,9 +224,9 @@ testringconvert(h, hring, "((1z^0)y^0)x^3+((1z^0)y^3+(1/9z^1+-16z^0)y^2+(1z^2+8z
-- testringconvert(i, gring, "", "ZZ[x][y][z]")
-- testringconvert(i, hring, "", "QQ[z][y][x]")
testringconvert(i, iring, "(1x^1+-2x^0)/(1x^2+3x^1+3x^0)", "ZZ(x)")
-testringconvert(i, jring, "(1x^1+-2x^0)/(1x^2+3x^1+3x^0)", "ZZ(x)")
+testringconvert(i, jring, "(1/1x^1+-2/1x^0)/(1/1x^2+3/1x^1+3/1x^0)", "QQ(x)")
-- testringconvert(i, kring, "", "Z/Z5[x]")
-testringconvert(i, lring, "((1x^1+-2x^0)/(1x^2+3x^1+3x^0))y^0", "ZZ(x)[y]")
+testringconvert(i, lring, "((1/1x^1+-2/1x^0)/(1/1x^2+3/1x^1+3/1x^0))y^0", "QQ(x)[y]")
-- testringconvert(j, aring, "", "ZZ")
-- testringconvert(j, bring, "", "QQ")