Skip to content

Commit

Permalink
transitioned to Reduce and 0.6
Browse files Browse the repository at this point in the history
  • Loading branch information
chakravala committed Jul 6, 2018
1 parent 0b62815 commit eae3113
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 138 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 4,6 @@ os:
- linux
- osx
julia:
- 0.5
- 0.6
- nightly
matrix:
Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 2,14 @@

[![Build Status](https://travis-ci.org/chakravala/Fatou.jl.svg?branch=master)](https://travis-ci.org/chakravala/Fatou.jl) [![Build status](https://ci.appveyor.com/api/projects/status/mdathjmu7jg57u77?svg=true)](https://ci.appveyor.com/project/chakravala/fatou-jl) [![Coverage Status](https://coveralls.io/repos/github/chakravala/Fatou.jl/badge.svg?branch=master)](https://coveralls.io/github/chakravala/Fatou.jl?branch=master) [![codecov.io](http://codecov.io/github/chakravala/Fatou.jl/coverage.svg?branch=master)](http://codecov.io/github/chakravala/Fatou.jl?branch=master)

Julia package for Fatou sets. Install using `Pkg.add("Fatou")` in Julia. See [Explore Fatou sets & Fractals](https://github.com/chakravala/Fatou.jl/wiki/Explore-Fatou-sets-&-fractals) in Wiki for detailed *examples*. This package provides: `fatou`, `juliafill`, `mandelbrot`, `newton`, `basin`, `plot`, and `orbit`; along with various internal functionality using `SymPy` and Julia expressions to help compute `Fatou.FilledSet` efficiently. Full documentation is included. The `fatou` function can be applied to a `Fatou.Define` object to produce a `Fatou.FilledSet`, which can then be passed as an argument to the `plot` function of `PyPlot`. Creation of `Fatou.Define` objects is done via passing a `parse`-able function expression string (in variables `z`, `c`) and optional keyword arguments to `juliafill`, `mandelbrot`, and `newton`.
Julia package for Fatou sets. Install using `Pkg.add("Fatou")` in Julia. See [Explore Fatou sets & Fractals](https://github.com/chakravala/Fatou.jl/wiki/Explore-Fatou-sets-&-fractals) in Wiki for detailed *examples*. This package provides: `fatou`, `juliafill`, `mandelbrot`, `newton`, `basin`, `plot`, and `orbit`; along with various internal functionality using `Reduce` and Julia expressions to help compute `Fatou.FilledSet` efficiently. Full documentation is included. The `fatou` function can be applied to a `Fatou.Define` object to produce a `Fatou.FilledSet`, which can then be passed as an argument to the `plot` function of `PyPlot`. Creation of `Fatou.Define` objects is done via passing a `parse`-able function expression string (in variables `z`, `c`) and optional keyword arguments to `juliafill`, `mandelbrot`, and `newton`.

## Basic Usage

Another feature is a plot function designed to visualize real-valued-orbits. The following is a cobweb orbit plot of a function:

```Julia
juliafill("z^2-0.67",∂=[-1.25,1.5],x0=1.25,orbit=17,depth=3,n=147) |> orbit
juliafill(:(z^2-0.67),∂=[-1.25,1.5],x0=1.25,orbit=17,depth=3,n=147) |> orbit
```

![img/orbit.png](img/orbit.png)
Expand All @@ -18,7 18,7 @@ With `fatou` and `plot` it is simple to display a filled in Julia set:

```Julia
c = -0.06 0.67im
nf = juliafill("z^2 $c",∂=[-1.5,1.5,-1,1],N=80,n=1501,cmap="gnuplot",iter=true)
nf = juliafill(:(z^2 $c),∂=[-1.5,1.5,-1,1],N=80,n=1501,cmap="gnuplot",iter=true)
plot(fatou(nf), bare=true)
```

Expand All @@ -27,15 27,15 @@ plot(fatou(nf), bare=true)
It is also possible to switch to `mandelbrot` mode:

```Julia
mandelbrot("z^2 c",n=800,N=20,∂=[-1.91,0.51,-1.21,1.21],cmap="gist_earth") |> fatou |> plot
mandelbrot(:(z^2 c),n=800,N=20,∂=[-1.91,0.51,-1.21,1.21],cmap="gist_earth") |> fatou |> plot
```

![img/mandelbrot.png](img/mandelbrot.png)

`Fatou` also provides `basin` to display the the Newton / Fatou basins using set notation in LaTeX in `IJulia`.

```Julia
map(display,[basin(newton("z^3-1"),i) for i 1:3])
map(display,[basin(newton(:(z^3-1)),i) for i 1:3])
```

![D1(ϵ)](http://latex.codecogs.com/svg.latex?D_1(\epsilon) = \left\\{z\in\mathbb{C}:\left|\\,z - \frac{z^{3} - 1}{3 z^{2}} - r_i\\,\right|<\epsilon,\\,\forall r_i(\\,f(r_i)=0 )\right\\})
Expand All @@ -47,7 47,7 @@ map(display,[basin(newton("z^3-1"),i) for i ∈ 1:3])
Compute the Newton fractal Julia set for a function with annotated plot of iteration count:

```Julia
nf = newton("z^3-1",n=800=0.1,N=25,iter=true,cmap="jet")
nf = newton(:(z^3-1),n=800=0.1,N=25,iter=true,cmap="jet")
nf |> fatou |> plot
basin(nf,3)
```
Expand All @@ -57,7 57,7 @@ basin(nf,3)
Generalized Newton fractal example:

```Julia
nf = newton("sin(z)-1",m=1-1im,∂=[-2π/3,-π/3,-π/6/6],n=500,N=33,iter=true=0.05,cmap="cubehelix")
nf = newton(:(sin(z)-1),m=1-1im,∂=[-2π/3,-π/3,-π/6/6],n=500,N=33,iter=true=0.05,cmap="cubehelix")
nf |> fatou |> plot
basin(nf,2)
```
Expand All @@ -68,4 68,4 @@ basin(nf,2)

## Detailed Explanation

View [Explore Fatou sets & Fractals](https://github.com/chakravala/Fatou.jl/wiki/Explore-Fatou-sets-&-fractals) in Wiki for detailed *examples*.
View [Explore Fatou sets & Fractals](https://github.com/chakravala/Fatou.jl/wiki/Explore-Fatou-sets-&-fractals) in Wiki for detailed *examples*.
6 changes: 3 additions & 3 deletions REQUIRE
Original file line number Diff line number Diff line change
@@ -1,4 1,4 @@
julia 0.5
julia 0.6
SyntaxTree
Reduce
PyPlot
SymPy
Colors
28 changes: 22 additions & 6 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,20 1,31 @@
environment:
matrix:
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.5/julia-0.5-latest-win32.exe"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe"
PYTHONDIR: "use_conda"
PYTHON: "use_conda"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.5/julia-0.5-latest-win64.exe"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe"
PYTHONDIR: "use_conda"
PYTHON: "use_conda"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.7/julia-0.7-latest-win32.exe"
PYTHONDIR: "use_conda"
PYTHON: "use_conda"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.7/julia-0.7-latest-win64.exe"
PYTHONDIR: "use_conda"
PYTHON: "use_conda"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
PYTHONDIR: "use_conda"
PYTHON: "use_conda"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
PYTHONDIR: "use_conda"
PYTHON: "use_conda"
# - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
# - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"

matrix:
allow_failures:
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.7/julia-0.7-latest-win32.exe"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.7/julia-0.7-latest-win64.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"

branches:
only:
- master
Expand All @@ -28,6 39,11 @@ notifications:

install:
- ps: "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12"
# If there's a newer build queued for the same PR, cancel this one
- ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
throw "There are newer queued builds for this pull request, failing early." }
# Download most recent Julia Windows binary
- ps: (new-object net.webclient).DownloadFile(
$env:JULIA_URL,
Expand Down
105 changes: 44 additions & 61 deletions src/Fatou.jl
Original file line number Diff line number Diff line change
@@ -1,15 1,15 @@
module Fatou
using Colors,SymPy,PyPlot,Base.Threads
using SyntaxTree,Reduce,PyPlot,Base.Threads

# This file is part of Fatou.jl. It is licensed under the MIT license
# Copyright (C) 2017 Michael Reed

export fatou, juliafill, mandelbrot, newton, basin, plot

"""
Fatou.Define(::String; # primary map, (z, c) -> F
Q::String = "abs2(z)", # escape criterion, (z, c) -> Q
C::String = "angle(z)/(2π))*n^p", # coloring, (z, n=iter., p=exp.) -> C
Fatou.Define(E::Any; # primary map, (z, c) -> F
Q::Expr = :(abs2(z)), # escape criterion, (z, c) -> Q
C::Expr = :((angle(z)/(2π))*n^p)# coloring, (z, n=iter., p=exp.) -> C
∂ = π/2, # Array{Float64,1} # Bounds, [x(a),x(b),y(a),y(b)]
n::Integer = 176, # horizontal grid points
N::Integer = 35, # max. iterations
Expand All @@ -29,6 29,7 @@ export fatou, juliafill, mandelbrot, newton, basin, plot
`Define` the metadata for a `Fatou.FilledSet`.
"""
type Define
E::Any # input expression
F::Function # primary map
Q::Function # escape criterion
C::Function # complex fixed point coloring
Expand All @@ -40,16 41,15 @@ type Define
p::Float64 # iteration color exponent
newt::Bool # toggle Newton mode
m::Number # newton multiplicity factor
O::Function # original Newton map
mandel::Bool # toggle Mandelbrot mode
seed::Number # Mandelbrot seed value
x0 # orbit starting point
orbit::Int # orbit cobweb depth
depth::Int # depth of function composition
cmap::String # imshow color map
function Define(F::String;
Q::String="abs2(z)",
C::String="angle(z)/(2π))*n^p",
function Define(E;
Q=:(abs2(z)),
C=:((angle(z)/(2π))*n^p),
=π/2,
n::Integer=176,
N::Integer=35,
Expand All @@ -58,7 58,6 @@ type Define
p::Number=0,
newt::Bool=false,
m::Number=0,
O::String=F,
mandel::Bool=false,
seed::Number=0.0 0.0im,
x0=nothing,
Expand All @@ -67,10 66,10 @@ type Define
cmap::String="")
!(typeof(∂) <: Array) && (∂ = [-float(∂),∂,-∂,∂])
length(∂) == 2 && (∂ = [∂[1],∂[2],∂[1],∂[2]])
!newt ? (f = funk(F) |> eval; q = funk(Q) |> eval) :
(f = newton_raphson(eval(funk(F)),m); q = eval(funk("abs("*F*")")))
c = funK(C) |> eval; o = funk(O) |> eval
return new(f,q,c,convert(Array{Float64,1},∂),UInt16(n),UInt8(N),float(ϵ),iter,float(p),newt,m,o,mandel,seed,x0,orbit,depth,cmap)
!newt ? (f = funk(E); q = funk(Q)) :
(f = funk(newton_raphson(E,m)); q = funk(Expr(:call,:abs,E)))
c = funK(C)
return new(E,f,q,c,convert(Array{Float64,1},∂),UInt16(n),UInt8(N),float(ϵ),iter,float(p),newt,m,mandel,seed,x0,orbit,depth,cmap)
end
end

Expand All @@ -84,10 83,9 @@ immutable FilledSet
set::Matrix{Complex{Float64}}
iter::Matrix{UInt8}
mix::Matrix{Float64}
function FilledSet(K::Define); (i,s)=Compute(K)
m(z::Complex{Float64},n::Number,p::Number) = (VERSION < v"0.6.0") ?
K.C(z,n,p)::Float64 : invokelatest(K.C,z,n,p)::Float64
return new(K,s,i,broadcast(m,s,broadcast(float,i./K.N),K.p))
function FilledSet(K::Define)
(i,s) = Compute(K)
return new(K,s,i,broadcast(K.C,s,broadcast(float,i./K.N),K.p))
end
end

Expand All @@ -104,9 102,9 @@ julia> fatou(K)
fatou(K::Define) = FilledSet(K)

"""
juliafill(::String; # primary map, (z, c) -> F
Q::String = "abs2(z)", # escape criterion, (z, c) -> Q
C::String = "angle(z)/(2π))*n^p", # coloring, (z, n=iter., p=exp.) -> C
juliafill(::Expr; # primary map, (z, c) -> F
Q::Expr = :(abs2(z)), # escape criterion, (z, c) -> Q
C::Expr = :((angle(z)/(2π))*n^p)# coloring, (z, n=iter., p=exp.) -> C
∂ = π/2, # Array{Float64,1} # Bounds, [x(a),x(b),y(a),y(b)]
n::Integer = 176, # horizontal grid points
N::Integer = 35, # max. iterations
Expand All @@ -125,9 123,9 @@ fatou(K::Define) = FilledSet(K)
julia> juliafill("z^2-0.06 0.67im",∂=[-1.5,1.5,-1,1],N=80,n=1501,cmap="RdGy")
```
"""
function juliafill(F::String;
Q::String= "abs2(z)",
C::String= "(angle(z)/(2π))*n^p",
function juliafill(E;
Q=:(abs2(z)),
C=:((angle(z)/(2π))*n^p),
=π/2,
n::Integer=176,
N::Integer=35,
Expand All @@ -140,13 138,13 @@ function juliafill(F::String;
orbit::Int=0,
depth::Int=1,
cmap::String="")
return Define(F,Q=Q,C=C,∂=∂,n=n,N=N,ϵ=ϵ,iter=iter,p=p,newt=newt,m=m,x0=x0,orbit=orbit,depth=depth,cmap=cmap)
return Define(E,Q=Q,C=C,∂=∂,n=n,N=N,ϵ=ϵ,iter=iter,p=p,newt=newt,m=m,x0=x0,orbit=orbit,depth=depth,cmap=cmap)
end

"""
mandelbrot(::String; # primary map, (z, c) -> F
Q::String = "abs2(z)", # escape criterion, (z, c) -> Q
C::String = "exp(-abs(z))*n^p", # coloring, (z, n=iter., p=exp.) -> C
mandelbrot(::Expr; # primary map, (z, c) -> F
Q::Expr = :(abs2(z)), # escape criterion, (z, c) -> Q
C::Expr = :(exp(-abs(z))*n^p), # coloring, (z, n=iter., p=exp.) -> C
∂ = π/2, # Array{Float64,1} # Bounds, [x(a),x(b),y(a),y(b)]
n::Integer = 176, # horizontal grid points
N::Integer = 35, # max. iterations
Expand All @@ -164,13 162,13 @@ end
# Examples
```Julia
mandelbrot("z^2 c",n=800,N=20,∂=[-1.91,0.51,-1.21,1.21],cmap="nipy_spectral")
mandelbrot(:(z^2 c),n=800,N=20,∂=[-1.91,0.51,-1.21,1.21],cmap="nipy_spectral")
```
"""
function mandelbrot(F::String;
Q::String= "abs2(z)",
function mandelbrot(E;
Q=:(abs2(z)),
=π/2,
C::String= "exp(-abs(z))*n^p",
C=:(exp(-abs(z))*n^p),
n::Integer=176,
N::Integer=35,
ϵ::Number=4,
Expand All @@ -184,12 182,12 @@ function mandelbrot(F::String;
depth::Int=1,
cmap::String="")
m 0 && (newt = true)
return Define(F,Q=Q,C=C,∂=∂,n=n,N=N,ϵ=ϵ,iter=iter,p=p,newt=newt,m=m,mandel=true,seed=seed,x0=x0,orbit=orbit,depth=depth,cmap=cmap)
return Define(E,Q=Q,C=C,∂=∂,n=n,N=N,ϵ=ϵ,iter=iter,p=p,newt=newt,m=m,mandel=true,seed=seed,x0=x0,orbit=orbit,depth=depth,cmap=cmap)
end

"""
newton(::String; # primary map, (z, c) -> F
C::String = "angle(z)/(2π))*n^p", # coloring, (z, n=iter., p=exp.) -> C
newton(::Expr; # primary map, (z, c) -> F
C::Expr = :((angle(z)/(2π))*n^p)# coloring, (z, n=iter., p=exp.) -> C
∂ = π/2, # Array{Float64,1} # Bounds, [x(a),x(b),y(a),y(b)]
n::Integer = 176, # horizontal grid points
N::Integer = 35, # max. iterations
Expand All @@ -211,8 209,8 @@ end
julia> newton("z^3-1",n=800,cmap="brg")
```
"""
function newton(F::String;
C::String= "(angle(z)/(2π))*n^p",
function newton(E;
C=:((angle(z)/(2π))*n^p),
=π/2,
n::Integer=176,
N::Integer=35,
Expand All @@ -226,7 224,7 @@ function newton(F::String;
orbit::Int=0,
depth::Int=1,
cmap::String="")
return Define(F,C=C,∂=∂,n=n,N=N,ϵ=ϵ,iter=iter,p=p,newt=true,m=m,O=F,mandel=mandel,seed=seed,x0=x0,orbit=orbit,depth=depth,cmap=cmap)
return Define(E,C=C,∂=∂,n=n,N=N,ϵ=ϵ,iter=iter,p=p,newt=true,m=m,mandel=mandel,seed=seed,x0=x0,orbit=orbit,depth=depth,cmap=cmap)
end

# load additional functionality
Expand All @@ -244,27 242,20 @@ julia> basin(newton("z^3-1"),2)
L"\$\\displaystyle D_2(\\epsilon) = \\left\\{z\\in\\mathbb{C}:\\left|\\,z - \\frac{\\left(z - \\frac{z^{3} - 1}{3 z^{2}}\\right)^{3} - 1}{3 \\left(z - \\frac{z^{3} - 1}{3 z^{2}}\\right)^{2}} - \\frac{z^{3} - 1}{3 z^{2}} - r_i\\,\\right|<\\epsilon,\\,\\forall r_i(\\,f(r_i)=0 )\\right\\}\$"
```
"""
basin(K::Define,j) = K.newt ? nrset(K.O,K.m,j) : jset(K.F,j)
basin(K::Define,j) = K.newt ? nrset(K.E,K.m,j) : jset(K.E,j)

"""
Compute(::Fatou.Define)::Union{Matrix{UInt8},Matrix{Float64}}
`Compute` the `Array` for `Fatou.FilledSet` as specefied by `Fatou.Define`.
"""
function Compute(K::Define)::Tuple{Matrix{UInt8},Matrix{Complex{Float64}}}
# define Complex{Float64} versions of polynomial and constant for speed
f = (VERSION < v"0.6.0") ?
(sym2fun(K.F(Sym(:a),Sym(:b)),:(Complex{Float64})) |> eval)::Function :
(sym2fun(invokelatest(K.F,Sym(:a),Sym(:b)),:(Complex{Float64})) |> eval)::Function
h = (VERSION < v"0.6.0") ?
(sym2fun(K.Q(Sym(:a),Sym(:b)),:(Complex{Float64})) |> eval)::Function :
(sym2fun(invokelatest(K.Q,Sym(:a),Sym(:b)),:(Complex{Float64})) |> eval)::Function
# define function for computing orbit of a z0 input
function nf(z0::Complex{Float64})
K.mandel ? (z = K.seed): (z = z0)
zn = 0x00
while (K.newt ? (h(z,z0)::Float64>K.ϵ)::Bool : (h(z,z0)::Float64<K.ϵ))::Bool && K.N>zn
z = f(z,z0)::Complex{Float64}
while (K.newt ? (K.Q(z,z0)::Float64>K.ϵ)::Bool : (K.Q(z,z0)::Float64<K.ϵ))::Bool && K.N>zn
z = K.F(z,z0)::Complex{Float64}
zn =0x01
end; #end
# return the normalized argument of z or iteration count
Expand All @@ -276,18 267,11 @@ function Compute(K::Define)::Tuple{Matrix{UInt8},Matrix{Complex{Float64}}}
y = linspace(K.∂[4],K.∂[3],Kyn)
Z = x' . im*y # apply Newton-Orbit function element-wise to coordinate grid
(matU,matF) = (Array{UInt8,2}(Kyn,K.n),Array{Complex{Float64},2}(Kyn,K.n))
#mat = Array{Tuple{UInt8,Complex{Float64}},2}(Kyn,K.n)
if VERSION < v"0.6.0" # backwards compatability
@time @threads for j = 1:length(y); for k = 1:length(x);
(matU[j,k],matF[j,k]) = nf(Z[j,k])::Tuple{UInt8,Complex{Float64}}
end; end
else
@time @threads for j = 1:length(y); for k = 1:length(x);
(matU[j,k],matF[j,k]) = invokelatest(nf,Z[j,k])::Tuple{UInt8,Complex{Float64}}
end; end
end
@time @threads for j = 1:length(y); for k = 1:length(x);
(matU[j,k],matF[j,k]) = invokelatest(nf,Z[j,k])::Tuple{UInt8,Complex{Float64}}
end; end
return (matU,matF)
end #mat[j,:] = nf.(Z[j,:]); end; return (matU.(mat),matF.(mat)); end
end

import PyPlot: plot

Expand All @@ -303,14 287,13 @@ function plot(K::FilledSet;c::String="",bare::Bool=false)
typeof(K.meta.iter ? K.iter : K.mix) == Matrix{UInt8} ? t = L"iter. " :
K.meta.m==1 ? t = L"roots" : t = L"limit"
# annotate title using LaTeX
ttext = (VERSION < v"0.6.0")?"f:z\\mapsto $(SymPy.latex(K.meta.O(Sym(:z),Sym(:c)))),\\," :
"f:z\\mapsto $(SymPy.latex(invokelatest(K.meta.O,Sym(:z),Sym(:c)))),\\,"
ttext = "f:z\\mapsto $(rdpm(Algebra.latex(K.meta.E))),\\,"
if K.meta.newt
title(latexstring("$ttext m = $(K.meta.m), ")*t)
# annotate y-axis with Newton's method
ylabel(L"Fatou\,set:\,"*L"z\,\,z-m\,×\,f(z)\,/\,f\,'(z)")
else
title(latexstring("$ttext")*t)
title(latexstring(ttext)*t)
end
tight_layout()
colorbar()
Expand Down
Loading

0 comments on commit eae3113

Please sign in to comment.