1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
import time, types, itertools, os.path
from scipy.interpolate import interp1d
from scipy.integrate import odeint
from scipy.optimize import fmin
from collections import OrderedDict
class DiffEq(object):
"""designed to make numerically solving diff eqs more readable
setattr and getattr have been modified to provide the following effects:
>>> self._foo=2.#setting an _under var makes it still returned by...
>>> self.foo
2.0
>>> self._foo=2 #but only if it's a float
>>> self.foo
AttributeError: self has no attribute 'foo'
>>> # Now suppose _foo is a class method and bar is in _flags.
>>> self._foo = lambda self: self.bar
>>> self.flags.append('bar')
>>> self.bar = 3.14
>>> self.foo #finding the object having not found it before:
#self._foo() is called and stored to self.__foo
3.14 #self.__foo is returned
>>> self.foo #finding the object having asked for it before:
3.14 #self.__foo is returned directly
>>> self.bar=2 #setting bar resets all self.__foos
>>> self.foo #self._foo() is called again, stored to self.__foo
2 #the new self.__foo is returned
Note that with this behavior you should treat all variable names, be they
normal, _under, or __dunder, as in the same namespace. Don't even try to
differentiate variable names by underscores.
The benefit of this system is that every normal float will be optimized,
while every _under float will be ignored completely, and flagging a var
with _under will not change the behavior of any functions using it.
Additionally, if you suddenly realize that foo should be dependent on
bar and baz, you simply define:
def _foo(self):
return do_stuff(self.bar, self.baz)
and bar and baz will be optimized while foo will be ignored -- and no
function code using foo needs to be rewritten.
"""
def __init__(self):
self._time = time.time()
# All floats lacking an initial _underscore will be optimized.
self.opt_vars = OrderedDict()
for key, value in vars(self).items():
if key[0] == "_": continue
if type(value) != float: continue
self.opt_vars[key] = value
def gettime(self): return time.time() - self.time
def __getattribute__(self, attr):
"""Provides a few getattr psuedonyms:
self.foo tries to return:
self.foo if foo exists
self._foo if _foo is a float
self._foo() if _foo is a method
see DiffEq's documentation for examples
"""
sgetattr = super(DiffEq, self).__getattribute__
try: return sgetattr(attr)
except AttributeError as err:
if attr[0] == "_": raise err
value = sgetattr("_" + attr)
if type(value) == types.MethodType:
try: return sgetattr("__" + attr)
except AttributeError:
value = value()
setattr(self, "__" + attr, value)
return value
if type(value) == float: return value
raise err
_flags = []
def __setattribute__(self, attr):
"""Clears dunder updates when a flag variable is changed."""
sgetattr = super(DiffEq, self).__getattribute__
ssetattr = super(DiffEq, self).__setattribute__
if attr in self.flags:
for key, value in vars(self).items():
if key[:2] != "__": continue
if type(sgetattr(key[2:])) != types.MethodType: continue
vars(self).remove(key)
ssetattr(attr)
def solve_diff_eq(self):
"""wrapper for odeint and self.diff_eq
requires the following:
self.diff_eq
self.init_vars
self.timespace
"""
time0 = self.gettime()
self.time = numpy.linspace(*self.timespace)
self.soln = odeint(self.diff_eq, self.init_vars, self.time)
print " :: took %s seconds" % (self.gettime() - time0)
def opt_init(self, guesses=None):
if guesses == None:
for var in self.opt_vars:
self.opt_vars[var] = getattr(self, var)
else:
for var, guess in itertools.izip(self.opt_vars, guesses):
setattr(self, var, guess)
#_outfile = tempfile.mktemp(dir='data', prefix=str(self.gettime()))
outfile = lambda: os.path.join('data', str(self.gettime()))
def opt_fun(self, guesses, f, func, init_vars):
"""Optimize the free variables for the diff eq."""
self.opt_init()
map(setattr, itertools.repeat(self), self.opt_vars.iterkeys(), guesses)
self.__dict__.update(dict(zip(self.opt_vars.iterkeys(), guesses)))
outfile = self.__dict__.get('outfile')
time, soln = self.solve_diff_eq()
phi, phi1, v_tan, tension, moment, momentum, max_arg = \
interpret(soln)
phi, phi1, v_tan, tension, moment, momentum, time = \
map(lambda x: numpy.ndarray.__getslice__(x, 0, max_arg+1),
[phi, phi1, v_tan, tension, moment, momentum, time])
time, (phi, phi1, v_tan, tension, moment, momentum, max_arg) = \
solver(func, init_vars, returns=['time', 'slices'])
# Parameter values.
f.write("%s, " % r_roll)
f.write("%s, " % length)
f.write("%s, " % r0)
f.write("%s, " % m)
f.write("%s, " % Mass)
# Values at the max velocity point.
f.write("%s, " % phi[-1])
f.write("%s, " % phi1[-1])
f.write("%s, " % tension[-1])
f.write("%s\n" % v_tan[-1])
time, soln = self.solve_func(
self.interpret()
return self.optimize_value()
|