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
import LinearAlgebra: factorize
5

6
const sbas = [
7
    :conj,
8
    :exp,
9
    :log,
10
    :cos,
11
    :cosh,
12
    :sin,
13
    :sinh,
14
    :sqrt,
15
    :abs,
16
    :factorial,
17
    :floor,
18
    :max,
19
    :min,
20
    :round,
21
    :sign,
22
    :acos,
23
    :acosh,
24
    :acot,
25
    :acoth,
26
    :acsc,
27
    :acsch,
28
    :asec,
29
    :asech,
30
    :asin,
31
    :asinh,
32
    :atan,
33
    :atanh,
34
    #:atan2,
35
    :cot,
36
    :coth,
37
    :csc,
38
    :csch,
39
    :hypot,
40
    :log10,
41
    :sec,
42
    :sech,
43
    :tan,
44
    :tanh,
45
]
46

47
const sdep = [
48
    :gamma,
49
    :beta,
50
    :besseli,
51
    :besselj,
52
    :besselk,
53
    :bessely,
54
    :polygamma,
55
    :zeta
56
]
57

58
const sfun = [
59
    :ibeta,
60
    :igamma,
61
    :ln,
62
    :psi,
63
    :bernoulli,
64
    :continued_fraction,
65
    :ci, #
66
    :dilog,
67
    :ei,
68
    :si,
69
    :airy_ai,
70
    :airy_aiprime,
71
    :airy_bi,
72
    :airy_biprime,
73
    :hanekl1,
74
    :hankel2,
75
    :kummerm,
76
    :kummeru,
77
    :lommel1,
78
    :lommel2,
79
    :struveh,
80
    :struvel,
81
    :whittakerm,
82
    :whittakeru,
83
    :solidharmonicy,
84
    :sphericalharmonicy,
85
    :expand_cases,
86
    :arglength,
87
    :decompose,
88
    :num,
89
    :den,
90
    :mainvar,
91
    :precision,
92
    :setmod,
93
    :rootval,
94
    :showrules,
95
    :reverse,
96
    :lhs,
97
    :rhs,
98
    :saveas,
99
    :root_val,
100
]
101

102
const snan = [
103
    :rlet,
104
    :clearrules,
105
    :scientific_notation,
106
    :optimize,
107
]
108

109
const snum = [
110
    :ceiling,
111
    :fix,
112
]
113

114
const scom = [
115
    :impart,
116
    :repart,
117
]
118

119
const sint = [
120
    :nextprime,
121
    :euler,
122
    :fibonacci,
123
    :motzkin,
124
]
125

126
const sran = [
127
    :random,
128
    :random_new_seed
129
]
130

131
const sbat = [
132
    :det,
133
    :trace,
134
    :nullspace,
135
    :rank
136
]
137

138
const smat = [
139
    :tp,
140
]
141

142 0
Expr(:block,[:(@inline $i(r)=Base.$i(r)) for i  [sbas[10:end];sdep;sbat;[:length]]]...) |> eval
143
#Expr(:toplevel,[:(import Base: $i) for i ∈ [sbas;sdep;sbat;[:length]]]...) |> eval
144
:(export $([sbas;sdep;sfun;snan;snum;scom;sint;sran;sbat;smat;[:length]]...)) |> eval
145
#:(export $(Symbol.("@",[sbas;sdep;sfun;snum;scom;sint])...)) |> eval
146

147 20
for fun in [sbas;sdep;sfun;snum;scom;sint;sran;sbat;smat;[:length]]
148 24
    Reduce.parsegen(fun,:unary) |> eval
149
end
150

151
for fun in [sbas;sdep;sfun;snum;scom;sint]
152
    @eval begin
153
        $(Reduce.unfoldgen(fun,:unary))
154 4
        function $fun(expr::String;be=0)
155 28
            convert(String, $fun(RExpr(expr);be=be))
156
        end
157
        #=macro $fun(expr)
158
            :($$(QuoteNode(fun))($(esc(expr))))
159
        end=#
160
    end
161
end
162

163
for fun in [sbat;smat]
164
    @eval begin
165 4
        function $fun(expr::Union{Array{T,2},T}) where T <: ExprSymbol
166 28
            $fun(RExpr(expr)) |> parse |> mat
167
        end
168 0
        function $fun(expr::Array{Any,2})
