Commit 97e19406 authored by MARTINEZ Thierry 's avatar MARTINEZ Thierry

Cleaner API for influences, reactions and graphs.

Influence terms and reaction terms and built and destructed by
influence/2 and reaction/2.

add_reaction/* is no longer a part of the public API: use reaction/2 and
add_item/1 instead.

influence_graph and draw_influences now infer again the inference graph.

reaction_graph/draw_reactions and
influence_hypergraph/draw_influence_hypergraph draw the (hyper)graph of the
reactions and influences respectively.
parent a7cc92df
......@@ -124,10 +124,15 @@ check_conserv_reactions(C) :-
(
% model: current_model?
item([kind: reaction, item: Item]),
reaction(Item, _Kinetics, Reactants, Products)
reaction(Item, [
reactants: Reactants,
inhibitors: Inhibitors,
products: Products
])
),
(
scalar_conservation(Reactants, C, Moiety),
scalar_conservation(Inhibitors, C, Moiety),
scalar_conservation(Products, C, Moiety)
)
).
......
......@@ -6,15 +6,16 @@
add_influence/1,
list_influences/0,
influence_model/0,
reaction_model/0,
% Public API
is_influence_model/0,
check_influence_model/0,
with_influence_model/1,
list_model_influences/0,
influence/6,
enumerate_molecules_influences/1,
influence/2,
compute_ode_for_influences/0,
print_influence/2
print_influence/2,
substract_list/3
]
).
......@@ -63,6 +64,19 @@ influence_model :-
influence_model(HybridModel, InfluenceModel).
reaction_model :-
biocham_command,
doc('
creates a new reaction model by inferring
the reactions between all molecular objects of the current hybrid model
'),
single_model(HybridModel),
new_model,
set_model_name(reaction_model),
single_model(ReactionModel),
reaction_model(HybridModel, ReactionModel).
:- devdoc('\\section{Public API}').
......@@ -129,22 +143,35 @@ prolog:error_message(not_an_influence_model) -->
['Not an influence model'].
influence(InfluenceRule, Force, PositiveInputs, NegativeInputs, Sign, Output) :-
influence(InfluenceRule, Name, Force, PositiveInputs, NegativeInputs, Sign, Output) :-
devdoc(
'builds or decomposes an influence rule.'
),
once((
Force = 'MA'(1),
Name = '',
(
var(InfluenceRule)
->
true
;
InfluenceRule \= (_ for _)
InfluenceRule \= (_ -- _)
),
AnonymousInfluenceRule = InfluenceRule
;
InfluenceRule = (Name -- AnonymousInfluenceRule)
)),
once((
Force = 'MA'(1),
(
var(AnonymousInfluenceRule)
->
true
;
AnonymousInfluenceRule \= (_ for _)
),
BasicInfluenceRule = InfluenceRule
BasicInfluenceRule = AnonymousInfluenceRule
;
InfluenceRule = (Force for BasicInfluenceRule)
AnonymousInfluenceRule = (Force for BasicInfluenceRule)
)),
once((
BasicInfluenceRule = (Inputs -> Output),
......@@ -156,10 +183,53 @@ influence(InfluenceRule, Force, PositiveInputs, NegativeInputs, Sign, Output) :-
inputs(Inputs, PositiveInputs, NegativeInputs).
influence(InfluenceRule, Components) :-
devdoc('
builds or decomposes an influence rule.
\\argument{InfluenceRule} is an infuence term.
\\argument{Components} is a record-style list with items of the form
\\begin{itemize}
\\item\\texttt{name: Name} where \\texttt{Name} is an atom,
\\item\\texttt{force: Force} where \\texttt{Force} is an arithmetic expression,
\\item\\texttt{positive_inputs: PositiveInputs},
\\item\\texttt{negative_inputs: NegativeInputs}
where \\texttt{PositiveInputs} and \\texttt{NegativeInputs} are list of objects,
\\item\\texttt{sign: Sign}
where \\texttt{Sign} is either \\texttt{+} or \\texttt{-},
\\item\\texttt{output: Output} where \\texttt{Output} is an object.
\\end{itemize}
'),
(
var(InfluenceRule)
->
field_default(name, '', Components, Name),
field_default(force, 'MA'(1), Components, Force),
field_default(positive_inputs, [], Components, PositiveInputs),
field_default(negative_inputs, [], Components, NegativeInputs),
field_default(sign, '+', Components, Sign),
field_default(output, '_', Components, Output),
influence(
InfluenceRule, Name, Force, PositiveInputs, NegativeInputs, Sign, Output
)
;
influence(
InfluenceRule, Name, Force, PositiveInputs, NegativeInputs, Sign, Output
),
unify_records(Components, [
name: Name,
force: Force,
positive_inputs: PositiveInputs,
negative_inputs: NegativeInputs,
sign: Sign,
output: Output
])
).
compute_ode_for_influences :-
\+ (
item([kind: influence, item: Item]),
influence(Item, Force, PositiveInputs, _NegativeInputs, Sign, Output),
influence(Item, _Name, Force, PositiveInputs, _NegativeInputs, Sign, Output),
\+ (
maplist(add_coefficient, PositiveInputs, PositiveInputsWithCoefficient),
kinetics(PositiveInputsWithCoefficient, Force, ForceExpression),
......@@ -200,6 +270,26 @@ print_influence(_Id, Item) :-
format(' ~w ~w', [Arrow, Output]).
substract_list([], Difference, Difference).
substract_list([Coefficient0 * Object | Tail], Products, Difference) :-
(
select(Coefficient1 * Object, Products, Others)
->
Coefficient is Coefficient1 - Coefficient0,
(
Coefficient = 0
->
substract_list(Tail, Others, Difference)
;
substract_list(Tail, [Coefficient * Object | Others], Difference)
)
;
Coefficient is - Coefficient0,
substract_list(Tail, [Coefficient * Object | Products], Difference)
).
:- devdoc('\\section{Private predicates}').
......@@ -220,35 +310,62 @@ influence_model(HybridModel, InfluenceModel) :-
),
\+ (
item([parent: HybridModel, kind: reaction, item: Reaction]),
reaction(Reaction, Kinetics, Reactants, Products),
reaction(Reaction, [
kinetics: Kinetics,
reactants: Reactants,
inhibitors: Inhibitors,
products: Products
]),
\+ (
substract_list(Reactants, Products, Difference),
create_influences(Reactants, Difference, Kinetics, InfluenceModel)
create_influences(Reactants, Inhibitors, Difference, Kinetics, InfluenceModel)
)
).
substract_list([], Difference, Difference).
substract_list([Coefficient0 * Object | Tail], Products, Difference) :-
(
select(Coefficient1 * Object, Products, Others)
->
Coefficient is Coefficient1 - Coefficient0,
(
Coefficient = 0
->
substract_list(Tail, Others, Difference)
;
substract_list(Tail, [Coefficient * Object | Others], Difference)
reaction_model(HybridModel, ReactionModel) :-
\+ (
item([parent: HybridModel, kind: reaction, item: Reaction]),
\+ (
add_item([kind: reaction, item: Reaction])
)
),
\+ (
item([parent: HybridModel, kind: influence, item: Influence]),
influence(Influence, [
name: Name,
force: Force,
positive_inputs: PositiveInputs,
negative_inputs: NegativeInputs,
sign: Sign,
output: Output
]),
\+ (
(
Sign = +
->
reaction(Reaction, [
name: Name,
kinetics: Force,
reactants: PositiveInputs,
inhibitors: NegativeInputs,
products: [Output | PositiveInputs]
])
;
reaction(Reaction, [
name: Name,
kinetics: Force,
reactants: [Output | PositiveInputs],
inhibitors: NegativeInputs,
products: PositiveInputs
])
),
add_item([parent: ReactionModel, kind: reaction, item: Reaction])
)
;
Coefficient is - Coefficient0,
substract_list(Tail, [Coefficient * Object | Products], Difference)
).
create_influences(Reactants, Difference, Kinetics, InfluenceModel) :-
create_influences(Reactants, Inhibitors, Difference, Kinetics, InfluenceModel) :-
\+ (
findall(
Input,
......@@ -266,7 +383,13 @@ create_influences(Reactants, Difference, Kinetics, InfluenceModel) :-
Sign = -,
simplify(- Coefficient * Kinetics, CoefficientKinetics)
),
influence(Influence, CoefficientKinetics, PositiveInputs, [], Sign, Output),
influence(Influence, [
force: CoefficientKinetics,
positive_inputs: PositiveInputs,
negative_inputs: Inhibitors,
sign: Sign,
output: Output
]),
add_item([parent: InfluenceModel, kind: influence, item: Influence])
)
).
......@@ -296,24 +419,3 @@ inputs(
list_enumeration(PositiveInputList, PositiveInputEnum),
list_enumeration(NegativeInputList, NegativeInputEnum),
!.
enumerate_molecules_influences(Molecules) :-
setof(
Molecule,
enumerate_molecule_influences(Molecule),
Molecules
).
enumerate_molecule_influences(Molecule) :-
item([kind: influence, item: Item]),
influence(Item, _Force, PositiveInputs, NegativeInputs, _Sign, Output),
(
member( Molecule, PositiveInputs)
;
member( Molecule, NegativeInputs)
;
Molecule = Output
).
......@@ -32,64 +32,96 @@ test(
test(
'influence builds',
[Influence == (2 for (a, b) / c -> d)]
[Influence == (i -- 2 for (a, b) / c -> d)]
) :-
influence(Influence, 2, [a, b], [c], +, d).
influence(Influence, [
name: 'i',
force: 2,
positive_inputs: [a, b],
negative_inputs: [c],
sign: +,
output: d
]).
test(
'influence builds with positive inputs',
[Influence == (b '-|' c)]
) :-
influence(Influence, 'MA'(1), [b], [], -, c).
influence(Influence, [
positive_inputs: [b],
sign: -,
output: c
]).
test(
'influence builds with negative inputs',
[Influence == (/ a '-|' a)]
) :-
influence(Influence, 'MA'(1), [], [a], -, a).
influence(Influence, [
negative_inputs: [a],
sign: -,
output: a
]).
test(
'influence builds with no inputs',
[Influence == ('_' -> a)]
) :-
influence(Influence, 'MA'(1), [], [], +, a).
influence(Influence, [
sign: +,
output: a
]).
test(
'influence destructs',
[
result(Force, PositiveInputs, NegativeInputs, Sign, Output)
result(Name, Force, PositiveInputs, NegativeInputs, Sign, Output)
==
result(2, [a, b], [c], +, d)
result(i, 2, [a, b], [c], +, d)
]
) :-
influence(
(2 for (a, b) / c -> d),
Force,
PositiveInputs,
NegativeInputs,
Sign,
Output
).
influence((i -- 2 for (a, b) / c -> d), [
name: Name,
force: Force,
positive_inputs: PositiveInputs,
negative_inputs: NegativeInputs,
sign: Sign,
output: Output
]).
test(
'influence destructs with positive inputs',
[
result(Force, PositiveInputs, NegativeInputs, Sign, Output)
result(Name, Force, PositiveInputs, NegativeInputs, Sign, Output)
==
result('MA'(1), [b], [], -, c)
result(Name, 'MA'(1), [b], [], -, c)
]
) :-
influence((b '-|' c), Force, PositiveInputs, NegativeInputs, Sign, Output).
influence((b '-|' c), [
name: Name,
force: Force,
positive_inputs: PositiveInputs,
negative_inputs: NegativeInputs,
sign: Sign,
output: Output
]).
test(
'influence destructs with negative inputs',
[
result(Force, PositiveInputs, NegativeInputs, Sign, Output)
result(Force, Name, PositiveInputs, NegativeInputs, Sign, Output)
==
result('MA'(1), [], [a], -, a)
result('MA'(1), '', [], [a], -, a)
]
) :-
influence((/ a '-|' a), Force, PositiveInputs, NegativeInputs, Sign, Output).
influence((/ a '-|' a), [
name: Name,
force: Force,
positive_inputs: PositiveInputs,
negative_inputs: NegativeInputs,
sign: Sign,
output: Output
]).
test(
'compute_ode_for_influence_model',
......
......@@ -3,9 +3,12 @@
[
% Commands
influence_graph/0,
influence_hypergraph/0,
draw_influences/0,
draw_influence_hypergraph/0,
% Public API
influence_graph/1
influence_graph/1,
influence_hypergraph/1
]
).
......@@ -18,17 +21,26 @@
influence_graph :-
biocham_command,
doc('builds the influence graph of the current model.'),
doc('infers the graph of influences of the current model.'),
new_graph,
set_graph_name(influence_graph),
get_current_graph(GraphId),
influence_graph(GraphId).
influence_hypergraph :-
biocham_command,
doc('builds the hypergraph of the influence rules of the current model.'),
new_graph,
set_graph_name(influence_hypergraph),
get_current_graph(GraphId),
influence_hypergraph(GraphId).
draw_influences :-
biocham_command,
doc('
Draws the influence graph of the current model.
infers and draws the influence graph of the current model.
\\begin{example}
'),
biocham_silent(clear_model),
......@@ -47,27 +59,97 @@ draw_influences :-
).
:- devdoc('\\section{Public API}').
draw_influence_hypergraph :-
biocham_command,
doc('
Draws the hypergraph of the influence rules of the current model.
'),
setup_call_cleanup(
new_graph(GraphId),
(
influence_hypergraph(GraphId),
draw_graph(GraphId)
),
delete_item(GraphId)
).
influence_graph(GraphId) :-
with_influence_model((
influence_graphs:influence_graph_aux(GraphId)
)).
:- devdoc('\\section{Public API}').
:- devdoc('\\section{Private predicates}').
influence_graph(GraphId) :-
\+ (
(
item([kind: reaction, item: Item]),
reaction(Item, [
reactants: Reactants,
inhibitors: Inhibitors,
products: Products
]),
substract_list(Reactants, Products, Difference),
(
member(_ * Input, Reactants),
InputSign = +
;
member(Input, Inhibitors),
InputSign = -
),
member(Coefficient * Output, Difference),
(
Coefficient > 0
->
RuleSign = +
;
RuleSign = -
)
;
item([kind: influence, item: Item]),
influence(Item, [
positive_inputs: PositiveInputs,
negative_inputs: NegativeInputs,
sign: RuleSign,
output: Output
]),
(
member(Input, PositiveInputs),
InputSign = +
;
member(Input, NegativeInputs),
InputSign = -
)
),
\+ (
sign_rule(RuleSign, InputSign, Sign),
add_vertex(GraphId, Input, InputId),
add_vertex(GraphId, Output, OutputId),
add_edge(GraphId, InputId, OutputId, EdgeId),
set_attribute(EdgeId, sign = Sign)
)
).
influence_graph_aux(GraphId) :-
influence_hypergraph(GraphId) :-
set_counter(influence, 0),
\+ (
item([kind: influence, item: Item]),
influence(Item, Force, PositiveInputs, NegativeInputs, Sign, Output),
influence(Item, [
force: Force,
name: Name,
positive_inputs: PositiveInputs,
negative_inputs: NegativeInputs,
sign: Sign,
output: Output
]),
\+ (
count(influence, InfluenceCount),
format(atom(InfluenceCounter), 'influence~d', [InfluenceCount]),
transition(GraphId, InfluenceCounter, TransitionId),
(
Name = ''
->
count(influence, InfluenceCount),
format(atom(TransitionName), 'influence~d', [InfluenceCount])
;
TransitionName = Name
),
transition(GraphId, TransitionName, TransitionId),
set_attribute(TransitionId, sign = Sign),
set_attribute(TransitionId, force = Force),
\+ (
......@@ -90,3 +172,14 @@ influence_graph_aux(GraphId) :-
add_edge(GraphId, TransitionId, OutputId, _)
)
).
:- devdoc('\\section{Private predicates}').
sign_rule(+, A, A).
sign_rule(-, +, -).
sign_rule(-, -, +).
......@@ -78,7 +78,11 @@ add_stable_constraints(BoolState) :-
(PositiveInputs, Sign, Output),
(
item([kind: influence, item: Item]),
influence(Item, _Force, PositiveInputs, _NegativeInputs, Sign, Output)
influence(Item, [
positive_inputs: PositiveInputs,
sign: Sign,
output: Output
])
),
InfluenceTriples
),
......@@ -90,8 +94,12 @@ add_tscc_constraints(BoolState) :-
(PositiveInputs, Sign, Output),
(
item([kind: influence, item: Item]),
influence(Item, _Force, PositiveInputs, _NegativeInputs, Sign, Output),
Sign = '+'
influence(Item, [
positive_inputs: PositiveInputs,
sign: Sign,
output: Output
]),
Sign = +
),
InfluenceTriples
),
......@@ -147,7 +155,11 @@ enumerate_objects(Objects) :-
enumerate_object(Object) :-
item([kind: influence, item: Item]),
influence(Item, _Force, PositiveInputs, NegativeInputs, _Sign, Output),
influence(Item, [
positive_inputs: PositiveInputs,
negative_inputs: NegativeInputs,
output: Output
]),
(
member(Object, PositiveInputs)
;
......@@ -159,7 +171,11 @@ enumerate_object(Object) :-
has_enabled_effective(Sign, BoolState, NewBoolState) :-
item([kind: influence, item: Item]),
influence(Item, _Force, PositiveInputs, _NegativeInputs, Sign, Output),
influence(Item, [
positive_inputs: PositiveInputs,
sign: Sign,
output: Output
]),
get_assoc_list(PositiveInputs, BoolState, BoolInputs),
maplist(=(1), BoolInputs),
(
......@@ -174,7 +190,11 @@ has_enabled_effective(Sign, BoolState, NewBoolState) :-
has_enabled_backward_effective(Sign, BoolState, PrevBoolState) :-
item([kind: influence, item: Item]),
influence(Item, _Force, PositiveInputs, _NegativeInputs, Sign, Output),
influence(Item, [
positive_inputs: PositiveInputs,
sign: Sign,
output: Output
]),
(
Sign = '+'
->
......
......@@ -193,7 +193,8 @@ clear_model :-
delete_item(Id)
)
),
retractall(nusmv:query_molecules(_)).
retractall(nusmv:query_molecules(_)),
assertz(nusmv:query_molecules([])).
list_models :-
......@@ -341,15 +342,13 @@ add_item(Options) :-
),
not_fresh,
create_item_id(Id),
put_item(Parent0, Kind, Key, Item, Id),
update_parent_model_identifier_kinds(Parent0).
put_item(Parent0, Kind, Key, Item, Id).
replace_item(Id, Kind, Key, Item) :-
retract(item(Id, Parent, _Kind, _Item)),
retractall(key(_Key, Id)),
put_item(Parent, Kind, Key, Item, Id),
update_parent_model_identifier_kinds(Parent).
put_item(Parent, Kind, Key, Item, Id).
change_item(Options, Kind, Key, Item) :-
......@@ -540,9 +539,9 @@ delete_item(Id) :-
item(SubId, Id, _SubKind, _SubItem),
\+ (
(
delete_item(SubId)
item(SubId, __Id, __SubKind, __SubItem)
->
true
delete_item(SubId)
;
true
)
......@@ -552,9 +551,9 @@ delete_item(Id) :-
dependency(SubId, Id),
\+ (
(
delete_item(SubId)
item(SubId, ___Id, ___SubKind, ___SubItem)
->
true
delete_item(SubId)
;
true
)
......@@ -751,7 +750,8 @@ put_item(Parent, Kind, Key, Item, Id) :-
;
assertz(key(Key, Id))
),
assertz(item(Id, Parent, Kind, Item)).
assertz(item(Id, Parent, Kind, Item)),
update_parent_model_identifier_kinds(Parent).
single_model(Model, ModelId) :-
......
:- module(
molecules,
[
% Commands
list_molecules/0,
list_locations/0,
% API
enumerate_all_molecules/1
% Public API
enumerate_molecules/1
]
).
:- devdoc('\\section{Commands}').
list_molecules :-
biocham_command,
doc('lists all the molecules of the current model.'),
......@@ -22,33 +26,23 @@ list_locations :-
maplist(extract_location,L,R),
format('~w\n', [R]).
:- devdoc('\\section{Public API}').
enumerate_molecules(Molecules) :-
single_model(ModelId),
setof(
Molecule,
identifier_kind(ModelId, Molecule, object),
Molecules
).
:- devdoc('\\section{Private predicates}').
extract_location(M,L):-
atom_chars(M,C),
append(_,[':',':'|D],C),
atom_chars(L,D).