Commit 630235db authored by MARTINEZ Thierry 's avatar MARTINEZ Thierry

Functions

parent 6ee5741f
......@@ -31,8 +31,7 @@ add_equivalence_class_list(EquivalenceClassList) :-
list_to_equals(EquivalenceClassList, EquivalenceClass),
add_item([
kind: alias, key: EquivalenceClassList, item: alias(EquivalenceClass)
]),
simplify_all_reactions
])
).
......
......@@ -4,8 +4,9 @@
test('alias', [true(Reactions == [2 * a => c])]) :-
clear_model,
add_reaction(a + b => c),
command(a + b => c),
command(alias(a = b)),
command(simplify_all_reactions),
all_items([kind: reaction], Reactions).
:- end_tests(aliases).
......@@ -42,6 +42,8 @@ initialize :-
set_image_viewer_driver(open_file),
set_draw_graph_driver(graph_pdf),
nb_setval(graph_pdf, 0),
nb_setval(current_models, []),
load_biocham('library:initial'),
new_model.
......
......@@ -450,6 +450,16 @@ instantiate_grammar_body(list(Grammar, NonTerminal)) :-
<a href="#~a">~a</a> <code>] ', [Id, Grammar, Id, Grammar]
).
instantiate_grammar_body(function_application(Grammar, NonTerminal)) :-
!,
make_id(Grammar, Id),
format(
atom(NonTerminal), '
</code> <a href="#name">name</a><code>(</code><a href="#~a">~a</a>
<code>,</code> ... <code>,</code>
<a href="#~a">~a</a><code>) ', [Id, Grammar, Id, Grammar]
).
instantiate_grammar_body(Item) :-
Item =.. [Grammar, NonTerminal],
make_id(Grammar, Id),
......
......@@ -4,7 +4,6 @@
input_file/1,
output_file/1,
filename/2,
chop_suffix/2,
automatic_suffix/4
]
).
......@@ -39,22 +38,9 @@ filename(Filename, ExpandedFilename) :-
path_delimiter('/').
chop_suffix(Filename, Suffix) :-
atom_chars(Filename, Chars),
(
append(_, ['.' | SuffixChars], Chars),
\+ member('.', SuffixChars),
path_delimiter(PathDelimiter),
\+ member(PathDelimiter, SuffixChars)
->
atom_chars(Suffix, ['.' | SuffixChars])
;
Suffix = ''
).
automatic_suffix(Filename, DefaultSuffix, Mode, FullFilename) :-
chop_suffix(Filename, Suffix),
file_name_extension(_, Suffix, Filename),
(
Suffix = '',
atom_concat(Filename, DefaultSuffix, FullFilename),
......
:- module(
functions,
[
'function'/1,
show_function/1,
list_functions/0,
delete_function/1,
op(1010, fx, function)
]
).
function(FunctionList) :-
biocham_command(*),
type(FunctionList, '*'(function_prototype = term)),
doc('sets the value of functions.'),
\+ (
member(Function = Value, FunctionList),
\+ (
Function =.. [Functor | _Arguments],
catch(
(
find_item([kind: function, key: Functor, id: Id]),
replace_item(Id, function, Functor, function(Function = Value))
),
error(unknown_item),
add_item([
kind: function, key: Functor, item: function(Function = Value)
])
)
)
).
show_function(Functor) :-
biocham_command,
type(Functor, name),
doc('shows the expression associated to the given function.'),
find_item([kind: function, key: Functor, item: function(_ = Expression)]),
write(Expression),
nl.
list_functions :-
biocham_command,
doc('lists all known functions.'),
list_items([kind: function]).
delete_function(FunctorSet) :-
biocham_command,
type(FunctorSet, {name}),
doc('deletes some functions.'),
\+ (
member(Functor, FunctorSet),
\+ (
delete_item([kind: function, key: Functor])
)
).
:- use_module(library(plunit)).
:- begin_tests(functions).
test(
'function',
[true(Functions == [function(a = 1), function(b(y) = y + 2)])]
) :-
clear_model,
command(function(a = 1, b(x) = x + 1)),
command(function(b(y) = y + 2)),
all_items([kind: function, no_inheritance], Functions).
:- end_tests(functions).
......@@ -174,6 +174,6 @@ test('get_attribute', [true(Kind == transition)]) :-
clear_model,
new_graph,
command(transition('A')),
get_attribute('A', kind: Kind).
once(get_attribute('A', kind: Kind)).
:- end_tests(graph_editor).
......@@ -28,7 +28,7 @@ export_graph(OutputFile) :-
\ttexttt{.png} or \ttexttt{.svg}
-- assuming no extension is \\texttt{.dot}.
'),
chop_suffix(OutputFile, Suffix),
file_name_extension(_, Suffix, OutputFile),
export_graph(Suffix, OutputFile).
......@@ -46,25 +46,25 @@ export_graph('', OutputFile) :-
atom_concat(OutputFile, '.dot', FilenameDot),
export_graph('.dot', FilenameDot).
export_graph('.dot', OutputFile) :-
export_graph('dot', OutputFile) :-
get_current_graph(GraphId),
create_cgraph(GraphId, Graph),
agwrite(Graph, OutputFile),
agclose(Graph).
export_graph('.pdf', OutputFile) :-
export_graph('pdf', OutputFile) :-
render_current_graph('pdf', OutputFile).
export_graph('.eps', OutputFile) :-
export_graph('eps', OutputFile) :-
render_current_graph('eps', OutputFile).
export_graph('.ps', OutputFile) :-
export_graph('ps', OutputFile) :-
render_current_graph('ps', OutputFile).
export_graph('.png', OutputFile) :-
export_graph('png', OutputFile) :-
render_current_graph('png', OutputFile).
export_graph('.svg', OutputFile) :-
export_graph('svg', OutputFile) :-
render_current_graph('svg', OutputFile).
......
......@@ -5,23 +5,59 @@
]
).
kinetics(Kinetics, Reactants, Expression) :-
kinetics(Reactants, single_reactant, Value) :-
!,
(
Kinetics = 'MA'(Coefficient)
Reactants = [Value]
->
mass_action(Coefficient, Reactants, Expression)
true
;
Expression = Kinetics
throw(error(not_single_reactant_reaction))
).
kinetics(Reactants, product(Pattern in List, Expression), Value) :-
!,
(
Pattern = S * O
->
true
;
throw(error(invalid_pattern))
),
(
List = [reactants]
->
true
;
throw(error(invalid_list))
),
make_product(Reactants, S, O, Expression, Value).
kinetics(Reactants, FunctionApplication, Expression) :-
callable(FunctionApplication),
functor(FunctionApplication, Functor, Arity),
item([kind: function, key: Functor, item: (function(Head = Body))]),
!,
functor(Head, Functor, ApplicationArity),
(
Arity = ApplicationArity
->
true
;
throw(error(arity_mismatch(Functor, Arity, ApplicationArity)))
),
Head =.. [Functor | Parameters],
FunctionApplication =.. [Functor | Arguments],
substitute(Parameters, Arguments, Body, NewBody),
kinetics(Reactants, NewBody, Expression).
mass_action(Coefficient, Reactants, Expression) :-
concentration_product(Reactants, ConcentrationProduct),
Expression = Coefficient * ConcentrationProduct.
kinetics(Reactants, Callable, Expression) :-
term_morphism(kinetics(Reactants), Callable, Expression).
concentration_product([], 1).
make_product([], _S, _O, _Expression, 1).
concentration_product([Coefficient * Reactant | Reactants], Product) :-
Product = [Reactant] ^ Coefficient * ProductTail,
concentration_product(Reactants, ProductTail).
make_product([RS * RO | Tail], S, O, Expression, Product) :-
substitute([S, O], [RS, RO], Expression, SubstitutedExpression),
Product = SubstitutedExpression * TailProduct,
make_product(Tail, S, O, Expression, TailProduct).
......@@ -7,7 +7,7 @@ fi
while true; do
filename=`printf BIOMD%.10d $i`
url="https://www.ebi.ac.uk/biomodels-main/download?mid=$filename"
if ! curl $url >$filename.xml; then
if ! curl $url >$filename.xml || grep -q '<!DOCTYPE' $filename.xml; then
rm -f $filename.xml
break
fi
......
function MA(k) = k * product(S * O in [reactants], O ^ S).
function MM(Vm, Km) = Vm * single_reactant / (Km + single_reactant).
function H(Vm, Km, n) =
Vm * single_reactant ^ n / (Km ^ n + single_reactant ^ n).
:- module(
macros,
[
set_macro/1,
show_macro/1,
list_macros/0,
delete_macro/1
]
).
set_macro(MacroList) :-
biocham_command(*),
type(MacroList, '*'(macro = term)),
doc('sets the value of macros.'),
\+ (
member(Macro = Value, MacroList),
\+ (
catch(
(
find_item([kind: macro, key: Macro, id: Id]),
replace_item(Id, macro, Macro, macro(Macro = Value))
),
error(unknown_item),
add_item([kind: macro, key: Macro, item: macro(Macro = Value)])
)
)
).
show_macro(Macro) :-
biocham_command,
type(Macro, macro),
doc('shows the expression associated to the given macro.'),
find_item([kind: macro, key: Macro, item: macro(_ = Expression)]),
write(Expression),
nl.
list_macros :-
biocham_command,
doc('lists all known macros.'),
list_items([kind: macro]).
delete_macro(MacroSet) :-
biocham_command,
type(MacroSet, {macro}),
doc('deletes some macros.'),
\+ (
member(Macro, MacroSet),
\+ (
delete_item([kind: macro, key: Macro])
)
).
:- use_module(library(plunit)).
:- begin_tests(macros).
test(
'set_macro',
[true(Macros == [macro(a = 1), macro(b = 3)])]
) :-
clear_model,
command(set_macro(a = 1, b = 2)),
command(set_macro(b = 3)),
all_items([kind: macro], Macros).
:- end_tests(macros).
......@@ -33,7 +33,10 @@
delete_item/1,
delete_items/1,
add_dependency/2,
add_file_suffix/2
add_file_suffix/2,
inherits/1,
inherits/2,
begin_command/0
]
).
......@@ -74,7 +77,7 @@ load_biocham(InputFile) :-
contained in the given Biocham \\texttt{.bc} file.
The suffix \\texttt{.bc} is automatically added to the name if such a
file exists.'),
load_all('.bc', InputFile).
load_all('bc', InputFile).
add_biocham(InputFile) :-
......@@ -85,7 +88,7 @@ add_biocham(InputFile) :-
\\emph{added} to the current set of rules.
The commands contained in the file are executed
(with the file directory as current directory).'),
add_all('.bc', InputFile).
add_all('bc', InputFile).
new_model :-
......@@ -155,6 +158,14 @@ select_model(RefSet) :-
member(Id, Ids)
;
find_item([parent: top, key: Ref, id: Id])
),
item([id: Id, kind: Kind]),
(
Kind = model
->
true
;
throw(error(not_a_model(Kind)))
)
),
CurrentModels
......@@ -201,7 +212,13 @@ load_all(Suffix, InputFile) :-
Id,
(
filename(InputFile, Filename),
chop_suffix(Filename, Suffix),
(
var(Suffix)
->
file_name_extension(_, Suffix, Filename)
;
true
),
load(Suffix, Filename),
current_models(Ids),
member(Id, Ids)
......@@ -242,7 +259,7 @@ add_all(Suffix, InputFile) :-
(
var(Suffix)
->
chop_suffix(Filename, Suffix)
file_name_extension(_, Suffix, Filename)
;
true
),
......@@ -253,7 +270,15 @@ add_all(Suffix, InputFile) :-
load(Suffix, Filename) :-
new_model,
set_model_name(Filename),
file_base_name(Filename, FileBaseName),
(
file_name_extension(Base, _, FileBaseName)
->
true
;
Base = FileBaseName
),
set_model_name(Base),
add(Suffix, Filename).
......@@ -273,7 +298,7 @@ add(Suffix, Filename) :-
add_file_suffix('', add_biocham_file).
add_file_suffix('.bc', add_biocham_file).
add_file_suffix('bc', add_biocham_file).
add_biocham_file(Filename) :-
......@@ -330,6 +355,13 @@ new_model(Id) :-
true
;
add_item([parent: top, kind: model, key: new_model, id: Id]),
(
item([parent:top, kind: model, key: initial, id: InitialId])
->
inherits(Id, InitialId)
;
true
),
set_current_models([Id]),
assertz(fresh)
).
......@@ -439,37 +471,49 @@ single_model(Model, ModelId) :-
).
item(Options) :-
item_parent_option(Options, ChosenParent) :-
optional(parent: Parent, Options),
optional(kind: Kind, Options),
optional(id: Id, Options),
optional(key: Key, Options),
optional(item: Item, Options),
(
var(Parent),
var(Id)
->
Parent = current_model
default(Parent, current_model),
(
Parent == current_model
->
single_model(ChosenParent)
;
Parent == current_models
->
current_models(Models),
member(ChosenParent, Models)
;
ChosenParent = Parent
)
;
true
),
ChosenParent = Parent
).
item(Options) :-
optional(kind: Kind, Options),
optional(id: Id, Options),
optional(key: Key, Options),
optional(item: Item, Options),
item_parent_option(Options, Parent),
(
Parent = current_model
->
single_model(Parent0)
;
Parent = current_models
var(Id)
->
current_models(Models),
member(Parent0, Models)
(
Parent0 = Parent
;
\+ member(no_inheritance, Options),
inherits_from(Parent, Parent0)
)
;
Parent0 = Parent
),
(
var(Kind)
->
true
;
list(Kind)
->
member(Kind0, Kind)
......@@ -530,9 +574,39 @@ optional(Item, List) :-
:- dynamic(listed_item/2).
begin_command :-
set_counter(list_item_counter, 0).
list_items(Options) :-
all_ids(Options, Ids),
list_ids(Options, Ids).
all_ids([no_inheritance | Options], Ids),
list_ids(Options, Ids),
(
member(no_inheritance, Options)
->
true
;
item_parent_option(Options, Parent),
(
var(Parent)
->
true
;
optional(indent: Indent, Options),
default(Indent, 0),
\+ (
inherits_from(Parent, Parent0),
all_ids([parent: Parent0, no_inheritance | Options], InheritedIds),
InheritedIds \= [],
\+ (
indent(Indent),
find_item([id: Parent0, item: ParentName]),
format('From inherited \'~w\':\n', [ParentName]),
list_ids(Options, InheritedIds)
)
)
)
).
list_ids(Ids) :-
......@@ -540,8 +614,13 @@ list_ids(Ids) :-
list_ids(Options, Ids) :-
retractall(listed_item(_, _)),
set_counter(list_item_counter, 0),
(
peek_count(list_item_counter, 0)
->
retractall(listed_item(_, _))
;
true
),
list_ids_aux(Options, Ids).
......@@ -665,7 +744,13 @@ ranges_ids(Ranges, Ids) :-
(
Range = Min - Max
->
between(Min, Max, Range)
(
Min =< Max
->
between(Min, Max, Range)
;
throw(error(invalid_range(Min, Max)))
)
;
Index = Range
),
......@@ -700,3 +785,34 @@ create_item_id(Id) :-
add_dependency(IdSub, IdMaster) :-
assertz(dependency(IdSub, IdMaster)).
inherits(Ancestors) :-
biocham_command(*),
type(Ancestors, '*'(name)),
doc('makes the current model inherit from the given ancestor models.'),
single_model(Id),
\+ (
member(Ancestor, Ancestors),
\+ (
find_item([kind: model, key: Ancestor, id: AncestorId]),
(
inherits(Id, AncestorId)
)
)
).
:- dynamic(directly_inherits_from/2).
inherits(Id, AncestorId) :-
assertz(directly_inherits_from(Id, AncestorId)).
inherits_from(Id, AncestorId) :-
directly_inherits_from(Id, AncestorId).
inherits_from(Id, AncestorId) :-
directly_inherits_from(Id, IntermediateAncestorId),
inherits_from(IntermediateAncestorId, AncestorId).
......@@ -13,8 +13,15 @@ test('new_model', [true(Reactions == [])]) :-
delete_item(Id0),
delete_item(Id1).
test('new_model inherits from initial') :-
new_model,
single_model(Id),
once((
models:inherits_from(Id, InitialId),
get_model_name(InitialId, 'initial')
)).
test('load', [true(atom_concat(_, 'examples/mapk/mapk', Name))]) :-
test('load', [true(Name == mapk)]) :-
command(load(library:examples/mapk/mapk)),
single_model(Id),
get_model_name(Id, Name),
......
......@@ -153,9 +153,9 @@ convert_expression(Value, Value) :-
number(Value),
!.
convert_expression([Molecule], [VariableIndex]) :-
!,
variable(Molecule, VariableIndex).
convert_expression(Molecule, [VariableIndex]) :-
variable(Molecule, VariableIndex),
!.
convert_expression(Parameter, p(ParameterIndex)) :-
atom(Parameter),
......
......@@ -4,7 +4,7 @@
concentration/1,
name/1,
parameter/1,
macro/1,
function_prototype/1,
object/1,
op(100, xfy, '~')
]
......@@ -39,11 +39,11 @@ parameter(Name) :-
atom(Name).
:- grammar(macro).
:- grammar(function_prototype).
macro(Name) :-
atom(Name).
function_prototype(FunctionPrototype) :-
term(FunctionPrototype).
:- grammar(object).
......
......@@ -32,7 +32,7 @@ compute_ode :-
item([kind: reaction, item: Item]),
reaction(Item, Kinetics, Reactants, Products),
\+ (
kinetics(Kinetics, Reactants, KineticsExpression),
kinetics(Reactants, Kinetics, KineticsExpression),
add_molecules(Reactants, -KineticsExpression),
add_molecules(Products, KineticsExpression)
)
......
:- use_module(library(plunit)).
:- begin_tests(ode).
test('compute_ode', [true(ODEs == [ode(b, a), ode(a, -a)])]) :-
clear_model,
command(a => b),
compute_ode,
findall(
ode(Variable, Expression),
ode(Variable, Expression),
ODEs).
:- end_tests(ode).
......@@ -19,8 +19,7 @@ add_reaction(Reaction) :-
adds reaction rules to the current set of reactions.
This command is implicit: reaction rules can be added directly in models.
'),
simplify_reaction(Reaction, SimplifiedReaction),
add_item([kind: reaction, item: SimplifiedReaction]).
add_item([kind: reaction, item: Reaction]).
add_reaction(Kinetics, Left, Right, Reversible) :-
......@@ -35,6 +34,11 @@ list_reactions :-
simplify_all_reactions :-
biocham_command,
doc('
replaces each reaction by a simplified form, by grouping common molecules,
identifying catalysts, and by using the canonical molecule for aliases.
'),
\+ (
item([kind: reaction, id: Id, item: Reaction]),
\+ (
......@@ -73,9 +77,9 @@ reaction(Item, Kinetics, Reactants, Products, Reversible) :-
Reversible = true,
Catalyst = '_'
),
solution_to_list(Left, LeftMolecules),
solution_to_list(Right, RightMolecules),
solution_to_list(Catalyst, CatalystMolecules),
solution_to_canonical_list(Left, LeftMolecules),