chakravala / Reduce.jl
1
#   This file is part of Reduce.jl. It is licensed under the MIT license
2
#   Copyright (C) 2017 Michael Reed
3

4
const calculus = [
5
    :df,
6
    :int,
7
    :limit,
8
    :logb,
9
    :solve,
10
    :pf,
11
    :structr,
12
    :coeff,
13
    :coeffn,
14
    :part,
15
    :factorize,
16
    :remainder,
17
    :resultant,
18
    :interpol,
19
    :deg,
20
    :lcof,
21
    :lpower,
22
    :lterm,
23
    :reduct,
24
    :totaldeg,
25
    :pochhammer,
26
    :fibonaccip,
27
    :remfac,
28
    :gcd,
29
    :lcm,
30
    :compact,
31
    :changevar,
32
    :odesolve,
33
]
34

35
const cnan = [
36
    :clear,
37
    :matrix,
38
    :operator,
39
    :listargp,
40
    :infix,
41
    :precedence,
42
    :depend,
43
    :nodepend,
44
    :realvalued,
45
    :notrealvalued,
46
    :set,
47
    :unset,
48
    :mkid,
49
    :even,
50
    :odd,
51
    :linear,
52
    :noncom,
53
    :symmetric,
54
    :antisymmetric,
55
    :order,
56
    :korder,
57
    :on,
58
    :off,
59
    :define,
60
    :select,
61
    :nospur,
62
    :spur,
63
    :vector,
64
    :index,
65
    :reminx,
66
    :g,
67
    :mass,
68
    :mshell,
69
]
70

71
const alg = [
72
    :sum,
73
    :prod,
74
    :max,
75
    :min,
76
    :map,
77
    :eps,
78
]
79

80
const iops = [
81
    :+,
82
    :-,
83
    :*,
84
    :/,
85
    :^,
86
    ://
87
]
88

89
const cmat = [
90
    #:mateigen,
91
    #:cofactor
92
]
93

94 0
Expr(:block,[:(@inline $i(r...)=Base.$i(r...)) for i  [alg;iops[6:end]]]...) |> eval
95
#Expr(:toplevel,[:(import Base: $i) for i ∈ [alg;iops]]...) |> eval
96
:(export $([calculus;cnan;alg;iops;cmat]...)) |> eval
97
#:(export $(Symbol.("@",[calculus;alg;iops])...)) |> eval
98

99 20
for fun in [calculus;alg;iops]
100 24
    @eval begin
101
        $(Reduce.parsegen(fun,:args))
102
        $(Reduce.unfoldgen(fun,:args))
103
        #=macro $fun(expr,s...)
104
            :($$(QuoteNode(fun))($(esc(expr)),$(esc(s))...))
105
        end=#
106
    end
107
end
108

109
for fun in [calculus;alg]
110
    @eval begin
111 4
        function $fun(expr::String,s...;be=0)
112 28
            convert(String, $fun(RExpr(expr),s...;be=be))
113
        end
114
    end
115
end
116

117
for fun in cnan
118
    @eval begin
119 28
        $fun(r::RExpr...) = string($(string(fun)),"(",join(string.(r),","),")") |> rcall |> RExpr
120 28
        $fun(r...) = $fun(RExpr.(r)...) |> parse
121
    end
122
end
123

124
for fun in cmat
125
    @eval begin
126
        $(Reduce.parsegen(fun,:args))
127 0
        function $fun(expr::Union{Array{Any,2},Expr,Symbol},s...)
128 0
            $fun(RExpr(expr),RExpr.(s)...)
129
        end
130 0
        function $fun(expr::Union{Array{T,2},Expr,Symbol},s...) where T <: ExprSymbol
131 0
            $fun(RExpr(expr),RExpr.(s)...)
132
        end
133
    end
134
end
135

136
for fun in iops
137
    @eval begin
138 4
        function $fun(a::Union{<:Number,Expr,Symbol},r::RExpr,s...)
139 28
            $fun(RExpr(a),r,RExpr.(s)...) |> parse
140
        end
141 4
        function $fun(a::T,b::ExprSymbol,s...) where T <: Number
142 28
            $fun(RExpr(a),RExpr(b),RExpr.(s)...) |> parse
143
        end
144 0
        function $fun(a::A,b::B,c::ExprSymbol,s...) where {A<:Number,B<:Number}
145 0
            $fun(RExpr(a),RExpr(b),RExpr(c),RExpr.(s)...) |> parse
146
        end
147
    end
148
end
149

150
const MatExpr = Union{Array{Any,2},Array{Expr,2},Array{Symbol,2},Expr,Symbol,<:Number}
151
const Mat = Union{Vector,Adjoint,Array{Any,2},Array{Expr,2},Array{Symbol,2}}
152
const MatOnly = Union{Array{Any,2},Array{Expr,2},Array{Symbol,2}}
153
const ESN = Union{Expr,Symbol,<:Number}
154

155 0
^(expr::Array{Any,2},s::Integer) = ^(RExpr(expr),s) |> parse |> mat
156 28
^(expr::Array{T,2},s::Integer) where T <: ExprSymbol = ^(RExpr(expr),s) |> parse |> mat
157 28
^(expr::RExpr,s::Integer) = ^(expr,RExpr(s))
158 0
^(a::T,s::ExprSymbol) where T <: Number = ^(RExpr(a),RExpr(s)) |> parse
159

160 0
*(a::T,s::S) where T <: MatOnly where S <: ESN = *(RExpr(a),RExpr(s)) |> parse |> mat
161 0
*(a::T,s::S) where T <: ESN where S <: MatOnly = *(RExpr(a),RExpr(s)) |> parse |> mat
162 0
*(a::T,s::S) where T <: MatOnly where S <: MatOnly = *(RExpr(a),RExpr(s)) |> parse |> mat
163 0
*(a::T,s::S) where T <: Vector where S <: Adjoint = *(RExpr(a),RExpr(s)) |> parse |> mat
164 0
*(a::T,s::S) where T <: Vector where S <: MatExpr = *(RExpr(a),RExpr(s)) |> parse |> mat
165 0
*(a::T,s::S) where T <: Adjoint where S <: Vector = *(RExpr(a),RExpr(s)) |> parse |> mat
166 0
*(a::T,s::S) where T <: Adjoint where S <: MatExpr = *(RExpr(a),RExpr(s)) |> parse |> mat
167 0
*(a::T,s::S) where T <: MatExpr where S <: Vector = *(RExpr(a),RExpr(s)) |> parse |> mat
168 0
*(a::T,s::S) where T <: MatExpr where S <: Adjoint = *(RExpr(a),RExpr(s)) |> parse |> mat
169

170
for o in [:+,:-]
171
    @eval begin
172 4
        function $o(a::T,s::S) where T <: MatOnly where S <: ESN
173 28
            $o(RExpr(a),RExpr(s)*RExpr(ones(size(a)))) |> parse |> mat
174
        end
175 4
        function $o(a::T,s::S) where T <: ESN where S <: MatOnly
176 28
            $o(RExpr(a)*RExpr(ones(size(s))),RExpr(s)) |> parse |> mat
177
        end
178 0
        $o(a::T,s::S) where T <: MatOnly where S <: MatOnly = $o(RExpr(a),RExpr(s)) |> parse |> mat
179 0
        $o(a::T,s::S) where T <: Vector where S <: Adjoint = $o(RExpr(a),RExpr(s)) |> parse |> mat
