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

8

for fun in [sbas;sdep;sfun;snum;scom;sint;sran;sbat;smat;[:length]]

148

10

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

14

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

14

$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

14

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 toplevel 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

14

length(r::Expr) = length(r > RExpr) > parse > eval

202



203


for fun in snan

204


nfun = fun ≠ :rlet ? fun : :let

205


@eval begin

206

14

$fun(r::RExpr) = string($(string(nfun)),"(",string(r),")") > rcall > RExpr

207

14

$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 `nm`, but not `m` by `nl`. 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

14

rlet(r::Dict{String,String}) = rlet(sub_list(r))

263

14

rlet(s::Dict{<:Any,<:Any}) = rlet(Dict([=>(string.(RExpr.([b[1],b[2]]))...) for b ∈ collect(s)]...))

264

14

rlet(s::Pair{<:Any,<:Any}) = rlet(Tuple([s]))

265

14

rlet(s::T) where T <: Tuple = rlet(RExpr(s)) > parse

266

14

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 fixedpoint 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

14

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

14

$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

14

x > RExpr > $fun > parse > eval

305


end

306


end

307


end

308



309

4

function bernoulli(n::T) where T <: Integer

310

14

bernoulli(RExpr(n)) > parse > eval

311


end

312



313


@doc """

314


lhs(::Union{Expr,RExpr})

315



316


Returns the lefthand 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 righthand 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 nonnumerical 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 nonnumerical 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 nonnumerical 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 deﬁned for the complex conjugate(s) of one or more nonnumerical 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) > ab*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 deﬁning the rule `conj z => z!*`, the rule `conj z!* => z` is (in eﬀect) automatically deﬁned. Note also that the standard elementary functions and their inverses (where appropriate) are automatically deﬁned 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 nonnegative 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 nonnumerical 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 nonnumerical 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 nonnumerical 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 pseudorandom 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 nonnumerical 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 nonnumeric 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_{n1} + F_{n2}\$

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 nonintersecting chords on a circle between n points. For a nonnegative 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_{n1}.\$

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^888*x^7+2924*x^643912*x^5+263431*x^4218900*x^3+65690*x^27700*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 nonmodular (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^3x1);

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 rulelist 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
