Skip to content

Commit

Permalink
first draft of polystr. models
Browse files Browse the repository at this point in the history
  • Loading branch information
archanarw committed Jul 24, 2023
1 parent 4d5aa61 commit 2403432
Show file tree
Hide file tree
Showing 5 changed files with 237 additions and 4 deletions.
3 changes: 3 additions & 0 deletions src/base/aexpr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ function showstring(aexpr::AExpr)
Expr(:object, name, args...) => "(object $(showstring(name)) $(join(map(showstring, args), " ")))"
Expr(:on, event, upd) => "(on $(showstring(event)) $(showstring(upd)))"
Expr(:deriv, x, val) => "(deriv $(showstring(x)) $(showstring(val)))"
Expr(:in, x, args...) => "(in $(showstring(x)) $(showstring(args...)))"
Expr(:runner, x) => "(runner $(showstring(x)))"
Expr(:run, x) => "(run $(showstring(x)))"
x => "Fail $x"
end
end
Expand Down
3 changes: 3 additions & 0 deletions src/base/sexpr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ function parseau(sexpr::AbstractArray)
[:list, vars...] => AExpr(:list, map(parseau, vars)...)
[:.., var, field] => AExpr(:field, parseau(var), parseau(field))
[:on, args...] => AExpr(:on, map(parseau, args)...)
[:run, model::Symbol] => AExpr(:run, model)
[:in, model::Symbol, args...] => AExpr(:in, model, map(parseau, args)...)
[:runner, model::Symbol] => AExpr(:runner, model)
[:object, args...] => AExpr(:object, map(parseau, args)...)
[:deriv, args...] => AExpr(:deriv, args[1], parseau(args[2]))
[f, xs...] => AExpr(:call, parseau(f), map(parseau, xs)...)
Expand Down
118 changes: 115 additions & 3 deletions src/interpreter/interpret.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,122 @@ using ..AExpressions: AExpr
using ..AutumnStandardLibrary
using ..SExpr
using Random
export empty_env, Environment, std_env, start, step, run, interpret_program, interpret_over_time, interpret_over_time_observations, interpret_over_time_observations_and_env
export empty_env, Environment, std_env, start, step, run, interpret_program, interpret_over_time, interpret_over_time_observations, interpret_over_time_observations_and_env, polystr_interpret_over_time
import MLStyle

"""Interpret program for given number of time steps, returning final environment"""
function polystr_interpret_over_time(aex::AExpr, iters, user_events=[]; show_rules=-1)::Env
run_line = filter(l -> l.head == :run, aex.args)
isempty(run_line) && return interpret_over_time(aex, iters, user_events, show_rules = show_rules) # Did this to keep the old interpreter intact
run_model = run_line[1].args[1]
interpret_over_time_runner(aex, run_model, iters, user_events, show_rules = show_rules)
end

function interpret_over_time_runner(aex::AExpr, run_model::Symbol, iters, user_events=[]; show_rules=-1)::Env
new_aex, env_ = start_runner(aex, run_model, show_rules=show_rules)
for i in 1:iters
env_ = (user_events == []) ? step(new_aex, env_) : step(new_aex, env_, user_events[i])
end
env_
end

function start_runner(aex::AExpr, run_model::Symbol, rng=Random.GLOBAL_RNG; show_rules=-1)
aex.head == :program || error("Must be a program aex")
env = Env(false, false, false, false, nothing, Dict(), State(0, 0, rng, Scene([], "white"), Dict(), Dict()), show_rules)

lines = aex.args

# reorder program lines
grid_params_and_object_type_lines = filter(l -> !(l.head in (:assign, :on, :deriv, :runner, :in, :run)), lines) # || (l.head == :assign && l.args[1] in [:GRID_SIZE, :background])
initnext_lines = filter(l -> l.head == :assign && (l.args[2] isa AExpr && l.args[2].head == :initnext), lines)
lifted_lines = filter(l -> l.head == :assign && (!(l.args[2] isa AExpr) || l.args[2].head != :initnext), lines) # GRID_SIZE and background here
deriv_lines = filter(l -> l.head == :deriv, lines)
on_clause_lines = filter(l -> l.head == :on, lines)

in_lines_ = filter(l -> l.head == :in && l.args[1] == run_model, lines)
in_lines = vcat((l.args[2:end] for l in in_lines_)...)

push!(grid_params_and_object_type_lines, filter(l -> !(l.head in (:assign, :on, :deriv, :runner, :in, :run)), in_lines)...)
push!(initnext_lines, filter(l -> l.head == :assign && (l.args[2] isa AExpr && l.args[2].head == :initnext), in_lines)...)
push!(lifted_lines, filter(l -> l.head == :assign && (!(l.args[2] isa AExpr) || l.args[2].head != :initnext), in_lines)...)
push!(deriv_lines, filter(l -> l.head == :deriv, in_lines)...)
push!(on_clause_lines, filter(l -> l.head == :on, in_lines)...)

