...
 
Commits (7)
......@@ -32,3 +32,6 @@ mix.lock
#Elixir_LS files
.elixir_ls
# Sublime Text
*.sublime-workspace
......@@ -19,12 +19,7 @@
use Mix.Config
config :marlon,
connect_handler: {:example, :connect_node},
disconnect_handler: {:example, :disconnect_node},
python_path: 'python',
communication_time: 2000,
processing_time: 5000,
visualization: true
config :libcluster,
topologies: [
......@@ -38,12 +33,5 @@ config :libcluster,
]
]
config :smile_it_demo_ui, SmileItDemoUiWeb.Endpoint,
url: [host: "localhost"],
secret_key_base: "/bytVRunQxwRMpbJ15th2HpDDHJchOMwl+SvoIjLMgnjcxtL9wdT8S3aoIsAneFa",
render_errors: [view: SmileItDemoUiWeb.ErrorView, accepts: ~w(html json)],
pubsub: [name: SmileItDemoUi.PubSub,
adapter: Phoenix.PubSub.PG2]
config :logger,
level: :info
\ No newline at end of file
......@@ -50,7 +50,9 @@ defactor Worker do
chunk_time: chunk_time}}
end
contract WorkerContract
# contract WorkerContract
# contract Marlon.ReporterContract
contract Marlon.FullReporterContract
async def start(this) do
Worker.do_action(self())
......@@ -125,8 +127,8 @@ defactor Master do
new_remaining = this[:chunks_remaining] - chunk_size
new_pending = this[:pending_request_size] - chunk_size
IO.puts "new_remaining: " <> Kernel.inspect(new_remaining)
IO.puts "new_pending: " <> Kernel.inspect(new_pending)
# IO.puts "new_remaining: " <> Kernel.inspect(new_remaining)
# IO.puts "new_pending: " <> Kernel.inspect(new_pending)
if (new_remaining >= 0) do
Marlon.reply(from, :ok)
......
# To run this example: iex -S mix run -r lib/examples/thermostat/thermostat-multi.exs
use Marlon
defactor House do
def init([init_temp]) do
{:ok, hp} = Heatpump.start_link([init_temp], [])
agent = Heatpump.attach_agent(hp, DistributeLoad)
{:ok, %{heatpump: hp, iterations: 1000}}
end
async def loop(this) do
Heatpump.step(this.heatpump)
Process.send_after self(), {:loop_reply}, 50
{:noreply, this}
end
reply def loop_reply(this) do
if (this.iterations > 0) do
House.loop(self())
end
{:noreply, %{this | iterations: this.iterations - 1}}
end
end
defactor Heatpump do
def init([init_temp]) do
{:ok, %{temperature: init_temp, load: 0}}
end
async def step(this) do
IO.puts (Kernel.inspect(self()) <> " temperature: " <> Float.to_string(this.temperature))
Heatpump.do_action(self()) # The attached agent should now do an action
{:noreply, this}
end
async def on(this) do
...
Heatpump.update_reward(self(), hp)
{:noreply, hp}
end
async def off(this) do
...
Heatpump.update_reward(self(), hp)
{:noreply, hp}
end
end
defgoal DistributeLoad do
type Marlon.ESRL
params [discount_factor: 0.0, learning_rate: 1.0, epsilon: 0.8]
actions [on: [], off: []]
shared [:load]
shared_deviation [load: 0.5]
reward fn(_agent, hp, shared) ->
1 / Util.sum(shared.load))
end
end
{:ok, house_1} = House.start_link([5.0], [])
{:ok, house_2} = House.start_link([8.0], [])
House.loop(house_1)
House.loop(house_2)
\ No newline at end of file
......@@ -74,9 +74,8 @@ defactor LoadBalancingExample do
if (this[:master] != nil) do
Master.work_cancelled(this[:master], node)
if (Application.fetch_env!(:marlon, :visualization)) do
ip = Enum.at(String.split(Atom.to_string(node), "@"),1)
Marlon.Utils.visualize(:broker_node, {:leave, ip})
end
Marlon.Utils.visualize(:broker_node, {:leave, node})
end
end
{:noreply, this}
end
......@@ -88,7 +87,7 @@ defactor LoadBalancingExample do
end
reply def nodedown(this, node) do
LoadBalancingExample.disconnect_node(self(), node)
# LoadBalancingExample.disconnect_node(self(), node)
{:noreply, this}
end
end
......@@ -181,7 +180,6 @@ defactor Master do
sync def request_work(this, from, chunk_size, worker_ip) do
Marlon.Utils.visualize(this[:visualization], {:update, Node.self(), "Communicating"})
IO.inspect worker_ip
Marlon.Utils.visualize(this[:visualization], {:update, worker_ip, "Communicating"})
new_pending = this[:pending_request_size] + chunk_size
Worker.notify_wait_time(elem(from,0), new_pending * this[:comm_time])
......@@ -233,4 +231,4 @@ defgoal ChunkSizeGoal do
params [explorations: 7, steps: 20]
actions [process_chunk: [[1,2,3]]]
reward fn(_agent, worker_state) -> 1 / worker_state[:wait_time] end
end
\ No newline at end of file
end
......@@ -38,6 +38,10 @@ defmodule Marlon do
not(System.get_env("MARLON_CONTRACTS_DISABLED") == "1")
end
def macro_reporting() do
System.get_env("MARLON_MACRO_REPORTING") == "1"
end
################################
## defactor
################################
......@@ -62,8 +66,6 @@ defmodule Marlon do
contract_checker = if contracts_enabled() do
quote do
def contract_check(name, sender, args) do
IO.puts Kernel.inspect(self()) <> " checking for a " <> Kernel.inspect(name)
if (sender != self()) do
contractor = Process.get(:contractor, nil)
if (contractor != nil) do
......@@ -96,7 +98,7 @@ defmodule Marlon do
def init(args) do
if (unquote(contract) != nil) do
contract = unquote(contract).contract()
contractor = Marlon.Contract.spawn_contractor(contract)
contractor = Marlon.Contract.spawn_contractor(contract, self(), __MODULE__)
Process.put(:contractor, contractor)
end
......@@ -112,18 +114,7 @@ defmodule Marlon do
end
end
IO.puts "------------------------------------"
IO.puts "------------------------------------"
IO.puts "------------------------------------"
IO.puts Macro.to_string(result)
IO.puts "------------------------------------"
IO.puts "------------------------------------"
IO.puts "------------------------------------"
result
macro_report(result)
end
# Generate an user-defined init function
......@@ -211,7 +202,7 @@ defmodule Marlon do
Enum.flat_map(lst, &get_argument_names/1)
end
defp get_argument_names(a) do
defp get_argument_names(_a) do
Kernel.inspect("For argument scanning: combination not supported!")
[]
end
......@@ -379,7 +370,7 @@ defmodule Marlon do
data = [params: params, actions: actions, reward: reward,
state_abstraction: abstraction, shared: shared, shared_deviation: shared_deviation]
quote do
result = quote do
defmodule unquote(name) do
import unquote(algo_module)
def instantiate() do
......@@ -387,6 +378,9 @@ defmodule Marlon do
end
end
end
macro_report(result)
end
......@@ -404,12 +398,9 @@ defmodule Marlon do
contract = Marlon.Contract.process(block)
quote do
result = quote do
defmodule unquote(name) do
def contract() do
done = fn () -> :done end
contract(done)
end
use Marlon.Contract
def contract(done) do
body = unquote(contract)
......@@ -417,8 +408,29 @@ defmodule Marlon do
end
end
end
macro_report(result)
end
##
## Macro Reporting
##
defp macro_report(macro) do
if (macro_reporting()) do
IO.puts "-----------------------------"
IO.puts "------ MACRO EXPANSION ------"
IO.puts "-----------------------------"
IO.puts Macro.to_string(macro)
IO.puts "\n\n"
end
# Return the macro as the result
macro
end
##
## Public interface
......
......@@ -33,7 +33,7 @@ defmodule Marlon.Application do
# Check whether this is the node initiated the Marlon system
node_name = Atom.to_string(Node.self())
children = if (String.contains?(node_name, "worker")) do
children = if (String.contains?(node_name, "aux")) do
Logger.info "Starting Marlon on auxiliary node"
[{__MODULE__, []}]
else
......
......@@ -17,7 +17,24 @@
# along with Marlon. If not, see http://www.gnu.org/licenses
defmodule Marlon.Contract do
#
# Mixin
#
@doc """
Mixin that contains all agent-related functions of actors
"""
defmacro __using__(_params) do
quote do
def contract() do
done = fn () -> :done end
contract(done)
end
end
end
#
# Processing
#
......@@ -60,8 +77,8 @@ defmodule Marlon.Contract do
# Spawn contractor
#
def spawn_contractor(processed_contract) do
{:ok, pid} = Marlon.Contract.Contractor.start_link(processed_contract)
def spawn_contractor(processed_contract, actor, module) do
{:ok, pid} = Marlon.Contract.Contractor.start_link(processed_contract, actor, module)
pid
end
......@@ -74,17 +91,28 @@ defmodule Marlon.Contract do
defp compile_expr(e, d) do
# IO.puts "compile_expr(" <> Kernel.inspect(e) <> "," <> Kernel.inspect(d) <> ")"
case e do
exprs when is_list(exprs) -> compile_sequence(exprs, d)
expr when is_atom(e) -> compile_atom(expr, d)
{:perclient, [exprs]} -> compile_perclient(exprs)
{:cycle, [exprs]} -> compile_cycle(exprs, exprs)
{:branch, [exprs]} -> compile_branch(exprs, d)
{:split, [exprs]} -> compile_split(exprs, d)
{:star, [exprs]} -> compile_star(exprs, d)
{:plus, [exprs]} -> compile_plus(exprs, d)
exprs when is_list(exprs) ->
compile_sequence(exprs, d)
expr when is_atom(e) ->
compile_atom(expr, d)
{:perclient, [exprs]} ->
compile_perclient(exprs)
{:cycle, [exprs]} ->
compile_cycle(exprs, exprs)
{:branch, [exprs]} ->
compile_branch(exprs, d)
# Dangerous operations
{:split, [exprs]} ->
compile_split(exprs, d)
{:star, [exprs]} ->
compile_star(exprs, d)
{:plus, [exprs]} ->
compile_plus(exprs, d)
# Callback with keywords
{callback, keywords} when is_atom(callback) and is_list(keywords) ->
compile_with_attribute(callback, keywords, d)
:reporter -> reporter()
end
end
......@@ -101,15 +129,6 @@ defmodule Marlon.Contract do
upper_done.()
end
# Reporter
defp reporter() do
fn (message) ->
IO.puts ">>> " <> Kernel.inspect(self()) <> " received " <> Kernel.inspect(message)
reporter
end
end
# Module and single message expression
defp is_module(atom) do
......
defmodule Marlon.ReporterContract do
use Marlon.Contract
def contract(done) do
fn (message) ->
actor = Process.get(:contractor_actor)
module = Process.get(:contractor_module)
IO.puts ">>> " <> Kernel.inspect(actor) <> " (" <> Kernel.inspect(module) <> ") checking for a " <> Kernel.inspect(message.name) <> " from " <> Kernel.inspect(message.sender)
contract(done)
end
end
end
defmodule Marlon.FullReporterContract do
use Marlon.Contract
def contract(done) do
fn (message) ->
actor = Process.get(:contractor_actor)
module = Process.get(:contractor_module)
IO.puts ">>> " <> Kernel.inspect(actor) <> " (" <> Kernel.inspect(module) <> ") checking for a " <> Kernel.inspect(message)
contract(done)
end
end
end
defmodule Marlon.SingleClientContract do
use Marlon.Contract
def contract(done) do
raise "NYI"
end
end
\ No newline at end of file
......@@ -2,11 +2,13 @@ defmodule Marlon.Contract.Contractor do
use GenServer
def start_link(contract_fn) do
GenServer.start_link(__MODULE__, %{current: contract_fn})
def start_link(contract_fn, actor, module) do
GenServer.start_link(__MODULE__, %{current: contract_fn, actor: actor, module: module})
end
def init(state) do
Process.put(:contractor_actor, state.actor)
Process.put(:contractor_module, state.module)
{:ok, state}
end
......
{
"folders":
[
{
"path": ".",
"folder_exclude_patterns": [".idea", ".vscode", "_build", "deps"],
"file_exclude_patterns": ["mix.exs.lock", "*.iml"]
}
]
}
......@@ -22,7 +22,7 @@ defmodule Marlon.Mixfile do
def project do
[
app: :marlon, # Application ID
app: :marlon,
version: "0.1.0",
elixir: "~> 1.5",
start_permanent: Mix.env == :prod,
......
# Just a Sandbox module for experimentation..
defmodule Sandbox do
use Marlon
def hello do
IO.puts "Hello"
end
def expand_macro do
quoted2 = quote do
defgoal ChunkSizeGoal,
[type: "ESRL",
params:
[exploration_phases: 7,
exploration_steps: 100],
actions: [process_chunk: [1,2,3]],
# action_trigger_fn: fn() -> true end,
# data_trigger_rate: 500,
reward: fn() -> true end
]
end
quoted2 |> Macro.expand_once(__ENV__) |> Macro.to_string()
end
# :observer.start
# LoadBalancing.run_example()
# :timer.sleep(100000000) # !! Otherwise, this process would exit, and any processes linked to it! Probably a better way to do this..
end
# {:ok, pid} = :python.start([{:python_path, '/Users/soft/Documents/Github/AI-Toolbox/build'}])
# :python.call(pid, :sys, :'version.__str__', [])
# IO.inspect :python.call(pid, :marlonEsrl, :createGoal, [3, 0.05, 2000, 7, 100])
# IO.inspect :python.call(pid, :testGuessingGame, :makeGoal, [])
# :python.call(pid, :test, :gameHelp, [])
# System.halt
# LoadBalancingExample.start_link(nil,[name: :example])
\ No newline at end of file