Package transsys
[hide private]
[frames] | no frames]

Source Code for Package transsys

   1  #!/usr/bin/env python 
   2   
   3  # $Id: __init__.py 349 2009-06-30 18:50:57Z jtk $ 
   4   
   5  # $Log$ 
   6  # Revision 1.17  2005/10/28 16:29:17  jtk 
   7  # TranssysInstance now has timestep member 
   8  # TranssysInstance.time_series now produces list instead of dictionary 
   9  # 
  10  # Revision 1.16  2005/06/22 09:56:44  jtk 
  11  # lsys parsing approaching completion 
  12  # 
  13  # Revision 1.15  2005/06/21 16:38:04  jtk 
  14  # initial success with lsys parser (no serious debugging yet) 
  15  # 
  16  # Revision 1.14  2005/06/21 09:34:04  jtk 
  17  # lsys parser accepts syntax (of one file), semantics still to be implemented 
  18  # 
  19  # Revision 1.13  2005/06/20 21:10:03  jtk 
  20  # in process of implementing lsys parsing capability 
  21  # 
  22  # Revision 1.12  2005/06/14 18:33:37  jtk 
  23  # added comments to factors and genes 
  24  # 
  25  # Revision 1.11  2005/06/14 09:57:17  jtk 
  26  # added some safeguards against bad types in __init__ functions 
  27  # 
  28  # Revision 1.10  2005/04/14 18:50:17  jtk 
  29  # added entropy computation, introduced magic line for transexpr 
  30  # 
  31  # Revision 1.9  2005/04/10 19:38:00  jtk 
  32  # fixed powerlaw_linkist off by one bug 
  33  # 
  34  # Revision 1.8  2005/04/08 21:07:58  jtk 
  35  # fixed random transsys generation to prevent generation of multiple links 
  36  # 
  37  # Revision 1.7  2005/04/08 20:05:18  jtk 
  38  # added indegree and outdegree methods to TranssysProgram 
  39  # 
  40  # Revision 1.6  2005/04/06 21:04:54  jtk 
  41  # minor fixes 
  42  # 
  43  # Revision 1.5  2005/04/06 09:54:38  jtk 
  44  # debugged transdisrupt.py 
  45  # 
  46  # Revision 1.4  2005/04/05 20:27:37  jtk 
  47  # allowed snippets in CyclicSequence, adapted time_series, lsys kludge 
  48  # 
  49  # Revision 1.3  2005/04/05 10:13:19  jtk 
  50  # fixed unresolved_copy for promoter element 
  51  # 
  52  # Revision 1.2  2005/04/04 21:26:50  jtk 
  53  # added merging and unresolved_copy functions to TranssysProgram 
  54  # 
  55  # Revision 1.1.1.1  2005/03/08 17:12:02  jtk 
  56  # new cvs after loss at INB 
  57  # 
  58  # Revision 1.16  2003/04/03 13:31:30  kim 
  59  # removed superfluous print statement in PromoterElementLink.__init__ 
  60  # 
  61  # Revision 1.15  2003/03/20 21:56:54  kim 
  62  # added regulated_genes() and regulating_factors() 
  63  # 
  64  # Revision 1.14  2003/03/12 19:22:12  kim 
  65  # fixed wait() for both transexpr child and python child 
  66  #     in TranssysInstance.time_series() 
  67  # 
  68  # Revision 1.13  2003/03/05 13:59:16  kim 
  69  # improved error reporting, other minor changes 
  70  # 
  71  # Revision 1.12  2003/02/28 00:46:14  kim 
  72  # improved intensity computation 
  73  # 
  74  # Revision 1.11  2003/02/27 10:36:48  kim 
  75  # added ArrayIntensityFunction class for simulating noisy arrays etc. 
  76  # 
  77  # Revision 1.10  2003/02/26 19:19:45  schwarzd 
  78  # fixed syntax by eliminating tabs... 
  79  # 
  80  # Revision 1.9  2003/02/26 19:17:24  schwarzd 
  81  # fixed problems with dot_attribute members set to None 
  82  # 
  83  # Revision 1.7  2003/02/26 18:22:53  schwarzd 
  84  # systematically implemented dot_attributes output 
  85  # 
  86  # Revision 1.6  2003/02/17 21:40:31  kim 
  87  # Transformed microarr.r into a R library called transarr. Added array_background 
  88  #     to regstruct system 
  89  # 
  90  # Revision 1.5  2003/02/14 16:31:27  kim 
  91  # regstruct project is nearing completion. regstruct_transsys for 
  92  #     generation of transsys programs and regstruct_transarray for 
  93  #     array simulation are (more or less) properly implemented. 
  94  #     Analysis with R has been assembled in microarr.r 
  95  # 
  96  # Revision 1.4  2003/02/05 14:58:05  kim 
  97  # minor updates 
  98  # 
  99  # Revision 1.3  2003/02/04 23:46:58  kim 
 100  # added parser, major extension and reworking of RandomTranssysParameters 
 101  # 
 102  # Revision 1.2  2003/01/30 12:14:33  kim 
 103  # initial proper implementation of regstruct_transsys 
 104  # 
 105  # Revision 1.1  2003/01/28 21:12:05  kim 
 106  # initial toolbox assembly 
 107  # 
 108   
 109  # old log from python/jtkmods 
 110  # Revision 1.1  2002/03/22 17:23:50  kim 
 111  # added transrnd.py and transsys.py to CVS repository 
 112  # 
 113   
 114   
 115  """transsys module 
 116   
 117  Classes: 
 118  ExpressionNode             Base class for nodes in an expression tree 
 119   
 120  Functions: 
 121  dot_attribute_string       xxx? 
 122  """ 
 123   
 124  import copy 
 125  import types 
 126  import os 
 127  import sys 
 128  import popen2 
 129  import string 
 130  import StringIO 
 131  import math 
 132  import re 
 133  import random 
 134   
 135  import clib 
 136   
 137  import utils 
 138   
 139  # __all__ appears to interfere with epydoc documentation generation 
 140  # and is not useful for clib anyway, as clib is not intended for 
 141  # general use 
 142  # __all__ = ['clib'] 
 143   
 144  # compatibility check based on manually managed version names. 
 145  # (unfortunately subversion does not provide anything suitable for this). 
 146  required_clib_api_version = '350' 
 147  if clib.clib_api_version != required_clib_api_version : 
 148    raise StandardError, 'transsys module requires clib API version %s but actual API version is %s' % (required_clib_api_version, clib.clib_api_version) 
 149   
 150   