169 0
            $fun(RExpr(expr)) |> parse |> mat
170
        end
171
    end
172
end
173

174
"""
175
    tp(exprn)
176

177
Syntax:
178
```
179
        tp(EXPRN:matrix_expression):matrix.
180
```
181
This operator takes a single matrix argument and returns its transpose.
182
"""
183 28
tp(r::Array{T,1}) where T <: ExprSymbol = r |> RExpr |> tp |> parse |> mat
184 0
tp(r::Union{Vector,Adjoint}) = r |> RExpr |> tp |> parse |> mat
185

186
"""
187
    length(r)
188

189
`length` is a generic operator for finding the length of various objects in the system. The meaning depends on the type of the object. In particular, the length of an algebraic expression is the number of additive top-level terms its expanded representation.
190

191
*Examples:*
192
```Julia
193
julia> length(:(a+b))
194
2
195

196
julia> length(2)
197
1
198
```
199
Other objects that support a length operator include arrays, lists and matrices. The explicit meaning in these cases is included in the description of these objects.
200
"""
201 28
length(r::Expr) = length(r |> RExpr) |> parse |> eval
202

203
for fun in snan
204
    nfun = fun  :rlet ? fun : :let
205
    @eval begin
206 28
        $fun(r::RExpr) = string($(string(nfun)),"(",string(r),")") |> rcall |> RExpr
207 28
        $fun(r) = $fun(RExpr(r)) |> parse
208
    end
209
end
210

211
"""
212
    rlet(::Union{Dict,Pair})
213

214
The simplest use of the `let` statement is in the form
215
```
216
R"let ⟨substitution list⟩"
217
```
218
where `⟨substitution list⟩` is a list of rules separated by commas, each of the form:
219
```
220
⟨variable⟩ = ⟨expression⟩
221
```
222
or
223
```
224
⟨prefix operator⟩(⟨argument⟩,…,⟨argument⟩) = ⟨expression⟩
225
```
226
or
227
```
228
⟨argument⟩⟨infix operator⟩,…,⟨argument⟩ = ⟨expression⟩
229
```
230
For example,
231
```
232
        let {x => y^2,
233
             h(u,v) => u - v,
234
             cos(pi/3) => 1/2,
235
             a*b => c,
236
             l+m => n,
237
             w^3 => 2*z - 3,
238
             z^10 => 0}
239
```
240
The list brackets can be left out if preferred. The above rules could also have been entered as seven separate `let` statements.
241

242
After such `let` rules have been input, `x` will always be evaluated as the square of `y`, and so on. This is so even if at the time the `let` rule was input, the variable `y` had a value other than `y`. (In contrast, the assignment `R"x:=y^2"` will set `x` equal to the square of the current value of `y`, which could be quite different.)
243

244
The rule `let a*b=c` means that whenever `a` and `b` are both factors in an expression their product will be replaced by `c`. For example, `a^5*b^7*w` would be replaced by `c^5*b^2*w`.
245

246
The rule for `l+m` will not only replace all occurrences of `l+m` by `n`, but will also normally replace `l` by `n-m`, but not `m` by `n-l`. A more complete description of this case is given in Section 11.2.5.
247

248
The rule pertaining to `w^3` will apply to any power of `w` greater than or equal to the third.
249

250
Note especially the last example, `let z^10=0`. This declaration means, in effect: ignore the tenth or any higher power of `z`. Such declarations, when appropriate, often speed up a computation to a considerable degree. (See Section 11.4 for more details.)
251

252
Any new operators occurring in such `let` rules will be automatically declared `operator` by the system, if the rules are being read from a file. If they are being entered interactively, the system will ask `Declare… Operator?`. Answer `Y` or `N` and hit `<Return>`.
253

254
In each of these examples, substitutions are only made for the explicit expressions given; i.e., none of the variables may be considered arbitrary in any sense. For example, the command
255
```Julia
256
julia> Algebra.rlet( :(h(u,v)) => :(u - v) )
257
```
258
will cause `h(u,v)` to evaluate to `u - v`, but will not affect `h(u,z)` or `h` with any arguments other than precisely the symbols `u,v`.
259

260
These simple `let` rules are on the same logical level as assignments made with the `:=` operator. An assignment `R"x := p+q"` cancels a rule `rlet( :x => :(y^2) )` made earlier, and vice versa.
261
"""
262 28
rlet(r::Dict{String,String}) = rlet(sub_list(r))
263 28
rlet(s::Dict{<:Any,<:Any}) = rlet(Dict([=>(string.(RExpr.([b[1],b[2]]))...) for b  collect(s)]...))
264 28
rlet(s::Pair{<:Any,<:Any}) = rlet(Tuple([s]))
265 28
rlet(s::T) where T <: Tuple = rlet(RExpr(s)) |> parse
266 28
rlet(s::Array{<:Pair{<:Any,<:Any},1}) = rlet(Tuple(s))
267

