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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
-- Seperates the various binary operations into their own files for readability
--- Automatic simplification of power expressions.
--- @return BinaryOperation
function BinaryOperation:simplifypower()
local base = self.expressions[1]
local exponent = self.expressions[2]
if base:isconstant() and exponent:isconstant() and exponent:getring() ~= Rational:getring() then
return self:evaluate()
end
-- Simplifies i^x for x integer.
if base == I and exponent:isconstant() and exponent:getring() == Integer:getring() then
if exponent % Integer(4) == Integer(0) then
return Integer(1)
end
if exponent % Integer(4) == Integer(1) then
return I
end
if exponent % Integer(4) == Integer(2) then
return Integer(-1)
end
if exponent % Integer(4) == Integer(3) then
return -I
end
end
-- Simplifies complex numbers raised to negative integer powers
if not base:isrealconstant() and base:iscomplexconstant() and exponent:isconstant() and exponent:getring() == Integer:getring() and exponent < Integer.zero() then
local a
local b
if base.operation == BinaryOperation.MUL then
a = Integer.zero()
b = base.expressions[1]
elseif base.operation == BinaryOperation.ADD and base.expressions[2] == I then
a = base.expressions[1]
b = Integer.one()
else
a = base.expressions[1]
b = base.expressions[2].expressions[1]
end
return (((a-b*I)/(a^Integer(2)+b^Integer(2)))^(-exponent)):expand():autosimplify()
end
-- Uses the property that 0^x = 0 if x does not equal 0
if base:isconstant() and base == base:zero() then
return Integer.zero()
end
-- Uses the property that 1^x = 1
if base:isconstant() and base == base:one() then
return base:one()
end
-- Uses the property that x^0 = 1
if exponent:isconstant() and exponent == exponent:zero() then
return exponent:one()
end
-- Uses the property that x^1 = x
if exponent:isconstant() and exponent == exponent:one() then
return base
end
-- Uses the property that b ^ (log(b, x)) == x
if exponent:type() == Logarithm and exponent.base == base then
return exponent.expression
end
-- Uses the property that b ^ (a * log(b, x)) == x ^ a
if exponent.operation == BinaryOperation.MUL then
local x
local rest = Integer.one()
for _, expression in ipairs(exponent.expressions) do
if expression:type() == Logarithm and expression.base == base and not log then
x = expression.expression
else
rest = rest * expression
end
end
if x then
return (x ^ rest):autosimplify()
end
end
-- Uses the property that (x^a)^b = x^(a*b)
if not base:isatomic() and base.operation == BinaryOperation.POW and exponent:isconstant() then
base, exponent = base.expressions[1], BinaryOperation(BinaryOperation.MUL, {exponent, base.expressions[2]}):autosimplify()
return BinaryOperation(BinaryOperation.POW, {base, exponent}):autosimplify()
end
-- Uses the property that (x_1*x_2*...*x_n)^a = x_1^a*x_2^a*..x_n^a if a is an integer
if base.operation == BinaryOperation.MUL and exponent:type() == Integer then
local results = {}
for index, expression in ipairs(base.expressions) do
results[index] = BinaryOperation(BinaryOperation.POW, {expression, exponent}):autosimplify()
end
return BinaryOperation(BinaryOperation.MUL, results):autosimplify()
end
-- Uses the property that sqrt(x,r)^d == sqrt(x,r/d)
if base:type() == SqrtExpression and exponent:type() == Integer and exponent > Integer.zero() then
local root = base.root
local expr = base.expression
local comm = Integer.gcd(root,exponent)
root = root / comm
local expo = exponent / comm
expr = expr ^ expo
return SqrtExpression(expr,root):autosimplify()
end
-- Rationalizing SqrtExpressions
if base:type() == SqrtExpression and exponent:type() == Integer and base.expression:type() == Integer and exponent < Integer.zero() then
local root = base.root
local expr = base.expression
local result = (SqrtExpression(expr ^ (root - Integer.one()),root) / expr) ^ exponent:neg()
return result:autosimplify()
end
if base:isconstant() and exponent:isconstant() and exponent:getring() == Rational.getring() then
return self --:simplifyrationalpower()
end
-- Our expression cannot be simplified
return self
end
-- Automatic simplification of rational power expressions
function BinaryOperation:simplifyrationalpower()
local base = self.expressions[1]
local exponent = self.expressions[2]
if base:getring() == Rational.getring() then
return (BinaryOperation(BinaryOperation.POW, {base.numerator, exponent}):simplifyrationalpower()) /
(BinaryOperation(BinaryOperation.POW, {base.denominator, exponent}):simplifyrationalpower())
end
if base == Integer(-1) then
if exponent == Integer(1) / Integer(2) then
return I
end
return self
end
local primes = base:primefactorization()
if primes.expressions[1] and not primes.expressions[2] then
local primeexponent = primes.expressions[1].expressions[2]
local primebase = primes.expressions[1].expressions[1]
local newexponent = primeexponent * exponent
local integerpart
if newexponent.getring() == Rational.getring() then
integerpart = newexponent.numerator // newexponent.denominator
else
integerpart = newexponent
end
if integerpart == Integer.zero() then
return BinaryOperation(BinaryOperation.POW, {primebase, newexponent})
end
return BinaryOperation(BinaryOperation.MUL,
{BinaryOperation(BinaryOperation.POW, {primebase, integerpart}),
BinaryOperation(BinaryOperation.POW, {primebase, newexponent - integerpart})}):autosimplify()
end
return BinaryOperation(BinaryOperation.POW, {primes:autosimplify(), exponent})
end
|