Commit ad72f2ec authored by MARTINEZ Thierry 's avatar MARTINEZ Thierry

Support for options (see numerical_simulation)

parent 551bfff0
......@@ -477,7 +477,7 @@ instantiate_grammar_body(Item) :-
generate_body_item_clause(Clause, Stream, Type) :-
predicate_info(Clause, ArgumentTypes, BiochamCommand, Doc),
predicate_info(Clause, ArgumentTypes, Options, BiochamCommand, Doc),
(
(
BiochamCommand = yes
......@@ -519,7 +519,24 @@ generate_body_item_clause(Clause, Stream, Type) :-
write_doc_item(DocItem, Stream, Type)
)
),
write(Stream, '</div>')
write(Stream, '\n</div>'),
(
Options = []
->
true
;
write(Stream, '\n<div>\n<h6>Options</h6>\n<dl>'),
\+ (
member(option(Option, _OptionType, OptionDoc), Options),
\+ (
format(Stream, '\n<dt>~a</dt>', [Option]),
write(Stream, '\n<dd>'),
write_doc(Stream, OptionDoc),
write(Stream, '</dd>')
)
),
write(Stream, '\n</dl>\n</div>')
)
;
true
).
......
......@@ -2,6 +2,7 @@
graph_editor,
[
% Grammars
attribute/1,
edge/1,
edgeref/1,
% Commands
......@@ -18,7 +19,6 @@
list_isolated_vertices/0,
list_graph_objects/0,
graph_object/1,
attribute/1,
set_attribute/2,
delete_attribute/2,
list_attributes/1,
......@@ -49,6 +49,17 @@
:- devdoc('\\section{Grammars}').
:- grammar(attribute).
attribute(Key = Value) :-
name(Key),
term(Value).
attribute(Name) :-
name(Name).
:- grammar(edge).
......@@ -198,22 +209,11 @@ graph_object(Name) :-
name(Name).
:- grammar(attribute).
attribute(Key: Value) :-
name(Key),
term(Value).
attribute(Name) :-
name(Name).
set_attribute(Id, Attribute) :-
integer(Id),
!,
(
Attribute = Key: _Value
Attribute = (Key = _Value)
->
true
;
......@@ -319,7 +319,7 @@ get_attribute(Id, Attribute) :-
integer(Id),
!,
(
Attribute = Key: _Value
Attribute = (Key = _Value)
->
true
;
......@@ -381,7 +381,7 @@ kind(GraphId, Name, Kind) :-
kind(GraphId, Name, Kind, VertexId) :-
add_vertex(GraphId, Name, VertexId),
set_attribute(VertexId, kind: Kind).
set_attribute(VertexId, kind = Kind).
add_vertex(GraphId, Name, VertexId) :-
......
......@@ -87,11 +87,11 @@ test(
'list_graph_objects',
[true(Atom == '\c
[0] A->B
[1] stochiometry:2
[1] stochiometry=2
[2] B
[3] kind:transition
[3] kind=transition
[4] C
[5] kind:place
[5] kind=place
[6] D
')]) :-
clear_model,
......@@ -101,7 +101,7 @@ test(
command(place('C')),
command(add_vertex('D')),
command(add_edge('A' -> 'B')),
command(set_attribute(('A' -> 'B'), stochiometry: 2)),
command(set_attribute(('A' -> 'B'), stochiometry = 2)),
with_output_to(atom(Atom), list_graph_objects).
test('set_attribute vertex', [true(Attributes == ['object', 'item'])]) :-
......@@ -115,17 +115,17 @@ test('set_attribute vertex', [true(Attributes == ['object', 'item'])]) :-
find_item([parent: GraphId, kind: vertex, key: 'A', id: VertexId]),
all_items([parent: VertexId, kind: attribute], Attributes).
test('set_attribute edge', [true(Attributes == [stochiometry: 2])]) :-
test('set_attribute edge', [true(Attributes == [stochiometry = 2])]) :-
clear_model,
new_graph,
command(add_vertex('A', 'B')),
command(add_edge('A' -> 'B')),
command(set_attribute(('A' -> 'B'), stochiometry: 2)),
command(set_attribute(('A' -> 'B'), stochiometry = 2)),
get_current_graph(GraphId),
find_item([parent: GraphId, kind: edge, key: ('A' -> 'B'), id: EdgeId]),
all_items([parent: EdgeId, kind: attribute], Attributes).
test('place', [true(Attributes == [kind: place])]) :-
test('place', [true(Attributes == [kind = place])]) :-
clear_model,
new_graph,
command(transition('A')),
......@@ -135,7 +135,7 @@ test('place', [true(Attributes == [kind: place])]) :-
find_item([parent: GraphId, kind: vertex, key: 'A', id: VertexId]),
all_items([parent: VertexId, kind: attribute], Attributes).
test('transition', [true(Attributes == [kind: transition])]) :-
test('transition', [true(Attributes == [kind = transition])]) :-
clear_model,
new_graph,
command(place('A')),
......@@ -155,19 +155,19 @@ test('delete_attribute', [true(Attributes == [])]) :-
find_item([parent: GraphId, kind: vertex, key: 'A', id: VertexId]),
all_items([parent: VertexId, kind: attribute], Attributes).
test('list_attributes vertex', [true(Atom == '[0] kind:place\n')]) :-
test('list_attributes vertex', [true(Atom == '[0] kind=place\n')]) :-
clear_model,
new_graph,
command(place('A')),
with_output_to(atom(Atom), list_attributes('A')).
test('list_attributes edge', [true(Atom == '[0] stochiometry:2\n')]) :-
test('list_attributes edge', [true(Atom == '[0] stochiometry=2\n')]) :-
clear_model,
new_graph,
command(add_vertex('A')),
command(add_vertex('B')),
command(add_edge('A' -> 'B')),
command(set_attribute(('A' -> 'B'), stochiometry: 2)),
command(set_attribute(('A' -> 'B'), stochiometry = 2)),
with_output_to(atom(Atom), list_attributes('A' -> 'B')).
test('get_attribute', [true(Kind == transition)]) :-
......@@ -175,6 +175,6 @@ test('get_attribute', [true(Kind == transition)]) :-
new_graph,
command(transition('A')),
get_current_graph(GraphId),
once(get_attribute(GraphId, 'A', kind: Kind)).
once(get_attribute(GraphId, 'A', kind = Kind)).
:- end_tests(graph_editor).
......@@ -53,7 +53,7 @@ write_headers(Options) :-
length(InitialParameterValues, ParameterCount),
write_header('VARIABLE_COUNT', '~d', VariableCount),
write_header('PARAMETER_COUNT', '~d', ParameterCount),
write_option('METHOD', '~a', method, Options),
write_option('METHOD', 'gsl_odeiv2_step_~a', method, Options),
write_option('ERROR_EPSILON_ABSOLUTE', '~f', error_epsilon_absolute, Options),
write_option('ERROR_EPSILON_RELATIVE', '~f', error_epsilon_relative, Options),
write_option('INITIAL_STEP_SIZE', '~f', initial_step_size, Options),
......
......@@ -7,7 +7,7 @@ test('van_der_pol') :-
equations: [[1], -[0] + p(0) * [1] * (1 - [0] ^ 2)],
initial_values: [1.0, 0.0],
initial_parameter_values: [10],
method: gsl_odeiv2_step_rk8pd,
method: rk8pd,
error_epsilon_absolute: 1e-6,
error_epsilon_relative: 1e-6,
initial_step_size: 1e-6,
......
......@@ -65,14 +65,14 @@ influence_graph_aux(GraphId) :-
count(influence, InfluenceCount),
format(atom(InfluenceCounter), 'influence~d', [InfluenceCount]),
transition(GraphId, InfluenceCounter, TransitionId),
set_attribute(TransitionId, sign: Sign),
set_attribute(TransitionId, force: Force),
set_attribute(TransitionId, sign = Sign),
set_attribute(TransitionId, force = Force),
\+ (
member(PositiveInput, PositiveInputs),
\+ (
place(GraphId, PositiveInput, PlaceId),
add_edge(GraphId, PlaceId, TransitionId, EdgeId),
set_attribute(EdgeId, sign: '+')
set_attribute(EdgeId, sign = '+')
)
),
\+ (
......@@ -80,7 +80,7 @@ influence_graph_aux(GraphId) :-
\+ (
place(GraphId, NegativeInput, PlaceId),
add_edge(GraphId, PlaceId, TransitionId, EdgeId),
set_attribute(EdgeId, sign: '-')
set_attribute(EdgeId, sign = '-')
)
),
place(GraphId, Output, PlaceId),
......
option(
method: rk8pd,
error_epsilon_absolute: 1e-6,
error_epsilon_relative: 1e-6,
initial_step_size: 1e-6,
precision: 5
).
function MA(k) = k * product(S * O in [reactants], O ^ S).
function MM(Vm, Km) = Vm * single_reactant / (Km + single_reactant).
......
:- module(
numerical_simulation,
[
numerical_simulation/0,
% Grammars
method/1,
% Commands
numerical_simulation/1
]
).
numerical_simulation :-
biocham_command,
doc('
performs a numerical simulation up to 20s.
\\begin{example}
'),
biocham_silent(clear_model),
biocham(a => b),
biocham(present(a)),
biocham(numerical_simulation),
biocham(plot),
doc('
\\end{example}
'),
numerical_simulation(20).
:- devdoc('\\section{Grammars}').
:- grammar(method).
method(rk2).
method(rk4).
method(rkf45).
method(rkck).
method(rk8pd).
method(rk1imp).
method(rk2imp).
method(rk4imp).
method(bsimp).
method(msadams).
method(msbdf).
:- devdoc('\\section{Commands}').
numerical_simulation(Time) :-
biocham_command,
type(Time, time),
option(method, method, Method, 'method for the numerical solver'),
option(
error_epsilon_absolute, number, ErrorEpsilonAbsolute,
'absolute error for the numerical solver'
),
option(
error_epsilon_relative, number, ErrorEpsilonRelative,
'relative error for the numerical solver'
),
option(
initial_step_size, number, InitialStepSize,
'initial step size for the numerical solver'
),
option(
precision, number, Precision,
'precision for the numerical solver'
),
doc('performs a numerical simulation up to a given time.'),
with_current_ode_system((
numerical_simulation:make_ode_system,
numerical_simulation:solve(Time)
numerical_simulation:solve(
Time, Method, ErrorEpsilonAbsolute, ErrorEpsilonRelative, InitialStepSize,
Precision
)
)).
......@@ -39,7 +76,13 @@ make_ode_system :-
convert_ode.
solve(Time) :-
:- devdoc('\\section{Private predicate}').
solve(
Time, Method, ErrorEpsilonAbsolute, ErrorEpsilonRelative, InitialStepSize,
Precision
) :-
gather_headers(Headers),
gather_equations(Equations),
gather_initial_values(InitialValues),
......@@ -49,11 +92,11 @@ solve(Time) :-
equations: Equations,
initial_values: InitialValues,
initial_parameter_values: InitialParameterValues,
method: gsl_odeiv2_step_rk8pd,
error_epsilon_absolute: 1e-6,
error_epsilon_relative: 1e-6,
initial_step_size: 1e-6,
precision: 6,
method: Method,
error_epsilon_absolute: ErrorEpsilonAbsolute,
error_epsilon_relative: ErrorEpsilonRelative,
initial_step_size: InitialStepSize,
precision: Precision,
time_initial: 0,
time_final: Time
],
......
......@@ -6,7 +6,7 @@
test('mapk') :-
clear_model,
command(load(library:examples/mapk/mapk)),
numerical_simulation.
numerical_simulation(100).
:- end_tests(numerical_simulation).
......@@ -65,7 +65,7 @@ reaction_graph(GraphId) :-
(
Reversible = true
->
set_attribute(GraphId, [ReactionCounter], reversible: Reversible)
set_attribute(GraphId, [ReactionCounter], reversible = Reversible)
;
true
),
......@@ -74,7 +74,7 @@ reaction_graph(GraphId) :-
->
true
;
set_attribute(GraphId, [ReactionCounter], kinetics: Kinetics)
set_attribute(GraphId, [ReactionCounter], kinetics = Kinetics)
),
\+ (
(
......@@ -90,7 +90,7 @@ reaction_graph(GraphId) :-
place(GraphId, Object),
add_edge(GraphId, From -> To, EdgeId),
(
get_attribute(EdgeId, stoichiometry: OldStoichiometry)
get_attribute(EdgeId, stoichiometry = OldStoichiometry)
->
NewStoichiometry is OldStoichiometry + Stoichiometry
;
......@@ -105,7 +105,7 @@ reaction_graph(GraphId) :-
true
)
;
set_attribute(EdgeId, stoichiometry: NewStoichiometry)
set_attribute(EdgeId, stoichiometry = NewStoichiometry)
)
)
)
......@@ -132,7 +132,7 @@ make_bipartite_graph :-
retractall(vertex_unknown(_)),
\+ (
item([parent: GraphId, kind: vertex, id: VertexId, item: Vertex]),
get_attribute(VertexId, kind: Kind),
get_attribute(VertexId, kind = Kind),
\+ (
(
Kind = place
......@@ -267,7 +267,7 @@ make_reactions :-
get_kinetics(GraphId, Vertex, Kinetics) :-
(
get_attribute(GraphId, Vertex, kinetics: Kinetics)
get_attribute(GraphId, Vertex, kinetics = Kinetics)
->
true
;
......@@ -277,7 +277,7 @@ get_kinetics(GraphId, Vertex, Kinetics) :-
get_reversible(GraphId, Vertex, Reversible) :-
(
get_attribute(GraphId, Vertex, reversible: Reversible)
get_attribute(GraphId, Vertex, reversible = Reversible)
->
(
(
......@@ -297,7 +297,7 @@ get_reversible(GraphId, Vertex, Reversible) :-
get_stoichiometry(EdgeId, Stoichiometry) :-
(
get_attribute(EdgeId, stoichiometry: Stoichiometry)
get_attribute(EdgeId, stoichiometry = Stoichiometry)
->
true
;
......
......@@ -6,11 +6,11 @@
test(
'reaction_graph',
[true((
Edges == ['A' -> 'reaction0', 'reaction0' -> 'B'],
Stoichiometry == 2,
Kinetics == 'MA'(3)
))]
[
result(Edges, Stoichiometry, Kinetics)
==
result(['A' -> 'reaction0', 'reaction0' -> 'B'], 2, 'MA'(3))
]
) :-
clear_model,
add_reaction('MA'(3) for 'A' => 2 * 'B'),
......@@ -18,8 +18,8 @@ test(
get_current_graph(GraphId),
all_items([parent: GraphId, kind: edge], Edges),
once((
get_attribute(GraphId, 'reaction0', kinetics: Kinetics),
get_attribute(GraphId, ('reaction0' -> 'B'), stoichiometry: Stoichiometry)
get_attribute(GraphId, 'reaction0', kinetics = Kinetics),
get_attribute(GraphId, ('reaction0' -> 'B'), stoichiometry = Stoichiometry)
)).
test(
......@@ -38,9 +38,9 @@ test(
'a' -> 'reaction1'
)
),
command(set_attribute('reaction1', kinetics: 'MA'(2))),
command(set_attribute(('c' -> 'reaction1'), stoichiometry: 3)),
command(set_attribute(('reaction1' -> 'd'), stoichiometry: 2)),
command(set_attribute('reaction1', kinetics = 'MA'(2))),
command(set_attribute(('c' -> 'reaction1'), stoichiometry = 3)),
command(set_attribute(('reaction1' -> 'd'), stoichiometry = 2)),
import_reactions_from_graph,
all_items([kind: reaction], Reactions).
......
......@@ -8,7 +8,10 @@
command/1,
execute_command/1,
prompt/1,
set_prompt/1
set_prompt/1,
option/4,
set_option/2,
set_options/1
]).
......@@ -39,31 +42,40 @@ command(Command) :-
the Biocham syntax.
'),
begin_command,
functor(Command, Functor, Arity),
retractall(local_option(_, _)),
extract_options(Command, CommandWithoutOptions, Options),
functor(CommandWithoutOptions, Functor, Arity),
(
Functor/Arity = option/0
->
set_options(Options)
;
(
predicate_info(Functor/Arity, ArgumentTypes, yes, _)
predicate_info(Functor/Arity, ArgumentTypes, CommandOptions, yes, _)
->
Command0 = Command
Command0 = CommandWithoutOptions
;
between(1, Arity, Arity0),
predicate_info(Functor/Arity0, ArgumentTypes, variantargs, _)
predicate_info(
Functor/Arity0, ArgumentTypes, CommandOptions, variantargs, _
)
->
Command =.. [Functor | Arguments],
CommandWithoutOptions =.. [Functor | Arguments],
PrefixLength is Arity0 - 1,
length(Prefix, PrefixLength),
append(Prefix, Tail, Arguments),
append(Prefix, [Tail], NewArguments),
Command0 =.. [Functor | NewArguments]
;
predicate_info(Functor/1, ArgumentTypes, yes, _)
predicate_info(Functor/1, ArgumentTypes, CommandOptions, yes, _)
->
Command =.. [Functor | Arguments],
CommandWithoutOptions =.. [Functor | Arguments],
merge_arguments(Arguments, Argument),
Command0 =.. [Functor, Argument]
)
->
check_types(Command0, ArgumentTypes, NewCommand),
check_options(Options, CommandOptions),
NewCommand
;
reaction_predicate(Command)
......@@ -109,9 +121,51 @@ set_prompt(NewPrompt) :-
asserta(prompt(NewPrompt)).
option(Name, _Type, Value, _Doc) :-
devdoc('defines an option for the command and gets its value.'),
(
local_option(Name, Value)
->
true
;
item([kind: option, key: Name, item: option(Name: Value)])
->
true
;
throw(error(option_required(Name), option))
).
set_option(Option, Value) :-
(
predicate_property(Head, visible),
functor(Head, Functor, Arity),
predicate_info(Functor/Arity, _, CommandOptions, BiochamCommand, _),
BiochamCommand \= no,
member(option(Option, Type, _Doc), CommandOptions)
->
check_type_with_error(Type, Value, TypedValue),
change_item([], option, Option, option(Option: TypedValue))
;
throw(error(unknown_option(Option), set_option))
).
set_options(List) :-
\+ (
member(Option: Value, List),
\+ (
set_option(Option, Value)
)
).
:- devdoc('\\section{Private predicates}').
:- dynamic(local_option/2).
read_execute_print :-
set_counter(warnings, 0),
read_command(Command),
......@@ -153,17 +207,7 @@ check_types(Command, ArgumentTypes, NewCommand) :-
->
NewArgument = Argument
;
catch(
(
check_type(ArgumentType, Argument, NewArgument)
->
true
;
throw(error(failure))
),
error(Type),
throw(error(invalid_type(Argument, Type)))
)
check_type_with_error(ArgumentType, Argument, NewArgument)
)
),
NewArguments
......@@ -171,7 +215,58 @@ check_types(Command, ArgumentTypes, NewCommand) :-
NewCommand =.. [Functor | NewArguments].
check_options(Options, CommandOptions) :-
\+ (
member(Option: UntypedValue, Options),
\+ (
(
member(option(Option, Type, _Doc), CommandOptions)
->
check_type_with_error(Type, UntypedValue, Value),
assertz(local_option(Option, Value))
;
throw(error(option_not_applicable(Option), check_options))
)
)
).
check_type_with_error(ArgumentType, Argument, NewArgument) :-
catch(
(
check_type(ArgumentType, Argument, NewArgument)
->
true
;
throw(error(failure))
),
error(Type),
throw(error(invalid_type(Argument, Type)))
).
merge_arguments(Arguments, Argument) :-
maplist(term_to_atom, Arguments, ArgumentAtoms),
atomic_list_concat(ArgumentAtoms, ',', ArgumentSequence),
term_to_atom(Argument, ArgumentSequence).
extract_options(Command, CommandWithoutOptions, Options) :-
Command =.. [Functor | Arguments],
extract_options_arguments(Arguments, RealArguments, Options),
CommandWithoutOptions =.. [Functor | RealArguments].
extract_options_arguments([], [], []).
extract_options_arguments(
[OptionValue | Arguments], RealArguments, [OptionValue | Options]
) :-
OptionValue = Option : _Value,
Option \= library,
!,
extract_options_arguments(Arguments, RealArguments, Options).
extract_options_arguments(
[Argument | Arguments], [Argument | RealArguments], Options
) :-
extract_options_arguments(Arguments, RealArguments, Options).
......@@ -2,7 +2,7 @@
types,
[
type/2,
predicate_info/4,
predicate_info/5,
check_type/3,
function_application/2
]
......@@ -31,11 +31,11 @@ type(L, '*'(_)) :-
type(_, _).
predicate_info((Head :- Body), ArgumentTypes, BiochamCommand, Doc) :-
predicate_info((Head :- Body), ArgumentTypes, Options, BiochamCommand, Doc) :-
functor(Head, Functor, Arity),
Head =.. [Functor | Arguments],
length(ArgumentTypes, Arity),
collect_info(Body, Arguments, ArgumentTypes, BiochamCommand0, Doc),
collect_info(Body, Arguments, ArgumentTypes, Options, BiochamCommand0, Doc),
(
var(BiochamCommand0)
->
......@@ -45,15 +45,21 @@ predicate_info((Head :- Body), ArgumentTypes, BiochamCommand, Doc) :-
),
BiochamCommand = BiochamCommand0.
predicate_info(Functor/Arity, ArgumentTypes, BiochamCommand, Doc) :-
predicate_info(Functor/Arity, ArgumentTypes, Options, BiochamCommand, Doc) :-
functor(Head, Functor, Arity),
(
clause(Head, Body),
predicate_info((Head :- Body), ArgumentTypes, BiochamCommand, Doc),
(
BiochamCommand = yes
;
BiochamCommand = variantargs
catch(
(
clause(Head, Body),
predicate_info((Head :- Body), ArgumentTypes, Options, BiochamCommand, Doc),
(
BiochamCommand = yes
;
BiochamCommand = variantargs
)
),
_E,
fail
)
->
true
......@@ -62,18 +68,30 @@ predicate_info(Functor/Arity, ArgumentTypes, BiochamCommand, Doc) :-
).
collect_info(biocham_command, _Arguments, _ArgumentTypes, yes, []) :-
collect_info(biocham_command, _Arguments, _ArgumentTypes, [], yes, []) :-
!.
collect_info(biocham_command(*), _Arguments, _ArgumentTypes, variantargs, []) :-
collect_info(
biocham_command(*), _Arguments, _ArgumentTypes, [], variantargs, []
) :-
!.
collect_info(type(Argument, Type), Arguments, ArgumentTypes, _, []) :-
collect_info(type(Argument, Type), Arguments, ArgumentTypes, [], _, []) :-
!,
once(nth0_eqq(Index, Arguments, Argument)),
nth0(Index, ArgumentTypes, Type).
collect_info(DocItem, _Arguments, _ArgumentTypes, _BiochamCommand, Doc) :-
collect_info(
option(Option, OptionType, _Value, Doc),
_Arguments,
_ArgumentTypes,
[option(Option, OptionType, Doc)],
_,
[]
) :-
!.
collect_info(DocItem, _Arguments, _ArgumentTypes, [], _BiochamCommand, [DocItem]) :-
(
DocItem = doc(_)