268
"""
269
    Algebra.scientific_notation(::Union{Number,Tuple,Vector})
270

271
The declaration `scientific_notation` controls the output format of floating point numbers. At the default settings, any number with five or less digits before the decimal point is printed in a fixed-point notation, e.g., `12345.6`. Numbers with more than five digits are printed in scientific notation, e.g., `1.234567E+5`. Similarly, by default, any number with eleven or more zeros after the decimal point is printed in scientific notation. To change these defaults, `scientific_notation` can be used in one of two ways.
272
```Julia
273
julia> Algebra.scientific_notation(m);
274
```
275
where `m` is a positive integer, sets the printing format so that a number with more than `m` digits before the decimal point, or `m` or more zeros after the decimal point, is printed in scientific notation.
276
```Julia
277
julia> Algebra.scientific_notation(m,n);
278
```
279
with `m` and `n` both positive integers, sets the format so that a number with more than `m` digits before the decimal point, or `n` or more zeros after the decimal point is printed in scientific notation.
280
"""
281 0
scientific_notation(r::T) where T <: Tuple = scientific_notation(RExpr(r)) |> parse
282 0
scientific_notation(r::Union{Vector,Adjoint}) = scientific_notation(list(r)) |> parse
283 0
scientific_notation(r::T...) where T <: Number = scientific_notation(list(r)) |> parse
284

285
for fun in [sint;sran]
286
    @eval begin
287 4
        function $fun(n::T) where T <: Integer
288 28
            convert(T, $fun(RExpr(n)) |> parse |> eval)
289
        end
290
    end
291
end
292

293
for fun in snum
294
    @eval begin
295 4
        function $fun(x::T) where T <: Real
296 28
            $fun(RExpr(x)) |> parse |> eval
297
        end
298
    end
299
end
300

301
for fun in scom
302
    @eval begin
303 4
        function $fun(x::T) where T <: Number
304 28
            x |> RExpr |> $fun |> parse |> eval
305
        end
306
    end
307
end
308

309 4
function bernoulli(n::T) where T <: Integer
310 28
    bernoulli(RExpr(n)) |> parse |> eval
311
end
312

313
@doc """
314
    lhs(::Union{Expr,RExpr})
315

316
Returns the left-hand side of an equation.
317

318
## Examples
319
```Julia
320
julia> Algebra.lhs(R"a+b=c")
321

322
a + b
323

324
```
325
""" Reduce.Algebra.lhs
326

327
@doc """
328
    rhs(::Union{Expr,RExpr})
329

330
Returns the right-hand side of an equation.
331

332
## Examples
333
```Julia
334
julia> Algebra.rhs(R"a+b=c")
335

336
c
337

338
```
339
""" Reduce.Algebra.rhs
340

341
@doc """
342
    abs(r)
343

344
`abs` returns the absolute value of its single argument, if that argument has a numerical value. A non-numerical argument is returned as an absolute value, with an overall numerical coefficient taken outside the absolute value operator. For example:
345

346
```Julia
347
julia> Algebra.abs(-3/4)
348
0.75
349

350
julia> Algebra.abs(:(2a))
351
:(2 * abs(a))
352

353
julia> Algebra.abs(im)
354
1.0
355

356
julia> Algebra.abs(:(-x))
357
:(abs(x))
358
```
359
""" Reduce.Algebra.abs
360

361
@doc """
362
    ceiling(r)
363

364
This operator returns the ceiling (i.e., the least integer greater than the given argument) if its single argument has a numerical value. A non-numerical argument is returned as an expression in the original operator. For example:
365

366
```Julia
367
julia> Algebra.ceiling(-5/4)
368
-1
369

370
julia> Algebra.ceiling(:(-a))
371
:(ceiling(-a))
372
```
373
""" Reduce.Algebra.ceiling
374

