Skip to content

Commit

Permalink
fix queries, fix tutorials/traces
Browse files Browse the repository at this point in the history
  • Loading branch information
thevolatilebit committed May 2, 2023
1 parent fe4edc5 commit 707e13d
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 61 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "AlgebraicAgents"
uuid = "f6eb0ae3-10fa-40e6-88dd-9006ba45093a"
version = "0.3.14"
version = "0.3.15"

[deps]
Crayons = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f"
Expand Down
2 changes: 1 addition & 1 deletion src/queries.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ filter(agents, f"_.age > 21 && _.name ∈ ['a', 'b']")
agents |> @filter _.age > 21 && _.name ∈ ['a', 'b']
```
"""
struct FilterQuery{T}
struct FilterQuery{T} <: AbstractQuery
query::T
end

Expand Down
22 changes: 9 additions & 13 deletions tutorials/traces/traces.jl
Original file line number Diff line number Diff line change
@@ -1,33 +1,29 @@
using AlgebraicAgents
import Distributions: Poisson
import Random: randstring
using MacroTools

# type system
include("types.jl")
# successor queries
include("successor_queries.jl")

# initial date
t0 = Date("1-1-2020", dateformat"dd-mm-yyyy")

# preclinical: wraps candidates/rejected/accepted molecules, schedules experiments
## (filter) queries - candidate rejection
q = [f"""any(t -> (t.name == "assay_1") && (t.readout > .5), _.trace)"""]
preclinical = Preclinical("preclinical", 3.0; queries_reject = q)
q = AlgebraicAgents.AbstractQuery[f"""any(t -> (t.name == "assay_1") && (t.readout > .5), _.trace)"""]
preclinical = Preclinical("preclinical", 3.0, t0; queries_reject = q)

## add assays: first a directory of assays (free agent)
superassay = entangle!(preclinical, FreeAgent("assays"))
N_assays = 5;
for i in 1:N_assays
entangle!(superassay, Assay("assay_$i", rand(1.0:5.0), 10e3 * rand(), rand(10.0:20.0)))
entangle!(superassay, Assay("assay_$i", Week(rand([1, 2, 3])), 10e3 * rand(), rand(10.0:20.0), t0))
end;

# discovery: emits candidate molecules
discovery = Discovery("discovery", 3.0)
discovery = Discovery("discovery", 3.0, t0)

# overarching model
pharma_model = (preclinical, discovery; name = "pharma_model")

# let the problem evolve
simulate(pharma_model, 100)
simulate(pharma_model, t0 + Week(50))

# queries
## successor query
Expand All @@ -41,4 +37,4 @@ i = 2;
pharma_model |> @filter(f"length(_.path)>$i");
### remove candidate molecules with more than two parents
pharma_model |> @filter(length(_.path)>$i) |> @filter(_.decision_time===missing) .|>
disentangle!
disentangle!
102 changes: 56 additions & 46 deletions tutorials/traces/types.jl
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
using AlgebraicAgents
using Dates
using Distributions, Random
using MacroTools

include("successor_queries.jl")

#=
declare type hierarchy of a toy preclinical development model:
- overarching pharma model (FreeAgent),
- discovery unit (emits drug candidates),
- preclinical unit; orchestrates experiments, executes queries,
- assay; reduces uncertainty about candidate's activity but bears cost,
- candidate molecule; undergoes experiments.
declare type hierarchy of a discovery straw man
processes:
- discovery unit
- preclinical unit
entities:
- candidate molecule
- experiments (capabilities; experiments implement their own schedule)
=#
using AlgebraicAgents

# candidate molecules
abstract type AbstractMolecule <: AbstractAlgebraicAgent end
Expand All @@ -18,88 +25,88 @@ const uncertainty_threshold = 0.2
# in-silico belief
const init_belief_generator = (r = rand(N); r ./ sum(r))

# candidate molecule; carries a scientist's belief about its activity
# candidate molecule
"Candidate molecule, parametrized by a chemical fingerprint."
@aagent FreeAgent AbstractMolecule struct Molecule
birth_time::Float64
decision_time::Union{Float64, Missing}
birth_time::Date
decision_time::Union{Date, Nothing}

fingerprint::NTuple{N, Float64}
path::Vector{AbstractString}

is_allocated::Bool
is_allocated::Bool # is in an experiment?

belief::Float64
trace::Vector{<:Any}
belief::Float64 # belief about biological activity
trace::Vector # experiments ran
end

# preclinical experiments
abstract type AbstractAssay <: AbstractAlgebraicAgent end

# parametric experiment; updates belief about candidate's activity
"Parametric experiment, updates belief about candidate's activity."
# experiment; updates belief about candidate's activity
"Parametric experiment, updates belief about a candidate molecule's biological activity."
@aagent FreeAgent AbstractAssay struct Assay
duration::Float64
duration::Period
cost::Float64
capacity::Float64
capacity::Int

belief_model::NTuple{N, Float64}

allocated::Vector{AlgebraicAgents.UUID}
planned::Vector{AlgebraicAgents.UUID}

t::Float64
t0::Float64
t::Date
t0::Date
end

## toy discovery unit - emits molecules with chemical fingerprints
## discovery unit;generates candidate molecules with chemical fingerprints
@aagent struct Discovery
rate::Float64 # expected number of mols per unit step

t::Float64
dt::Float64
t::Date
dt::Period

t0::Float64
t0::Date
end

## toy preclinical development model - orchestrates experiments, runs queries
"Toy discovery unit; emits molecules."
@aagent struct Preclinical
queries_accept::Vector{AlgebraicAgents.AbstractQuery}
queries_reject::Vector{AlgebraicAgents.AbstractQuery}
queries_accept::Vector{<:AlgebraicAgents.AbstractQuery}
queries_reject::Vector{<:AlgebraicAgents.AbstractQuery}

total_costs::Float64

perturb_rate::Float64 # expected number of perturbed mols (successors) born per a unit step

t::Float64
t0::Float64
dt::Float64
t::Date
t0::Date
dt::Period
end

# constructors
"Emit a candidate molecule."
function Molecule(mol, fingerprint, t, path = AbstractString[])
Molecule(mol, t, missing, fingerprint, path, false, init_belief_from_fingerprint(i), [])
"Generate a candidate molecule."
function Molecule(mol::AbstractString, fingerprint, t, path = AbstractString[])
Molecule(mol, t, nothing, fingerprint, path, false, init_belief_from_fingerprint(fingerprint), [])
end

"Initialize a discovery unit, parametrized by molecule production rate."
function Discovery(name, rate, t = 0.0; dt = 2.0)
Discovery(name, rate, t, dt, t0)
function Discovery(name::AbstractString, rate, t::Date; dt::Period = Week(1))
Discovery(name, rate, t, dt, t)
end

"Initialize an assay, parametrized by duration, cost, capacity, and a belief model."
function Assay(name, duration::Float64, cost::Float64, capacity::Float64,
belief_model = tuple(rand(-1:1, 5)...), t = 0.0)
function Assay(name::AbstractString, duration::Period, cost::Float64, capacity::Float64, t::Date,
belief_model = tuple(rand(-1:1, 5)...))
Assay(name, duration, cost, capacity, belief_model,
Vector{AlgebraicAgents.UUID}(undef, 0), Vector{AlgebraicAgents.UUID}(undef, 0),
t, t)
end

"Initialize a preclinical unit comprising candidate molecules and parametrized by removal queries."
function Preclinical(name, perturb_rate::Float64, t = 0.0; dt = 1.0,
queries_accept = AlgebraicAgents.AbstractQuery[],
queries_reject = AlgebraicAgents.AbstractQuery[])
function Preclinical(name::AbstractString, perturb_rate::Float64, t::Date; dt::Period=Week(1),
queries_accept=AlgebraicAgents.AbstractQuery[],
queries_reject=AlgebraicAgents.AbstractQuery[])
p = Preclinical(name, queries_accept, queries_reject, 0.0, perturb_rate, t, t, dt)

# candidates and accepted, rejected candidates
Expand All @@ -116,7 +123,7 @@ end
function AlgebraicAgents._step!(dx::Discovery)
t = projected_to(dx)
# emit candidates
for _ in 1:rand(Poisson(dx.rate * dx.dt))
for _ in 1:rand(Poisson(dx.rate * Day(dx.dt).value))
mol = Molecule(randstring(5), Tuple(rand(N)), t)
entangle!(getagent(getparent(dx), "preclinical/candidates"), mol)
end
Expand Down Expand Up @@ -153,13 +160,10 @@ end

AlgebraicAgents._projected_to(a::Assay) = a.t

# empty schedule
AlgebraicAgents._reinit!(a::Assay) = empty!(a.allocated)

## belief updating
### output in-silico belief
function init_belief_from_fingerprint(mol::Molecule)
mol.belief = init_belief_generator' * collect(mol.fingerprint)
function init_belief_from_fingerprint(fingerprint)
init_belief_generator' * collect(fingerprint)
end

### update belief (in vitro/vivo), update trace
Expand Down Expand Up @@ -237,16 +241,22 @@ function AlgebraicAgents._step!(a::Preclinical)
# add perturbed candidates (from accepted)
if !isempty(inners(getagent(a, "accepted")))
for c in rand(collect(values(inners(getagent(a, "accepted")))),
rand(Poisson(a.dt * a.perturb_rate)))
rand(Poisson(Day(a.dt).value * a.perturb_rate)))
mol = Molecule(randstring(5), c.fingerprint .+ 0.1 .* Tuple(rand(N)), t,
[c.path; "parent_$(rand(1:2))"; c.name])
entangle!(getagent(a, "candidates"), mol)
end
end

a.t += a.dt
end

AlgebraicAgents._projected_to(a::Preclinical) = a.t

# empty schedule
AlgebraicAgents._reinit!(a::Assay) = (a.t = a.t0; a.total_costs = 0.0)
function AlgebraicAgents._reinit!(a::Assay)
a.t = a.t0; a.total_costs = 0.0
empty!(a.allocated)

a
end

0 comments on commit 707e13d

Please sign in to comment.