summaryrefslogtreecommitdiff
path: root/macros/luatex/latex/luacas/tex/core/binaryoperation/product.lua
diff options
context:
space:
mode:
Diffstat (limited to 'macros/luatex/latex/luacas/tex/core/binaryoperation/product.lua')
-rw-r--r--macros/luatex/latex/luacas/tex/core/binaryoperation/product.lua231
1 files changed, 231 insertions, 0 deletions
diff --git a/macros/luatex/latex/luacas/tex/core/binaryoperation/product.lua b/macros/luatex/latex/luacas/tex/core/binaryoperation/product.lua
new file mode 100644
index 0000000000..b104cb5e8a
--- /dev/null
+++ b/macros/luatex/latex/luacas/tex/core/binaryoperation/product.lua
@@ -0,0 +1,231 @@
+-- Seperates the various binary operations into their own files for readability
+
+--- Automatic simplification of multiplication expressions.
+--- @return BinaryOperation
+function BinaryOperation:simplifyproduct()
+ if not self.expressions[1] then
+ error("Execution error: attempted to simplify empty product")
+ end
+
+ if not self.expressions[2] then
+ return self.expressions[1]
+ end
+
+ -- Uses the property that x*0=0
+ for _, expression in ipairs(self.expressions) do
+ if expression:isconstant() and expression == expression:zero() then
+ return expression:zero()
+ end
+ end
+
+ local result = self:simplifyproductrec()
+
+ -- We don't really know what ring we are working in here, so just assume the integer ring
+ if not result.expressions[1] then
+ return Integer.one()
+ end
+
+ if not result.expressions[2] then
+ return result.expressions[1]
+ end
+
+ return result
+end
+
+function BinaryOperation:simplifyproductrec()
+ local term1 = self.expressions[1]
+ local term2 = self.expressions[2]
+
+ if not self.expressions[3] then
+ if (term1:isconstant() or not (term1.operation == BinaryOperation.MUL)) and
+ (term2:isconstant() or not (term2.operation == BinaryOperation.MUL)) then
+
+ if term1:isconstant() and term2:isconstant() then
+ local result = self:evaluate()
+ if result == result:one() then
+ return BinaryOperation(BinaryOperation.MUL, {})
+ end
+ return BinaryOperation(BinaryOperation.MUL, {result})
+ end
+
+ -- Uses the property that x*1 = x
+ if term1:isconstant() and term1 == term1:one() then
+ return BinaryOperation(BinaryOperation.MUL, {term2})
+ end
+
+ if term2:isconstant() and term2 == term2:one() then
+ return BinaryOperation(BinaryOperation.MUL, {term1})
+ end
+
+ -- Distributes constants if the other term is a sum expression.
+ if term1:isconstant() and term2.operation == BinaryOperation.ADD then
+ local distributed = BinaryOperation(BinaryOperation.ADD, {})
+ for i, exp in ipairs(term2:subexpressions()) do
+ distributed.expressions[i] = term1 * exp
+ end
+ return BinaryOperation(BinaryOperation.MUL, {distributed:autosimplify()})
+ end
+
+ if term2:isconstant() and term1.operation == BinaryOperation.ADD then
+ local distributed = BinaryOperation(BinaryOperation.ADD, {})
+ for i, exp in ipairs(term1:subexpressions()) do
+ distributed.expressions[i] = term2 * exp
+ end
+ return BinaryOperation(BinaryOperation.MUL, {distributed:autosimplify()})
+ end
+
+ -- Uses the property that sqrt(a,r)*sqrt(b,r) = sqrt(a*b,r) if a,r are positive integers
+ if term1:type() == SqrtExpression and term2:type() == SqrtExpression and term1.expression:isconstant() and term2.expression:isconstant() and term1.root:type() == Integer then
+ if term1.root == term2.root and term1.expression > Integer.zero() then
+ local expression = term1.expression*term2.expression
+ local result = SqrtExpression(expression,term1.root):autosimplify()
+ if result == Integer.one() then
+ return BinaryOperation(BinaryOperation.MUL,{})
+ else
+ return BinaryOperation(BinaryOperation.MUL,{result})
+ end
+ end
+ end
+
+ --if term1.operation == BinaryOperation.POW and term2.operation == BinaryOperation.POW and term1.expressions[1]:type() == SqrtExpression and term2.expressions[1]:type() == SqrtExpression and term1.expressions[2]:type() == Integer and term2.expressions[2]:type() == Integer and term1.expressions[2] < Integer.zero() and term2.expressions[2] < Integer.zero() and term1.expressions[1].root == term2.expressions[1].root then
+ -- local expo1 = term1.expressions[2]:neg()
+ -- local expo2 = term2.expressions[2]:neg()
+ -- local root = term1.expressions[1].root
+ -- local expr1 = term1.expressions[1].expression
+ -- local expr2 = term2.expressions[1].expression
+ -- local result1 = BinaryOperation(BinaryOperation.POW,{SqrtExpression(expr1,root),expo1}):simplifypower()
+ -- local result2 = BinaryOperation(BinaryOperation.POW,{SqrtExpression(expr2,root),expo2}):simplifypower()
+ -- local result = BinaryOperation(BinaryOperation.MUL,{result1,result2}):autosimplify()
+ -- if result == Integer.one() then
+ -- return BinaryOperation(BinaryOperation.MUL,{})
+ -- end
+ -- if result:type() == Integer then
+ -- return BinaryOperation(BinaryOperation.MUL,{Rational(Integer.one(),result)})
+ -- end
+ -- return BinaryOperation(BinaryOperation.MUL,{BinaryOperation(BinaryOperation.POW, {result,Integer(-1)})}):autosimplify()
+ --end
+
+ -- Uses the property that x^a*x^b=x^(a+b)
+ local revertterm1 = false
+ local revertterm2 = false
+ if term1.operation ~= BinaryOperation.POW then
+ term1 = BinaryOperation(BinaryOperation.POW, {term1, Integer.one()})
+ revertterm1 = true
+ end
+ if term2.operation ~= BinaryOperation.POW then
+ term2 = BinaryOperation(BinaryOperation.POW, {term2, Integer.one()})
+ revertterm2 = true
+ end
+ if term1.expressions[1] == term2.expressions[1]
+ --and not
+ -- (term1.expressions[1]:type() == Integer and
+ -- term1.expressions[2]:type() ~= term2.--expressions[2]:type())
+ then
+ local result = BinaryOperation(BinaryOperation.POW,
+ {term1.expressions[1],
+ BinaryOperation(BinaryOperation.ADD,
+ {term1.expressions[2], term2.expressions[2]}):autosimplify()}):autosimplify()
+ if result:isconstant() and result == result:one() then
+ return BinaryOperation(BinaryOperation.MUL, {})
+ end
+ return BinaryOperation(BinaryOperation.MUL, {result})
+ end
+
+ if revertterm1 then
+ term1 = term1.expressions[1]
+ end
+ if revertterm2 then
+ term2 = term2.expressions[1]
+ end
+
+ if term2:order(term1) then
+ return BinaryOperation(BinaryOperation.MUL, {term2, term1})
+ end
+
+ return self
+ end
+
+ if term1.operation == BinaryOperation.MUL and not (term2.operation == BinaryOperation.MUL) then
+ return term1:mergeproducts(BinaryOperation(BinaryOperation.MUL, {term2}))
+ end
+
+ if not (term1.operation == BinaryOperation.MUL) and term2.operation == BinaryOperation.MUL then
+ return BinaryOperation(BinaryOperation.MUL, {term1}):mergeproducts(term2)
+ end
+
+ return term1:mergeproducts(term2)
+ end
+
+ local rest = {}
+ for index, expression in ipairs(self.expressions) do
+ if index > 1 then
+ rest[index - 1] = expression
+ end
+ end
+
+ local result = BinaryOperation(BinaryOperation.MUL, rest):simplifyproductrec()
+
+ if term1.operation ~= BinaryOperation.MUL then
+ term1 = BinaryOperation(BinaryOperation.MUL, {term1})
+ end
+ if result.operation ~= BinaryOperation.MUL then
+ result = BinaryOperation(BinaryOperation.MUL, {result})
+ end
+ return term1:mergeproducts(result)
+end
+
+-- Merges two lists of products
+function BinaryOperation:mergeproducts(other)
+ if not self.expressions[1] then
+ return other
+ end
+
+ if not other.expressions[1] then
+ return self
+ end
+
+ local first = BinaryOperation(BinaryOperation.MUL, {self.expressions[1], other.expressions[1]}):simplifyproductrec()
+
+ local selfrest = {}
+ for index, expression in ipairs(self.expressions) do
+ if index > 1 then
+ selfrest[index - 1] = expression
+ end
+ end
+
+ local otherrest = {}
+ for index, expression in ipairs(other.expressions) do
+ if index > 1 then
+ otherrest[index - 1] = expression
+ end
+ end
+
+ if first.operation ~= BinaryOperation.MUL or not first.expressions[2] then
+ local result = BinaryOperation(self.operation, selfrest):mergeproducts(BinaryOperation(other.operation, otherrest))
+ if not first.expressions[1] then
+ return result
+ end
+ table.insert(result.expressions, 1, first.expressions[1])
+
+ if result.operation == BinaryOperation.MUL and not result.expressions[3] and result.expressions[1] and result.expressions[2] then
+ if result.expressions[1]:isconstant() and result.expressions[2]:isconstant() then
+ return result:simplifyproductrec()
+ end
+ end
+ return result
+ end
+
+ local result
+ if first.expressions[1] == self.expressions[1] then
+ result = BinaryOperation(self.operation, selfrest):mergeproducts(other)
+ else
+ result = self:mergeproducts(BinaryOperation(other.operation, otherrest))
+ end
+ table.insert(result.expressions, 1, first.expressions[1])
+ if result.operation == BinaryOperation.MUL and not result.expressions[3] and result.expressions[1] and result.expressions[2] then
+ if result.expressions[1]:isconstant() and result.expressions[2]:isconstant() then
+ return result:simplifyproductrec()
+ end
+ end
+ return result
+end \ No newline at end of file