375
@doc """
376
    conj(r)
377

378
This returns the complex conjugate of an expression, if that argument has a numerical value. By default the complex conjugate of a non-numerical argument is returned as an expression in the operators
379
`repart` and `impart`. For example:
380

381
```Julia
382
julia> Algebra.conj(1+im)
383
1 - 1im
384

385
julia> Algebra.conj(:(a+im*b))
386
:(repart(a) - ((impart(a) + repart(b)) * im + impart(b)))
387

388
However, if rules have been previously defined for the complex conjugate(s) of one or more non-numerical terms appearing in the argument, these rules are applied and the expansion in terms of the operators `repart` and `impart` is suppressed.
389

390
For example:
391
```
392
        realvalued a,b;  
393
        conj(a+i*b)   ->   a-b*i  
394
        let conj z => z!*, conj c => c!*;  
395
        conj(a+b*z*z!*+z*c!*)   ->   a+b*z*z* + c*z*  
396
        conj atan z    ->   atan(z*)
397
```
398

399
Note that in defining the rule `conj z => z!*`, the rule `conj z!* => z` is (in effect) automatically defined. Note also that the standard elementary functions and their inverses (where appropriate) are automatically defined to be `selfconjugate` so that `conj(f(z)) => f(conj(z))`. 
400
```
401
""" Reduce.Algebra.conj
402

403
@doc """
404
    factorial(r)
405

406
If the single argument of `factorial` evaluates to a non-negative integer, its factorial is returned. Otherwise an expression involving `factorial` is returned. For example:
407

408
```Julia
409
julia> Algebra.factorial(5)
410
120
411

412
julia> Algebra.factorial(:a)
413
:(factorial(a))
414
```
415
""" Reduce.Algebra.factorial
416

417
@doc """
418
    fix(r)
419

420
This operator returns the fixed value (i.e., the integer part of the given argument) if its single argument has a numerical value. A non-numerical argument is returned as an expression in the original operator. For example:
421

422
```Julia
423
julia> Algebra.fix(-5/4)
424
-1
425

426
julia> Algebra.fix(:a)
427
:(fix(a))
428
```
429
""" Reduce.Algebra.fix
430

431
@doc """
432
    floor(r)
433

434
This operator returns the floor (i.e., the greatest integer less than the given argument) if its single argument has a numerical value. A non-numerical argument is returned as an expression in the original operator. For example:
435

436
```Julia
437
julia> Algebra.floor(-5/4)
438
-2.0
439

440
julia> Algebra.floor(:a)
441
:(floor(a))
442
```
443
""" Reduce.Algebra.floor
444

445
@doc """
446
    impart(r)
447

448
This operator returns the imaginary part of an expression, if that argument has an numerical value. A non-numerical argument is returned as an expression in the operators `repart` and `impart`. For example:
449

450
```Julia
451
julia> Algebra.impart(1+im)
452
1
453

454
julia> Algebra.impart(:(a+im*b))
455
:(impart(a) + repart(b))
456
```
457
""" Reduce.Algebra.impart
458

459
@doc """
460
    nextprime(r)
461

462
`nextprime` returns the next prime greater than its integer argument, using a probabilistic algorithm. A type error occurs if the value of the argument is not an integer. For example:
463

464
```Julia
465
julia> Algebra.nextprime(5)
466
7
467

468
julia> Algebra.nextprime(-2)
469
2
470

471
julia> Algebra.nextprime(-7)
472
-5
473

474
julia> Algebra.nextprime(1000000)
475
1000003
476
```
477
whereas `Algebra.nextprime(:a)` gives a type error.
478
""" Reduce.Algebra.nextprime
479

480
@doc """
481
    random(r)
482

483

484
`random(n)` returns a random number ``r`` in the range ``0 ≤ r < n``. A type error occurs if the value of the argument is not a positive integer in algebraic mode, or positive number in symbolic mode. For example:
485

486
```Julia
487
julia> Algebra.random(5)
488
3
489

490
julia> Algebra.random(1000)
491
191
492
```
493
whereas `Algebra.random(:a)` gives a type error.
494
""" Reduce.Algebra.random
495