default_on_clause_lines = []
for line in initnext_lines
var_name = line.args[1]
next_clause = line.args[2].args[2]
if !(next_clause isa AExpr && next_clause.head == :call && length(next_clause.args) == 2 && next_clause.args[1] == :prev && next_clause.args[2] == var_name)
new_on_clause = AExpr(:on, Symbol("true"), AExpr(:assign, var_name, next_clause))
push!(default_on_clause_lines, new_on_clause)
end
end

# ----- START deriv handling -----
deriv_on_clause_lines = []
for line in deriv_lines
new_on_clause = AExpr(:on, Symbol("true"), line)
push!(deriv_on_clause_lines, new_on_clause)
end

on_clause_lines_ = [default_on_clause_lines..., deriv_on_clause_lines..., on_clause_lines...]

on_clause_lines = []
for oc in on_clause_lines_
if oc.args[2].head == :deriv
var = oc.args[2].args[1]
update = oc.args[2].args[2]
new_oc = AExpr(:on, oc.args[1], parseautumn("""(= $(var) (+ $(var) (* (/ 1 2) $(repr(update)))))"""))
push!(on_clause_lines, new_oc)
else
push!(on_clause_lines, oc)
end
end
# ----- END deriv handling -----

reordered_lines_init = vcat(grid_params_and_object_type_lines,
initnext_lines,
on_clause_lines,
# lifted_lines
)

# following initialization, we no longer need initnext lines
reordered_lines = on_clause_lines

# add prev functions and variable history to state for lifted variables
for line in lifted_lines
var_name = line.args[1]
# construct history variable in state
env.state.histories[var_name] = Dict()
# construct prev function
# env.current_var_values[Symbol(string(:prev, uppercasefirst(string(var_name))))] = [AExpr(:list, [:state]), AExpr(:call, :get, env.state.histories[var_name], AExpr(:call, :-, AExpr(:field, :state, :time), 1), var_name)]
# _, env = interpret(AExpr(:assign, Symbol(string(:prev, uppercasefirst(string(var_name)))), parseautumn("""(fn () (get (.. (.. state histories) $(string(var_name))) (- (.. state time) 1) $(var_name)))""")), env)
end

# add background to scene
background_assignments = filter(l -> l.args[1] == :background, lifted_lines)
background = background_assignments != [] ? background_assignments[end].args[2] : "#ffffff00"
env.state.scene.background = background

# initialize lifted variables
for line in lifted_lines
var_name = line.args[1]
# env.lifted[var_name] = line.args[2]
if var_name in [:GRID_SIZE, :background]
env.current_var_values[var_name] = interpret(line.args[2], env)[1]
end
end

new_aex = AExpr(:program, reordered_lines_init...) # try interpreting the init_next's before on for the first time step (init)
@show new_aex
aex_, env_ = interpret_program(new_aex, env)

# update state (time, histories, scene)
env_ = update_state(env_)

AExpr(:program, reordered_lines...), env_
end

"""Interpret program for given number of time steps, returning final environment"""
function interpret_over_time(aex::AExpr, iters, user_events=[]; show_rules=-1)::Env
new_aex, env_ = start(aex, show_rules=show_rules)
Expand All @@ -24,12 +137,11 @@ function start(aex::AExpr, rng=Random.GLOBAL_RNG; show_rules=-1)
lines = aex.args

# reorder program lines
grid_params_and_object_type_lines = filter(l -> !(l.head in (:assign, :on, :deriv)), lines) # || (l.head == :assign && l.args[1] in [:GRID_SIZE, :background])
grid_params_and_object_type_lines = filter(l -> !(l.head in (:assign, :on, :deriv, :runner, :in, :run)), lines) # || (l.head == :assign && l.args[1] in [:GRID_SIZE, :background])
initnext_lines = filter(l -> l.head == :assign && (l.args[2] isa AExpr && l.args[2].head == :initnext), lines)
lifted_lines = filter(l -> l.head == :assign && (!(l.args[2] isa AExpr) || l.args[2].head != :initnext), lines) # GRID_SIZE and background here
deriv_lines = filter(l -> l.head == :deriv, lines)
on_clause_lines = filter(l -> l.head == :on, lines)

default_on_clause_lines = []
for line in initnext_lines
var_name = line.args[1]
Expand Down
6 changes: 5 additions & 1 deletion src/interpreter/interpretutils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ using ..AExpressions: AExpr
using ..SExpr
using ..AutumnStandardLibrary
using Setfield
export interpret, interpret_let, interpret_call, interpret_init_next, interpret_object, interpret_object_call, interpret_on, Environment, empty_env, std_env, update, primapl, isprim, update
export interpret, interpret_let, interpret_call, interpret_init_next, interpret_object, interpret_object_call, interpret_on, Environment, empty_env, std_env, update, primapl, isprim, update, +
import MLStyle
using MappedArrays

Expand Down Expand Up @@ -48,6 +48,10 @@ function update(Γ::Object, x::Symbol, v)::Object
Γ
end

# function +₂(x, y)
# (x + y)%2
# end

# primitive function handling
const prim_to_func = let prims = (:+, :-, :*, :/, :&, :!, :|, :>, :>=, :<, :<=, :(==), :%, :!=,)
NamedTuple{prims}(getproperty.(Ref(Base), prims))
Expand Down
111 changes: 111 additions & 0 deletions test/polystr_model_examples.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
using Autumn

