summaryrefslogtreecommitdiff
path: root/macros/luatex/latex/luacas/tex/algebra/sqrtexpression.lua
diff options
context:
space:
mode:
Diffstat (limited to 'macros/luatex/latex/luacas/tex/algebra/sqrtexpression.lua')
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/sqrtexpression.lua196
1 files changed, 196 insertions, 0 deletions
diff --git a/macros/luatex/latex/luacas/tex/algebra/sqrtexpression.lua b/macros/luatex/latex/luacas/tex/algebra/sqrtexpression.lua
new file mode 100644
index 0000000000..bc96f4e1d8
--- /dev/null
+++ b/macros/luatex/latex/luacas/tex/algebra/sqrtexpression.lua
@@ -0,0 +1,196 @@
+--- @class SqrtExpression
+--- 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 = {}
+
+----------------------------
+-- Instance functionality --
+----------------------------
+
+--- Creates a new sqrt expression with the given expression.
+--- @param expression Expression
+--- @param root Integer
+--- @return SqrtExpression
+function SqrtExpression:new(expression, root)
+ root = root or Integer(2)
+ local o = {}
+ local __o = Copy(__ExpressionOperations)
+
+ o.expression = Copy(expression)
+ o.root = root
+
+ __o.__index = SqrtExpression
+ __o.__tostring = function(a)
+ return tostring(a.expression) .. ' ^ (1/' .. tostring(a.root) .. ')'
+ end
+ __o.__eq = function(a, b)
+ -- This shouldn't be needed, since __eq should only fire if both metamethods have the same function, but for some reason Lua always rungs this anyway
+ if not b:type() == SqrtExpression then
+ return false
+ end
+ return a.expression == b.expression and a.root == b.root
+ end
+ o = setmetatable(o, __o)
+
+ return o
+end
+
+
+--- @return table<number, Expression>
+function SqrtExpression:subexpressions()
+ return {self.expression}
+end
+
+--- @param subexpressions table<number, Expression>
+--- @return SqrtExpression
+function SqrtExpression:setsubexpressions(subexpressions)
+ return SqrtExpression(subexpressions[1], self.root)
+end
+
+--- @param other Expression
+--- @return boolean
+function SqrtExpression:order(other)
+ return self:topower():order(other)
+end
+
+function SqrtExpression:topower()
+ local exponent = BinaryOperation(BinaryOperation.DIV,{Integer.one(),self.root}):autosimplify()
+ local base = self.expression
+ return BinaryOperation(BinaryOperation.POW,{base,exponent}):autosimplify()
+end
+
+function SqrtExpression:autosimplify()
+ local expression = self.expression:autosimplify()
+ local root = self.root:autosimplify()
+
+ if root == Integer.one() then
+ return expression
+ end
+
+ if root:type() == Rational then
+ return SqrtExpression(BinaryOperation(BinaryOperation.POW,{expression,root.denominator}):autosimplify(), root.numerator):autosimplify()
+ end
+
+ if not root:isconstant() then
+ return BinaryOperation(BinaryOperation.POW,{expression,Integer.one() / root}):autosimplify()
+ end
+
+ if not expression:isconstant() then
+ if expression.operation == BinaryOperation.MUL and expression.expressions[1]:isconstant() then
+ local coeff = SqrtExpression(expression.expressions[1],root):autosimplify()
+ expression.expressions[1] = BinaryOperation(BinaryOperation.MUL,{Integer.one()})
+ expression = expression:autosimplify()
+ local sqrtpart = SqrtExpression(expression,root):autosimplify()
+ local result = coeff*sqrtpart
+ return result:autosimplify()
+ end
+ return BinaryOperation(BinaryOperation.POW,{expression,Integer.one() / root}):autosimplify()
+ end
+
+ if expression:type() == Rational then
+ local result = BinaryOperation(BinaryOperation.MUL, {SqrtExpression(expression.numerator,root):autosimplify(),BinaryOperation(BinaryOperation.POW,{SqrtExpression(expression.denominator,root):autosimplify(),Integer(-1)})})
+ return result:autosimplify()
+ end
+
+ if expression:type() == Integer then
+ if expression == Integer.zero() then
+ return Integer.zero()
+ end
+ if expression == Integer.one() then
+ return Integer.one()
+ end
+ if expression < Integer.zero() then
+ if root == Integer(2) then
+ local result = SqrtExpression(expression:neg(),root):autosimplify()
+ result = I*result
+ return result:autosimplify()
+ end
+ if root % Integer(2) == Integer.one() then
+ local result = SqrtExpression(expression:neg(),root):autosimplify()
+ result = -result
+ return result:autosimplify()
+ end
+ end
+ local primes = expression:primefactorization()
+ local coeffresult = {}
+ local exprresult = {}
+ local reduction = root
+ for _, term in ipairs(primes.expressions) do
+ local primepower = term.expressions[2]
+ reduction = Integer.gcd(primepower,reduction)
+ if reduction == Integer.one() then
+ goto skip
+ end
+ end
+ ::skip::
+ local newroot = root / reduction
+ for index, term in ipairs(primes.expressions) do
+ local prime = term.expressions[1]
+ local primepower = term.expressions[2] / reduction
+ local coeffpower = primepower // newroot
+ coeffresult[index] = prime ^ coeffpower
+ local exprpower = primepower - coeffpower*newroot
+ exprresult[index] = prime ^ exprpower
+ end
+ local newexpression = BinaryOperation(BinaryOperation.MUL,exprresult):autosimplify()
+ local coeff = BinaryOperation(BinaryOperation.MUL,coeffresult):autosimplify()
+ if coeff == Integer.one() then
+ if reduction == Integer.one() then
+ goto stop
+ end
+ return SqrtExpression(newexpression,newroot)
+ end
+ if newroot == Integer.one() then
+ return coeff
+ end
+ return BinaryOperation(BinaryOperation.MUL,{coeff,SqrtExpression(newexpression,newroot)}):autosimplify()
+ end
+ ::stop::
+
+ if expression.operation == BinaryOperation.POW and expression.expressions[2]:type() == Integer then
+ local exponent = expression.expressions[2]
+ local power = exponent // root
+ local newexponent = (exponent / root) - power
+ local coeff = expression.expressions[1] ^ power
+ coeff = coeff:evaluate()
+ if newexponent == Integer.zero() then
+ return coeff
+ else
+ local num = newexponent.numerator
+ local den = newexponent.denominator
+ local newexpression = expression ^ num
+ newexpression = newexpression:autosimplify()
+ local result = coeff * SqrtExpression(newexpression,den)
+ return result
+ end
+ end
+
+ return SqrtExpression(expression,root)
+end
+
+function SqrtExpression:tolatex()
+ local printout = '\\sqrt'
+ if self.root == Integer(2) then
+ printout = printout .. '{' .. self.expression:tolatex() .. '}'
+ else
+ printout = printout .. '[' .. self.root:tolatex() .. ']' .. '{' .. self.expression:tolatex() .. '}'
+ end
+ return printout
+end
+
+
+-----------------
+-- Inheritance --
+-----------------
+__SqrtExpression.__index = CompoundExpression
+__SqrtExpression.__call = SqrtExpression.new
+SqrtExpression = setmetatable(SqrtExpression, __SqrtExpression)
+
+----------------------
+-- Static constants --
+----------------------
+
+sqrt = function(expression, root)
+ return SqrtExpression(expression, root)
+end \ No newline at end of file