496
@doc """
497
    random_new_seed(r)
498

499
`random_new_seed(n)` reseeds the random number generator to a sequence determined by the integer argument `n`. It can be used to ensure that a repeatable pseudo-random sequence will be delivered regardless of any previous use of `random`, or can be called early in a run with an argument derived from something variable (such as the time of day) to arrange that different runs of a REDUCE program will use different random sequences. When a fresh copy of REDUCE is first created it is as if `random_new_seed(1)` has been obeyed.
500

501
A type error occurs if the value of the argument is not a positive integer.
502
""" Reduce.Algebra.random_new_seed
503

504
@doc """
505
    repart(r)
506

507
This returns the real part of an expression, if that argument has an numerical value. A non-numerical argument is returned as an expression in the operators `repart` and `impart`. For example:
508

509
```Julia
510
julia> Algebra.repart(1+im)
511
1
512

513
julia> Algebra.repart(:(a+im*b))
514
:(repart(a) - impart(b))
515
```
516
""" Reduce.Algebra.repart
517

518
@doc """
519
    round(r)
520

521
This operator returns the rounded value (i.e, the nearest integer) of its single argument if that argument has a numerical value. A non-numeric argument is returned as an expression in the original operator. For example:
522

523
```Julia
524
julia> Algebra.round(-5/4)
525
-1.0
526

527
julia> Algebra.round(:a)
528
:(round(a))
529
```
530
""" Reduce.Algebra.round
531

532
@doc """
533
    sign(r)
534

535
`sign` tries to evaluate the sign of its argument. If this is possible `sign` returns one of `1`, `0` or `-1`. Otherwise, the result is the original form or a simplified variant. For example:
536

537
```Julia
538
julia> Algebra.sign(-5)
539
-1
540

541
julia> Algebra.sign(:(-a^2*b))
542
:(-(sign(b)))
543
```
544
Note that even powers of formal expressions are assumed to be positive only as long as the switch `complex` is off.
545
""" Reduce.Algebra.sign
546

547
@doc """
548
    bernoulli(n)
549

550
The unary operator `bernoulli` provides notation and computation for Bernoulli numbers. `bernoulli(n)` evaluates to the `n`th Bernoulli number; all of the odd Bernoulli numbers, except `bernoulli(1)`, are zero.
551

552
The algorithms are based upon those by Herbert Wilf, presented by Sandra Fillebrown [?]. If the `rounded` switch is off, the algorithms are exactly those; if it is on, some further rounding may be done to prevent computation of redundant digits. Hence, these functions are particularly fast when used to approximate the Bernoulli numbers in rounded mode.
553
""" Reduce.Algebra.bernoulli
554

555
@doc """
556
    fibonacci(n)
557

558
The unary operator `fibonacci` provides notation and computation for Fibonacci numbers. `fibonacci(n)` evaluates to the `n`th Fibonacci number. If `n` is a positive or negative integer, it will be evaluated following the definition:
559

560
\$F_0 = 0; F_1 = 1; F_n = F_{n-1} + F_{n-2}\$
561
""" Reduce.Algebra.fibonacci
562

563
@doc """
564
    motzkin(n)
565

566
A Motzkin number \$M_n\$ (named after Theodore Motzkin) is the number of different ways of drawing non-intersecting chords on a circle between n points. For a non-negative integer `n`, the operator `motzkin(n)` returns the `n`th Motzkin number, according to the recursion formula
567

568
\$M_0 =  1;  M_1 = 1;  M_{n+1}  =  \\frac{2n+3}{n+3}M_n + \\frac{3n}{n+3}M_{n-1}.\$
569
""" Reduce.Algebra.motzkin
570

571
@doc """
572
    saveas(expr)
573

574
If the user wishes to assign the workspace to a variable or expression for later use, the `saveas` statement can be used. It has the syntax
575
```Julia
576
R"saveas ⟨expression⟩"
577
```
578
For example, after the differentiation in the last example, the workspace holds the expression `2*x+2*y`. If we wish to assign this to the variable `z` we can now say
579
```Julia
580
julia> Algebra.saveas(:z)
581
```
582
If the user wishes to save the expression in a form that allows him to use some of its variables as arbitrary parameters, the `for all` command can be used.
583

584
*Example:*
585
```Julia
586
R"for all x saveas h(x)"
587
```
588
with the above expression would mean that `h(z)` evaluates to `2*y+2*z`.
589
""" Reduce.Algebra.saveas
590

