Current section
Files
Jump to
Current section
Files
lib/exun_isol.ex
defmodule Exun.Isol do
@moduledoc """
Isolation module. Try to isolate an ast from other AST.
"""
alias Exun.Fun, as: F
alias Exun.Simpl, as: S
alias Exun.Collect, as: C
alias Exun.Eq, as: E
@zero {:numb,0,1}
@doc """
Return a list of tuples of form {:ok, solution} where olution is the isolated tree for original ast
May be return more than one, if we can not collect ast in a single place of eqzero.
"""
def isol({:equal, left, right}, ast) do
eqzero = C.coll(S.rest(left, right))
downtrace(eqzero, ast, @zero)
|> Enum.reject(fn {res, _} -> res == :ko end)
|> Enum.map(fn {res, sol} -> {res, C.coll(sol)} end)
end
defp downtrace(expr, ast, right) do
case expr do
^ast ->
[{:ok, right}]
{:minus, a} ->
downtrace(a, ast, {:minus, right})
{:deriv, f, v} ->
downtrace(f, ast, {:integ, right, v})
{:integ, f, v} ->
downtrace(f, ast, {:deriv, right, v})
{:elev, a, b} ->
try_base = downtrace(a, ast, S.elev(right,S.chpow(b)))
try_expo = downtrace(b, ast, S.divi(S.ln(right),S.ln(a)))
try_base ++ try_expo
{:fcall, name, args} ->
case F.finv(name) do
nil ->
[{:ko, right}]
inv ->
Enum.reduce(args, [], fn opand, ac ->
downtrace(opand, ast, {:fcall, inv, [right]}) ++ ac
end)
end
{{:m, op}, opands} ->
rev = if op == :suma, do: &S.chsign/1, else: &S.chpow/1
Enum.reduce(opands, [], fn opand, acu ->
newlist =
List.delete(opands, opand)
|> Enum.map(rev)
|> List.insert_at(0, right)
|> Enum.sort(&E.smm/2)
downtrace(opand, ast, {{:m, op}, newlist}) ++ acu
end)
_ ->
[{:ko, right}]
end
end
@doc """
Find a subtree (fnd) all around tree and substitute it by rpl
Simple exercise, not used for now in lib; I love the simplicity of
Elixir for that kind of problems
"""
def find_repl(tree, fnd, rpl) do
case tree do
^fnd ->
rpl
{{:m, op}, l} ->
{{:m, op}, Enum.map(l, &find_repl(&1, fnd, rpl))}
{:fcall, f, args} ->
{:fcall, f, Enum.map(args, &find_repl(&1, fnd, rpl))}
{op, arg} ->
{op, find_repl(arg, fnd, rpl)}
{op, l, r} ->
{op, find_repl(l, fnd, rpl), find_repl(r, fnd, rpl)}
_ ->
tree
end
end
end