180 0
        $o(a::T,s::S) where T <: Vector where S <: MatOnly = $o(RExpr(a),RExpr(s)) |> parse |> mat
181 4
        function $o(a::T,s::ESN) where T <: Vector
182 28
            $o(RExpr(a),RExpr(s)*RExpr(ones(size(a)))) |> parse |> mat
183
        end
184 0
        $o(a::T,s::S) where T <: Adjoint where S <: Vector = $o(RExpr(a),RExpr(s)) |> parse |> mat
185 0
        $o(a::T,s::S) where T <: Adjoint where S <: MatOnly = $o(RExpr(a),RExpr(s)) |> parse |> mat
186 4
        function $o(a::T,s::ESN) where T <: Adjoint
187 28
            $o(RExpr(a),RExpr(s)*RExpr(ones(size(a)))) |> parse |> mat
188
        end
189 0
        $o(a::T,s::S) where T <: MatOnly where S <: Vector = $o(RExpr(a),RExpr(s)) |> parse |> mat
190 4
        function $o(a::ESN,s::S) where S <: Vector
191 28
            $o(RExpr(a)*RExpr(ones(size(s))),RExpr(s)) |> parse |> mat
192
        end
193 0
        $o(a::T,s::S) where T <: MatOnly where S <: Adjoint = $o(RExpr(a),RExpr(s)) |> parse |> mat
194 4
        function $o(a::ESN,s::S) where S <: Adjoint
195 28
            $o(RExpr(a)*RExpr(ones(size(s))),RExpr(s)) |> parse |> mat
196
        end
197
    end
198
end
199

