Skip to content

Commit

Permalink
updated documentation and test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
chakravala committed Apr 15, 2018
1 parent 623a45e commit fa13646
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 53 deletions.
69 changes: 50 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ Interface for applying symbolic manipulation on [Julia expressions](https://docs
* interface link communicates and interprets via various reduce output modes using `rcall` method;
* high-level reduce-julia syntax parser-generator walks arbitrary expression to rewrite mathematical code;
* import operators from REDUCE using code generation to apply to arbitrary computational expressions;
* interactive `reduce>` REPL within the Julia terminal window activated by `}` key.
* interactive `reduce>` REPL within the Julia terminal window activated by `}` key;
* extended arithmetic operators `+`,`-`,`*`,`^`,`/`,`//` compute on `Symbol` and `Expr` types;
* provides over 330 internal and external methods each supporting many argument types.

## Setup

Expand All @@ -53,31 +55,46 @@ View the documentation [stable](https://chakravala.github.io/Reduce.jl/stable) /

Reduce expressions encapsulated into `RExpr` objects can be manipulated within julia using the standard syntax. Create an expression object either using the `RExpr("expression")` string constructor or `R"expression"`. Additionally, arbitrary julia expressions can also be parsed directly using the `RExpr(expr)` constructor. Internally `RExpr` objects are represented as an array that can be accessed by calling `*.str[n]` on the object.

Sequences of reduce statements are automatically parsed into julia `quote` blocks using the `RExpr` constructor, which can `parse` back into a julia expression.
When `Reduce` is used in Julia, all of the standard arithmetic operations are now extended to also work on `Symbol` and `Expr` types.
```Julia
julia> :((x+im+π)^2; int(1/(1+x^3),x)) |> RExpr
^(+(x,i,pi),2);
int(/(1,+(1,^(x,3))),x);
julia> 1-1/:n
:((n - 1) // n)

julia> rcall(ans,:expand) |> parse
quote
(((π + 2x) * π + x ^ 2) - 1) + 2 *+ x) * im
((2 * sqrt(3) * atan((2x - 1) // sqrt(3)) - log((x ^ 2 - x) + 1)) + 2 * log(x + 1)) // 6
end
```
Call `split(::RExpr)` to create a new `RExpr` object with all expressions split into separate array elements.
julia> ans^-:n
:(1 // ((n - 1) // n) ^ n)

julia> limit(ans,:n,Inf)
e = 2.7182818284590...
```
Julia abstract syntax trees are automatically converted into sequences of reduce statements that are in return parsed into julia `quote` blocks using the `RExpr` constructor.
The `rcall` method is used to evaluate any type of expression.
```Julia
julia> :(int(sin(im*x+pi)^2-1,x)) |> rcall
:(-(((e ^ (4x) + 4 * e ^ (2x) * x) - 1)) // (8 * e ^ (2x)))
:((1 - (e ^ (4x) + 4 * e ^ (2x) * x)) // (8 * e ^ (2x)))
```
However, there are often multiple equivalent ways of achieving the same result:
```Julia
julia> int(sin(im*:x+π)^2-1,:x)
:((1 - (e ^ (4x) + 4 * e ^ (2x) * x)) // (8 * e ^ (2x)))
```
The output of `rcall` will be the same as its input type.
```Julia
julia> "int(sin(y)^2, y)" |> rcall
"( - cos(y)*sin(y) + y)/2"
```
Use `rcall(expr,switches...)` to evaluate `expr` using REDUCE mode `switches` like `:expand`, `:factor`, and `:latex`.
```Julia
julia> :((x+im+π)^2; int(1/(1+x^3),x)) |> RExpr
^(+(x,i,pi),2);
int(/(1,+(1,^(x,3))),x);

julia> rcall(ans,:horner) |> parse
quote
((π + 2x) * π + 2 *+ x) * im + x ^ 2) - 1
((2 * sqrt(3) * atan((2x - 1) // sqrt(3)) - log((x ^ 2 - x) + 1)) + 2 * log(x + 1)) // 6
end
```
Call `split(::RExpr)` to create a new `RExpr` object with all expressions internally split into separate array elements.

Mathematical operators and REDUCE modes can be applied directly to `Expr` and `RExpr` objects.
```Julia
Expand All @@ -91,11 +108,23 @@ Although not all language features have been implemented yet, it is possible to
julia> Expr(:for,:(i=2:34),:(product(i))) |> rcall
:(@big_str "295232799039604140847618609643520000000")
```
The `squash` function provides a way to reduce full program blocks into simplified functions,
```Julia
julia> Expr(:function,:(example(a,b)),quote
z = 3
target = z * :a * :b
z -= 1
target += z*(1-:a)*(1-:b)
end) |> squash |> factor
:(function example(a, b)
(5b - 2) * a - 2 * (b - 1)
end)
```

### Output mode
Various output modes are supported. While in the REPL, the default `nat` output mode will be displayed for `RExpr` objects.
```Julia
julia> :(sin(x*im) + cos(y*φ)) |> RExpr
```Julia
julia> :(sin(x*im) + cos(y*φ)) |> RExpr

(sqrt(5) + 1)*y
cos(-----------------) + sinh(x)*i
Expand All @@ -105,14 +134,14 @@ This same output can also be printed to the screen by calling `print(nat(r))` me

It is possible to direclty convert a julia expression object to LaTeX code using the `latex` method.
```Julia
julia> print(@latex sin(x*im) + cos(y*φ))
julia> print(@latex sin(x) + cos(y*φ))
\begin{displaymath}
\cos \left(\left(\left(\sqrt {5}+1\right) y\right)/2\right)+\sinh \,x\: i
\cos \left(\left(\left(\sqrt {5}+1\right) y\right)/2\right)+\sin \,x
\end{displaymath}
```
Internally, this command essentially expands to `rcall(:(sin(x*im) + cos(y*φ)),:latex) |> print`, which is equivalent.
Internally, this command essentially expands to `rcall(:(sin(x) + cos(y*φ)),:latex) |> print`, which is equivalent.

![latex-equation](https://latex.codecogs.com/svg.latex?\cos&space;\left(\left(\left(\sqrt&space;{5}+1\right)&space;y\right)/2\right)+\sinh&space;x\:&space;i)
![latex-equation](https://latex.codecogs.com/svg.latex?\cos&space;\left(\left(\left(\sqrt&space;{5}+1\right)&space;y\right)/2\right)+\sin&space;x)

In `IJulia` the display output of `RExpr` objects will be rendered LaTeX with the `rlfi` REDUCE package in `latex` mode.

Expand Down Expand Up @@ -145,6 +174,8 @@ Releases of `Reduce.jl` enable the general application of various REDUCE functio

If the `reduce>` REPL is not appearing when `}` is pressed or the `Reduce.PSL` pipe is broken, the session can be restored by simply calling `Reduce.Reset()`, without requiring a restart of `julia` or reloading the package. This kills the currently running `redpsl` session and then re-initializes it for new use.

Otherwise, questions can be asked on gitter/discourse or submit your issue or pull-request if you require additional features or noticed some unusual edge-case behavior.

### OhMyREPL Compatibility

Reduce.jl is compatible with the [OhMyREPL.jl](https://github.com/KristofferC/OhMyREPL.jl) package.
Expand Down
2 changes: 1 addition & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ deploydocs(
branch = "gh-pages",
latest = "master",
osname = "linux",
julia = "0.5",
julia = "0.6",
deps = nothing,
make = nothing,
)
79 changes: 55 additions & 24 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ Interface for applying symbolic manipulation on [Julia expressions](https://docs
* high-level reduce-julia syntax parser-generator walks arbitrary expression to rewrite mathematical code;
* import operators from REDUCE using code generation to apply to arbitrary computational expressions;
* interactive `reduce>` REPL within the Julia terminal window activated by `}` key.
* extended arithmetic operators `+`,`-`,`*`,`^`,`/`,`//` compute on `Symbol` and `Expr` types;
* provides over 330 internal and external methods each supporting many argument types.

## Setup

Expand Down Expand Up @@ -69,31 +71,46 @@ Releases of `Reduce.jl` enable the general application of various REDUCE functio

Reduce expressions encapsulated into `RExpr` objects can be manipulated within julia using the standard syntax. Create an expression object either using the `RExpr("expression")` string constructor or `R"expression"`. Additionally, arbitrary julia expressions can also be parsed directly using the `RExpr(expr)` constructor. Internally `RExpr` objects are represented as an array that can be accessed by calling `*.str[n]` on the object.

Sequences of reduce statements are automatically parsed into julia `quote` blocks using the `RExpr` constructor, which can `parse` back into a julia expression.
When `Reduce` is used in Julia, all of the standard arithmetic operations are now extended to also work on `Symbol` and `Expr` types.
```Julia
julia> :((x+im+π)^2; int(1/(1+x^3),x)) |> RExpr
^(+(x,i,pi),2);
int(/(1,+(1,^(x,3))),x);
julia> 1-1/:n
:((n - 1) // n)

julia> rcall(ans,:expand) |> parse
quote
(((π + 2x) * π + x ^ 2) - 1) + 2 *+ x) * im
((2 * sqrt(3) * atan((2x - 1) // sqrt(3)) - log((x ^ 2 - x) + 1)) + 2 * log(x + 1)) // 6
end
```
Call `split(::RExpr)` to create a new `RExpr` object with all expressions split into separate array elements.
julia> ans^-:n
:(1 // ((n - 1) // n) ^ n)

julia> limit(ans,:n,Inf)
e = 2.7182818284590...
```
Julia abstract syntax trees are automatically converted into sequences of reduce statements that are in return parsed into julia `quote` blocks using the `RExpr` constructor.
The `rcall` method is used to evaluate any type of expression.
```Julia
julia> :(int(sin(im*x+pi)^2-1,x)) |> rcall
:(-(((e ^ (4x) + 4 * e ^ (2x) * x) - 1)) // (8 * e ^ (2x)))
:((1 - (e ^ (4x) + 4 * e ^ (2x) * x)) // (8 * e ^ (2x)))
```
However, there are often multiple equivalent ways of achieving the same result:
```Julia
julia> int(sin(im*:x+π)^2-1,:x)
:((1 - (e ^ (4x) + 4 * e ^ (2x) * x)) // (8 * e ^ (2x)))
```
The output of `rcall` will be the same as its input type.
```Julia
julia> "int(sin(y)^2, y)" |> rcall
"( - cos(y)*sin(y) + y)/2"
```
Use `rcall(expr,switches...)` to evaluate `expr` using REDUCE mode `switches` like `:expand`, `:factor`, and `:latex`.
```Julia
julia> :((x+im+π)^2; int(1/(1+x^3),x)) |> RExpr
^(+(x,i,pi),2);
int(/(1,+(1,^(x,3))),x);

julia> rcall(ans,:horner) |> parse
quote
((π + 2x) * π + 2 *+ x) * im + x ^ 2) - 1
((2 * sqrt(3) * atan((2x - 1) // sqrt(3)) - log((x ^ 2 - x) + 1)) + 2 * log(x + 1)) // 6
end
```
Call `split(::RExpr)` to create a new `RExpr` object with all expressions internally split into separate array elements.

Mathematical operators and REDUCE modes can be applied directly to `Expr` and `RExpr` objects.
```Julia
Expand All @@ -107,28 +124,40 @@ Although not all language features have been implemented yet, it is possible to
julia> Expr(:for,:(i=2:34),:(product(i))) |> rcall
:(@big_str "295232799039604140847618609643520000000")
```
The `squash` function provides a way to reduce full program blocks into simplified functions,
```Julia
julia> Expr(:function,:(example(a,b)),quote
z = 3
target = z * :a * :b
z -= 1
target += z*(1-:a)*(1-:b)
end) |> squash |> factor
:(function example(a, b)
(5b - 2) * a - 2 * (b - 1)
end)
```

### Output mode
Various output modes are supported. While in the REPL, the default `nat` output mode will be displayed for `RExpr` objects.
```Julia
julia> :(sin(x*im) + cos(y*φ)) |> RExpr

(sqrt(5) + 1)*y
cos(-----------------) + sinh(x)*i
2
(sqrt(5) + 1)*y
cos(-----------------) + sinh(x)*i
2
```
This same output can also be printed to the screen by calling `print(nat(r))` method.

It is possible to direclty convert a julia expression object to LaTeX code using the `latex` method.
```Julia
julia> print(@latex sin(x*im) + cos(y*φ))
julia> print(@latex sin(x) + cos(y*φ))
\begin{displaymath}
\cos \left(\left(\left(\sqrt {5}+1\right) y\right)/2\right)+\sinh \,x\: i
\cos \left(\left(\left(\sqrt {5}+1\right) y\right)/2\right)+\sin \,x
\end{displaymath}
```
Internally, this command essentially expands to `rcall(:(sin(x*im) + cos(y*φ)),:latex) |> print`, which is equivalent.
Internally, this command essentially expands to `rcall(:(sin(x) + cos(y*φ)),:latex) |> print`, which is equivalent.

![latex-equation](https://latex.codecogs.com/svg.latex?\cos&space;\left(\left(\left(\sqrt&space;{5}+1\right)&space;y\right)/2\right)+\sinh&space;x\:&space;i)
![latex-equation](https://latex.codecogs.com/svg.latex?\cos&space;\left(\left(\left(\sqrt&space;{5}+1\right)&space;y\right)/2\right)+\sin&space;x)

In `IJulia` the display output of `RExpr` objects will be rendered LaTeX with the `rlfi` REDUCE package in `latex` mode.

Expand All @@ -137,17 +166,19 @@ Similar to <kbd>?</kbd> help and <kbd>;</kbd> shell modes in Julia, `Reduce` pro
```Julia
reduce> df(atan(golden_ratio*x),x);

2 2
sqrt(5)*x + sqrt(5) - x + 1
-------------------------------
4 2
2*(x + 3*x + 1)
2 2
sqrt(5)*x + sqrt(5) - x + 1
-------------------------------
4 2
2*(x + 3*x + 1)
```

## Troubleshooting

If the `reduce>` REPL is not appearing when `}` is pressed or the `Reduce.PSL` pipe is broken, the session can be restored by simply calling `Reduce.Reset()`, without requiring a restart of `julia` or reloading the package. This kills the currently running `redpsl` session and then re-initializes it for new use.

Otherwise, questions can be asked on gitter/discourse or submit your issue or pull-request if you require additional features or noticed some unusual edge-case behavior.

### OhMyREPL Compatibility

Reduce.jl is compatible with the [OhMyREPL.jl](https://github.com/KristofferC/OhMyREPL.jl) package.
Expand Down
42 changes: 35 additions & 7 deletions docs/src/library.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,29 +30,41 @@ parse
load_package
```

```@docs
sub
```

```@docs
squash
```

## Imported Operators

Reduce `switch` modes callable as functions from Julia
> :expand, :complex, :factor, :expandlog, :combinelog, :precise, :combineexpt, :rounded, :evallhseq, :nat, :latex
> expand, complex, factor, horner, expandlog, combinelog, precise, combineexpt, rounded, evallhseq, nat, latex
Calculus operators
> :df, :int
Reduce operators with multiple arguments
> df, int, limit, sum, prod, +, -, ^, *, /, //
Unary operators
> :abs, :conj, :factorial, :floor, :max, :min, :round, :sign, :acos, :acosh, :acot, :acoth, :acsc, :acsch, :asec, :asech, :asin, :asinh, :atan, :atanh, :atan2, :cos, :cosh, :cot, :coth, :csc, :csch, :exp, :hypot, :log, :log10, :sec, :sech, :sin, :sinh, :sqrt, :tan, :tanh, :gamma, :factorize
> abs, conj, factorial, floor, max, min, round, sign, acos, acosh, acot, acoth, acsc, acsch, asec, asech, asin, asinh, atan, atanh, atan2, cos, cosh, cot, coth, csc, csch, exp, hypot, log, log10, sec, sech, sin, sinh, sqrt, tan, tanh, gamma, factorize
> :beta, :besseli, :besselj, :besselk, :bessely, :polygamma, :zeta
> beta, besseli, besselj, besselk, bessely, polygamma, zeta
> :ibeta, :igamma, :ln, :psi, :bernoulli, :continued_fraction, :ci, :dilog, :ei, :si, :airy_ai, :airy_aiprime, :airy_bi, :airy_biprime, :hanekl1, :hankel2, :kummerm, :kummeru, :lommel1, :lommel2, :struveh, :struvel, :whittakerm, :whittakeru, :solidharmonicy, :sphericalharmonicy
> ibeta, igamma, ln, psi, bernoulli, continued_fraction, ci, dilog, ei, si, airy_ai, airy_aiprime, airy_bi, airy_biprime, hanekl1, hankel2, kummerm, kummeru, lommel1, lommel2, struveh, struvel, whittakerm, whittakeru, solidharmonicy, sphericalharmonicy
> :ceiling, :fix, :impart, :repart, :nextprime, :euler, :fibonacci, :motzkin, :random, :random_new_seed
> ceiling, fix, impart, repart, nextprime, euler, fibonacci, motzkin, random, random_new_seed
## Tools & Options

```@docs
Reduce.parsegen
```

```@docs
Reduce.unfoldgen
```

```@docs
Reduce.linefilter
```
Expand All @@ -64,3 +76,19 @@ Reduce.Rational
```@docs
Reduce.SubCall
```

```@docs
Reduce.SubHold
```

```@docs
Reduce.SubFail
```

```@docs
Reduce.ColCheck
```

```@docs
Reduce.DisplayLog
```
2 changes: 1 addition & 1 deletion src/parser.jl
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,7 @@ end
"""
unfoldgen(::Symbol,::Symbol)
Parser generator that outputs code to walk and manipulate REDUCE expressions
Parser generator that outputs code to walk and manipulate Julia expressions
"""
function unfoldgen(fun::Symbol,mode::Symbol)
modefun = Symbol(:parse,"_",mode)
Expand Down
17 changes: 16 additions & 1 deletion src/rexpr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,23 @@ const repjlr = jl_to_r_utf
const gexrjl = Regex("($(join(keys(r_to_jl),")|(")))")
const gexjlr = Regex("($(join(keys(jl_to_r),")|(")))")

"""
sub(::Union{Dict,Pair},expr)
Make variable substitutions using Reduce's native sub command
"""
sub(syme::String,expr::RExpr) = "sub($syme,$expr)" |> rcall |> RExpr
sub(syme::String,expr::T) where T = convert(T,sub(syme,RExpr(expr)))
sub(s::Dict{String,String},expr) = sub(_syme(s),expr)
sub(s::Dict{<:Any,<:Any},expr) = sub(Dict([=>(string.(RExpr.([b[1],b[2]]))...) for b collect(s)]...),expr)
sub(s::Pair{<:Any,<:Any},expr) = sub(Dict(s),expr)
sub(s::Array{Pair{<:Any,<:Any},1},expr) = sub(Dict(s...),expr)
sub(s::Array{<:Pair{<:Any,<:Any},1},expr) = sub(Dict(s...),expr)

"""
sub(T::DataType,expr::Expr)
Make a substitution to conver numerical values to type T
"""
function sub(T::DataType,ixpr)
if typeof(ixpr) == Expr
expr = deepcopy(ixpr)
Expand Down Expand Up @@ -465,6 +475,11 @@ end
end
end=#

"""
squash(expr)
Reduces an entire program statement block using symbolic rewriting
"""
function squash(expr)
typeof(expr) == Expr && if expr.head == :block
return @eval $expr
Expand Down
Loading

0 comments on commit fa13646

Please sign in to comment.