Packages

Gyx allows designing and training Reinforcement Learning tasks. It includes environment abstractions that allows interaction with Python based environments like OpenAI Gym.

Current section

Files

Jump to
gyx lib experience replay_buffer_ets.ex
Raw

lib/experience/replay_buffer_ets.ex

defmodule Gyx.Experience.ReplayBufferETS do
@moduledoc """
Implements ReplayMemory behaviour relying on ETS
"""
alias Gyx.Core.ReplayMemory
use GenServer
use ReplayMemory
@compile {:parse_transform, :ms_transform}
@ets_name :__MODULE__
def start_link(_, ops) do
GenServer.start_link(__MODULE__, %{}, ops)
end
@impl true
def init(_) do
experiences =
:ets.new(@ets_name, [:ordered_set, :public, :named_table, write_concurrency: true])
{:ok, experiences}
end
def delete(replay_buffer, key) do
GenServer.cast(replay_buffer, {:delete, key})
end
def get(replay_buffer, key) do
GenServer.call(replay_buffer, {:get, key})
end
@doc """
Adds a new experience to the reppay buffer
"""
@impl true
def add(replay_buffer, experience) do
GenServer.cast(replay_buffer, {:add, experience})
end
@impl true
def get_batch(replay_buffer, {n, sampling_strategy}) do
GenServer.call(replay_buffer, {:get_batch, {n, sampling_strategy}})
end
def delete(replay_buffer), do: GenServer.cast(replay_buffer, :delete)
@impl true
def handle_cast(:delete, state) do
:ets.delete(:__MODULE__)
{:noreply, state}
end
def handle_cast({:delete, key}, state) do
:ets.delete(:__MODULE__, key)
{:noreply, state}
end
def handle_cast({:add, exp}, _state) do
{:ok, timestamp_key} = DateTime.now("Etc/UTC")
:ets.insert(@ets_name, {timestamp_key, exp})
{:noreply, timestamp_key}
end
@impl true
def handle_call({:get, key}, _from, state) do
reply =
case :ets.lookup(@ets_name, key) do
[] -> nil
[{_timestamp, experience}] -> experience
end
{:reply, reply, state}
end
def handle_call({:get_batch, {n, :random}}, _from, state) do
reply =
@ets_name
|> :ets.select(all_match_specification())
|> Enum.shuffle()
|> Enum.take(n)
{:reply, reply, state}
end
def handle_call({:get_batch, {n, :latest}}, _from, state) do
reply =
@ets_name
|> :ets.select(all_match_specification())
|> Enum.sort_by(fn {d, _exp} -> {d.year, d.month, d.day, d.second, d.microsecond} end)
|> Enum.take(-n)
{:reply, reply, state}
end
defp all_match_specification, do: :ets.fun2ms(fn {k, v} -> {k, v} end)
end