# Copyright (c) 1996, 1997, 1998 The Regents of the University of California. # All rights reserved. See legal notices for full text and disclaimer. """ Conditions that are possibly time-dependent Conditions available in this file are: OneTime(time) #True when the time is reached. Cycles(start_cycle, stop_cycle=ForeverCycle, stride = 1) # True every so many cycles Times(start_time, stop_time=ForeverTime, stride = 1.0) # True every so many "seconds" And (Condition1, Condition2) #True if both are true Or (Condition1, Condition2) #True if one of the conditions is true Not (Condition1) #True if the condition is not true When ("expression to be evaluated", context) # True if expression evaluates true The context can be (a) a dictionary, (b) a string naming a module, or (c) a module. In (b) and (c) the modules' __dict__ is used. A condition can be tested at a given cycle/time via this API: c.evaluate (cycle, time) if c.state: ...condition was true... if c.state_final: ...condition intended for use as "last" sample To define a new kind of Condition, inherit from Condition and define a method _value (self, cycle, time) which evaluates the condition at that time and returns a tuple-pair of logical values. The first should be the value of the condition, true or false, at the current time. The second should be true or false under assuming this is the "last" timestep. You can assume that _value (resp. _value_last) is called only once for a given cycle number, and that these calls are in increasing order for both cycle and time. Your __init__ routine must call Condition.initialize (self) It is recommended that you also redefine __repr__ and __str__, and name any routine which resets the condition "set". """ import sys import types import contexts # times and cycles for "never stopping" ForeverCycle = 1000000 ForeverTime = 1.0 * ForeverCycle # time and cycle that are smaller than any time and cycle NeverCycle = - 1000000 NeverTime = - 1.0e30 class Condition: "Root of the family of conditions" def __init__ (self): self.initialize () def initialize (self): self.evaluation_cycle = NeverCycle # cycle at last evaluation self.evaluation_time = NeverTime # time at last evaluation self.state = 0 self.state_final = 0 self.state_final_enabled = 1 def evaluate (self, cycle, time): "Calculate state at given time." if cycle > self.evaluation_cycle: self.state, self.state_final = self._value (cycle, time) self.state_final = self.state_final and self.state_final_enabled self.evaluation_cycle = cycle self.evaluation_time = time # due to roundoff, might not be strictly monotonic def _value (self, cycle, time): return (1, 1) def __add__ (self, other): "Return logical and of self and other." return And(self,other) def report (self): "String representation of internal state." result = `self` + '\n' result = result + "\tEvaluation cycle: " + `self.evaluation_cycle` + '\n' result = result + "\tEvaluation time: " + `self.evaluation_time` + '\n' result = result + "\tState: " + `self.state` + '\n' result = result + "\tState (final): " + `self.state_final` + '\n' result = result + "\tFinal state enabled: " + `self.state_final_enabled` + '\n' return result def __repr__ (self): return "Condition ()" __str__ = __repr__ EveryCycle = Condition() class TimeList (Condition): "A condition that is true at a list of times." def __init__ (self, when): Condition.initialize (self) self.set (when) def set (self, when): self.timelist = list(when) self.timelist.sort () self.cursor = 0 def _value (self, cycle, time): try: c = self.timelist[self.cursor] except IndexError: return (0, 0) t = (self.evaluation_time < c) and (c <= time) if t: self._advance (time, self.timelist) return (t, 1) def _advance (self, t, tlist): c = tlist[self.cursor] while c <=t: self.cursor = self.cursor + 1 try: c = tlist[self.cursor] except IndexError: return def __repr__ (self): return "TimeList: " + `self.timelist` __str__ = __repr__ class CycleList (Condition): "A condition that is true at a list of cycles." def __init__ (self, when): Condition.initialize (self) self.set (when) def set (self, when): self.cyclelist = list(when) self.cyclelist.sort () self.cursor = 0 def _value (self, cycle, time): try: c = self.cyclelist[self.cursor] except IndexError: return (0, 0) t = (self.evaluation_cycle < c) and (c <= cycle) if t: self._advance (cycle, self.cyclelist) return (t, 1) def _advance (self, t, tlist): c = tlist[self.cursor] while c <=t: self.cursor = self.cursor + 1 try: c = tlist[self.cursor] except IndexError: return def __repr__ (self): return "Cyclelist: " + `self.cyclelist` __str__ = __repr__ class Cycles (Condition): "Condition on cycle number of the form start stop stride." def __init__ (self, start=0, stop=ForeverCycle, stride=1): Condition.initialize (self) self.set (start, stop, stride) def set (self, start, stop, stride): "Set the condition to start:stop:stride" if (stop >= start) and (stride > 0): self.start = start self.stop = stop self.stride = stride else: raise ValueError, "Cycles specification illegal." def _value (self, cycle, time): t = (cycle <= self.stop) and (cycle >= self.start) if t: if (cycle - self.start) % self.stride == 0: return (1, 1) else: return (0, 1) else: return (0, 0) def __repr__ (self): s = "Cycles (" + `self.start` + ", " + `self.stop` if self.stride != 1: s = s + ", " + `self.stride` s = s + ')' return s __str__ = __repr__ class Times (Condition): "Condition on time of the form start stop stride" def __init__ (self, start=0.0, stop=ForeverTime, stride=1.0): Condition.initialize (self) self.set (start, stop, stride) def set (self, start, stop, stride): "Set the condition to start:stop:stride" if (stop >= start) and (stride > 0.0): self.start = float(start) self.stop = float(stop) self.stride = float(stride) self.next_picket = start self.picket_number = 0 else: raise ValueError, "TimeIntervalCondition specification illegal." def _value (self, cycle, time): t = (time >= self.start) and (time <= self.stop) if t: if(time >= self.next_picket): start = self.start stride = self.stride picket_number = self.picket_number + 1 next_picket = start + picket_number * stride while next_picket <= time: picket_number = picket_number + 1 next_picket = start + picket_number * stride self.next_picket = next_picket self.picket_number = picket_number return (1, 1) else: return (0, 1) else: return (0, 0) def __repr__ (self): s = "Times (" + `self.start` + ", " + `self.stop` if self.stride != 1.0: s = s + ", " + `self.stride` s = s + ')' return s __str__ = __repr__ class And (Condition): "Logical and of two conditions" def __init__ (self, c1, c2): Condition.initialize (self) self.set (c1, c2) def set (self, c1, c2): "Set the condition to be true if c1 and c2 are true." self.c1 = c1 self.c2 = c2 def _value (self, cycle, time): "Are both the conditions true?" self.c1.evaluate (cycle, time) self.c2.evaluate (cycle, time) s1a = self.c1.state s1b = self.c1.state_final s2a = self.c2.state s2b = self.c2.state_final return (s1a and s2a, s1b and s2b) def __repr__ (self): return "And (" + `self.c1` + ", " + `self.c2` + ")" __str__ = __repr__ class Or (Condition): "Logical or of two conditions" def __init__ (self, c1, c2): Condition.initialize (self) self.set (c1, c2) def set (self, c1, c2): "Set the condition to be true if c1 or c2 (or both) are true." self.c1 = c1 self.c2 = c2 def _value (self, cycle, time): "Are one or both conditions true?" self.c1.evaluate (cycle, time) self.c2.evaluate (cycle, time) s1a = self.c1.state s1b = self.c1.state_final s2a = self.c2.state s2b = self.c2.state_final return (s1a or s2a, s1b or s2b) def __repr__ (self): return "Or (" + `self.c1` + ", " + `self.c2` + ")" __str__ = __repr__ class Not (Condition): "Logical negation of a condition" def __init__ (self, c1): Condition.initialize (self) self.set (c1) def set (self, c1): "Set the condition to be true iff c1 is false." self.c1 = c1 def _value (self, cycle, time): "Is the target conditon false?" self.c1.evaluate (cycle, time) return (not self.c1.state, not self.c1.state_final) def __repr__ (self): return "Not (" + `self.c1` + ")" __str__ = __repr__ class When (Condition): "A logical condition, and the context dictionary in which to evaluate it." def __init__ (self, item, context = "__main__"): Condition.initialize (self) self.set (item, context) def set (self, item, context = "__main__"): "Set the condition and its context." if type(item) == types.StringType: self.item = item else: raise TypeError, (types.StringType, type(item)) self.context = contexts.resolve_context (context) def _value (self, cycle, time): "Is this true at the time given by the clock?" t = eval(self.item, self.context) return (t, t) def __repr__ (self): return "When (" + self.item + ")" __str__ = __repr__ if __name__ == "__main__": z = open("history_condition_out.txt", "w") import sys sys.stdout = z b = Cycles (2, 10, 4) c = Times (.3, 1.0, .3) ll = When ("xx > .3") t1 = TimeList ([.4, .7, .9]) t2 = TimeList ([.4, .8, 1.5]) t3 = CycleList ([5, 6, 8]) # a = And(ll, c) a = ll + c e = Or(ll, b) d = Not(ll) for i in range(12): cycle = i time = i / 10. xx = time / 2.0 print cycle, time, xx for x in (b,c,ll,a,e,d, t1, t2,t3): x.evaluate (cycle, time) print "\t", (x.state, x.state_final), x for x in (b,c,ll,a,e,d,t1,t2,t3): print x.report() raise SystemExit