arithmatic = au"""(program
(: x Int)
(: y Int)
(: z Int)
(= x (initnext 0 (+ (prev x) 2)))
(= y (initnext 1 (+ 1 (prev y))))
(= z (initnext (+ x y) (+ x y)))
(runner R)
(in R (: z Bool))
(in R (= z (initnext (== (% (+ x y) 2) 1) (== (% (+ x y) 2) 1))))
(run R)
)"""

env = polystr_interpret_over_time(arithmatic, 4, [])

light_switch = au"""(program
(= GRID_SIZE 16)
(in HIGH_LEVEL
(: light Bool)
(= light (initnext false (prev light)))
)
(: switch Bool)
(= switch (initnext false (prev switch)))
(on clicked (= switch (! switch)))
(on switch (= light true))
(on (! switch) (= light false))
(runner R)
(in R
(: light Bool)
(= light (initnext false (prev light)))
(: powercut Bool)
(= powercut (initnext false (prev powercut)))
(on switch (= light (! powercut)))
)
(runner P)
(in P
(: light Int)
(= light (initnext 0 (prev light)))
(: volt Int)
(= volt (initnext 7 (prev volt)))
(on switch (= light volt))
)
(run P)
)"""

env = polystr_interpret_over_time(light_switch, 4, [(click=Autumn.AutumnStandardLibrary.Click(5,5),), empty_env(), (click=Autumn.AutumnStandardLibrary.Click(9,9),), empty_env()])

a = au"""(program
(= GRID_SIZE 16)
(object Lamp (: on Bool) (map (--> pos (Cell pos (if on then "gold" else "gray"))) (vcat (list (Position 0 0))
(rect (Position -1 1) (Position 1 1))
(rect (Position -2 2) (Position 2 3))
(rect (Position 0 4) (Position 0 6))
(rect (Position -2 7) (Position 2 7))
)) )
(object Switch (: on Bool) (Cell 0 0 (if on then "red" else "black")))
(object Outlet (: powerOut Bool) (map (--> pos (Cell pos "darkorange")) (rect (Position 0 -1) (Position 0 1))))
(object Wire (: attached Bool) (if attached then (map (--> pos (Cell pos "brown")) (vcat (rect (Position 0 0) (Position 4 0)) (rect (Position 4 -2) (Position 4 -1)) (Position 5 -2)))
else (map (--> pos (Cell pos "brown")) (vcat (rect (Position 0 0) (Position 4 0)) (rect (Position 4 1) (Position 4 2)) (Position 5 2)))
))
(: lamp Lamp)
(= lamp (initnext (Lamp false (Position 5 5)) (prev lamp)))
(: switch Switch)
(= switch (initnext (Switch false (Position 3 11)) (prev switch)))
(: outlet Outlet)
(= outlet (initnext (Outlet false (Position 14 10)) (prev outlet)))
(: wire Wire)
(= wire (initnext (Wire true (Position 8 12)) (prev wire)))
(on (clicked outlet) (= outlet (updateObj outlet "powerOut" (! (.. outlet powerOut)))))
(on (clicked switch) (= switch (updateObj switch "on" (! (.. switch on)))))
(on (clicked wire) (= wire (updateObj wire "attached" (! (.. wire attached)))))
(on (& (! (.. outlet powerOut)) (& (.. switch on) (.. wire attached))) (= lamp (updateObj lamp "on" true)))
(on (! (& (! (.. outlet powerOut)) (& (.. switch on) (.. wire attached)))) (= lamp (updateObj lamp "on" false)))
)"""

env = polystr_interpret_over_time(a, 4, [(click=Autumn.AutumnStandardLibrary.Click(5,5),), empty_env(), (click=Autumn.AutumnStandardLibrary.Click(9,9),), empty_env()])

particles = au"""(program
(= GRID_SIZE 16)
(= particleSize (initnext 1 (prev particleSize)))
(runner R1)
(in R1 (= particleSize (initnext 2 (prev particleSize))))
(runner R2)
(in R2 (= particleSize (initnext 3 (prev particleSize))))
(object Particle (: size Int) (map (--> pos (Cell pos "blue")) (rect (Position 0 0) (Position (- size 1) (- size 1)))))
(= particles (initnext (list) (updateObj (prev particles) (--> obj (uniformChoice (list (moveNoCollision obj (- 0 particleSize) 0) (moveNoCollision obj particleSize 0) (moveNoCollision obj 0 particleSize) (moveNoCollision obj 0 (- 0 particleSize))) ))))) 
(on clicked (= particles (addObj (prev particles) (Particle particleSize (Position (- (.. click x) (% (.. click x) particleSize)) (- (.. click y) (% (.. click y) particleSize)) )))))
(run R1)
)"""

env = polystr_interpret_over_time(particles, 4, [(click=Autumn.AutumnStandardLibrary.Click(5,5),), empty_env(), (click=Autumn.AutumnStandardLibrary.Click(9,9),), empty_env()])

0 comments on commit 2403432

Please sign in to comment.