200
for o in [:/,://]
201
    @eval begin
202 28
        $o(a::MatOnly,b::ESN) = $o(RExpr(a),RExpr(b)) |> parse |> mat
203
    end
204
end
205 28
//(expr,b::T) where T <: AbstractFloat = //(RExpr(expr),RExpr(b)) |> parse
206 28
//(a::T,expr) where T <: AbstractFloat = //(RExpr(a),RExpr(expr)) |> parse
207 0
//(expr::ExprSymbol,b::T) where T <: AbstractFloat = //(RExpr(expr),RExpr(b)) |> parse
208 0
//(a::T,expr::ExprSymbol) where T <: AbstractFloat = //(RExpr(a),RExpr(expr)) |> parse
209 4
function //(a::T,b::T) where T <: AbstractFloat
210 28
    isnan(a) | isnan(b) | (isinf(a) & isinf(b)) && return NaN
211 28
    return //(RExpr(a),RExpr(b)) |> parse |> eval
212
end
213

214
export inv, \
215

216 0
inv(r::RExpr) = AbstractTensors.:^(r,-1)
217 28
inv(r::T) where T <: MatExpr = AbstractTensors.:^(r,-1)
218

219 28
\(a,b) = Base.:\(a,b)
220 0
\(a::T,s::S) where T <: MatExpr where S <: Vector = (RExpr(a)^-1)*RExpr(s) |> parse |> mat
221 0
\(a::T,s::S) where T <: Vector where S <: MatExpr = (RExpr(a)^-1)*RExpr(s) |> parse |> mat
222

223 4
function solve(a::Array{T,1},s::Array{Symbol,1}) where T <: Any
224 28
    out = solve(list(a),list(s))
225 28
    return T <: String ? out.str : parse(out)
226
end
227 0
solve(a::T,s::Symbol) where T <: Vector = solve(a,[s])
228 28
solve(a::Expr,s::Array{Symbol,1}) = solve(a.head == :block ? a.args : [a],s)
229 28
solve(a::Expr,s::Symbol) = solve(a,[s])
230 28
solve(a::T,s::S) where T <: Tuple where S <: Tuple = solve(RExpr(a),RExpr(s)) |> parse
231 28
solve(a::T,s::Symbol) where T <: Tuple = solve(a,(s,))
232

233 0
odesolve(r...) = odesolve(RExpr.(r)...) |> parse
234

235 0
changevar(r...) = changevar(RExpr.(r)...) |> parse
236 0
map(a,b) = map(RExpr(a),RExpr(b)) |> parse
237 0
map(a::S,b::T) where S <: ExprSymbol where T <: MatOnly = map(RExpr(a),RExpr(b)) |> parse |> mat
238 0
select(a,b)  = select(RExpr(a),RExpr(b)) |> parse
239

240 28
order(::Nothing) = order(R"nil") |> parse
241 28
korder(::Nothing) = korder(R"nil") |> parse
242

243
export , , sub
244

245
const (, ) = (sum, prod)
246

247
@doc """
248
    sum(expr,k,lolim,uplim)
249

250
This implements the Gosper algorithm for the summation of series. The operator `sum` returns the indefinite or definite summation of a given expression, used with the syntax:
251
```
252
SUM(EXPR:expression, K:kernel, [LOLIM:expression [, UPLIM:expression]]) 
253
```
254
If there is no closed form solution, these operators return the input unchanged. `UPLIM` and `LOLIM` are optional parameters specifying the lower limit and upper limit of the summation. If `UPLIM` is not supplied, the upper limit is taken as `K` (the summation variable itself).
255

256
For example:
257
```Julia
258
Algebra.sum(:(n^3),:n)
259
Algebra.sum(:(a+k*r),:k,0,:(n-1))
260
Algebra.sum(:(1/((p+(k-1)*q)*(p+k*q))),:k,1,:(n+1))
261
```
262
""" Reduce.Algebra.sum
263

264
@doc """
265
    prod(expr,k,lolim,uplim)
266

267
The operator `prod` returns the product of the given expression, used with the syntax:
268
```
269
PROD(EXPR:expression, K:kernel, [LOLIM:expression [, UPLIM:expression]])
270
```
271
If there is no closed form solution, these operators return the input unchanged. `UPLIM` and `LOLIM` are optional parameters specifying the lower limit and upper limit of the product. If `UPLIM` is not supplied, the upper limit is taken as `K` (the product variable itself).
272

273
For example:
274
```Julia
275
Algebra.prod(:(k/(k-2)),:k)
276
```
277
""" Reduce.Algebra.prod
278

279
"""
280
    sub(::Union{Dict,Pair},expr)
281

282
Make variable substitutions using Reduce's native sub command. Syntax:
283
```
284
R"(⟨substitution_list⟩,⟨EXPRN1:algebraic⟩)"
285
```
286
where `⟨substitution_list⟩` is a list of one or more equations of the form
287
```
288
⟨VAR:kernel⟩ = ⟨EXPRN:algebraic⟩
289
```
290
or a kernel that evaluates to such a list.
291

292
The `sub` operator gives the algebraic result of replacing every occurrence of the variable `var` in the expression `EXPRN1` by the expression `EXPRN`. Specifically, `EXPRN1` is first evaluated using all available rules. Next the substitutions are made, and finally the substituted expression is reevaluated. When more than one variable occurs in the substitution list, the substitution is performed by recursively walking down the tree representing `EXPRN1`, and replacing every `VAR` found by the appropriate `EXPRN`. The `EXPRN` are not themselves searched for any occurrences of the various `VAR`s. The trivial case `sub`(EXPRN1)` returns the algebraic value of `EXPRN1`.
293

294
*Examples:*
295
```Julia
296
julia> Algebra.sub((:(x=a+y),:(y=y+1)),:(x^2+y^2))
297
:((a + y) ^ 2 + (y + 1) ^ 2)
298
```
299
and with `@rcall s = (x=a+y,y=y+1)`,
300
```
301
julia> Algebra.sub(:s,:(x^2+y^2))
302
:((a + y) ^ 2 + (y + 1) ^ 2)
303
```
304
Note that the global assignments `R"x:=a+y"`, etc., do not take place.
305

306
`EXPRN1` can be any valid algebraic expression whose type is such that a substitution process is defined for it (e.g., scalar expressions, lists and matrices). An error will occur if an expression of an invalid type for substitution occurs either in `EXPRN` or `EXPRN1`.
307
"""
308 28
sub(syme::String,expr::RExpr) = "sub($syme,$expr)" |> rcall |> RExpr
309 28
sub(syme::String,expr::T) where T = convert(T,sub(syme,RExpr(expr)))
310 28
sub(s::Dict{String,String},expr) = sub(Reduce._syme(s),expr)
311 28
sub(s::Dict{<:Any,<:Any},expr) = sub(Dict([=>(string.(RExpr.([b[1],b[2]]))...) for b  collect(s)]...),expr)
312 28
sub(s::Pair{<:Any,<:Any},expr) = sub(Dict(s),expr)
313 28
sub(s::Array{<:Pair{<:Any,<:Any},1},expr) = sub(Dict(s...),expr)
314 0
sub(s::Symbol,expr) = sub(string(s),expr)
315 0
sub(s::T,expr) where T <: Tuple = sub(string(list(s)),expr)
316 0
sub(s::Expr,expr) = sub(string(list(s)),expr)
317

318
@doc """
319
    on(::Symbol...)
320

321
Takes a list of switch names as argument and turns them on.
322
""" Reduce.Algebra.on
323

324
@doc """
325
    off(::Symbol...)
326

327
Takes a list of switch names as argument and turns them off.
328
""" Reduce.Algebra.off
329

330
@doc """
331
    max(r...)
332

333
`max` can take an arbitrary number of expressions as their arguments. If all arguments evaluate to numerical values, the maximum of the argument list is returned. If any argument is non-numeric, an appropriately reduced expression is returned. For example:
334

335
```Julia
336
julia> Algebra.max(2,-3,4,5)
337
5
338

339
julia> Algebra.max(:a,2,3)
340
:(max(3, a))
341
```
342

343
`max` of an empty list returns 0.
344
""" Reduce.Algebra.max
345

346
@doc """
347
    min(r...)
348

349
`min` can take an arbitrary number of expressions as their arguments. If all arguments evaluate to numerical values, the minimum of the argument list is returned. If any argument is non-numeric, an appropriately reduced expression is returned. For example:
350

351
```Julia
352
julia> Algebra.min(2,-2)
353
-2
354

355
julia> Algebra.min(:x)
356
:x
357
```
358

359
`min` of an empty list returns 0.
360
""" Reduce.Algebra.min
361

362
@doc """
363
    df(r...)
364

365
The operator `df` is used to represent partial differentiation with respect to one or more variables. It is used with the syntax:
366
```Julia
367
R"df(⟨EXPRN:algebraic⟩[,⟨VAR:kernel⟩ <,⟨NUM:integer⟩ >])"
368
```
369
The first argument is the expression to be differentiated. The remaining arguments specify the differentiation variables and the number of times they are applied.
370

371
The number `num` may be omitted if it is `1`. For example,
372
```Julia
373
reduce> df(y,x)
374

375
reduce> df(y,x,2)
376

377
reduce> df(y,x1,2,x2,x3,2)
378
```
379
The evaluation of `df(y,x)` proceeds as follows: first, the values of `y` and `x` are found. Let us assume that `x` has no assigned value, so its value is `x`. Each term or other part of the value of `y` that contains the variable `x` is differentiated by the standard rules. If `z` is another variable, not `x` itself, then its derivative with respect to `x` is taken to be `0`, unless `z` has previously been declared to `depend` on `x`, in which case the derivative is reported as the symbol `df(z,x)`.
380
""" Reduce.Algebra.df
381

382
@doc """
383
    int(r...)
384

385
`int` is an operator in REDUCE for indefinite integration using a combination of the Risch-Norman algorithm and pattern matching. It is used with the syntax:
386
```Julia
387
R"int(⟨EXPRN:algebraic⟩,⟨VAR:kernel⟩)"
388
```
389
This will return correctly the indefinite integral for expressions comprising polynomials, log functions, exponential functions and tan and atan. The arbitrary constant is not represented. If the integral cannot be done in closed terms, it returns a formal integral for the answer in one of two ways:
390

391
1. It returns the input, `int(…,…)` unchanged.
392
2. It returns an expression involving `int`s of some other functions (sometimes more complicated than the original one, unfortunately).
393

394
Rational functions can be integrated when the denominator is factorizable by the program. In addition it will attempt to integrate expressions involving error functions, dilogarithms and other trigonometric expressions. In these cases it might not always succeed in finding the solution, even if one exists.
395

396
*Examples:*
397
```Julia
398
julia> Algebra.int(:(log(x)),:x)
399
:((log(x) - 1) * x)
400

401
julia> Algebra.int(:(e^x),:x)
402
:(e ^ x)
403
```
404
The program checks that the second argument is a variable and gives an error if it is not.
405

406
*Note:* If the `int` operator is called with 4 arguments, REDUCE will implicitly call the definite integration package (DEFINT) and this package will interpret the third and fourth arguments as the lower and upper limit of integration, respectively. For details, consult the documentation on the DEFINT package.
407
""" Reduce.Algebra.int
408

409
@doc """
410
    pochhammer(a,k)
411

412
The Pochhammer notation ``(a)_k`` (also called Pochhammer’s symbol) is supported by the binary operator `pochhammer(a,k)`. For a non-negative integer `k`, it is defined as ([http://dlmf.nist.gov/5.2.iii](http://dlmf.nist.gov/5.2.iii))
413

414
``(a)_0	= 1,``
415

416
``(a)_k	= a(a + 1)(a + 2)⋅⋅⋅(a + k - 1).``
417

418
For ``a ⁄= 0,±1,±2,…``, this is equivalent to
419

420
``(a)k	= \\frac{\\Gamma (a+-k-)}{\\Gamma (a)}``
421

422
With `rounded` off, this expression is evaluated numerically if `a` and `k` are both integral, and otherwise may be simplified where appropriate. The simplification rules are based upon algorithms supplied by Wolfram Koepf.
423
""" Reduce.Algebra.pochhammer
424

425
@doc """
426
    pf(expr,var)
427

428
`R"pf(⟨exp⟩,⟨var⟩)"` transforms the expression `⟨exp⟩` into a list of partial fractions with respect to the main variable, `⟨var⟩`. `pf` does a complete partial fraction decomposition, and as the algorithms used are fairly unsophisticated (factorization and the extended Euclidean algorithm), the code may be unacceptably slow in complicated cases.
429
""" Reduce.Algebra.pf
430

431
@doc """
432
    solve(r...)
433

434
`solve` is an operator for solving one or more simultaneous algebraic equations. It is used with the syntax:
435
```Julia
436
R"SOLVE(⟨EXPRN:algebraic⟩[,⟨VAR:kernel⟩∣,⟨VARLIST:list of kernels⟩])"
437
```
438
`exprn` is of the form `⟨expression⟩` or `{⟨expression1⟩,⟨expression2⟩, …}`. Each expression is an algebraic equation, or is the difference of the two sides of the equation. The second argument is either a kernel or a list of kernels representing the unknowns in the system. This argument may be omitted if the number of distinct, non-constant, top-level kernels equals the number of unknowns, in which case these kernels are presumed to be the unknowns.
439

440
For one equation, `solve` recursively uses factorization and decomposition, together with the known inverses of `log`, `sin`, `cos`, `^`, `acos`, `asin`, and linear, quadratic, cubic, quartic, or binomial factors. Solutions of equations built with exponentials or logarithms are often expressed in terms of Lambert’s `W` function. This function is (partially) implemented in the special functions package.
441

442
Linear equations are solved by the multi-step elimination method due to Bareiss, unless the switch `cramer` is on, in which case Cramer’s method is used. The Bareiss method is usually more efficient unless the system is large and dense.
443

444
Non-linear equations are solved using the Groebner basis package (chapter 16.28). Users should note that this can be quite a time consuming process.
445

446
*Examples:*
447
```Julia
448
Algebra.solve(:(log(sin(x+3))^5 == 8),:x)
449
Algebra.solve(:(a*log(sin(x+3))^5 - b), :(sin(x+3)))
450
Algebra.solve((:(a*x+y==3),:(y=-2)),(:x,:y))
451
```
452
`solve` returns a list of solutions. If there is one unknown, each solution is an equation for the unknown. If a complete solution was found, the unknown will appear by itself on the left-hand side of the equation. On the other hand, if the solve package could not find a solution, the “solution” will be an equation for the unknown in terms of the operator `root_of`. If there are several unknowns, each solution will be a list of equations for the unknowns. For example,
453
```Julia
454
julia> Algebra.solve(:(x^2==1),:x)
455
(:(x = 1), :(x = -1))
456

457
julia> Algebra.solve(:(x^7-x^6+x^2==1),:x)
458
(:(x = root_of(x_ ^ 6 + x_ + 1, x_, tag_1)), :(x = 1))
459

460
julia> Algebra.solve((:(x+3y==7),:(y-x==1)),(:x,:y))
461
(:(x = 1), :(y = 2))
462
```
463
The `tag` argument is used to uniquely identify those particular solutions.
464
```
465
""" Reduce.Algebra.solve
466

467
@doc """
468
    even(r...)
469

470
An operator can be declared to be even in its first argument by the declarations `even`. Expressions involving an operator declared in this manner are transformed if the first argument contains a minus sign. Any other arguments are not affected. For example, the declaration
471
```Julia
472
julia> Algebra.even(:f1)
473
```
474
means that
475
```
476
        f1(-a)    ->    f1(a)  
477
        f1(-a,-b) ->    f1(a,-b)  
478
```
479
""" Reduce.Algebra.even
480

481
@doc """
482
    odd(r...)
483

484
An operator can be declared to be odd in its first argument by the declarations `odd`. Expressions involving an operator declared in this manner are transformed if the first argument contains a minus sign. Any other arguments are not affected. In addition, if say `f` is declared odd, then `f(0)` is replaced by zero unless `f` is also declared non zero by the declaration `nonzero`. For example, the declarations
485
```Julia
486
julia> Algebra.odd(:f2)
487
```
488
means that
489
```
490
        f2(-a)    ->   -f2(a)  
491
        f2(0)     ->    0
492
```
493
To inhibit the last transformation, say `nonzero(:f2)`.
494
""" Reduce.Algebra.odd
495

496
@doc """
497
    linear(r...)
498

499
An operator can be declared to be linear in its first argument over powers of its second argument. If an operator `f` is so declared, `f` of any sum is broken up into sums of `f`s, and any factors that are not powers of the variable are taken outside. This means that `f` must have (at least) two arguments. In addition, the second argument must be an identifier (or more generally a kernel), not an expression.
500

501
*Example:* If `f` were declared linear, then
502
```
503
f(a*x^5+b*x+c,x) ->  f(x^5,x)*a + f(x,x)*b + f(1,x)*c
504
```
505
More precisely, not only will the variable and its powers remain within the scope of the `f` operator, but so will any variable and its powers that had been declared to `depend` on the prescribed variable; and so would any expression that contains that variable or a dependent variable on any level, e.g. `cos(sin(x))`.
506

507
To declare operators `f` and `g` to be linear operators, use:
508
```Julia
509
julia> Algebra.linear(:f,:g)
510
```
511
The analysis is done of the first argument with respect to the second; any other arguments are ignored. It uses the following rules of evaluation:
512
```
513
f(0) 		-> 0
514
f(-y,x) 	-> -f(y,x)
515
f(y+z,x) 	-> f(y,x)+f(z,x)
516
f(y*z,x) 	-> z*f(y,x)   	if z does not depend on x
517
f(y/z,x) 	-> f(y,x)/z	if z does not depend on x
518
```
519
""" Reduce.Algebra.linear
520

521
@doc """
522
    noncom(r...)
523

524
An operator can be declared to be non-commutative under multiplication by the declaration `noncom`.
525

526
*Example:* After the declaration
527
```Julia
528
julia> Algebra.noncom(:u,:v);
529
```
530
the expressions `u(x)*u(y)-u(y)*u(x)` and `u(x)*v(y)-v(y)*u(x)` will remain unchanged on simplification, and in particular will not simplify to zero.
531

532
Note that it is the operator (`u` and `v` in the above example) and not the variable that has the non-commutative property.
533
""" Reduce.Algebra.noncom
534

535

536
@doc """
537
    symmetric(r...)
538

539
An operator can be declared to be symmetric with respect to its arguments by the declaration `symmetric`. For example
540
```Julia
541
julia> Algebra.symmetric(:u,:v);
542
```
543
means that any expression involving the top level operators `u` or `v` will have its arguments reordered to conform to the internal order used by REDUCE. The user can change this order for kernels by the command `korder`.
544
For example, `u(x,v(1,2))` would become `u(v(2,1),x)`, since numbers are ordered in decreasing order, and expressions are ordered in decreasing order of complexity.
545
""" Reduce.Algebra.symmetric
546

547
@doc """
548
    antisymmetric(r...)
549

550
the declaration `antisymmetric` declares an operator antisymmetric. For example,
551
```Julia
552
julia> Algebra.antisymmetric(:l,:m);
553
```
554
means that any expression involving the top level operators `l` or `m` will have its arguments reordered to conform to the internal order of the system, and the sign of the expression changed if there are an odd number of argument interchanges necessary to bring about the new order.
555

556
For example, `l(x,m(1,2))` would become `-l(-m(2,1),x)` since one interchange occurs with each operator. An expression like `l(x,x)` would also be replaced by `0`.
557
""" Reduce.Algebra.antisymmetric
558

559
@doc """
560
    operator(r...)
561

562
The user may add new prefix operators to the system by using the declaration `operator`. For example:
563
```Julia
564
julia> Algebra.operator(:h,:g1,:arctan)
565
```
566
adds the prefix operators `h`, `g1` and `arctan` to the system.
567

568
This allows symbols like `h(w)`, `h(x,y,z)`, `g1(p+q)`, `arctan(u/v)` to be used in expressions, but no meaning or properties of the operator are implied. The same operator symbol can be used equally well as a 0-, 1-, 2-, 3-, etc.-place operator.
569

570
To give a meaning to an operator symbol, or express some of its properties, `let` statements can be used, or the operator can be given a definition as a procedure.
571
""" Reduce.Algebra.operator
572

573
@doc """
574
    depend(r...)
575

576
There are several facilities in REDUCE, such as the differentiation operator and the linear operator facility, that can utilize knowledge of the dependency between various variables, or kernels. Such dependency may be expressed by the command `depend`. This takes an arbitrary number of arguments and sets up a dependency of the first argument on the remaining arguments. For example,
577
```Julia
578
julia> Algebra.depend(:x,:y,:z)
579
```
580
says that `x` is dependent on both `y` and `z`.
581
```Julia
582
julia> Algebra.depend(:z,:(cos(x)),:y)
583
```
584
says that `z` is dependent on `cos(x)` and `y`.
585
""" Reduce.Algebra.depend
586

587
@doc """
588
    nodepend(r...)
589

590
Dependencies introduced by `depend` can be removed by `nodepend`. The arguments of this are the same as for `depend`. For example, given the above dependencies,
591
```Julia
592
julia> Algebra.nodepend(:z,:(cos(x)))
593
```
594
says that `z` is no longer dependent on `cos(x)`, although it remains dependent on `y`.
595
""" Reduce.Algebra.nodepend
596

597
@doc """
598
    set(a,b)
599

600
In some cases, it is desirable to perform an assignment in which both the left- and right-hand sides of an assignment are evaluated. In this case, the `set` statement can be used with the syntax:
601
```Julia
602
R"set(⟨expression⟩,⟨expression⟩)"
603
```
604
For example, the statements
605
```
606
        j := 23;  
607
        set(mkid(a,j),x);
608
```
609
assigns the value `x` to `a23`.
610
""" Reduce.Algebra.set
611

612
@doc """
613
    unset(r)
614

615
To remove a value from such a variable, the `unset` statement can be used with the syntax:
616
```
617
R"unset(⟨expression⟩)"
618
```
619
For example, the statement
620
```
621
        j := 23;  
622
        unset(mkid(a,j));
623
```
624
clears the value of `a23`.
625
""" Reduce.Algebra.unset
626

627
@doc """
628
    fibonacci(n,x)
629

630
Fibonacci Polynomials are computed by the binary operator `fibonaccip`. `fibonaccip(n,x)` returns the `n`th Fibonacci polynomial in the variable `x`. If `n` is a positive or negative integer, it will be evaluated following the definition:
631

632
\$F_0(x) = 0; F_1(x) = 1; F_n(x) = xF_{n-1}(x) + F_{n-2}(x)\$
633
""" Reduce.Algebra.fibonaccip
634

635
@doc """
636
    mkid(u,v)
637

638
In many applications, it is useful to create a set of identifiers for naming objects in a consistent manner. In most cases, it is sufficient to create such names from two components. The operator `mkid` is provided for this purpose. Its syntax is:
639
```Julia
640
R"mkid(U:id,V:id|non-negative integer)"
641
```
642
for example
643
```Julia
644
julia> Algebra.mkid(:a,3)
645
:a3
646

647
julia> Algebra.mkid(:apple,:s)
648
:apples
649
```
650
while `mkid(:(a+b),2)` gives an error.
651
""" Reduce.Algebra.mkid
652

653
@doc """
654
    infix(r...)
655

656
Users can add new infix operators by using the declarations `infix` and `precedence`. For example,
657
```Julia
658
julia> Algebra.infix(:mm)
659
```
660
The declaration `infix(:mm)` would allow one to use the symbol `mm` as an infix operator:
661
`R"a mm b"` instead of `R"mm(a,b)"`.
662
""" Reduce.Algebra.infix
663

664
@doc """
665
    precedence(a,b)
666

667
Users can add new infix operators by using the declarations `infix` and `precedence`. For example,
668
```Julia
669
julia> Algebra.precedence(:mm,:-)
670
```
671
The declaration `precedence(:mm,:-)` says that `mm` should be inserted into the infix operator precedence list just after the `-` operator. This gives it higher precedence than `-` and lower precedence than `*` . Thus `R"a - b mm c - d"` means `R"a - (b mm c) - d"`, while `R"a * b mm c * d"` means `R"(a * b) mm (c * d)"`.
672
""" Reduce.Algebra.precedence
673

674
@doc """
675
    order(r...)
676

677
The declaration `order` may be used to order variables on output. The syntax is:
678
```Julia
679
julia> Algebra.order(v1,...vn)
680
```
681
where the `vi` are kernels. Thus,
682
```Julia
683
julia> Algebra.order(:x,:y,:z)
684
```
685
orders `x` ahead of `y`, `y` ahead of `z` and all three ahead of other variables not given an order. `order(nothing)` resets the output order to the system default. The order of variables may be changed by further calls of `order`, but then the reordered variables would have an order lower than those in earlier `order` calls. Thus,
686
```Julia
687
julia> Algebra.order(:x,:y,:z)  
688

689
julia> Algebra.order(:y,:x)
690
```
691
would order `z` ahead of `y` and `x`. The default ordering is usually alphabetic.
692
""" Reduce.Algebra.order
693

694
@doc """
695
    factor(r...)
696

697

698
This declaration takes a list of identifiers or kernels as argument. `factor` is not a factoring command (use `factorize` or the `factor` switch for this purpose); rather it is a separation command. All terms involving fixed powers of the declared expressions are printed as a product of the fixed powers and a sum of the rest of the terms.
699

700
For example, after the declaration
701
```Julia
702
julia> Algebra.factor(:x)
703
```
704
the polynomial \$(x + y + 1)^2\$ will be printed as
705
```
706
         2                  2  
707
        x  + 2*x*(y + 1) + y  + 2*y + 1
708
```
709
All expressions involving a given prefix operator may also be factored by putting the operator name in the list of factored identifiers. For example:
710
```Julia
711
julia> Algebra.factor(:x,:cos,:(sin(x))
712
```
713
causes all powers of `x` and `sin(x)` and all functions of `cos` to be factored.
714
""" Reduce.Algebra.factor
715

716
@doc """
717
    remfac(r...)
718

719
The declaration `remfac(v1,...,vn)` removes the factoring flag from the expressions `v1` through `vn`.
720
""" Reduce.Algebra.remfac
721

722
@doc """
723
    korder(r...)
724

725
The internal ordering of variables (more specifically kernels) can have a significant effect on the space and time associated with a calculation. In its default state, REDUCE uses a specific order for this which may vary between sessions. However, it is possible for the user to change this internal order by means of the declaration `korder`. The syntax for this is:
726
```Julia
727
julia> Algebra.korder(v1,...,vn)
728
```
729
where the `vi` are kernels. With this declaration, the `vi` are ordered internally ahead of any other kernels in the system. `v1` has the highest order, `v2` the next highest, and so on. A further call of `korder` replaces a previous one. `korder(nothing)` resets the internal order to the system default.
730
""" Reduce.Algebra.korder
731

732
@doc """
733
    realvalued(r...)
734

735
The declaration `realvalued` may be used to restrict variables to the real numbers. The syntax is:
736
```Julia
737
	Algebra.realvalued(v1,...vn)
738
```
739
For such variables the operator `impart` gives the result zero. Thus, with
740
```Julia
741
julia> Algebra.realvalued(:x,:y)
742
```
743
the expression `impart(x+sin(y))` is evaluated as zero. You may also declare an operator as real valued with the meaning, that this operator maps real arguments always to real values. Example:
744
```Julia
745
julia> Algebra.operator(:h); Algebra.realvalued(:h,:x)
746

747
julia> Algebra.impart(:(h(x)))
748
0  
749
 
750
julia> Algebra.impart(:(h(w)))
751
:(impart(h(w)))
752
```
753
Such declarations are not needed for the standard elementary functions.
754
""" Reduce.Algebra.realvalued
755

756
@doc """
757
    notrealvalued(r...)
758

759
To remove the `realvalued` propery from a variable or an operator use the declaration `notrealvalued` with the syntax:
760
```Julia
761
julia> Algebra.notrealvalued(v1,...vn)
762
```
763
""" Reduce.Algebra.notrealvalued
764

765
@doc """
766
    factorize(r...)
767

768
It is also possible to factorize a given expression explicitly. The operator `factorize` that invokes this facility is used with the syntax
769
```Julia
770
R"factorize(EXPRN:polynomial[,INTEXP:prime integer])"
771
```
772
the optional argument of which will be described later. Thus to find and display all factors of the cyclotomic polynomial ``x^{105} - 1``, one could write:
773
```
774
julia> Algebra.factorize(:(x^105-1))
775
```
776
The result is a list of factor,exponent pairs. In the above example, there is no overall numerical factor in the result, so the results will consist only of polynomials in x. The number of such polynomials can be found by using the operator `length`. If there is a numerical factor, as in factorizing ``12x^2 - 12``, that factor will appear as the first member of the result. It will however not be factored further. Prime factors of such numbers can be found, using a probabilistic algorithm, by turning on the switch `ifactor`. For example,
777
```
778
julia> Algebra.on(:ifactor); Algebra.factorize(:(12x^2-12))
779
```
780
would result in the output
781
```
782
((2, 2), (3, 1), (:(x ^ 2 + 1), 1), (:(x + 1), 1), (:(x - 1), 1))
783
```
784
If the first argument of `factorize` is an integer, it will be decomposed into its prime components, whether or not `ifactor` is on.
785

786
Note that the `ifactor` switch only affects the result of `factorize`. It has no effect if the `factor` switch is also on.
787
""" Reduce.Algebra.factorize
788

789
@doc """
790
    remainder(a,b)
791

792
This operator is used with the syntax
793
```Julia
794
R"REMAINDER(EXPRN1:polynomial,EXPRN2:polynomial)"
795
```
796
It returns the remainder when `EXPRN1` is divided by `EXPRN2`. This is the true remainder based on the internal ordering of the variables, and not the pseudo-remainder. The pseudo-remainder and in general pseudo-division of polynomials can be calculated after loading the `polydiv` package. Please refer to the documentation of this package for details.
797

798
*Examples:*
799
```Julia
800
julia> Algebra.on(:exp); Algebra.remainder(:((x+y)*(x+2*y)),:(x+3*y))
801
:(2 * y ^ 2)
802

803
julia> Algebra.remainder(:(2*x+y),2)
804
:y
805
```
806
""" Reduce.Algebra.remainder
807

808
@doc """
809
    resultant(a,b,var)
810

811
This is used with the syntax
812
```Julia
813
R"resultant(EXPRN1:polynomial,EXPRN2:polynomial,VAR:kernel)"
814
```
815
It computes the resultant of the two given polynomials with respect to the given variable, the coefficients of the polynomials can be taken from any domain. The result can be identified as the determinant of a Sylvester matrix, but can often also be thought of informally as the result obtained when the given variable is eliminated between the two input polynomials. If the two input polynomials have a non-trivial GCD their resultant vanishes.
816

817
The switch `bezout` controls the computation of the resultants. It is off by default. In this case a subresultant algorithm is used. If the switch Bezout is turned on, the resultant is computed via the Bezout Matrix. However, in the latter case, only polynomial coefficients are permitted.
818
""" Reduce.Algebra.resultant
819

820
@doc """
821
    interpol(val,var,mp)
822

823
Syntax:
824
```Julia
825
R"interpol(⟨values⟩,⟨variable⟩,metapoints)"
826
```
827
where `⟨values⟩` and `⟨points⟩` are lists of equal length and `<variable>` is an algebraic expression (preferably a kernel).
828

829
`interpol` generates an interpolation polynomial ``f`` in the given variable of degree `length(⟨values⟩)-1`. The unique polynomial ``f`` is defined by the property that for corresponding elements ``v`` of `⟨values⟩` and ``p`` of `⟨points⟩` the relation ``f(p) = v`` holds.
830

831
The Aitken-Neville interpolation algorithm is used which guarantees a stable result even with rounded numbers and an ill-conditioned problem.
832
""" Reduce.Algebra.interpol
833

834
@doc """
835
    deg(p,var)
836

837
This operator is used with the syntax
838
```Julia
839
R"deg(EXPRN:polynomial,VAR:kernel)"
840
```
841
It returns the leading degree of the polynomial `EXPRN` in the variable `VAR`. If `VAR` does not occur as a variable in `EXPRN`, 0 is returned.
842

843
*Examples:*
844
```Julia
845
julia> Algebra.on(:exp)
846

847
julia> Algebra.deg(:((a+b)*(c+2*d)^2),:a)
848
1
849

850
julia> Algebra.deg(:((a+b)*(c+2*d)^2),:d)
851
2
852

853
julia> Algebra.deg(:((a+b)*(c+2*d)^2),:e)
854
0
855
```
856
Note also that if `ratarg` is on,
857
```
858
        deg((a+b)^3/a,a)       ->  3
859
```
860
since in this case, the denominator `a` is considered part of the coefficients of the numerator in `a`. With `ratarg` off, however, an error would result in this case.
861
""" Reduce.Algebra.deg
862

863
@doc """
864
    lcof(expr,var)
865

866
`lcof` is used with the syntax
867
```Julia
868
R"lcof(EXPRN:polynomial,VAR:kernel)"
869
```
870
It returns the leading coefficient of the polynomial `EXPRN` in the variable `VAR`. If `VAR` does not occur as a variable in `EXPRN`, `EXPRN` is returned.
871

872
*Examples:*
873
```Julia
874
julia> Algebra.on(:exp)
875

876
julia> Algebra.lcof(:((a+b)*(c+2*d)^2),:a)
877
:(c ^ 2 + 4 * c * d + 4 * d ^ 2)
878

879
julia> Algebra.lcof(:((a+b)*(c+2*d)^2),:d)
880
:(4 * (a + b))
881

882
julia> Algebra.lcof(:((a+b)*(c+2*d)),:e)
883
:(a * c + 2 * a * d + b * c + 2 * b * d)
884
```
885
""" Reduce.Algebra.lcof
886

887
@doc """
888
    lpower(exprn,var)
889

890
Syntax:
891
```Julia
892
R"lpower(EXPRN:polynomial,VAR:kernel)"
893
```
894
`lpower` returns the leading power of `EXPRN` with respect to `VAR`. If `EXPRN` does not depend on `VAR`, 1 is returned.
895
*Examples:*
896
```Julia
897
julia> Algebra.on(:exp)
898

899
julia> Algebra.lpower(:((a+b)*(c+2*d)^2),:a)
900
:a
901

902
julia> Algebra.lpower(:((a+b)*(c+2*d)^2),:d)
903
:(d ^ 2)
904

905
julia> Algebra.lpower(:((a+b)*(c+2*d)),:e)
906
1
907
```
908
""" Reduce.Algebra.lpower
909

910
@doc """
911
    lterm(exprn,var)
912

913
Syntax:
914
```Julia
915
R"lterm(EXPRN:polynomial,VAR:kernel)"
916
```
917
`lterm` returns the leading term of `EXPRN` with respect to `VAR`. If `EXPRN` does not depend on `VAR`, `EXPRN` is returned.
918

919
*Examples:*
920
```Julia
921
julia> Algebra.on(:exp)
922

923
julia> Algebra.lterm(:((a+b)*(c+2*d)^2),:a)
924
:(a * (c ^ 2 + 4 * c * d + 4 * d ^ 2))
925

926
julia> Algebra.lterm(:((a+b)*(c+2*d)^2),:d)
927
:(4 * d ^ 2 * (a + b))
928

929
julia> Algebra.lterm(:((a+b)*(c+2*d)),:e)
930
:(a * c + 2 * a * d + b * c + 2 * b * d)
931
```
932
""" Reduce.Algebra.lterm
933

934
@doc """
935
    reduct(exprn,var)
936

937
Syntax:
938
```Julia
939
R"reduct(EXPRN:polynomial,VAR:kernel)"
940
```
941
Returns the reductum of `EXPRN` with respect to `VAR` (i.e., the part of `EXPRN` left after the leading term is removed). If `EXPRN` does not depend on the variable `VAR`, 0 is returned.
942

943
*Examples:*
944
```Julia
945
julia> Algebra.on(:exp)
946

947
julia> Algebra.reduct(:((a+b)*(c+2*d)),:a)
948
:(b * (c + 2d))
949

950
julia> Algebra.reduct(:((a+b)*(c+2*d)),:d)
951
:(c * (a + b))
952

953
julia> Algebra.reduct(:((a+b)*(c+2*d)),:e)
954
0
955
```
956
""" Reduce.Algebra.reduct
957

958
@doc """
959
    totaldeg(expr,var)
960

961
Syntax:
962
```Julia
963
julia> Algebra.totaldeg(:(a*x^2+b*x+c), :x)
964
2
965

966
julia> Algebra.totaldeg(:(a*x^2+b*x+c), (:a,:b,:c))
967
1
968

969
julia> Algebra.totaldeg(:(a*x^2+b*x+c), (:x, :a))
970
3
971

972
julia> Algebra.totaldeg(:(a*x^2+b*x+c), (:x,:b))
973
2
974

975
julia> Algebra.totaldeg(:(a*x^2+b*x+c), (:p,:q,:r))
976
0
977
```
978
`totaldeg(u, kernlist)` finds the total degree of the polynomial `u` in the variables in `kernlist`. If `kernlist` is not a list it is treated as a simple single variable. The denominator of `u` is ignored, and "degree" here does not pay attention to fractional powers. Mentions of a kernel within the argument to any operator or function (eg `sin`, `cos`, `log`, `sqrt`) are ignored. Really `u` is expected to be just a polynomial.
979
""" Reduce.Algebra.totaldeg
980

981
@doc """
982
    clear(r...)
983

984
The user may remove all assignments and substitution rules from any expression by the command `clear`, in the form
985
```
986
R"cilear ⟨expression⟩,…,⟨expression⟩ = ⟨terminator⟩"
987
```
988
e.g.
989
```Julia
990
julia> Algebra.clear(:x,:(h(x,y)))
991
```
992
Because of their *instant evaluation* property, array and matrix elements cannot be cleared with `clear`. For example, if `a` is an array, you must say
993
```Julia
994
R"a(3) := 0"
995
```
996
rather than
997
```Julia
998
R"clear a(3)"
999
```
1000
to “clear” element `a(3)`.
1001

1002
On the other hand, a whole array (or matrix) `a` can be cleared by the command `clear(:a)`. This means much more than resetting to 0 all the elements of `a`. The fact that `a` is an array, and what its dimensions are, are forgotten, so `a` can be redefined as another type of object, for example an operator.
1003

1004
If you need to clear a variable whose name must be computed, see the `unset` statement.
1005
""" Reduce.Algebra.clear
1006

1007
"""
1008
    mateign(exprn,id)
1009

1010
Syntax:
1011
```
1012
        MATEIGEN(EXPRN:matrix_expression,ID):list.
1013
```
1014
`mateigen` calculates the eigenvalue equation and the corresponding eigenvectors of a matrix, using the variable `id` to denote the eigenvalue. A square free decomposition of the characteristic polynomial is carried out. The result is a list of lists of 3 elements, where the first element is a square free factor of the characteristic polynomial, the second its multiplicity and the third the corresponding eigenvector (as an *n* by *1* matrix). If the square free decomposition was successful, the product of the first elements in the lists is the minimal polynomial. In the case of degeneracy, several eigenvectors can exist for the same eigenvalue, which manifests itself in the appearance of more than one arbitrary variable in the eigenvector. To extract the various parts of the result use the operations defined on lists.
1015

1016
*Example:* The command
1017
```
1018
        mateigen(mat((2,-1,1),(0,1,1),(-1,1,1)),eta);
1019
```
1020
gives the output
1021
```
1022
        {{ETA - 1,2,  
1023
 
1024
          [ARBCOMPLEX(1)]  
1025
          [             ]  
1026
          [ARBCOMPLEX(1)]  
1027
          [             ]  
1028
          [      0      ]  
1029
 
1030
          },  
1031
 
1032
         {ETA - 2,1,  
1033
 
1034
          [      0      ]  
1035
          [             ]  
1036
          [ARBCOMPLEX(2)]  
1037
          [             ]  
1038
          [ARBCOMPLEX(2)]  
1039
 
1040
          }}
1041
```
1042
""" Reduce.Algebra.mateign
1043

1044
@doc """
1045
    cofactor(exprn,row,column)
1046

1047
Syntax:
1048
```
1049
  cofactor(EXPRN:matrix_expression,ROW:integer,COLUMN:integer):algebraic
1050
```
1051
The operator `cofactor` returns the cofactor of the element in row `ROW` and column `COLUMN` of the matrix `EXPRN`. Errors occur if `ROW` or `COLUMN` do not simplify to integer expressions or if `EXPRN` is not square.
1052
""" Reduce.Algebra.cofactor
1053

1054
@doc """
1055
    limit(exprn,var,limpint)
1056

1057
Syntax
1058
```
1059
LIMIT(⟨EXPRN:algebraic⟩,⟨VAR:kernel⟩,⟨LIMPOINT:algebraic⟩) : algebraic
1060
```
1061
This is the standard way of calling limit, applying all of the methods. The result is the limit of `EXPRN` as `VAR` approaches `LIMPOINT`.
1062
""" Reduce.Algebra.limit
1063

1064
@doc """
1065
    compact(exprn,list)
1066

1067
COMPACT is a package of functions for the reduction of a polynomial in the presence of side relations. `compact` applies the side relations to the polynomial so that an equivalent expression results with as few terms as possible. For example, the evaluation of
1068
```Julia
1069
Algebra.compact(:(s*(1-sin(x^2))+c*(1-cos(x^2))+sin(x^2)+cos(x^2)),
1070
    (:(cos(x^2)+sin(x^2)=1),))
1071
```
1072
yields the result
1073
```Julia
1074
:(sin(x ^ 2) * c + 1 + cos(x ^ 2) * s)
1075
```
1076
The switch `trcompact` can be used to trace the operation.
1077
""" Reduce.Algebra.compact
1078

1079
@doc """
1080
    define(r...)
1081

1082
The command `define` allows a user to supply a new name for any identifier or replace it by any well-formed expression. Its argument is a list of expressions of the form
1083
```
1084
⟨identifier⟩ = 	⟨number⟩∣⟨identifier⟩∣⟨operator⟩∣
1085
		⟨reserved word⟩∣⟨expression⟩
1086
```
1087
*Example:*
1088
```Julia
1089
Algebra.define(:(x==y+z))
1090
```
1091
""" Reduce.Algebra.define
1092

1093
@doc """
1094
    changevar(depvars,newvars,eqlist,diffeq)
1095

1096
The operator `changevar` does a variable transformation in a set of differential equations. Syntax:
1097
```
1098
changevar(⟨depvars⟩,⟨newvars⟩,⟨eqlist⟩,⟨diffeq⟩)
1099
```
1100
`⟨diffeq⟩` is either a single differential equation or a list of differential equations, `⟨depvars⟩` are the dependent variables to be substituted, `⟨newvars⟩` are the new depend variables, and `⟨eqlist⟩` is a list of equations of the form `⟨depvar⟩=⟨expression⟩` where `⟨expression⟩` is some function in the new dependent variables.
1101

1102
The three lists `⟨depvars⟩`, `⟨newvars⟩`, and `⟨eqlist⟩` must be of the same length. If there is only one variable to be substituted, then it can be given instead of the list. The same applies to the list of differential equations, i.e., the following two commands are equivalent
1103
```Julia
1104
Algebra.operator(:u)
1105
Algebra.changevar(:u,:y,:(x==e^y),:(df(u(x),x) - log(x)))
1106
Algebra.changevar((:u,),(:y,),(:(x=e^y),),(:(df(u(x),x) - log(x)),))
1107
```
1108
except for one difference: the first command returns the transformed differential equation, the second one a list with a single element.
1109
""" Reduce.Algebra.changevar
1110

1111
@doc """
1112
    map(fnc,obj)
1113

1114
The `map` operator applies a uniform evaluation pattern to all members of a composite structure: a matrix, a list, or the arguments of an operator expression. The evaluation pattern can be a unary procedure, an operator, or an algebraic expression with one free variable.
1115

1116
It is used with the syntax:
1117
```
1118
   map(FNC:function,OBJ:object)
1119
```
1120
Here `OBJ` is a list, a matrix or an operator expression. `FNC` can be one of the following:
1121

1122
1. the name of an operator with a single argument: the operator is evaluated once with each element of `OBJ` as its single argument;
1123
2. an algebraic expression with exactly one free variable, i.e. a variable preceded by the tilde symbol. The expression is evaluated for each element of `OBJ`, with the element substituted for the free variable;
1124
3. a replacement rule of the form `var => rep` where `var` is a variable (a kernel without a subscript) and `rep` is an expression that contains `var`. The replacement expression `rep` is evaluated for each element of `OBJ` with the element substituted for `var`. The variable `var` may be optionally preceded by a tilde.
1125

1126
The rule form for `FNC` is needed when more than one free variable occurs.
1127

1128
*Examples:*
1129
```Julia
1130
julia> Algebra.map(:abs, (1,-2,:a,:(-a)))
1131
(1, 2, :(abs(a)), :(abs(a)))
1132

1133
julia> Algebra.map(:(int(~w,x)), [:(x^2) :(x^5); :(x^4) :(x^5)])
1134
2×2 Array{Any,2}:
1135
 :(x ^ 3 // 3)  :(x ^ 6 // 6)
1136
 :(x ^ 5 // 5)  :(x ^ 6 // 6)
1137

1138
 julia> Algebra.map(:(~w*6), :(x^2/3 == y^3/2 -1))
1139
:(2 * x ^ 2 = 3 * (y ^ 3 - 2))
1140
```
1141
You can use `map` in nested expressions. However, you cannot apply `map` to a non-composite object, e.g. an identifier or a number.
1142
""" Reduce.Algebra.map
1143

1144
@doc """
1145
    select(fnc,lst)
1146

1147
The `select` operator extracts from a list, or from the arguments of an n–ary operator, elements corresponding to a boolean predicate. It is used with the syntax:
1148
```
1149
select(⟨FNC:function⟩,⟨LST:list⟩)
1150
```
1151
`FNC` can be one of the following forms:
1152

1153
1. the name of an operator with a single argument: the operator is evaluated once on each element of `LST`;
1154
2. an algebraic expression with exactly one free variable, i.e. a variable preceded by the tilde symbol. The expression is evaluated for each element of `⟨LST⟩`, with the element substituted for the free variable;
1155
3. a replacement rule of the form `⟨var⟩ => ⟨rep⟩` where `⟨var⟩` is a variable (a kernel without subscript) and `⟨rep⟩` is an expression that contains `⟨var⟩`. `⟨rep⟩` is evaluated for each element of `LST` with the element substituted for `⟨var⟩`. `⟨var⟩` may be optionally preceded by a tilde.
1156

1157
The rule form for `FNC` is needed when more than one free variable occurs.
1158

1159
The result of evaluating `FNC` is interpreted as a boolean value corresponding to the conventions of REDUCE. These values are composed with the leading operator of the input expression.
1160

1161
*Examples:*
1162
```Julia
1163
julia> Algebra.select(:(~w>0), (1,-1,2,-3,3))
1164
(1, 2, 3)
1165
```
1166
```
1167
    select(evenp deg(~w,y),part((x+y)^5,0):=list)  
1168
           -> {X^5 ,10*X^3*Y^2 ,5*X*Y^4}  
1169
    select(evenp deg(~w,x),2x^2+3x^3+4x^4) -> 4X^4 + 2X^2
1170
```
1171
""" Reduce.Algebra.select
1172

1173
@doc """
1174
    g(id,exprn...)
1175

1176
Syntax:
1177
```
1178
        G(ID:identifier[,EXPRN:vector_expression])  
1179
                :gamma_matrix_expression.
1180
```
1181
`g` is an n-ary operator used to denote a product of γ matrices contracted with Lorentz four-vectors. Gamma matrices are associated with fermion lines in a Feynman diagram. If more than one such line occurs, then a different set of γ matrices (operating in independent spin spaces) is required to represent each line. To facilitate this, the first argument of `g` is a line identification identifier (not a number) used to distinguish different lines.
1182
""" Reduce.Algebra.g
1183

1184
@doc """
1185
    eps(exprn1,...,exprn4)
1186

1187
Syntax:
1188
```
1189
         EPS(EXPRN1:vector_expression,...,EXPRN4:vector_exp):vector_exp.
1190
```
1191
The operator `eps` has four arguments, and is used only to denote the completely antisymmetric tensor of order 4 and its contraction with Lorentz four-vectors. Thus
1192

1193
\$ϵ_{ijkl} = \\begin{cases} +1 & \\text{if }i,j,k,l\\text{ is an even permutation of 0,1,2,3} \\\\ - 1  & \\text{if }i,j,k,l\\text{ is an odd permutation of 0,1,2,3} \\\\ 0 & \\text{otherwise} \\end{cases}.\$
1194

1195
A contraction of the form \$ϵ_{ijμν}p_μq_ν\$ may be written as `eps(i,j,p,q)`, with `i` and `j` flagged as indices, and so on.
1196
""" Reduce.Algebra.eps

Read our documentation on viewing source code .

Loading