161 lines
4.1 KiB
Elixir
161 lines
4.1 KiB
Elixir
defmodule Scopes.Core.Program do
|
|
alias Scopes.Core
|
|
alias Scopes.Core.Environ
|
|
alias Scopes.Core.Shape
|
|
alias Scopes.Util
|
|
|
|
require Logger
|
|
require Util
|
|
|
|
defmodule State do
|
|
defstruct [:value, :count, :stage, :prog]
|
|
end
|
|
|
|
def prepare(prog, args) do
|
|
state = %State{
|
|
value: args[:bias] || 0,
|
|
count: 0,
|
|
stage: :initial,
|
|
prog: prog
|
|
}
|
|
{state, get_proc(state)}
|
|
end
|
|
|
|
def get_proc(state) do
|
|
get_proc(state.prog, state.stage)
|
|
end
|
|
|
|
defp get_proc(stages, stage) do
|
|
stages[stage] || stages[:default]
|
|
end
|
|
|
|
# basic program
|
|
|
|
def basic_prog(args) do
|
|
default = basic_active(args)
|
|
%{default: default,
|
|
initial: basic_initial(args),
|
|
active: default,
|
|
retired: default
|
|
}
|
|
end
|
|
|
|
def prepare_basic(args \\ []) do
|
|
prepare(basic_prog(args), args)
|
|
end
|
|
|
|
# basic processors
|
|
|
|
def basic_initial(args) do
|
|
basic(args)
|
|
end
|
|
|
|
def basic_active(args) do
|
|
basic(args)
|
|
end
|
|
|
|
def basic(args) do
|
|
fn msg, scope ->
|
|
case Shape.head(msg) do
|
|
[:csys, :data | _rest] -> process_basic(msg, scope, args)
|
|
#[:csys, :trigger | _rest] -> process_trigger(msg, scope)
|
|
[:csys, :connect | _rest] -> Core.connect(msg, scope)
|
|
[:csys, :create, :succ | _rest] -> create_succ(msg, scope)
|
|
[:csys, :create, :pred | _rest] -> create_pred(msg, scope)
|
|
#[:csys, :next | _rest] -> next(msg, scope)
|
|
_ -> Core.forward(msg, scope) || Core.notify(msg, scope)
|
|
end
|
|
end
|
|
end
|
|
|
|
# message handlers // proc steps
|
|
|
|
def process_basic(msg, scope, args) do
|
|
threshold = args[:threshold] || 0
|
|
bias = args[:bias] || 0
|
|
limit = args[:limit]
|
|
data = Shape.data(msg)
|
|
state = Core.state(scope)
|
|
Logger.debug(Util.show [data, state.value, threshold])
|
|
value_n = state.value + data.value
|
|
if value_n >= threshold do
|
|
value_out = limit && rem(value_n - 1, limit) + limit || value_n
|
|
value_next = limit && max(value_n - limit, bias) || bias
|
|
msg = Shape.create(Shape.head(msg), data: %{data | value: value_out})
|
|
Core.forward(msg, scope) || Core.notify(msg, scope)
|
|
state_n = %{state | value: value_next}
|
|
Core.update(put_elem(scope, 0, state_n))
|
|
else
|
|
state_n = %{state | value: value_n}
|
|
Core.update(put_elem(scope, 0, state_n))
|
|
end
|
|
end
|
|
|
|
def create_succ(msg, scope) do
|
|
new = Core.create(msg, restart(scope))
|
|
data = Shape.data(msg)
|
|
Core.send_message(self(), ~w(csys connect)a, Map.put(data, :target, new))
|
|
end
|
|
|
|
def create_pred(msg, scope) do
|
|
new = Core.create(msg, restart(scope))
|
|
data = Shape.data(msg)
|
|
Core.send_message(new, ~w(csys connect)a, Map.put(data, :target, self()))
|
|
end
|
|
|
|
# synapse operations
|
|
|
|
def multiply(n) do
|
|
fn msg ->
|
|
value = Shape.data(msg)[:value] || 0
|
|
Shape.create(Shape.head(msg), data: %{Shape.data(msg) | value: n * value})
|
|
end
|
|
end
|
|
|
|
def negate(), do: multiply(-1)
|
|
|
|
# helper functions
|
|
|
|
def restart({state, _proc, syns, env}) do
|
|
state_n = %{state | stage: :initial}
|
|
{state_n, get_proc(state_n), syns, env}
|
|
end
|
|
|
|
# demo init sequences
|
|
|
|
def init_seq_b1() do
|
|
zero = [:csys, :c00, "0-0"]
|
|
one = [:csys, :s01, "1-0"]
|
|
two = [:csys, :c00, "1-1"]
|
|
three = [:csys, :s01, "1-1"]
|
|
[
|
|
fn state ->
|
|
Environ.send_message(state, zero, ~w(csys create pred)a,
|
|
%{op: [Core.data_only(), negate()], addr: one})
|
|
end,
|
|
fn state ->
|
|
Environ.send_message(state, one, ~w(csys create succ)a,
|
|
%{op: Core.data_only(), addr: two})
|
|
end,
|
|
fn state ->
|
|
Environ.send_message(state, two, ~w(csys create pred)a, %{addr: three})
|
|
end,
|
|
fn state -> Environ.connect(state, three, zero) end
|
|
]
|
|
end
|
|
|
|
def init_recursive_1() do
|
|
zero = [:csys, :c00, "0-0"]
|
|
[
|
|
fn state ->
|
|
Environ.connect(state, zero, zero, negate())
|
|
Environ.send_message(state, zero, ~w(csys create succ)a,
|
|
%{addr: [:csys, :e01, "1-1"]})
|
|
end,
|
|
fn state ->
|
|
Environ.send_message(state, zero, ~w(csys create pred)a,
|
|
%{addr: [:csys, :s01, "1-1"]})
|
|
end
|
|
]
|
|
end
|
|
end
|