591
@doc """
592
    decompose(p)
593

594
The `decompose` operator takes a multivariate polynomial as argument, and returns an expression and a list of equations from which the original polynomial can be found by composition. Its syntax is:
595
```Julia
596
R"decompose(EXPRN:polynomial)"
597
```
598
For example:
599
```Julia
600
julia> Algebra.decompose(:(x^8-88*x^7+2924*x^6-43912*x^5+263431*x^4-218900*x^3+65690*x^2-7700*x+234))
601
(:(u ^ 2 + 35u + 234), :(u = v ^ 2 + 10v), :(v = x ^ 2 - 22x))
602

603
julia> Algebra.decompose(:(u^2+v^2+2u*v+1))
604
(:(w ^ 2 + 1), :(w = u + v))
605
```
606
Users should note however that, unlike factorization, this decomposition is not unique.
607
""" Reduce.Algebra.decompose
608

609 0
den(r::T) where T <: Number = den(RExpr(r)) |> parse
610

611
@doc """
612
    den(r)
613

614
This is used with the syntax:
615
```Julia
616
R"den(EXPRN:rational)"
617
```
618
It returns the denominator of the rational expression `EXPRN`. If `EXPRN` is a polynomial, 1 is returned.
619

620
*Examples:*
621
```Julia
622
julia> Algebra.den(:(x/y^2))
623
:(y ^ 2)
624

625
julia> Algebra.den(100//6)
626
3               [since 100/6 is first simplified to 50/3]  
627

628
julia> Algebra.den(:(a/4+b/6))
629
12
630

631
julia> Algebra.den(:(a+b))
632
1
633
```
634
""" Reduce.Algebra.den
635

636 0
mainvar(r::T) where T <: Number = mainvar(RExpr(r)) |> parse
637

638
@doc """
639
    mainvar(exprn)
640

641
Syntax:
642
```Julia
643
R"mainvar(EXPRN:polynomial)"
644
```
645
Returns the main variable (based on the internal polynomial representation) of `EXPRN`. If `EXPRN` is a domain element, 0 is returned.
646

647
*Examples:* Assuming `a` has higher kernel order than `b`, `c`, or `d`:
648
```Julia
649
julia> Algebra.on(:exp)
650

651
julia> Algebra.mainvar(:((a+b)*(c+2*d)^2))
652
:a
653

654
julia> Algebra.mainvar(2)
655
0
656
```
657
""" Reduce.Algebra.mainvar
658

659 0
num(r::T) where T <: Number = num(RExpr(r)) |> parse
660

661
@doc """
662
    num(exprn)
663

664
Syntax:
665
```Julia
666
R"num(EXPRN:rational)"
667
```
668
Returns the numerator of the rational expression `EXPRN`. If `EXPRN` is a polynomial, that polynomial is returned.
669

670
*Examples:*
671
```Julia
672
julia> Algebra.num(:(x/y^2))
673
:x
674

675
julia> Algebra.num(100//6)
676
50
677

678
julia> Algebra.num(:(a/4+b/6))
679
:(3a + 2b)
680

681
julia> Algebra.num(:(a+b))
682
:(a + b)
683
```
684
""" Reduce.Algebra.num
685

686 0
setmod(r::Integer) = setmod(RExpr(r)) |> parse
687

688
@doc """
689
    setmod(::Integer)
690

691
REDUCE includes facilities for manipulating polynomials whose coefficients are computed modulo a given base. To use this option, two commands must be used; `R"setmod ⟨integer⟩"`, to set the prime modulus, and `on(:modular)` to cause the actual modular calculations to occur. For example, with `R"setmod 3"` and `R"on modular"`, the polynomial `(a+2*b)^3` would become `a^3+2*n^3`.
692

693
The argument of `setmod` is evaluated algebraically, except that non-modular (integer) arithmetic is used. Thus the sequence
694
```Julia
695
R"setmod 3; on modular; setmod 7"
696
```
697
will correctly set the modulus to 7.
698
""" Reduce.Algebra.setmod
699

700
@doc """
701
    root_val(exprn)
702

703
The `root_val` operator takes a single univariate polynomial as argument, and returns a list of root values at system precision (or greater if required to separate roots). It is used with the syntax
704
```Julia
705
R"root_val(EXPRN:univariate polynomial)"
706
```
707
For example, the sequence
708
```Julia
709
reduce> on rounded; root_val(x^3-x-1);
710
```
711
gives the result
712
```
713
{0.562279512062*I - 0.662358978622, - 0.562279512062*I  
714
 
715
  - 0.662358978622,1.32471795724}
716
```
717
""" Reduce.Algebra.root_val
718

