influence_editor.pl 7.14 KB
Newer Older
Thierry Martinez's avatar
Thierry Martinez committed
1 2 3
:- module(
  influence_editor,
  [
4
    s/0,
Thierry Martinez's avatar
Thierry Martinez committed
5 6 7
    % Commands
    add_influence/1,
    list_influences/0,
8
    influence_model/0,
Thierry Martinez's avatar
Thierry Martinez committed
9 10 11
    % Public API
    is_influence_model/0,
    check_influence_model/0,
Thierry Martinez's avatar
Thierry Martinez committed
12
    with_influence_model/1,
13
    list_model_influences/0,
14
    influence/6,
15
    enumerate_molecules_influences/1,
16 17
    compute_ode_for_influence_model/0,
    print_influence/2
Thierry Martinez's avatar
Thierry Martinez committed
18 19 20
  ]
).

21 22 23 24 25 26 27 28 29 30
s :- 
    biocham_command,
    write('id parent kind item\n'),
    models:item(W,X,Y,Z),
    write(W), write(' '),
    write(X), write(' '),
    write(Y), write(' '),
    write(Z), write(' '), nl, fail.
s.

Thierry Martinez's avatar
Thierry Martinez committed
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46

:- devdoc('\\section{Commands}').


add_influence(Influence) :-
  biocham_command,
  type(Influence, influence),
  doc('
    adds influence rules to the current set of influences.
    This command is implicit: influence rules can be added directly in
    influence models.
  '),
  check_influence_model,
  add_item([kind: influence, item: Influence]).


47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
list_influences :-
  biocham_command,
  doc('
    lists the current set of influence rules.
    If the current model is a reaction model,
    the influence rules are inferred from the reaction model
    (see \\command{influence_model/0}).'),
  (
    is_influence_model
  ->
    list_items([kind: influence])
  ;
    is_reaction_model
  ->
    single_model(ReactionModel),
    setup_call_cleanup(
      new_model(InfluenceModel),
      (
        influence_model(ReactionModel, InfluenceModel),
        list_items([parent: InfluenceModel, kind: influence, no_numbering])
      ),
      delete_item(InfluenceModel)
    )
  ).
Thierry Martinez's avatar
Thierry Martinez committed
71 72


73
influence_model :-
Thierry Martinez's avatar
Thierry Martinez committed
74
  biocham_command,
75 76 77 78 79 80 81 82 83 84
  doc('
    creates a new influence model by inferring
    the influences between all molecular objects of the current reaction model
  '),
  check_reaction_model,
  single_model(ReactionModel),
  new_model,
  set_model_name(influence_model),
  single_model(InfluenceModel),
  influence_model(ReactionModel, InfluenceModel).
Thierry Martinez's avatar
Thierry Martinez committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98


:- devdoc('\\section{Public API}').


is_influence_model :-
   devdoc('
     succeeds if the current model is an influence model
     (i.e., does not contain any reaction rules).
   '),
   \+ item([kind: reaction]).


check_influence_model :-
99 100 101 102 103
  devdoc('
     succeeds if the current model is an influence model
     (i.e., does not contain any reaction rules)
     and throws an exception otherwise.
  '),
Thierry Martinez's avatar
Thierry Martinez committed
104 105 106 107 108 109 110 111 112
  (
    is_influence_model
  ->
    true
  ;
    throw(error(not_an_influence_model, check_influence_model))
  ).


Thierry Martinez's avatar
Thierry Martinez committed
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
with_influence_model(G) :-
  (
    is_influence_model
  ->
    G
  ;
    single_model(ReactionModel),
    setup_call_cleanup(
      new_model(InfluenceModel),
      (
        influence_model(ReactionModel, InfluenceModel),
        set_current_models([InfluenceModel]),
        G
      ),
      (
        delete_item(InfluenceModel),
        set_current_models([ReactionModel])
      )
    )
  ).


135 136 137 138 139 140
list_model_influences :-
  devdoc('
    lists all the influence rules in a loadable syntax
    (auxiliary predicate of list_model).
  '),
  \+ (
141
    item([no_inheritance, kind: influence, id: Id, item: Influence]),
142
    \+ (
143 144
      print_influence(Id, Influence),
      write('.\n')
145 146 147 148
    )
  ).


Thierry Martinez's avatar
Thierry Martinez committed
149 150 151 152
prolog:error_message(not_an_influence_model) -->
  ['Not an influence model'].


Thierry Martinez's avatar
Thierry Martinez committed
153 154 155 156 157
influence(InfluenceRule, Force, PositiveInputs, NegativeInputs, Sign, Output) :-
  devdoc(
    'builds or decomposes an influence rule.'
  ),
  once((
158
    Force = 'MA'(1),
Thierry Martinez's avatar
Thierry Martinez committed
159 160 161 162 163 164 165 166 167 168 169
    (
      var(InfluenceRule)
    ->
      true
    ;
      InfluenceRule \= (_ for _)
    ),
    BasicInfluenceRule = InfluenceRule
  ;
    InfluenceRule = (Force for BasicInfluenceRule)
  )),
Thierry Martinez's avatar
Thierry Martinez committed
170
  once((
Thierry Martinez's avatar
Thierry Martinez committed
171
    BasicInfluenceRule = (Inputs -> Output),
Thierry Martinez's avatar
Thierry Martinez committed
172 173
    Sign = +
  ;
Thierry Martinez's avatar
Thierry Martinez committed
174
    BasicInfluenceRule = (Inputs -< Output),
Thierry Martinez's avatar
Thierry Martinez committed
175 176 177 178 179
    Sign = -
  )),
  inputs(Inputs, PositiveInputs, NegativeInputs).


180 181 182 183 184 185 186 187 188 189 190 191 192
compute_ode_for_influence_model :-
  \+ (
    item([kind: influence, item: Item]),
    influence(Item, Force, PositiveInputs, _NegativeInputs, Sign, Output),
    \+ (
      maplist(add_coefficient, PositiveInputs, PositiveInputsWithCoefficient),
      kinetics(PositiveInputsWithCoefficient, Force, ForceExpression),
      sign(Sign, ForceExpression, SignedForce),
      ode_add_expression_to_molecule(SignedForce, Output)
    )
  ).


193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
print_influence(_Id, Item) :-
  (
    Item = (Force for BasicInfluence)
  ->
    format('~w for ', [Force])
  ;
    BasicInfluence = Item
  ),
  (
    BasicInfluence = (Inputs -> Output)
  ->
    Arrow = '->'
  ;
    BasicInfluence = (Inputs -< Output)
  ->
    Arrow = '-<'
  ),
  (
    Inputs = (PositiveInputs / NegativeInputs)
  ->
    format('~w / ~w', [PositiveInputs, NegativeInputs])
  ;
    Inputs = (/ NegativeInputs)
  ->
    format('/ ~w', [NegativeInputs])
  ;
    write(Inputs)
  ),
  format(' ~w ~w', [Arrow, Output]).


Thierry Martinez's avatar
Thierry Martinez committed
224 225 226
:- devdoc('\\section{Private predicates}').


227 228 229 230 231 232 233 234
add_coefficient(C, 1 * C).


sign(-, Force, - Force).

sign(+, Force, Force).


235 236 237
influence_model(ReactionModel, InfluenceModel) :-
  \+ (
    item([parent: ReactionModel, kind: reaction, item: Reaction]),
238
    reaction(Reaction, Kinetics, Reactants, Products),
239 240
    \+ (
      substract_list(Reactants, Products, Difference),
241
      create_influences(Reactants, Difference, Kinetics, InfluenceModel)
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
    )
  ).


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)
  ).


266
create_influences(Reactants, Difference, Kinetics, InfluenceModel) :-
267
  \+ (
268 269 270 271 272
    findall(
      Input,
      member(_ * Input, Reactants),
      PositiveInputs
    ),
273 274 275 276 277
    member(Coefficient * Output, Difference),
    \+ (
      (
        Coefficient > 0
      ->
278 279
        Sign = +,
        simplify(Coefficient * Kinetics, CoefficientKinetics)
280
      ;
281 282 283 284 285
        Sign = -,
        simplify(- Coefficient * Kinetics, CoefficientKinetics)
      ),
      influence(Influence, CoefficientKinetics, PositiveInputs, [], Sign, Output),
      add_item([parent: InfluenceModel, kind: influence, item: Influence])
286 287 288 289
    )
  ).


Thierry Martinez's avatar
Thierry Martinez committed
290 291 292 293 294 295
inputs(PositiveInputEnum, PositiveInputList, []) :-
  (
    var(PositiveInputEnum)
  ->
    true
  ;
296 297
    PositiveInputEnum \= (_ / _),
    PositiveInputEnum \= (/ _)
Thierry Martinez's avatar
Thierry Martinez committed
298 299 300 301
  ),
  list_enumeration(PositiveInputList, PositiveInputEnum),
  !.

302
inputs(/ NegativeInputEnum, [], NegativeInputList) :-
Thierry Martinez's avatar
Thierry Martinez committed
303 304 305 306
  list_enumeration(NegativeInputList, NegativeInputEnum),
  !.

inputs(
307
  PositiveInputEnum / NegativeInputEnum,
Thierry Martinez's avatar
Thierry Martinez committed
308 309 310 311 312 313 314 315
  PositiveInputList,
  NegativeInputList
) :-
  list_enumeration(PositiveInputList, PositiveInputEnum),
  list_enumeration(NegativeInputList, NegativeInputEnum),
  !.


316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
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
  ).
334