diff options
author | Norbert Preining <norbert@preining.info> | 2022-11-06 03:01:22 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2022-11-06 03:01:22 +0000 |
commit | 0a7c9b85de9aeaffafa0cf8944fa81ffe9652d09 (patch) | |
tree | a8a932b3f786cf3601808c4e352b3b6b07731742 /macros/luatex/latex/luacas/tex/core/binaryoperation/product.lua | |
parent | 5a47812f51f3d10a580db0c74aa20d73f5ed2ae4 (diff) |
CTAN sync 202211060301
Diffstat (limited to 'macros/luatex/latex/luacas/tex/core/binaryoperation/product.lua')
-rw-r--r-- | macros/luatex/latex/luacas/tex/core/binaryoperation/product.lua | 231 |
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 |