151 -def dot_attribute_string(d) :
152 """Produce an attribute list in the dot language 153 """ 154 s = '' 155 glue = '' 156 for k in d.keys() : 157 s = s + '%s%s="%s"' % (glue, k, d[k]) 158 glue = ' ' 159 return s
160 161
162 -def _comment_lines(clines, prefix = '') :
163 s = '' 164 for l in clines : 165 s = s + prefix + '// ' + l + '\n' 166 return s
167 168 169 # note on expression evaluation: this is not yet properly designed. 170 # Implementation fragments should be taken to be no more than random notices. 171 # the transsys_instance argument may be replaced with some more adequate 172 # evaluation_context thingy... 173
174 -class ExpressionNode(object) :
175 """Base class for nodes in expression trees. 176 """ 177 178
179 - def resolve(self, tp) :
180 pass
181 182
183 - def unresolved_copy(self) :
184 """Return an unresolved copy of this node.""" 185 return copy.deepcopy(self)
186 187
188 - def getValueNodes(self) :
189 """Return all constant value nodes in expression subtree. This 190 is the default implementation which returns an empty list. 191 192 @return: a list of value nodes in the subtree rooted at this node 193 @rtype: C{list} 194 """ 195 return []
196 197
198 - def getIdentifierNodes(self) :
199 """get all identifier nodes in expression subtree. This 200 is the default implementation which returns an empty list.""" 201 return []
202 203
204 -class ExpressionNodeValue(ExpressionNode) :
205 """Expression node holding a constant floating point value. 206 207 @ivar value: the value 208 @type value: C{float} 209 """ 210 # v should be a numeric type (float or int, or perhaps long). Other 211 # types may be accepted now, but are not guaranteed to work in the 212 # future.
213 - def __init__(self, v) :
214 """Constructor. 215 216 @param v: the constant value 217 @type v: C{float} 218 """ 219 self.value = float(v)
220 221
222 - def __str__(self) :
223 return str(self.value)
224 225 226 # FIXME: this is obsolete now that simulation is available through the clib module.
227 - def evaluate(self, transsys_instance_list) :
228 return self.value
229 230
231 - def getValueNodes(self) :
232 return [self]
233 234
235 - def clip(self, minValue = None, maxValue = None) :
236 """Clip value to [C{minValue}, C{maxValue}]. 237 238 Both parameters may be C{None} to specify an open-ended interval. 239 """ 240 # print 'clipping value = %f to [%s, %s]' % (self.value, str(minValue), str(maxValue)), 241 if minValue is not None : 242 self.value = max(minValue, self.value) 243 if maxValue is not None : 244 self.value = min(maxValue, self.value)
245 # print '--> %f' % self.value 246 247
248 -class ExpressionNodeIdentifier(ExpressionNode) :
249 """Node representing an identifier, i.eE{.} a factor, possibly qualified by a 250 transsys label. 251 252 Qualification by a transsys label occurs within L-transsys contexts. 253 254 @ivar factor: The factor identified by this node 255 @type factor: Either a C{Factor} instance (resolved case) or a C{string} 256 (unresolved case). 257 @ivar transsys_label: the transsys label, C{None} if no label 258 @type transsys_label: C{string} 259 """ 260
261 - def __init__(self, factor, transsys_label = None) :
262 if not (isinstance(factor, Factor) or (type(factor) is types.StringType)) : 263 raise StandardError, 'ExpressionNodeIdentifier::__init__: bad type of factor' 264 self.factor = factor 265 self.transsys_label = transsys_label
266 267
268 - def __str__(self) :
269 if self.transsys_label is None : 270 return self.factor_name() 271 else : 272 return '%s.%s' % (self.transsys_label, self.factor_name())
273 274
275 - def factor_name(self) :
276 if type(self.factor) is types.StringType : 277 return self.factor 278 else : 279 return self.factor.name
280 281
282 - def resolve(self, tp) :
283 if isinstance(self.factor, Factor) : 284 raise StandardError, 'ExpressionNodeIdentifier::resolve: identifier is already resolved' 285 self.factor = tp.find_factor(self.factor)
286 287
288 - def unresolved_copy(self) :
289 return self.__class__(self.factor_name(), self.transsys_label)
290 291
292 - def getIdentifierNodes(self) :
293 """Returns itself (obviously). 294 Notice, however, that an ExpressionNodeIdentifier might also have a transsys_label. 295 The current mechanism is ok for use with self-contained transsys programs, but 296 might need further thought for use with lsys programs.""" 297 return [self]
298 299
300 - def evaluate(self, transsys_instance) :
301 """transsys_instance may either be a single instance or a list of 302 instances (in a L-transsys context)""" 303 if self.transsys_label is None : 304 return transsys_instance.factor_concentration[self.factor.index] 305 else : 306 return transsys_instance[self.transsys_label].factor_concentration[self.factor.index]
307 308
309 -class ExpressionNodeBinary(ExpressionNode) :
310
311 - def __init__(self, op1, op2, operator_sym = None) :
312 if not isinstance(op1, ExpressionNode) : 313 raise StandardError, 'ExpressionNodeBinary::__init__: bad type of op1' 314 if not isinstance(op2, ExpressionNode) : 315 raise StandardError, 'ExpressionNodeBinary::__init__: bad type of op2' 316 self.operand1 = op1 317 self.operand2 = op2 318 self.operator_sym = operator_sym
319 320
321 - def __str__(self) :
322 return '(%s %s %s)' % (str(self.operand1), self.operator_sym, str(self.operand2))
323 324
325 - def resolve(self, tp) :
326 self.operand1.resolve(tp) 327 self.operand2.resolve(tp)
328 329
330 - def unresolved_copy(self) :
331 op1 = self.operand1.unresolved_copy() 332 op2 = self.operand2.unresolved_copy() 333 # This constructor call with two operand parameters works for 334 # subclasses of ExpressionNodeBinary, but not for this class 335 # itself. This is justified because ExpressionNodeBinary is 336 # an abstract base class 337 return self.__class__(op1, op2)
338 339
340 - def getValueNodes(self) :
341 return self.operand1.getValueNodes() + self.operand2.getValueNodes()
342 343
344 - def getIdentifierNodes(self) :
345 return self.operand1.getIdentifierNodes() + self.operand2.getIdentifierNodes()
346 347
348 -class ExpressionNodeAdd(ExpressionNodeBinary) :
349
350 - def __init__(self, op1, op2) :
351 ExpressionNodeBinary.__init__(self, op1, op2, '+')
352 353
354 - def evaluate(self, transsys_instance) :
355 return self.operand1.evaluate(transsys_instance) + self.operand2.evaluate(transsys_instance)
356 357
358 -class ExpressionNodeSubtract(ExpressionNodeBinary) :
359
360 - def __init__(self, op1, op2) :
361 ExpressionNodeBinary.__init__(self, op1, op2, '-')
362 363
364 - def evaluate(self, transsys_instance) :
365 return self.operand1.evaluate(transsys_instance) - self.operand2.evaluate(transsys_instance)
366 367
368 -class ExpressionNodeMult(ExpressionNodeBinary) :
369
370 - def __init__(self, op1, op2) :
371 ExpressionNodeBinary.__init__(self, op1, op2, '*')
372 373
374 - def evaluate(self, transsys_instance) :
375 return self.operand1.evaluate(transsys_instance) * self.operand2.evaluate(transsys_instance)
376 377
378 -class ExpressionNodeDiv(ExpressionNodeBinary) :
379
380 - def __init__(self, op1, op2) :
381 ExpressionNodeBinary.__init__(self, op1, op2, '/')
382 383
384 - def evaluate(self, transsys_instance) :
385 return self.operand1.evaluate(transsys_instance) / self.operand2.evaluate(transsys_instance)
386 387
388 -class ExpressionNodeLower(ExpressionNodeBinary) :
389
390 - def __init__(self, op1, op2) :
391 ExpressionNodeBinary.__init__(self, op1, op2, '<')
392 393
394 - def evaluate(self, transsys_instance) :
395 return self.operand1.evaluate(transsys_instance) < self.operand2.evaluate(transsys_instance)
396 397
398 -class ExpressionNodeLowerEqual(ExpressionNodeBinary) :
399
400 - def __init__(self, op1, op2) :
401 ExpressionNodeBinary.__init__(self, op1, op2, '<=')
402 403
404 - def evaluate(self, transsys_instance) :
405 return self.operand1.evaluate(transsys_instance) <= self.operand2.evaluate(transsys_instance)
406 407
408 -class ExpressionNodeGreater(ExpressionNodeBinary) :
409
410 - def __init__(self, op1, op2) :
411 ExpressionNodeBinary.__init__(self, op1, op2, '>')
412 413
414 - def evaluate(self, transsys_instance) :
415 return self.operand1.evaluate(transsys_instance) > self.operand2.evaluate(transsys_instance)
416 417
418 -class ExpressionNodeGreaterEqual(ExpressionNodeBinary) :
419
420 - def __init__(self, op1, op2) :
421 ExpressionNodeBinary.__init__(self, op1, op2, '>=')
422 423
424 - def evaluate(self, transsys_instance) :
425 return self.operand1.evaluate(transsys_instance) >= self.operand2.evaluate(transsys_instance)
426 427
428 -class ExpressionNodeEqual(ExpressionNodeBinary) :
429
430 - def __init__(self, op1, op2) :
431 ExpressionNodeBinary.__init__(self, op1, op2, '==')
432 433
434 - def evaluate(self, transsys_instance) :
435 return self.operand1.evaluate(transsys_instance) == self.operand2.evaluate(transsys_instance)
436 437
438 -class ExpressionNodeUnequal(ExpressionNodeBinary) :
439
440 - def __init__(self, op1, op2) :
441 ExpressionNodeBinary.__init__(self, op1, op2, '!=')
442 443
444 - def evaluate(self, transsys_instance) :
445 return self.operand1.evaluate(transsys_instance) != self.operand2.evaluate(transsys_instance)
446 447
448 -class ExpressionNodeNot(ExpressionNode) :
449
450 - def __init__(self, operand) :
451 if not isinstance(operand, ExpressionNode) : 452 raise StandardError, 'ExpressionNodeNot::__init__: bad type of operand' 453 self.operand = operand
454 455
456 - def __str__(self) :
457 return '(!(%s))' % str(self.operand)
458 459
460 - def evaluate(self, transsys_instance) :
461 return not self.operand.evaluate(transsys_instance)
462 463
464 - def resolve(self, tp) :
465 self.operand.resolve(tp)
466 467
468 - def unresolved_copy(self) :
469 op = self.op.unresolved.copy() 470 return self.__class__(op)
471 472
473 - def getValueNodes(self) :
474 return self.operand.getValueNodes()
475 476
477 - def getIdentifierNodes(self) :
478 return self.operand.getIdentifierNodes()
479 480
481 -class ExpressionNodeAnd(ExpressionNodeBinary) :
482
483 - def __init__(self, op1, op2) :
484 ExpressionNodeBinary.__init__(self, op1, op2, '&&')
485 486
487 - def evaluate(self, transsys_instance) :
488 return self.operand1.evaluate(transsys_instance) and self.operand2.evaluate(transsys_instance)
489 490
491 -class ExpressionNodeOr(ExpressionNodeBinary) :
492
493 - def __init__(self, op1, op2) :
494 ExpressionNodeBinary.__init__(self, op1, op2, '||')
495 496
497 - def evaluate(self, transsys_instance) :
498 return self.operand1.evaluate(transsys_instance) or self.operand2.evaluate(transsys_instance)
499 500
501 -class ExpressionNodeFunction(ExpressionNode) :
502
503 - def __init__(self, operand, funcname = 'undefined_function') :
504 for op in operand : 505 if not isinstance(op, ExpressionNode) : 506 raise StandardError, 'ExpressionNodeFunction::__init__: bad type of operand' 507 self.operand = operand 508 self.funcname = funcname
509 510
511 - def __str__(self) :
512 s = self.funcname 513 glue = '(' 514 for op in self.operand : 515 s = s + glue + str(op) 516 glue = ', ' 517 s = s + ')' 518 return s
519 520
521 - def evaluate(self, transsys_instance) :
522 raise StandardError, 'cannot evaluate undefined function'
523 524
525 - def resolve(self, tp) :
526 for op in self.operand : 527 op.resolve(tp)
528 529
530 - def unresolved_copy(self) :
531 u = [] 532 for op in self.operand : 533 u.append(op.unresolved_copy()) 534 return self.__class__(u)
535 536
537 - def getValueNodes(self) :
538 vn = [] 539 for op in self.operand : 540 vn = vn + op.getValueNodes() 541 return vn
542 543
544 - def getIdentifierNodes(self) :
545 identifierNodes = [] 546 for op in self.operand : 547 identifierNodes = identifierNodes + op.getIdentifierNodes() 548 return identifierNodes
549 550
551 -class ExpressionNodeUniformRandom(ExpressionNodeFunction) :
552
553 - def __init__(self, op1, op2) :
554 ExpressionNodeFunction.__init__(self, [op1, op2], 'random')
555 556
557 - def evaluate(self, transsys_instance) :
558 arg1 = self.operand[0].evaluate() 559 arg2 = self.operand[1].evaluate() 560 if arg1 < arg2 : 561 return arg1 + (arg2 - arg1) * transsys_instance[0].rng.rnd() 562 else : 563 return arg2 + (arg1 - arg2) * transsys_instance[0].rng.rnd()
564 565
566 -class ExpressionNodeGaussianRandom(ExpressionNodeFunction) :
567
568 - def __init__(self, op1, op2) :
569 ExpressionNodeFunction.__init__(self, [op1, op2], 'gauss')
570 571
572 - def evaluate(self, transsys_instance) :
573 arg1 = self.operand[0].evaluate() 574 arg2 = self.operand[1].evaluate() 575 return arg1 + arg2 * transsys_instance[0].rng.gauss()
576 577
578 -class ExpressionNodePower(ExpressionNodeFunction) :
579
580 - def __init__(self, op1, op2) :
581 ExpressionNodeFunction.__init__(self, [op1, op2], 'pow')
582 583
584 - def evaluate(self, transsys_instance) :
585 arg1 = self.operand[0].evaluate() 586 arg2 = self.operand[1].evaluate() 587 return math.pow(arg1, arg2)
588 589
590 -class ExpressionNodeLogarithm(ExpressionNodeFunction) :
591
592 - def __init__(self, op1, op2) :
593 ExpressionNodeFunction.__init__(self, [op1, op2], 'log')
594 595
596 - def evaluate(self, transsys_instance) :
597 arg1 = self.operand[0].evaluate() 598 arg2 = self.operand[1].evaluate() 599 return math.log(arg1, arg2)
600 601
602 -class ExpressionNodeAtan(ExpressionNodeFunction) :
603
604 - def __init__(self, op1) :
605 ExpressionNodeFunction.__init__(self, [op1], 'atan')
606 607
608 - def evaluate(self, transsys_instance) :
609 arg1 = self.operand[0].evaluate() 610 return math.atan(arg1)
611 612
613 -class PromoterElement(object) :
614 pass
615 616
617 -class PromoterElementConstitutive(PromoterElement) :
618
619 - def __init__(self, expr) :
620 if not isinstance(expr, ExpressionNode) : 621 raise StandardError, 'ExpressionNodeNot::__init__: bad type of expr' 622 self.expression = expr
623 624
625 - def __str__(self) :
626 return 'constitutive: %s' % str(self.expression)
627 628
629 - def resolve(self, tp) :
630 self.expression.resolve(tp)
631 632
633 - def unresolved_copy(self) :
634 return self.__class__(self.expression.unresolved_copy())
635 636
637 - def getValueNodes(self) :
638 """Get the constant value nodes of this constitutive promoter element.""" 639 return self.expression.getValueNodes()
640 641
642 - def getIdentifierNodes(self) :
643 """Get the factor identifier nodes of this constitutive promoter element. 644 This implementation only works for transsy, not for lsys programs which use 645 complex identifiers.""" 646 # FIXME: it's not entirely clear what should be done with complex 647 # identifiers in lsys programs. 648 return self.expression.getIdentifierNodes()
649 650
651 - def canonicalise(self) :
652 """Does nothing. 653 654 Negative constitutive expression can be useful at times to set a 655 threshold that must be overcome by activation. Negative parameters 656 to constitutive are therefore currently not canonicalised away. 657 658 Negative constitutive expression is a bit of a hack, though, and 659 should be used sparingly and avoided where possible. 660 """
661 # if isinstance(self.expression, ExpressionNodeValue) : 662 # self.expression.clip(0.0, None) 663 664
665 - def write_dot_edge(self, f, target_name, dot_parameters, transsys) :
666 # FIXME: constitutive expression of genes should probably be indicated 667 # by node shape / border or the like... 668 pass
669 670 789 790 791 # FIXME: there should be a "Michaelis-Menten" parent class for 792 # activate and repress 793
794 -class PromoterElementActivate(PromoterElementLink) :
795 796 # FIXME: not a "new" python class like superclass constructor call
797 - def __init__(self, expr1, expr2, factor_list, dot_attrs = None) :
798 PromoterElementLink.__init__(self, expr1, expr2, factor_list, dot_attrs)
799 800
801 - def __str__(self) :
802 return '%s: activate(%s, %s)' % (PromoterElementLink.__str__(self), str(self.expression1), str(self.expression2))
803 804
805 - def write_dot_edge(self, f, target_name, dot_parameters, transsys) :
806 PromoterElementLink.write_dot_edge(self, f, target_name, dot_parameters.display_factors, dot_parameters.activate_arrowhead, transsys)
807 808
809 -class PromoterElementRepress(PromoterElementLink) :
810
811 - def __init__(self, expr1, expr2, factor_list, dot_attrs = None) :
812 PromoterElementLink.__init__(self, expr1, expr2, factor_list, dot_attrs)
813 814
815 - def __str__(self) :
816 return '%s: repress(%s, %s)' % (PromoterElementLink.__str__(self), str(self.expression1), str(self.expression2))
817 818
819 - def write_dot_edge(self, f, target_name, dot_parameters, transsys) :
820 PromoterElementLink.write_dot_edge(self, f, target_name, dot_parameters.display_factors, dot_parameters.repress_arrowhead, transsys)
821 822
823 -class Factor(object) :
824 """Class representing a transsys factor. 825 826 @ivar name: the factor's name 827 @type name: C{string} 828 @ivar decay_expression: expression to compute the factor's decay rate 829 @type decay_expression: C{ExpressionNode} subclass 830 @ivar diffusibility_expression: expression to compute the factor's diffusibility 831 @type diffusibility_expression: C{ExpressionNode} subclass 832 @ivar comments: comments pertaining to the factor 833 @type comments: C{list} of C{string}s 834 @ivar dot_attributes: attributes for rendering the factor in the dot (graphviz) 835 language 836 @type dot_attributes: C{dictionary}, keys are attribute names, values are 837 attribute values 838 """
839 - def __init__(self, name, decay_expr, diffusibility_expr, dot_attrs = None) :
840 if not isinstance(decay_expr, ExpressionNode) : 841 raise StandardError, 'Factor::__init__: bad decay_expr type' 842 if not isinstance(diffusibility_expr, ExpressionNode) : 843 raise StandardError, 'Factor::__init__: bad diffusibility_expr type' 844 self.name = name 845 self.decay_expression = decay_expr 846 self.diffusibility_expression = diffusibility_expr 847 self.comments = [] 848 if dot_attrs is None : 849 self.dot_attributes = {} 850 else : 851 self.dot_attributes = copy.deepcopy(dot_attrs)
852 853
854 - def __str__(self) :
855 return """ factor %s 856 { 857 %s decay: %s; 858 diffusibility: %s; 859 } 860 """ % (self.name, _comment_lines(self.comments, ' '), str(self.decay_expression), str(self.diffusibility_expression))
861 862
863 - def resolve(self, tp) :
864 self.decay_expression.resolve(tp) 865 self.diffusibility_expression.resolve(tp)
866 867
868 - def unresolved_copy(self) :
869 return self.__class__(self.name, self.decay_expression.unresolved_copy(), self.diffusibility_expression.unresolved_copy(), self.dot_attributes)
870 871
872 - def getDecayValueNodes(self) :
873 """get all constant value expression nodes in the decay expression.""" 874 return self.decay_expression.getValueNodes()
875 876
877 - def getDiffusibilityValueNodes(self) :
878 """get all constant value expression nodes in the diffusiblility expression.""" 879 return self.diffusibility_expression.getValueNodes()
880 881
882 - def getValueNodes(self) :
883 """get all constant value expression nodes controlling the factor's behaviour.""" 884 return self.getDecayValueNodes() + self.getDiffusibilityValueNodes()
885 886
887 - def getDecayIdentifierNodes(self) :
888 """get all identifier expression nodes in the decay expression.""" 889 return self.decay_expression.getIdentifierNodes()
890 891
893 """get all identifier expression nodes in the diffusiblility expression.""" 894 return self.diffusibility_expression.getIdentifierNodes()
895 896
897 - def getIdentifierNodes(self) :
898 """get all identifier expression nodes controlling the factor's behaviour.""" 899 return self.getDecayIdentifierNodes() + self.getDiffusibilityIdentifierNodes()
900 901
902 - def write_dot_node(self, f, dot_parameters, transsys) :
903 f.write(' %s' % self.name) 904 if len(self.dot_attributes) > 0 : 905 f.write(' [%s]' % dot_attribute_string(self.dot_attributes)) 906 f.write(';\n')
907 908
909 - def canonicalise(self) :
910 """""" 911 if isinstance(self.decay_expression, ExpressionNodeValue) : 912 self.decay_expression.clip(0.0, 1.0) 913 if isinstance(self.diffusibility_expression, ExpressionNodeValue) : 914 self.diffusibility_expression.clip(0.0, 1.0)
915 916
917 -class Gene(object) :
918 """Class to represent a gene. 919 920 @ivar name: name of the gene 921 @type name: C{string} 922 @ivar product: product of this gene 923 @type product: C{string} (unresolved) or C{Factor} (resolved) 924 @ivar promoter: list of promoter elements 925 @type promoter: C{list} of C{PromoterElement} subclass instances 926 """ 927
928 - def __init__(self, name, product, promoter = None, dot_attrs = None) :
929 if not (isinstance(product, Factor) or (type(product) is types.StringType)) : 930 raise StandardError, 'Gene::__init__: bad type of product' 931 self.name = name 932 self.product = product 933 if promoter is None : 934 self.promoter = [] 935 else : 936 for p in promoter : 937 if not isinstance(p, PromoterElement) : 938 raise StandardError, 'Gene::__init__: bad element in promoter' 939 self.promoter = copy.deepcopy(promoter) 940 self.comments = [] 941 if dot_attrs is None : 942 self.dot_attributes = {} 943 else : 944 self.dot_attributes = copy.deepcopy(dot_attrs)
945 946
947 - def __str__(self) :
948 s = ' gene %s\n' % self.name 949 s = s + ' {\n' 950 s = s + _comment_lines(self.comments, ' ') 951 s = s + ' promoter\n' 952 s = s + ' {\n' 953 for p in self.promoter : 954 s = s + ' %s;\n' % str(p) 955 s = s + ' }\n' 956 s = s + ' product\n' 957 s = s + ' {\n' 958 s = s + ' default: %s;\n' % self.product_name() 959 s = s + ' }\n' 960 s = s + ' }\n' 961 return s
962 963
964 - def product_name(self) :
965 if type(self.product) is types.StringType : 966 return self.product 967 else : 968 return self.product.name
969 970
971 - def resolve(self, tp) :
972 for pe in self.promoter : 973 pe.resolve(tp) 974 self.product = tp.find_factor(self.product)
975 976
977 - def unresolved_copy(self) :
978 unresolved_promoter = [] 979 for pe in self.promoter : 980 unresolved_promoter.append(pe.unresolved_copy()) 981 return self.__class__(self.name, self.product_name(), unresolved_promoter, self.dot_attributes)
982 983
984 - def getConstitutiveValueNodes(self) :
985 """Get a list of constant value nodes from all constitutive 986 promoter elements of this gene.""" 987 vn = [] 988 for p in self.promoter : 989 if isinstance(p, PromoterElementConstitutive) : 990 vn = vn + p.getValueNodes() 991 return vn
992 993
994 - def getActivateSpecValueNodes(self) :
995 """Get a list of constant value nodes from all spec ("K_M") 996 parameters to activate promoter elements.""" 997 vn = [] 998 for p in self.promoter : 999 if isinstance(p, PromoterElementActivate) : 1000 vn = vn + p.getSpecValueNodes() 1001 return vn
1002 1003
1004 - def getActivateMaxValueNodes(self) :
1005 """Get a list of constant value nodes from all max ("v_max") 1006 parameters to activate promoter elements.""" 1007 vn = [] 1008 for p in self.promoter : 1009 if isinstance(p, PromoterElementActivate) : 1010 vn = vn + p.getMaxValueNodes() 1011 return vn
1012 1013
1014 - def getRepressSpecValueNodes(self) :
1015 """Get a list of constant value nodes from all spec ("K_M") 1016 parameters to repress promoter elements.""" 1017 vn = [] 1018 for p in self.promoter : 1019 if isinstance(p, PromoterElementRepress) : 1020 vn = vn + p.getSpecValueNodes() 1021 return vn
1022 1023
1024 - def getRepressMaxValueNodes(self) :
1025 """Get a list of constant value nodes from all max ("v_max") 1026 parameters to repress promoter elements.""" 1027 vn = [] 1028 for p in self.promoter : 1029 if isinstance(p, PromoterElementRepress) : 1030 vn = vn + p.getMaxValueNodes() 1031 return vn
1032 1033
1034 - def getLinkValueNodes(self) :
1035 """Get a list of constant value nodes from all link 1036 promoter elements (activate, repress) of this gene.""" 1037 vn = [] 1038 for p in self.promoter : 1039 if isinstance(p, PromoterElementLink) : 1040 vn = vn + p.getValueNodes() 1041 return vn
1042 1043
1044 - def getValueNodes(self) :
1045 """Get a list of constant value nodes from all promoter elements of this gene.""" 1046 vn = [] 1047 for p in self.promoter : 1048 vn = vn + p.getValueNodes() 1049 return vn
1050 1051
1052 - def getIdentifierNodes(self) :
1053 """Get a list of identifier nodes from all promoter elements of this gene.""" 1054 identifierNodes = [] 1055 for p in self.promoter : 1056 identifierNodes = identifierNodes + p.getIdentifierNodes() 1057 return identifierNodes
1058 1059
1060 - def write_dot_node(self, f, dot_parameters, transsys) :
1061 f.write(' %s' % self.name) 1062 if len(self.dot_attributes) > 0 : 1063 f.write(' [%s]' % dot_attribute_string(self.dot_attributes)) 1064 f.write(';\n')
1065 1066
1067 - def write_dot_edges(self, f, dot_parameters, transsys) :
1068 """write edges directed towards this gene""" 1069 for p in self.promoter : 1070 p.write_dot_edge(f, self.name, dot_parameters, transsys)
1071 1072
1073 - def regulating_factors(self) :
1074 """return a list of factors that regulate expression of this gene""" 1075 rfactors = [] 1076 for p in self.promoter : 1077 if isinstance(p, PromoterElementLink) : 1078 for f in p.factor_list : 1079 if f not in rfactors : 1080 rfactors.append(f) 1081 return rfactors
1082 1083
1084 - def canonicalise(self) :
1085 """Canonicalise parameters in promoter elements.""" 1086 for p in self.promoter : 1087 p.canonicalise()
1088 1089
1090 -class TranssysProgram(object) :
1091 """Class to represent a transsys program. 1092 1093 References to objects within the transsys program can in some 1094 places either be specified by a python reference, or alternatively 1095 by a string specifying the name of the object being referred to. 1096 The process of replacing these names with proper python references 1097 is called I{resolving}, and hence a transsys program in which 1098 objects are referred to by proper python references is said to 1099 be I{resolved}, whereas one in which references are specified by 1100 "raw" strings is said to be I{unresolved}. 1101 1102 Note: unresolved_copy returns a TranssysProgram instance, also for 1103 classes derived from TranssysProgram. If unresolved_copy for such classes 1104 is required to return the derived class, these classes will have to 1105 re-implement this method. 1106 1107 @ivar name: name of the transsys program 1108 @type name: C{string} 1109 @ivar factor_list: list containing the factors of the program 1110 @type factor_list: C{list} of C{Factor} instances 1111 @ivar gene_list: list containing the genes of the program 1112 @type gene_list: C{list} of C{Gene} instances 1113 @ivar comments: list of strings that will be provided as 1114 comments upon converting the transsys program to a string 1115 @type comments: C{list} of C{string}s 1116 """ 1117
1118 - def __init__(self, name, factor_list = None, gene_list = None, resolve = True) :
1119 self.name = name 1120 if factor_list is None : 1121 self.factor_list = [] 1122 else : 1123 for f in factor_list : 1124 if not isinstance(f, Factor) : 1125 raise StandardError, 'TranssysProgram::__init__: unsuitable element in factor_list' 1126 # FIXME: I don't think this deepcopy works usefully for a list of resolved factors 1127 self.factor_list = copy.deepcopy(factor_list) 1128 if gene_list is None : 1129 self.gene_list = [] 1130 else : 1131 for g in gene_list : 1132 if not isinstance(g, Gene) : 1133 raise StandardError, 'TranssysProgram::__init__: unsuitable element in gene_list' 1134 # FIXME: same deepcopy problem as above 1135 self.gene_list = copy.deepcopy(gene_list) 1136 self.comments = [] 1137 if resolve : 1138 self.resolve()
1139 1140
1141 - def __str__(self) :
1142 """Render the transsys program as a multi-line string. 1143 1144 Parsing this string results in a transsys program equal to 1145 this instance itself. 1146 """ 1147 s = 'transsys %s\n' % self.name 1148 s = s + _comment_lines(self.comments) 1149 s = s + '{\n' 1150 glue = '' 1151 for f in self.factor_list : 1152 s = s + glue + str(f) 1153 glue = '\n' 1154 for g in self.gene_list : 1155 s = s + glue + str(g) 1156 glue = '\n' 1157 s = s + '}\n' 1158 return s
1159 1160
1161 - def num_factors(self) :
1162 """Return the number of factors in this transsys program.""" 1163 return len(self.factor_list)
1164 1165
1166 - def num_genes(self) :
1167 """Return the number of genes in this transsys program.""" 1168 return len(self.gene_list)
1169 1170
1171 - def factor_names(self) :
1172 """Return a list of names of the factors in this transsys program.""" 1173 fnames = [] 1174 for f in self.factor_list : 1175 fnames.append(f.name) 1176 return fnames
1177 1178
1179 - def gene_names(self) :
1180 """Return a list of names of the genes in this transsys program.""" 1181 gnames = [] 1182 for g in self.gene_list : 1183 gnames.append(g.name) 1184 return gnames
1185 1186
1187 - def find_factor_index(self, f_name) :
1188 """Find the index of factor C{f_name}. 1189 1190 @return: the index of factor C{f_name}, or -1 if no factor with that name 1191 exists 1192 @rtype: int 1193 """ 1194 for i in xrange(len(self.factor_list)) : 1195 if self.factor_list[i].name == f_name : 1196 return i 1197 return -1
1198 1199
1200 - def find_factor(self, f_name) :
1201 """Find the factor specified by C{f_name}. 1202 1203 @return: the requested factor 1204 @rtype: Factor 1205 @raise StandardError: if the specified factor does not exist 1206 """ 1207 if isinstance(f_name, Factor) : 1208 f_name = f_name.name 1209 elif type(f_name) is not types.StringType : 1210 raise StandardError, 'TranssysProgram::find_factor: illegal argument type' 1211 i = self.find_factor_index(f_name) 1212 if i < 0 : 1213 raise StandardError, 'TranssysProgram::find_factor: no factor "%s" in transsys %s' % (f_name, self.name) 1214 return self.factor_list[i]
1215 1216
1217 - def find_gene_index(self, g_name) :
1218 """Find the index of gene C{g_name}. 1219 1220 @return: the index of gene C{g_name}, or -1 if no gene with that name 1221 exists 1222 @rtype: int 1223 """ 1224 for i in xrange(len(self.gene_list)) : 1225 if self.gene_list[i].name == g_name : 1226 return i 1227 return -1
1228 1229
1230 - def find_gene(self, g_name) :
1231 """Find the gene specified by C{g_name}. 1232 1233 @return: the requested gene 1234 @rtype: Gene 1235 @raise StandardError: if the specified gene does not exist 1236 """ 1237 if isinstance(g_name, Gene) : 1238 g_name = g_name.name 1239 if type(g_name) is not types.StringType : 1240 raise StandardError, 'TranssysProgram::find_gene: illegal argument type' 1241 i = self.find_gene_index(g_name) 1242 if i < 0 : 1243 raise StandardError, 'TranssysProgram::find_gene: no gene "%s" in transsys %s' % (g_name, self.name) 1244 return self.gene_list[i]
1245 1246
1247 - def check_uniqueness(self) :
1248 """Verify that factor and gene names are unique. 1249 1250 This method raises an exception if problems are found and has no useful 1251 return value. 1252 1253 @raise StandardError: if duplicate factor or gene names found 1254 """ 1255 fnames = [] 1256 for factor in self.factor_list : 1257 if factor.name in fnames : 1258 raise StandardError, 'factor name "%s" duplicated' % factor.name 1259 fnames.append(factor.name) 1260 gnames = [] 1261 for gene in self.gene_list : 1262 if gene.name in self.gene_list : 1263 raise StandardError, 'gene name "%s" duplicated' % gene.name 1264 gnames.append(gene.name)
1265 1266
1267 - def resolve(self) :
1268 """The resolve() method replaces all gene and factor specifications 1269 by strings with references to the gene object or factor object, respectively. 1270 Strings which do not properly resolve trigger an exception. resolve() 1271 should be called whenever alterations are done to a TranssysProgram instance in 1272 which strings are used to specify genes or factors. Only after resolving, 1273 gene names and factor names can be altered without changing the network.""" 1274 self.check_uniqueness() 1275 for factor in self.factor_list : 1276 factor.resolve(self) 1277 for gene in self.gene_list : 1278 gene.resolve(self)
1279 1280
1281 - def unresolved_copy(self) :
1282 """Produce an unresolved transsys program equal to this program itself""" 1283 factor_list = [] 1284 for f in self.factor_list : 1285 factor_list.append(f.unresolved_copy()) 1286 gene_list = [] 1287 for g in self.gene_list : 1288 gene_list.append(g.unresolved_copy()) 1289 # since we don't know what might be derived from TranssysProgram and what 1290 # constructors they may have, we don't use the self.__class__() constructor 1291 # call here. 1292 return TranssysProgram(self.name, factor_list, gene_list, False)
1293 1294
1295 - def get_knockout_copy(self, gene_name) :
1296 """Construct a copy of this transsys program with the specified gene 1297 deleted (knocket out). 1298 1299 Notice that this method does not modify the instance on which 1300 it is invoked. This is not a mutator method. 1301 1302 @param gene_name: the name of the gene to be knocked out 1303 @type gene_name: C{String} 1304 @return: the transsys program with the gene knocked out 1305 @rtype: L{TranssysProgram} 1306 """ 1307 tp_knockout = copy.deepcopy(self) 1308 gene_index = tp_knockout.find_gene_index(gene_name) 1309 if gene_index == -1 : 1310 raise StandardError, 'no gene "%s" to be knocked out' % gene_name 1311 del tp_knockout.gene_list[gene_index] 1312 return tp_knockout
1313 1314
1315 - def getDecayValueNodes(self) :
1316 """Get all constant value nodes pertaining to decay attributes in factors.""" 1317 valueNodes = [] 1318 for factor in self.factor_list : 1319 valueNodes = valueNodes + factor.getDecayValueNodes() 1320 return valueNodes
1321 1322
1323 - def getDiffusibilityValueNodes(self) :
1324 """Get all constant value nodes pertaining to diffusibility attributes in factors.""" 1325 valueNodes = [] 1326 for factor in self.factor_list : 1327 valueNodes = valueNodes + factor.getDiffusibilityValueNodes() 1328 return valueNodes
1329 1330
1331 - def getFactorValueNodes(self, decayNodes = True, diffusibilityNodes = True) :
1332 """Get all constant value nodes pertaining to factors 1333 in this transsys program.""" 1334 valueNodes = [] 1335 if decayNodes : 1336 valueNodes = valueNodes + self.getDecayValueNodes() 1337 if diffusibilityNodes : 1338 valueNodes = valueNodes + self.getDiffusibilityValueNodes() 1339 return valueNodes
1340 1341
1342 - def getConstitutiveValueNodes(self) :
1343 """Get all constant value nodes pertaining to constitutive promoter 1344 elements in this transsys program.""" 1345 valueNodes = [] 1346 for gene in self.gene_list : 1347 valueNodes = valueNodes + gene.getConstitutiveValueNodes() 1348 return valueNodes
1349 1350
1351 - def getActivateSpecValueNodes(self) :
1352 """Get all constant value nodes pertaining to aspec in 1353 activate promoter elements in this transsys program.""" 1354 valueNodes = [] 1355 for gene in self.gene_list : 1356 valueNodes = valueNodes + gene.getActivateSpecValueNodes() 1357 return valueNodes
1358 1359
1360 - def getActivateMaxValueNodes(self) :
1361 """Get all constant value nodes pertaining to amax in 1362 activate promoter elements in this transsys program.""" 1363 valueNodes = [] 1364 for gene in self.gene_list : 1365 valueNodes = valueNodes + gene.getActivateMaxValueNodes() 1366 return valueNodes
1367 1368
1369 - def getRepressSpecValueNodes(self) :
1370 """Get all constant value nodes pertaining to aspec in 1371 repress promoter elements in this transsys program.""" 1372 valueNodes = [] 1373 for gene in self.gene_list : 1374 valueNodes = valueNodes + gene.getRepressSpecValueNodes() 1375 return valueNodes
1376 1377
1378 - def getRepressMaxValueNodes(self) :
1379 """Get all constant value nodes pertaining to amax in 1380 repress promoter elements in this transsys program.""" 1381 valueNodes = [] 1382 for gene in self.gene_list : 1383 valueNodes = valueNodes + gene.getRepressMaxValueNodes() 1384 return valueNodes
1385 1386
1387 - def getGeneValueNodes(self, constitutiveNodes = True, linkNodes = True) :
1388 """Get all constant value nodes pertaining to genes 1389 in this transsys program.""" 1390 valueNodes = [] 1391 for gene in self.gene_list : 1392 if constitutiveNodes : 1393 valueNodes = valueNodes + gene.getConstitutiveValueNodes() 1394 if linkNodes : 1395 valueNodes = valueNodes + gene.getLinkValueNodes() 1396 return valueNodes
1397 1398
1399 - def getValueNodes(self) :
1400 """Get all constant value nodes in this transsys program.""" 1401 return self.getFactorValueNodes() + self.getGeneValueNodes()
1402 1403
1404 - def getFactorIdentifierNodes(self) :
1405 """Get all identifier nodes pertaining to 1406 factors in this transsys program.""" 1407 identifierNodes = [] 1408 for factor in self.factor_list : 1409 identifierNodes = identifierNodes + factor.getIdentifierNodes() 1410 return identifierNodes
1411 1412
1413 - def getGeneIdentifierNodes(self) :
1414 """Get all identifier nodes pertaining to 1415 genes in this transsys program.""" 1416 identifierNodes = [] 1417 for gene in self.gene_list : 1418 identifierNodes = identifierNodes + gene.getIdentifierNodes() 1419 return identifierNodes
1420 1421
1422 - def getIdentifierNodes(self) :
1423 """Get all identifier nodes in this transsys program.""" 1424 return self.getFactorIdentifierNodes() + self.getGeneIdentifierNodes()
1425 1426
1427 - def encoding_gene_list(self, factor_name) :
1428 """return a list of all genes which encode factor named factor_name""" 1429 # print 'encoding_gene_list("%s")' % factor_name 1430 glist = [] 1431 for gene in self.gene_list : 1432 if gene.product_name() == factor_name : 1433 glist.append(gene) 1434 return glist
1435 1436
1437 - def write_dot(self, f, dot_parameters) :
1438 """write transsys program as graph in the dot language""" 1439 f.write('digraph %s\n' % self.name) 1440 f.write('{\n') 1441 for gene in self.gene_list : 1442 gene.write_dot_node(f, dot_parameters, self) 1443 if dot_parameters.display_factors : 1444 for factor in self.factor_list : 1445 factor.write_dot_node(f, dot_parameters, self) 1446 for gene in self.gene_list : 1447 # print 'write_dot: edges for gene "%s"' % gene.name 1448 gene.write_dot_edges(f, dot_parameters, self) 1449 f.write('}\n')
1450 1451
1452 - def dot_positions_circle(self, x0, y0, radius) :
1453 """Set the dot language coordinates of genes to arrange them in a circle.""" 1454 for i in xrange(len(self.gene_list)) : 1455 angle = 2.0 * math.pi * i / len(self.gene_list) 1456 self.gene_list[i].dot_attributes['pos'] = '%f,%f!' % (x0 + radius * math.cos(angle), y0 + radius * math.sin(angle))
1457 1458
1459 - def regulated_genes(self, factor) :
1460 """Find the genes regulated by C{factor}.""" 1461 if type(factor) is types.StringType : 1462 i = self.find_factor_index(factor) 1463 if i == -1 : 1464 raise StandardError, 'TranssysProgram.regulated_genes: transsys program "%s" does not contain factor "%s"' % (self.name, factor) 1465 factor = self.factor_list[i] 1466 if not isinstance(factor, Factor) : 1467 raise TypeError, 'TranssysProgram.regulated_genes: factor argument not a Factor instance' 1468 rgenes = [] 1469 for gene in self.gene_list : 1470 if factor in gene.regulating_factors() : 1471 rgenes.append(gene) 1472 return rgenes
1473 1474
1475 - def indegree_list(self) :
1476 """Get a gene-based list of indegree values.""" 1477 dlist = [] 1478 for gene in self.gene_list : 1479 dlist.append(len(gene.regulating_factors())) 1480 return dlist
1481 1482
1483 - def outdegree_list(self) :
1484 """Get a gene-based list of outdegree values.""" 1485 dlist = [] 1486 for gene in self.gene_list : 1487 factor = gene.product 1488 dlist.append(len(self.regulated_genes(factor))) 1489 return dlist
1490 1491
1492 - def merge(self, other) :
1493 """Merge the factors and genes of transsys program C{other} into this program.""" 1494 other_unresolved = other.unresolved_copy() 1495 for f in other_unresolved.factor_list : 1496 if self.find_factor_index(f.name) == -1 : 1497 self.factor_list.append(f) 1498 else : 1499 sys.stderr.write('TranssysProgram::merge: factor %s already present -- skipping\n' % f.name) 1500 for g in other_unresolved.gene_list : 1501 if self.find_gene_index(g.name) == -1 : 1502 self.gene_list.append(g) 1503 else : 1504 sys.stderr.write('TranssysProgram::merge: gene %s already present -- skipping\n' % g.name) 1505 self.resolve() 1506 self.comments.append('merged with transsys %s' % other.name)
1507 1508
1509 - def canonicalise(self) :
1510 """Replace values in numeric nodes with the canonical value. 1511 1512 Canonicalisation clips values that are outside of their range 1513 with the closest value within the range. This does not alter the 1514 dynamical properties of the transsys program, as such clipping is 1515 done by the transsys engine during simulation of dynamics too. 1516 1517 In other words, the clipping done by the transsys gene expression 1518 simulator engine implies that there exist multiple transsys programs 1519 with identical dynamics, and canonicalisation serves to reduce this 1520 degeneracy by converting such multiple equivalent programs to one 1521 canonical form. 1522 1523 Canonicalisation only operates on constant values in certain 1524 contexts, see C{canonicalise} documentation for C{Factor} and C{Gene} 1525 for more details. Notice that this implies that transsys programs 1526 may have identical dynamics even though their canonical forms differ. 1527 """ 1528 for factor in self.factor_list : 1529 factor.canonicalise() 1530 for gene in self.gene_list : 1531 gene.canonicalise()
1532 1533
1534 -class GraphicsPrimitive(object) :
1535
1536 - def __init__(self) :
1537 pass
1538 1539
1540 - def dissociate_transsys(self) :
1541 pass
1542 1543
1544 - def associate_transsys(self) :
1545 pass
1546 1547
1548 -class GraphicsPrimitiveMove(GraphicsPrimitive) :
1549
1550 - def __init__(self, expression) :
1551 self.expression = expression
1552 1553
1554 - def __str__(self) :
1555 return 'move(%s);' % str(self.expression)
1556 1557
1558 - def dissociate_transsys(self) :
1559 self.expression = self.expression.unresolved_copy()
1560 1561
1562 - def associate_transsys(self, tp) :
1563 self.expression.resolve(tp)
1564 1565
1566 -class GraphicsPrimitivePush(GraphicsPrimitive) :
1567
1568 - def __str__(self) :
1569 return 'push();'
1570 1571
1572 -class GraphicsPrimitivePop(GraphicsPrimitive) :
1573
1574 - def __str__(self) :
1575 return 'pop();'
1576 1577
1578 -class GraphicsPrimitiveTurn(GraphicsPrimitive) :
1579
1580 - def __init__(self, expression) :
1581 self.expression = expression
1582 1583
1584 - def __str__(self) :
1585 return 'turn(%s);' % str(self.expression)
1586 1587
1588 - def dissociate_transsys(self) :
1589 self.expression = self.expression.unresolved_copy()
1590 1591
1592 - def associate_transsys(self, tp) :
1593 self.expression.resolve(tp)
1594 1595
1596 -class GraphicsPrimitiveRoll(GraphicsPrimitive) :
1597
1598 - def __init__(self, expression) :
1599 self.expression = expression
1600 1601
1602 - def __str__(self) :
1603 return 'roll(%s);' % str(self.expression)
1604 1605
1606 - def dissociate_transsys(self) :
1607 self.expression = self.expression.unresolved_copy()
1608 1609
1610 - def associate_transsys(self, tp) :
1611 self.expression.resolve(tp)
1612 1613
1614 -class GraphicsPrimitiveBank(GraphicsPrimitive) :
1615
1616 - def __init__(self, expression) :
1617 self.expression = expression
1618 1619
1620 - def __str__(self) :
1621 return 'bank(%s);' % str(self.expression)
1622 1623
1624 - def dissociate_transsys(self) :
1625 self.expression = self.expression.unresolved_copy()
1626 1627
1628 - def associate_transsys(self, tp) :
1629 self.expression.resolve(tp)
1630 1631
1632 -class GraphicsPrimitiveSphere(GraphicsPrimitive) :
1633
1634 - def __init__(self, expression) :
1635 self.expression = expression
1636 1637
1638 - def __str__(self) :
1639 return 'sphere(%s);' % str(self.expression)
1640 1641
1642 - def dissociate_transsys(self) :
1643 self.expression = self.expression.unresolved_copy()
1644 1645
1646 - def associate_transsys(self, tp) :
1647 self.expression.resolve(tp)
1648 1649
1650 -class GraphicsPrimitiveCylinder(GraphicsPrimitive) :
1651
1652 - def __init__(self, diameterExpression, lengthExpression) :
1653 self.diameterExpression = diameterExpression 1654 self.lengthExpression = lengthExpression
1655 1656
1657 - def __str__(self) :
1658 return 'cylinder(%s, %s);' % (str(self.diameterExpression), str(self.lengthExpression))
1659 1660
1661 - def dissociate_transsys(self) :
1662 self.diameterExpression = self.diameterExpression.unresolved_copy() 1663 self.lengthExpression = self.lengthExpression.unresolved_copy()
1664 1665
1666 - def associate_transsys(self, tp) :
1667 self.diameterExpression.resolve(tp) 1668 self.lengthExpression.resolve(tp)
1669 1670
1671 -class GraphicsPrimitiveBox(GraphicsPrimitive) :
1672
1673 - def __init__(self, xExpression, yExpression, zExpression) :
1674 self.xExpression = xExpression 1675 self.yExpression = yExpression 1676 self.zExpression = zExpression
1677 1678
1679 - def __str__(self) :
1680 return 'box(%s, %s, %s);' % (str(self.xExpression), str(self.yExpression), str(self.zExpression))
1681 1682
1683 - def dissociate_transsys(self) :
1684 self.xExpression = self.xExpression.unresolved_copy() 1685 self.yExpression = self.yExpression.unresolved_copy() 1686 self.zExpression = self.zExpression.unresolved_copy()
1687 1688
1689 - def associate_transsys(self, tp) :
1690 self.xExpression.resolve(tp) 1691 self.yExpression.resolve(tp) 1692 self.zExpression.resolve(tp)
1693 1694
1695 -class GraphicsPrimitiveColor(GraphicsPrimitive) :
1696
1697 - def __init__(self, redExpression, greenExpression, blueExpression) :
1698 self.redExpression = redExpression 1699 self.greenExpression = greenExpression 1700 self.blueExpression = blueExpression
1701 1702
1703 - def __str__(self) :
1704 return 'color(%s, %s, %s);' % (str(self.redExpression), str(self.greenExpression), str(self.blueExpression))
1705 1706
1707 - def dissociate_transsys(self) :
1708 self.redExpression = self.redExpression.unresolved_copy() 1709 self.greenExpression = self.greenExpression.unresolved_copy() 1710 self.blueExpression = self.blueExpression.unresolved_copy()
1711 1712
1713 - def associate_transsys(self, tp) :
1714 self.redExpression.resolve(tp) 1715 self.greenExpression.resolve(tp) 1716 self.blueExpression.resolve(tp)
1717 1718
1719 -class Symbol(object) :
1720
1721 - def __init__(self, name, transsys, graphics = None) :
1722 self.name = name 1723 self.transsys = transsys 1724 self.graphics = graphics
1725 1726
1727 - def __str__(self) :
1728 if self.transsys is None : 1729 return 'symbol %s' % self.name 1730 else : 1731 return 'symbol %s(%s)' % (self.name, self.transsys_name())
1732 1733
1734 - def transsys_name(self) :
1735 if self.transsys is None : 1736 return None 1737 elif isinstance(self.transsys, TranssysProgram) : 1738 return self.transsys.name 1739 elif type(self.transsys) is types.StringType : 1740 return self.transsys 1741 else : 1742 raise StandardError, 'Symbol::transsys_name: bad type %s of transsys member' % str(type(self.transsys))
1743 1744
1745 - def is_associated(self) :
1746 return isinstance(self.transsys, TranssysProgram)
1747 1748
1749 - def dissociate_transsys(self) :
1750 if self.is_associated() : 1751 if self.graphics is not None : 1752 for g in self.graphics : 1753 g.dissociate_transsys() 1754 self.transsys = self.transsys_name()
1755 1756
1757 - def associate_transsys(self, tp) :
1758 if self.transsys is None : 1759 return 1760 self.dissociate_transsys() 1761 if tp.name != self.transsys_name() : 1762 raise StandardError, 'associating incompatible transsys: "%s" != "%s"' % (tp.name, self.transsys_name()) 1763 if self.graphics is not None : 1764 for g in self.graphics : 1765 g.associate_transsys(tp) 1766 self.transsys = tp
1767 1768
1769 - def graphics_string(self) :
1770 if self.graphics is None : 1771 return ' // symbol %s: no graphics\n' % self.name 1772 s = ' %s\n' % self.name 1773 s = s + ' {\n' 1774 for g in self.graphics : 1775 s = s + ' %s\n' % str(g) 1776 s = s + ' }\n' 1777 return s
1778 1779 1780
1781 -class Assignment(object) :
1782
1783 - def __init__(self, transsys, factor, expression) :
1784 self.transsys = transsys 1785 self.factor = factor 1786 self.expression = expression
1787 1788
1789 - def __str__(self) :
1790 if isinstance(self.factor, Factor) : 1791 return '%s = %s' % (self.factor.name, str(self.expression)) 1792 else : 1793 return '%s = %s' % (self.factor, str(self.expression))
1794 1795
1796 - def dissociate_transsys(self) :
1797 if isinstance(self.factor, Factor) : 1798 self.factor = self.factor.name 1799 self.expression = self.expression.unresolved_copy()
1800 1801
1802 - def associate_transsys(self, tp) :
1803 self.factor = tp.find_factor(self.factor) 1804 self.expression.resolve(tp)
1805 1806
1807 -class LhsSymbol(object) :
1808
1809 - def __init__(self, symbol, transsys_label) :
1810 self.symbol = symbol 1811 self.transsys_label = transsys_label
1812 1813
1814 - def __str__(self) :
1815 if self.transsys_label : 1816 return '%s(%s)' % (self.symbol.name, self.transsys_label) 1817 else : 1818 return self.symbol_name
1819 1820
1821 -class ProductionElement(object) :
1822
1823 - def __init__(self, symbol, template_label, assignments) :
1824 self.symbol = symbol 1825 self.template_label = template_label 1826 self.assignments = assignments
1827 1828
1829 - def __str__(self) :
1830 tl = '' 1831 if self.template_label is not None : 1832 tl = 'transsys %s: ' % self.template_label 1833 as = '' 1834 glue = '' 1835 for a in self.assignments : 1836 as = as + glue + str(a) 1837 glue = ', ' 1838 if tl != '' or as != '' : 1839 return '%s(%s%s)' % (self.symbol.name, tl, as) 1840 else : 1841 return self.symbol.name
1842 1843
1844 - def dissociate_transsys(self) :
1845 for a in self.assignments : 1846 a.dissociate_transsys()
1847 1848
1849 - def associate_transsys(self, tp) :
1850 for a in self.assignments : 1851 a.associate_transsys(tp)
1852 1853
1854 -class Rule(object) :
1855
1856 - def __init__(self, name, lhs, condition, rhs) :
1857 self.name = name 1858 self.lhs = lhs 1859 self.condition = condition 1860 self.rhs = rhs
1861 1862
1863 - def __str__(self) :
1864 s = ' rule %s\n' % self.name 1865 s = s + ' {\n' 1866 s = s + ' ' 1867 for l in self.lhs : 1868 s = s + ' %s' % str(l) 1869 if self.condition is not None : 1870 s = s + ':\n' 1871 s = s + ' %s' % str(self.condition) 1872 s = s + '\n' 1873 s = s + ' -->' 1874 for r in self.rhs : 1875 s = s + ' %s' % str(r) 1876 s = s + '\n' 1877 s = s + ' }\n' 1878 return s
1879 1880
1881 - def dissociate_transsys(self) :
1882 if self.condition is not None : 1883 self.condition = self.condition.unresolved_copy() 1884 for r in self.rhs : 1885 r.dissociate_transsys()
1886 1887
1888 - def associate_transsys(self, tp) :
1889 if self.condition is not None : 1890 self.condition.resolve(tp) 1891 for r in self.rhs : 1892 r.associate_transsys(tp)
1893 1894
1895 -class LsysProgram(object) :
1896
1897 - def __init__(self, name, symbols, axiom, diffusionrange, rules) :
1898 self.name = name 1899 self.symbols = symbols 1900 self.axiom = axiom 1901 self.diffusionrange = diffusionrange 1902 self.rules = rules
1903 1904
1905 - def __str__(self) :
1906 s = 'lsys %s\n' % self.name 1907 s = s + '{\n' 1908 s = s + ' diffusionrange: %d;\n' % self.diffusionrange 1909 s = s + '\n' 1910 for sym in self.symbols : 1911 s = s + ' %s;\n' % str(sym) 1912 s = s + '\n' 1913 s = s + ' axiom' 1914 for a in self.axiom : 1915 s = s + ' %s;\n' % str(a) 1916 s = s + '\n' 1917 for rule in self.rules : 1918 s = s + str(rule) 1919 s = s + '\n' 1920 s = s + ' graphics\n' 1921 s = s + ' {\n' 1922 for sym in self.symbols : 1923 s = s + sym.graphics_string() 1924 s = s + ' }\n' 1925 s = s + '}\n' 1926 return s
1927 1928
1929 - def dissociate_transsys(self) :
1930 for s in self.symbols : 1931 s.dissociate_transsys() 1932 for r in self.rules : 1933 r.dissociate_transsys()
1934 1935
1936 - def associate_transsys(self, tp) :
1937 for s in self.symbols : 1938 s.associate_transsys(tp) 1939 for r in self.rules : 1940 r.associate_transsys(tp)
1941 1942
1943 - def find_symbol_index(self, symbol_name) :
1944 for i in xrange(len(self.symbols)) : 1945 if self.symbols[i].name == symbol_name : 1946 return i 1947 return -1
1948 1949
1950 - def find_symbol(self, symbol_name) :
1951 if type(symbol_name) is not types.StringType : 1952 raise StandardError, 'LsysProgram::find_symbol: illegal argument type' 1953 i = self.find_symbol_index(symbol_name) 1954 if i < 0 : 1955 raise StandardError, 'LsysProgram::find_symbol: no symbol "%s" in lsys %s' % (symbol_name, self.name) 1956 return self.symbols[i]
1957 1958
1959 - def find_rule_index(self, rule_name) :
1960 for i in xrange(len(self.rules)) : 1961 if self.rules[i].name == rule_name : 1962 return i 1963 return -1
1964 1965
1966 - def find_rule(self, rule_name) :
1967 if type(rule_name) is not types.StringType : 1968 raise StandardError, 'LsysProgram::find_rule: illegal argument type' 1969 i = self.find_rule_index(rule_name) 1970 if i < 0 : 1971 raise StandardError, 'LsysProgram::find_rule: no rule "%s" in lsys %s' % (rule_name, self.name) 1972 return self.rules[i]
1973 1974
1975 - def derivation_series(self, nsteps, sampling_period = 1) :
1976 return clib.stringseries(self, nsteps, sampling_period)
1977 1978
1979 -class TranssysInstance(object) :
1980 1981 # the 'magic first line' of transexpr output. If this is not found 1982 # an error is triggered, as a safeguard against nonsense due to 1983 # incompatiblilities between TranssysInstance and the transexpr 1984 # program invoked by the time_series method. 1985 1986 magic = '# transsys expression records 1.0' 1987
1988 - def __init__(self, transsys_program, timestep = None) :
1989 if not isinstance(transsys_program, TranssysProgram) : 1990 raise StandardError, 'TranssysInstance::__init__: unsuitable type of transsys_program (no TranssysProgram)' 1991 self.transsys_program = transsys_program 1992 self.timestep = timestep 1993 self.factor_concentration = [0.0] * self.transsys_program.num_factors() 1994 # FIXME (conceptual issue): 1995 # the stddev and entropy members are optional and they do not pertain 1996 # to an individual instance (obviously). As long as TranssysInstance 1997 # instances are only used for getting levels from transexpr, this is 1998 # not too much of a problem, but eventually, instances and statistical 1999 # results should be handled by separated classes. 2000 self.factor_concentration_stddev = [0.0] * self.transsys_program.num_factors() 2001 self.factor_concentration_entropy = [0.0] * self.transsys_program.num_factors()
2002 2003
2004 - def __str__(self) :
2005 s = 'transsys instance of %s\n' % self.transsys_program.name 2006 s = s + 'timestep: %s\n' % str(self.timestep) 2007 for f in xrange(len(self.factor_concentration)) : 2008 s = s + ' %s: %1.17e\n' % (self.transsys_program.factor_list[f].name, self.factor_concentration[f]) 2009 return s
2010 2011
2012 - def assignmentString(self) :
2013 s = '' 2014 glue = '' 2015 for f in xrange(len(self.factor_concentration)) : 2016 sys.stdout.flush() 2017 s = s + glue + '%s = %g' % (self.transsys_program.factor_list[f].name, self.factor_concentration[f]) 2018 glue = ', ' 2019 return s
2020 2021
2022 - def get_factor_concentration(self, factor) :
2023 """Get the concentration of a named factor. 2024 2025 @param factor: the name of the factor 2026 @type factor: C{String} 2027 @return: the concentration of the factor 2028 @rtype: C{float} 2029 """ 2030 factor_index = self.transsys_program.find_factor_index(factor) 2031 if factor_index == -1 : 2032 raise StandardError, 'factor "%s" not in transsys program "%s"' % (factor, self.transsys_program.name) 2033 return self.factor_concentration[factor_index]
2034 2035
2036 - def set_factor_concentration(self, factor, concentration) :
2037 """Set the concentration of the named factor. 2038 2039 @param factor: the name of the factor 2040 @type factor: C{String} 2041 @param concentration: the concentration of the factor 2042 @type concentration: C{float} 2043 """ 2044 factor_index = self.transsys_program.find_factor_index(factor) 2045 if factor_index == -1 : 2046 raise StandardError, 'factor "%s" not in transsys program "%s"' % (factor, self.transsys_program.name) 2047 self.factor_concentration[factor_index] = concentration
2048 2049
2050 - def clone(self) :
2051 """Clones this transsys instance. 2052 The state (factor concentrations, time step etc.) is copied, but for the 2053 transsys program, the reference is copied, not the program itself. 2054 In this respect, cloning a TranssysInstance differs from using 2055 copy.deepcopy on it.""" 2056 ti = TranssysInstance(self.transsys_program) 2057 ti.timestep = self.timestep 2058 ti.factor_concentration = self.factor_concentration[:] 2059 ti.factor_concentration_stddev = self.factor_concentration_stddev[:] 2060 ti.factor_concentration_entropy = self.factor_concentration_entropy[:] 2061 return ti
2062 2063
2064 - def set_uniform_random(self, rng, c_min, c_max) :
2065 self.factor_concentration = [] 2066 c_range = c_max - c_min 2067 for i in xrange(len(self.transsys_program.factor_list)) : 2068 self.factor_concentration.append(c_min + rng.rnd() * c_range)
2069 2070
2071 - def perturb(self, perturb_func) :
2072 for i in xrange(len(self.transsys_program.factor_list)) : 2073 self.factor_concentration[i] = perturb_func(self.factor_concentration[i], self.transsys_program.factor_list[i].name)
2074 2075
2076 - def perturbed_copy(self, perturb_func) :
2077 pc = TranssysInstance(self.transsys_program) 2078 pc.factor_concentration = copy.deepcopy(self.factor_concentration) 2079 pc.perturb(perturb_func) 2080 return pc
2081 2082
2083 - def squared_difference_sum(self, other) :
2084 """Compute the sum of squared differences in factor concentrations. 2085 2086 The other transsys instance must be of the same program than this 2087 one. 2088 """ 2089 if self.transsys_program is not other.transsys_program : 2090 raise StandardError, 'transsys programs are not identical' 2091 s = 0.0 2092 for i in xrange(len(self.factor_concentration)) : 2093 d = self.factor_concentration[i] - other.factor_concentration[i] 2094 s = s + d * d 2095 return s
2096 2097
2098 - def write_table_line(self, f) :
2099 if self.timestep is None : 2100 f.write('NA') 2101 else : 2102 f.write('%d' % self.timestep) 2103 for c in self.factor_concentration : 2104 f.write(' %1.17e' % c) 2105 f.write('\n')
2106 2107 2108 # FIXME: lsys_lines, lsys_symbol are obsolete 2109 # FIXME: when invoked by a TranssysInstance subclass instance, should return instances of that 2110 # subclass 2111 # FIXME: num_timesteps is a badly named parameter as it really specifies the number of 2112 # instances to be created, not the number of timesteps (number of timesteps is effectively 2113 # num_timesteps - 1
2114 - def time_series(self, num_timesteps, sampling_period = 1, lsys_lines = None, lsys_symbol = None) :
2115 if lsys_lines is not None or lsys_symbol is not None : 2116 raise StandardError, 'lsys_lines and lsys_symbol are no longer supported -- try using time_series_old' 2117 return clib.timeseries(self, num_timesteps, sampling_period)
2118 2119
2120 - def time_series_old(self, num_timesteps, sampling_period = 1, lsys_lines = None, lsys_symbol = None) :
2121 # FIXME: lsys_lines is a kludge that should be removed once lsys parsing 2122 # is available. 2123 cmd = 'transexpr -n %d -d %d' % (num_timesteps, sampling_period) 2124 glue = '' 2125 s = '' 2126 for x in self.factor_concentration : 2127 s = s + '%s%f' % (glue, x) 2128 glue = ' ' 2129 cmd = cmd + ' -F \'%s\'' % s 2130 if lsys_lines is not None : 2131 cmd = cmd + ' -l -t \'%s\'' % self.transsys_program.name 2132 if lsys_symbol is not None : 2133 cmd = cmd + ' -y \'%s\'' % lsys_symbol 2134 # sys.stderr.write('%s\n' % cmd) 2135 p = popen2.Popen3(cmd, 1) 2136 sys.stdout.flush() 2137 sys.stderr.flush() 2138 pid = os.fork() 2139 if pid == 0 : 2140 p.fromchild.close() 2141 p.tochild.write(str(self.transsys_program)) 2142 if lsys_lines is not None : 2143 for l in lsys_lines : 2144 p.tochild.write('%s\n' % l) 2145 #sys.stdout.write(str(self.transsys_program)) 2146 p.tochild.close() 2147 os._exit(os.EX_OK) 2148 p.tochild.close() 2149 tseries = [] 2150 line = p.fromchild.readline() 2151 magic = line.strip() 2152 if magic != self.magic : 2153 sys.stderr.write('bad "magic" first line: got "%s", expected "%s"\n' % (magic, self.magic)) 2154 raise StandardError, 'TranssysInstance.time_series: bad header (incompatible transexpr version?)' 2155 while line : 2156 line = string.strip(line) 2157 if line : 2158 # the second condition is a kludge to allow time_series_old to 2159 # work with output containing a header line 2160 if line[0] != '#' and line[:16] != 'time n.instances' : 2161 l = string.split(line) 2162 if len(l) != 3 * self.transsys_program.num_factors() + 2 : 2163 raise StandardError, 'TranssysInstance.time_series: bad line format: expected %d words, got %d' % (3 * self.transsys_program.num_factors() + 2, len(l)) 2164 t = string.atoi(l[0]) 2165 ti = TranssysInstance(self.transsys_program, t) 2166 for i in xrange(len(self.transsys_program.factor_list)) : 2167 ti.factor_concentration[i] = float(l[3 * i + 2]) 2168 ti.factor_concentration_stddev[i] = float(l[3 * i + 3]) 2169 ti.factor_concentration_stddev[i] = float(l[3 * i + 4]) 2170 tseries.append(ti) 2171 line = p.fromchild.readline() 2172 p.fromchild.close() 2173 status = p.wait() 2174 if status != 0 : 2175 errmsg = p.childerr.readline() 2176 while errmsg : 2177 sys.stderr.write(errmsg) 2178 errmsg = p.childerr.readline() 2179 raise StandardError, 'TranssysInstance::time_series: transexpr exit status %d ("%s")' % (status, errmsg.strip()) 2180 os.wait() 2181 return tseries
2182 2183
2184 -class CollectionStatistics(object) :
2185 """Aggregate statistics computed from a C{TranssysInstanceCollection}. 2186 2187 @ivar transsys_program: the transsys program of the collection 2188 @type transsys_program: C{TranssysProgram} or C{None} 2189 @ivar average: list of average factor concentrations 2190 @type average: C{List} of C{float}s, or C{None} 2191 @ivar standard_deviation: list of standard deviation values of factor concentrations 2192 @type standard_deviation: C{List} of C{float}s, or C{None} 2193 @ivar shannon_entropy: list of Shannon entropy values of factor concentrations 2194 @type shannon_entropy: C{List} of C{float}s, or C{None} 2195 @ivar min_factor_concentration: list of minimal values of factor concentrations 2196 @type min_factor_concentration: C{List} of C{float}s, or C{None} 2197 @ivar max_factor_concentration: list of maximal values of factor concentrations 2198 @type max_factor_concentration: C{List} of C{float}s, or C{None} 2199 """ 2200
2201 - def __init__(self, transsys_program = None) :
2202 self.transsys_program = transsys_program 2203 self.average = None 2204 self.standard_deviation = None 2205 self.shannon_entropy = None 2206 self.min_factor_concentration = None 2207 self.max_factor_concentration = None
2208 2209
2210 - def __str__(self) :
2211 if self.transsys_program is None : 2212 return '# empty statistics instance\n' 2213 s = '# %s\n' % self.transsys_program.name 2214 s = s + 'factor\taverage\tstddev\tentropy\n' 2215 for i in xrange(self.transsys_program.num_factors()) : 2216 s = s + '%s\t%1.17e\t%1.17e\t%1.17e\t%1.17e\t%1.17e\n' % (self.transsys_program.factor_list[i].name, self.average[i], self.standard_deviation[i], self.shannon_entropy[i], self.min_factor_concentration[i], self.max_factor_concentration[i]) 2217 return s
2218 2219 2220 # FIXME: should really have a complete set of accessors, these should be used 2221 # when working with statistics objects rather than accessing lists by index
2222 - def get_average(self, factor_name) :
2223 return self.average(self.transsys_program.find_factor_index(factor_name))
2224 2225
2226 -class TranssysInstanceCollection(object) :
2227 """Abstract base class of collections of transsys instances which 2228 are all instances of the same transsys program. This base 2229 class provides generic functions for computing average 2230 concentrations, standard deviation of concentrations etc. 2231 2232 This class is abstract in the sense that the methods 2233 transsys_instance_list and get_transsys_program are implemented 2234 to raise exceptions. Subclasses must override (i.e. implement) 2235 these methods. In this sense, the methods are abstract. 2236 """ 2237
2238 - def __init__(self) :
2239 pass
2240 2241
2242 - def transsys_instance_list(self) :
2243 """Return a list of all transsys instances in this collection. 2244 2245 Implementing subclasses are allowed to return a list of references 2246 to their transsys instances. Therefore, the instances in a list 2247 obtained by this method should be used for reading only. If modifications 2248 are required, the instances should be cloned. 2249 """ 2250 raise StandardError, 'transsys_instance_list not overridden by subclass'
2251 2252
2253 - def get_factor_expression_list(self, factor) :
2254 """Return a list of expression levels for a factor. 2255 2256 @param factor: the name of the factor, as a string 2257 @type factor: C{String} 2258 @return list of expression levels 2259 @rtype: list of floats 2260 """ 2261 instance_list = self.transsys_instance_list() 2262 expression_list = [] 2263 for i in instance_list : 2264 expression_list.append(i.get_factor_concentration(factor)) 2265 return expression_list
2266 2267
2268 - def write_table_header(self, f) :
2269 """Write a header for a table of records describing the instances in this 2270 collection. 2271 """ 2272 if self.transsys_program is None : 2273 raise StandardError, 'no transsys program, cannot write header' 2274 f.write('timestep') 2275 for factor in self.transsys_program.factor_list : 2276 f.write(' %s' % factor.name) 2277 f.write('\n')
2278 2279
2280 - def write_table(self, f) :
2281 """Write a table of records describing the instances in this collection. 2282 2283 The output format should be suitable for reading by the R function 2284 read.table(file, header = TRUE). 2285 2286 Subclasses can override this method to add more information (e.g. 2287 symbol name, lattice coordinates etc.). In this case, remember to 2288 also override write_table_header accordingly. 2289 """ 2290 self.write_table_header(f) 2291 for ti in self.transsys_instance_list() : 2292 ti.write_table_line(f)
2293 2294
2295 - def get_transsys_program(self) :
2296 """Return the transsys program of which the instances.""" 2297 raise StandardError, 'get_transsys_program not overridden by subclass'
2298 2299
2300 - def statistics(self) :
2301 """Compute an instance of C{CollectionStatistics} from this collection. 2302 2303 If the collection is empty, a C{CollectionStatistics} instance containing 2304 C{None} values for all statistics is produced. 2305 2306 @return: A C{CollectionStatistics} instance or C{None} 2307 @rtype: A C{CollectionStatistics} instance or C{None} 2308 """ 2309 tp = self.get_transsys_program() 2310 if tp is None : 2311 return None 2312 stats = CollectionStatistics(tp) 2313 ti_list = self.transsys_instance_list() 2314 n = tp.num_factors() 2315 fc_sum = [0.0] * n 2316 if len(ti_list) == 0 : 2317 stats.min_factor_concentration = [None] * n 2318 stats.max_factor_concentration = [None] * n 2319 else : 2320 stats.min_factor_concentration = ti_list[0].factor_concentration[:] 2321 stats.max_factor_concentration = ti_list[0].factor_concentration[:] 2322 for ti in ti_list : 2323 for i in xrange(n) : 2324 fc_sum[i] = fc_sum[i] + ti.factor_concentration[i] 2325 if stats.min_factor_concentration[i] > ti.factor_concentration[i] : 2326 stats.min_factor_concentration[i] = ti.factor_concentration[i] 2327 if stats.max_factor_concentration[i] < ti.factor_concentration[i] : 2328 stats.max_factor_concentration[i] = ti.factor_concentration[i] 2329 stats.average = [None] * n 2330 for i in xrange(n) : 2331 stats.average[i] = fc_sum[i] / len(ti_list) 2332 stats.standard_deviation = [0.0] * n 2333 for ti in ti_list : 2334 # iterate over factors by index 2335 for i in xrange(n) : 2336 d = stats.average[i] - ti.factor_concentration[i] 2337 stats.standard_deviation[i] = stats.standard_deviation[i] + d * d 2338 for i in xrange(n) : 2339 stats.standard_deviation[i] = math.sqrt(stats.standard_deviation[i] / (float(len(ti_list)) - 1.0)) 2340 stats.shannon_entropy = [0.0] * n 2341 for ti in ti_list : 2342 if fc_sum[i] > 0.0 : 2343 for i in xrange(n) : 2344 p = ti.factor_concentration[i] / fc_sum[i] 2345 if (p > 0.0) : 2346 stats.shannon_entropy[i] = stats.shannon_entropy[i] - p * math.log(p, 2.0) 2347 return stats
2348 2349
2350 -class SimpleCollection(TranssysInstanceCollection) :
2351 """A very simple, container-like implementation of the abstract 2352 TranssysInstanceCollection base class. 2353 """ 2354
2355 - def __init__(self) :
2356 self.transsys_program = None 2357 self.collection = []
2358 2359
2360 - def __str__(self) :
2361 if self.transsys_program is None : 2362 return 'empty SimpleCollection' 2363 s = 'SimpleCollection of %d instances of "%s":\n' % (len(self.collection), self.transsys_program.name) 2364 for ti in self.collection : 2365 s = s + str(ti) 2366 return s
2367 2368
2369 - def add(self, ti) :
2370 if self.transsys_program is None : 2371 self.transsys_program = ti.transsys_program 2372 self.collection = [ti] 2373 else : 2374 if self.transsys_program is not ti.transsys_program : 2375 raise StandardError, 'members of collection must be instances of the same program' 2376 self.collection.append(ti)
2377 2378
2379 - def get_transsys_program(self) :
2380 return self.transsys_program
2381 2382
2383 - def transsys_instance_list(self) :
2384 return self.collection
2385 2386
2387 -class TimeSeries(TranssysInstanceCollection) :
2388
2389 - def __init__(self, ti, num_timesteps, sampling_period = 1) :
2390 self.transsys_program = ti.transsys_program 2391 self.series = ti.time_series(num_timesteps, sampling_period)
2392 2393
2394 - def get_transsys_program(self) :
2395 return self.transsys_program
2396 2397
2398 - def transsys_instance_list(self) :
2399 return self.series
2400 2401
2402 -class SymbolInstance(object) :
2403
2404 - def __init__(self, symbol, transsys_instance = None, rule = None) :
2405 if not isinstance(symbol, Symbol) : 2406 raise StandardError, 'symbol must be an instance of Symbol' 2407 if symbol.transsys is not None and transsys_instance is None : 2408 transsys_instance = TranssysInstance(symbol.transsys) 2409 if symbol.transsys is not None : 2410 if symbol.transsys is not transsys_instance.transsys_program : 2411 raise StandardError, 'symbol and transsys_instance are not compatible' 2412 self.symbol = symbol 2413 self.transsys_instance = transsys_instance 2414 self.rule = rule
2415 2416
2417 - def __str__(self) :
2418 s = self.symbol.name 2419 if self.transsys_instance is not None : 2420 s = '%s(%s)' % (s, self.transsys_instance.assignmentString()) 2421 if self.rule is None : 2422 s = s + ' [rule: <copy>]' 2423 else : 2424 s = s + ' [rule: %s]' % self.rule.name 2425 return s
2426 2427
2428 -class LsysSymbolString(TranssysInstanceCollection) :
2429
2430 - def __init__(self, lsys, timestep = None, symbol_list = None) :
2431 self.lsys = lsys 2432 self.timestep = timestep 2433 if symbol_list is None : 2434 symbol_list = [] 2435 self.symbol_list = symbol_list
2436 2437
2438 - def __str__(self) :
2439 s = 'string of %s' % self.lsys.name 2440 if self.timestep is not None : 2441 s = s + ', timestep = %d' % self.timestep 2442 s = s + '\n' 2443 for si in self.symbol_list : 2444 s = s + ' %s\n' % str(si) 2445 return s
2446 2447
2448 - def length(self) :
2449 return len(self.symbol_list)
2450 2451
2452 - def transsys_instance_list(self) :
2453 tp = None 2454 ti_list = [] 2455 for sym in symbol_list : 2456 if sym.transsys_instance is not None : 2457 if tp is None : 2458 tp = sym.transsys_instance.transsys_program 2459 else : 2460 if tp is not sym.transsys_instance.transsys_program : 2461 raise StandardError, 'lsys has transsys instances of multiple transsys programs' 2462 ti_list.append(sym.transsys_instance) 2463 return ti_list
2464 2465
2466 -class DotParameters(object) :
2467
2468 - def __init__(self) :
2469 self.display_genes = 1 2470 self.display_factors = 1 2471 self.activate_arrowhead = 'normal' 2472 self.repress_arrowhead = 'tee'
2473 2474 2475
2476 -class CyclicSequence(object) :
2477 """A convenience class for use with RandomTranssysParameters. Implements an 2478 object from which numerical values can be pulled out indefinitely using the 2479 nextval() method. Values are taken sequentially from a list, repeating from 2480 the start when the end is reached. 2481 2482 One could subclass from this class in order to design other value 2483 generators. But then, this might be of limited use, considering that 2484 all methods will have to be overridden anyway.""" 2485
2486 - def __init__(self, l, start = None) :
2487 if len(l) == 0 : 2488 raise StandardError, 'CyclicSequence::__init__: cannot init with empty list' 2489 self.l = copy.deepcopy(l) 2490 if start is None : 2491 self.i = len(self.l) - 1 2492 else : 2493 self.i = start % len(self.l)
2494 2495
2496 - def __str__(self) :
2497 if len(self.l) == 1 : 2498 return str(self.l[0]) 2499 else : 2500 return str(self.l)
2501 2502
2503 - def from_string(self, s) :
2504 # fixme (?) this implementation allows a trailing comma 2505 # ... but then, python does this too in several contexts... 2506 quoted_string_re = re.compile(' *\'([^\']+)\'( *, *)?') 2507 string_re = re.compile(' *([^,]*)(, *)?') 2508 s = s.strip() 2509 l = [] 2510 while s : 2511 m = quoted_string_re.match(s) 2512 if m is None : 2513 m = string_re.match(s) 2514 if m is None : 2515 raise StandardError, 'CyclicSequence::from_string: malformed string "%s"' % s 2516 l.append(m.group(1)) 2517 s = s[len(m.group(0)):] 2518 self.i = len(l) - 1 2519 self.l = l
2520 2521
2522 - def currval(self) :
2523 return self.l[self.i]
2524 2525
2526 - def nextval(self) :
2527 self.i = (self.i + 1) % len(self.l) 2528 return self.l[self.i]
2529 2530
2531 - def reset(self) :
2532 self.i = len(self.l) - 1
2533 2534
2535 -class RandomTranssysParameters(object) :
2536 """A factory for generating "random" transsys programs. 2537 The name "RandomTranssysParameters" really is a historical accident, 2538 this class started out as a dumb class with just a bunch of member 2539 variables for conveniently storing an ever growing bunch of parameters 2540 for random program generation. But finally, the implementation of 2541 classes for the transsys program components has permitted writing a 2542 reasonable generate_program() method. 2543 2544 Usage of this class: Instantiate with a random seed. 2545 Set the member variables by direct assignment as you 2546 see fit. Finally, call generate_program() to pull out endless 2547 variations of transsys programs...""" 2548 2549 savefile_magic = 'RandomTranssysParameters-1.1' 2550
2551 - def __init__(self, rndseed = 1) :
2552 self.set_seed(rndseed) 2553 self.serial = 0 2554 self.topology = None 2555 self.constitutive = CyclicSequence([0.0]) 2556 self.km_activation = CyclicSequence([0.0]) 2557 self.km_repression = CyclicSequence([0.0]) 2558 self.vmax_activation = CyclicSequence([0.0]) 2559 self.vmax_repression = CyclicSequence([0.0]) 2560 self.decay = CyclicSequence([0.0]) 2561 self.diffusibility = CyclicSequence([0.0])
2562 2563
2564 - def __str__(self) :
2565 """display transsys program generation parameters in a string, in a 2566 format that can later on be loaded into a RandomTranssysParameter instance 2567 using the parse() method. 2568 2569 Important note: The state of the RandomTranssysParameters instance is 2570 not completely represented; the RNG state as well as the current value positions 2571 in the CyclicSequence instances are lost. Reproducible transsys generation 2572 after parsing a saved file should work if __str__() is used before generating 2573 any programs, and if no fancy tricks with CyclicSequence instances are 2574 played.""" 2575 s = 'topology: %s\n' % self.topology 2576 if self.topology == 'random_nk' : 2577 s = s + 'n: %d\n' % self.n 2578 s = s + 'k: %d\n' % self.k 2579 elif self.topology == 'random_uniform' : 2580 s = s + 'n: %d\n' % self.n 2581 s = s + 'num_edges: %d\n' % self.num_edges 2582 elif self.topology == 'random_powerlaw' : 2583 s = s + 'n: %d\n' % self.n 2584 s = s + 'num_edges: %d\n' % self.num_edges 2585 s = s + 'power_exp: %g\n' % self.power_exp 2586 s = s + 'power_base: %g\n' % self.power_base 2587 elif self.topology == 'linklist' : 2588 for in_list in self.linklist : 2589 s = s + 'in_list: %s\n' % str(in_list) 2590 else : 2591 raise StandardError, 'RandomTranssysParameters::write: unknown topology type "%s"' % self.topology 2592 s = s + 'topology: end\n' 2593 s = s + 'constitutive: %s\n' % str(self.constitutive) 2594 s = s + 'km_activation: %s\n' % str(self.km_activation) 2595 s = s + 'km_repression: %s\n' % str(self.km_repression) 2596 s = s + 'vmax_activation: %s\n' % str(self.vmax_activation) 2597 s = s + 'vmax_repression: %s\n' % str(self.vmax_repression) 2598 s = s + 'decay: %s\n' % str(self.decay) 2599 s = s + 'diffusibility: %s\n' % str(self.diffusibility) 2600 s = s + 'rndseed: %d\n' % self.rndseed 2601 return s
2602 2603
2604 - def write(self, f) :
2605 """write the transsys program generation parameters in file f, in a 2606 format that can later on be loaded into a RandomTranssysParameter instance 2607 using the parse() method. 2608 2609 Important note: The state of the RandomTranssysParameters instance is 2610 not completely saved; the RNG state as well as the current value positions 2611 in the CyclicSequence instances are lost. Reproducible transsys generation 2612 after parsing a saved file should work if write() is used before generating 2613 any programs, and if no fancy tricks with CyclicSequence instances are 2614 played.""" 2615 f.write('%s\n' % self.savefile_magic) 2616 f.write(str(self)) 2617 f.write('\n')
2618 2619
2620 - def parse(self, f) :
2621 """set parameter members by parsing from file f. This should work with files 2622 generated by the write() method, but of course, files can also be manually written. 2623 2624 Notes on the format: The format is of the simple <identifier>: <value> type. 2625 All parameters must be specified in the order in which they are written by the 2626 write() method. Permuting this order was deliberately not permitted because 2627 that would make it more easy to omit parameters, and more difficult to check 2628 against this. Incomplete specifications are considered dangerous because 2629 unspecified parameters may end up in unclear defaults or even undefined states, 2630 so it's best to require explicit specification of all parameters.""" 2631 2632 def parse_cyclicseq(f, label) : 2633 r = '%s\\s*:\\s*(.*)' % label 2634 line = f.readline() 2635 m = re.match(r, line.strip()) 2636 if m is None : 2637 raise StandardError, 'RandomTranssysParameters::parse: failed to obtain CyclicSequence "%s"' % (label, line.strip()) 2638 c = CyclicSequence([0.0]) 2639 c.from_string(m.group(1)) 2640 return c
2641 2642 2643 line = f.readline() 2644 if string.strip(line) != self.savefile_magic : 2645 raise StandardError, 'RandomTranssysParameters::parse: bad magic "%s"' % string.strip(line) 2646 2647 line = f.readline() 2648 m = re.match('topology\\s*:\\s*([A-Za-z_]+)', line) 2649 if m is None : 2650 raise StandardError, 'RandomTranssysParameters::parse: failed to obtain topology' 2651 # print 'topology type: "%s"' % m.group(1) 2652 self.topology = m.group(1) 2653 if self.topology == 'random_nk' : 2654 self.n = utils.parse_int(f, 'n') 2655 self.k = utils.parse_int(f, 'k') 2656 elif self.topology == 'random_uniform' : 2657 self.n = utils.parse_int(f, 'n') 2658 self.num_edges = utils.parse_int(f, 'num_edges') 2659 elif self.topology == 'random_powerlaw' : 2660 self.n = utils.parse_int(f, 'n') 2661 self.num_edges = utils.parse_int(f, 'num_edges') 2662 self.power_exp = utils.parse_float(f, 'power_exp') 2663 self.power_base = utils.parse_float(f, 'power_base') 2664 elif self.topology == 'linklist' : 2665 self.topology = 'linklist' 2666 in_list_re = re.compile('in_list\\s*:\\s*\\[([-0-9,\\s]*)\\]') 2667 csvsplit_re = re.compile('\\s*,\\s*') 2668 linklist = [] 2669 line = f.readline() 2670 m = in_list_re.match(line) 2671 while m : 2672 l = csvsplit_re.split(m.group(1)) 2673 linklist.append([]) 2674 for x in l : 2675 if len(x) > 0 : 2676 linklist[-1].append(int(x)) 2677 line = f.readline() 2678 m = in_list_re.match(line) 2679 # print 'parsed topology linklist:', str(linklist) 2680 self.topology_linklist = linklist 2681 else : 2682 raise StandardError, 'RandomTranssysParameters::parse: unknown topology type %s' % self.topology 2683 line = f.readline() 2684 m = re.match('topology\\s*:\\s*end', line.strip()) 2685 if m is None : 2686 raise StandardError, 'RandomTranssysParameters::parse: topology improperly terminated by "%s"' % line.strip() 2687 self.constitutive = parse_cyclicseq(f, 'constitutive') 2688 self.km_activation = parse_cyclicseq(f, 'km_activation') 2689 self.km_repression = parse_cyclicseq(f, 'km_repression') 2690 self.vmax_activation = parse_cyclicseq(f, 'vmax_activation') 2691 self.vmax_repression = parse_cyclicseq(f, 'vmax_repression') 2692 self.decay = parse_cyclicseq(f, 'decay') 2693 self.diffusibility = parse_cyclicseq(f, 'diffusibility') 2694 rndseed = utils.parse_int(f, 'rndseed') 2695 self.set_seed(rndseed) 2696 line = f.readline() 2697 if line.strip() != '' : 2698 raise StandardError, 'RandomTranssysParameters::parse: trailing garbage line "%s"' % line.strip()
2699 2700
2701 - def set_seed(self, rndseed = 1) :
2702 self.rndseed = rndseed 2703 self.rng = random.Random(rndseed)
2704 2705
2706 - def get_seed(self) :
2707 return self.rndseed
2708 2709
2710 - def set_constitutive(self, v) :
2711 if type(v) is types.ListType : 2712 self.constitutive = CyclicSequence(v) 2713 else : 2714 self.constitutive = CyclicSequence([v])
2715 2716
2717 - def set_km_activation(self, v) :
2718 if type(v) is types.ListType : 2719 self.km_activation = CyclicSequence(v) 2720 else : 2721 self.km_activation = CyclicSequence([v])
2722 2723
2724 - def set_km_repression(self, v) :
2725 if type(v) is types.ListType : 2726 self.km_repression = CyclicSequence(v) 2727 else : 2728 self.km_repression = CyclicSequence([v])
2729 2730
2731 - def set_vmax_activation(self, v) :
2732 if type(v) is types.ListType : 2733 self.vmax_activation = CyclicSequence(v) 2734 else : 2735 self.vmax_activation = CyclicSequence([v])
2736 2737
2738 - def set_vmax_repression(self, v) :
2739 if type(v) is types.ListType : 2740 self.vmax_repression = CyclicSequence(v) 2741 else : 2742 self.vmax_repression = CyclicSequence([v])
2743 2744
2745 - def set_decay(self, v) :
2746 if type(v) is types.ListType : 2747 self.decay = CyclicSequence(v) 2748 else : 2749 self.decay = CyclicSequence([v])
2750 2751
2752 - def set_diffusibility(self, v) :
2753 if type(v) is types.ListType : 2754 self.diffusibility = CyclicSequence(v) 2755 else : 2756 self.diffusibility = CyclicSequence([v])
2757 2758 2764 2765
2766 - def num_genes(self) :
2767 if self.topology == 'random_nk' or self.topology == 'random_uniform' or self.topology == 'random_powerlaw' : 2768 return self.n 2769 elif self.topology == 'linklist' : 2770 return len(self.linklist) 2771 else : 2772 raise StandardError, 'RandomTranssysParameters::num_genes: unknown topology type "%s"' % self.topology
2773 2774 2787 2788
2789 - def write_parameter_comments(self, f) :
2790 for s in str(self).split('\n') : 2791 f.write('// %s\n' % s)
2792 2793
2794 - def generate_transsys(self, name) :
2795 """Generate a random transsys program. A large variety of parameters controlling 2796 the "random" generation of the transsys program can be set in the 2797 RandomTranssysParameters instance rtp passed as the third argument to this 2798 function.""" 2799 2800 def factor_name(i) : 2801 return 'f%04d' % i
2802 2803 def gene_name(i) : 2804 return 'g%04d' % i 2805 2806 2807 def random_nk_linklist(n, k, rng) : 2808 if rng is None : 2809 raise StandardError, 'RandomTranssysParameters::generate_transsys: cannot generate random NK linklist without RNG' 2810 linklist = [] 2811 for i in xrange(n) : 2812 linklist.append([]) 2813 in_list = range(n) 2814 for j in xrange(k) : 2815 x = rng.randrange(len(in_list)) 2816 t = in_list[x] 2817 del in_list[x] 2818 if rng.random() < 0.5 : 2819 linklist[i].append(-t -1) 2820 else : 2821 linklist[i].append(t) 2822 return linklist 2823 2824 def random_powerlaw_linklist(num_genes, num_edges, power_exp, power_base, rng) : 2825 2826 linklist = [] 2827 rw = [] 2828 for i in xrange(1, num_genes + 1) : 2829 linklist.append([]) 2830 # WATCHME: can this still result in a repairable overflow?? 2831 x = (power_base * i)**power_exp 2832 rw.append(x) 2833 # print 'rw', rw 2834 rng.shuffle(rw) 2835 # print 'rw (shuffled)', rw 2836 rw_sum = sum(rw) 2837 # last element is left out so last interval will be 2838 # open-ended, including 1.0 (to avoid possible floating 2839 # point imprecision issues). 2840 rw = map(lambda x : x / rw_sum, rw[:-1]) 2841 # print 'rw (normalised to [0, 1[)', rw 2842 rw_borders = utils.interval_list(rw) 2843 # print 'rw_borders', rw_borders 2844 for i in xrange(num_edges) : 2845 # print 'edge #%d' % i 2846 g0 = utils.find_interval_index(rng.random(), rw_borders) 2847 g1 = utils.find_interval_index(rng.random(), rw_borders) 2848 # FIXME: this loop may run very often or even infinitely often when 2849 # generating dense graphs 2850 while g1 in linklist[g0] or -g1 - 1 in linklist[g0] : 2851 g0 = utils.find_interval_index(rng.random(), rw_borders) 2852 g1 = utils.find_interval_index(rng.random(), rw_borders) 2853 if rng.random() < 0.5 : 2854 linklist[g0].append(-g1 - 1) 2855 else : 2856 linklist[g0].append(g1) 2857 # print linklist 2858 return linklist 2859 2860 def random_uniform_linklist(num_genes, num_edges, rng) : 2861 """generate a link list by selecting from all possible edges with 2862 uniform probability. 2863 Notices: This function does not generate any links of a node to itself. 2864 This function does not create any multilinks.""" 2865 all_links = [] 2866 for i in xrange(num_genes) : 2867 for j in xrange(num_genes) : 2868 if i != j : 2869 all_links.append((i, j)) 2870 if len(all_links) < num_edges : 2871 raise StandardError, 'number of edges %d too large: max %d for %d nodes' % (num_edges, len(all_links), num_genes) 2872 linklist = [] 2873 for i in xrange(num_genes) : 2874 linklist.append([]) 2875 for i in xrange(num_edges) : 2876 r = rng.randrange(len(all_links)) 2877 g0, g1 = all_links[r] 2878 del all_links[r] 2879 if rng.random() < 0.5 : 2880 linklist[g0].append(-g1 - 1) 2881 else : 2882 linklist[g0].append(g1) 2883 return linklist 2884 2885 def next_expression(s) : 2886 p = TranssysProgramParser(StringIO.StringIO(s.nextval())) 2887 return p.parse_expr([]) 2888 2889 if self.topology == 'random_nk' : 2890 linklist = random_nk_linklist(self.n, self.k, self.rng) 2891 elif self.topology == 'random_uniform' : 2892 linklist = random_uniform_linklist(self.n, self.num_edges, self.rng) 2893 elif self.topology == 'random_powerlaw' : 2894 linklist = random_powerlaw_linklist(self.n, self.num_edges, self.power_exp, self.power_base, self.rng) 2895 elif self.topology == 'linklist' : 2896 linklist = self.linklist 2897 flist = [] 2898 glist = [] 2899 for i in xrange(self.num_genes()) : 2900 flist.append(Factor(factor_name(i), next_expression(self.decay), next_expression(self.diffusibility))) 2901 promoter = [] 2902 promoter.append(PromoterElementConstitutive(next_expression(self.constitutive))) 2903 for t in linklist[i] : 2904 if t < 0 : 2905 promoter.append(PromoterElementRepress(next_expression(self.km_repression), next_expression(self.vmax_repression), [factor_name(abs(t) - 1)])) 2906 else : 2907 promoter.append(PromoterElementActivate(next_expression(self.km_activation), next_expression(self.vmax_activation), [factor_name(t)])) 2908 glist.append(Gene(gene_name(i), factor_name(i), promoter)) 2909 tp =