719
@doc """
720
    clearrules(r)
721

722
`clearrules` has the syntax
723
```Julia
724
R"clearrules <rule list>|<name of rule list>(,...)"
725
```
726
""" Reduce.Algebra.clearrules
727

728
@doc """
729
    showrules(r)
730

731
The operator `showrules` takes a single identifier as argument, and returns in rule-list form the operator rules associated with that argument. For example:
732
```Julia
733
reduce> showrules log;  
734
 
735
{log(e) => 1,  
736
 
737
 log(1) => 0,  
738
 
739
      ~x  
740
 log(e  ) => ~x,  
741
 
742
                    1  
743
 df(log(~x),~x) => ----}  
744
                    ~x
745
```
746
Such rules can then be manipulated further as with any list. For example `R"rhs first ws"` has the value `1`. Note that an operator may have other properties that cannot be displayed in such a form, such as the fact it is an odd function, or has a definition defined as a procedure.
747
""" Reduce.Algebra.showrules
748

749
@doc """
750
    det(exprn)
751

752
Syntax:
753
```
754
        det(EXPRN:matrix_expression):algebraic.
755
```
756
The operator `det` is used to represent the determinant of a square matrix expression. E.g.,
757
```
758
Algebra.det(:(y^2))
759
```
760
is a scalar expression whose value is the determinant of the square of the matrix `y`, and
761
```
762
Algebra.det([:a :b :c; :d :e :f; :g :h :j])
763
```
764
is a scalar expression whose value is the determinant of the matrix
765
```Julia
766
3×3 Array{Symbol,2}:
767
 :a  :b  :c
768
 :d  :e  :f
769
 :g  :h  :j
770
```
771
Determinant expressions have the instant evaluation property. In other words, the statement
772
```
773
        let det mat((a,b),(c,d)) = 2;
774
```
775
sets the value of the determinant to `2`, and does not set up a rule for the determinant itself.
776
""" Reduce.Algebra.det
777

778
@doc """
779
    trace(exprn)
780

781
Syntax:
782
```
783
        TRACE(EXPRN:matrix_expression):algebraic.
784
```
785
The operator TRACE is used to represent the trace of a square matrix.
786
""" Reduce.Algebra.trace
787

788
@doc """
789
    nullspace(exprn)
790

791
Syntax:
792
```
793
        NULLSPACE(EXPRN:matrix_expression):list
794
```
795
`nullspace` calculates for a matrix `a` a list of linear independent vectors (a basis) whose linear combinations satisfy the equation \$Ax = 0\$. The basis is provided in a form such that as many upper components as possible are isolated.
796

797
Note that with `b := nullspace a` the expression `length b` is the *nullity* of `a`, and that `second length a - length b` calculates the *rank* of `a`. The rank of a matrix expression can also be found more directly by the `rank` operator described below.
798

799
*Example:* The command
800
```
801
        nullspace mat((1,2,3,4),(5,6,7,8));
802
```
803
gives the output
804
```
805
        {  
806
         [ 1  ]  
807
         [ 0  ]  
808
         [ - 3]  
809
         [ 2  ]  
810
         ,  
811
         [ 0  ]  
812
         [ 1  ]  
813
         [ - 2]  
814
         [ 1  ]  
815
         }
816
```
817
In addition to the REDUCE matrix form, `nullspace` accepts as input a matrix given as a list of lists, that is interpreted as a row matrix. If that form of input is chosen, the vectors in the result will be represented by lists as well. This additional input syntax facilitates the use of `nullspace` in applications different from classical linear algebra.
818
""" Reduce.Algebra.nullspace
819

820
@doc """
821
    rank(exprn)
822

823
Syntax:
824
```
825
        RANK(EXPRN:matrix_expression):integer
826
```
827
`rank` calculates the rank of its argument, that, like `nullspace` can either be a standard matrix expression, or a list of lists, that can be interpreted either as a row matrix or a set of equations.
828

829
*Example:*
830
```Julia
831
Algebra.rank([:a :b :c; :d :e :f])
832
```
833
returns the value `2`.
834
""" Reduce.Algebra.rank

Read our documentation on viewing source code .

Loading