1
2
3
4
5
6 from numpy import mat, c_, r_, multiply, where, sqrt, newaxis
7 from numpy.linalg import solve
8 from numpy.matlib import diag
9
11
12 Aout = A2.copy(); Bout = B2.copy(); Qout = Q.copy(); Zout = Z.copy()
13 ix = i-1
14
15 a = mat(A2[ix, ix]); d = mat(B2[ix, ix]); b = mat(A2[ix, ix+1]);
16 e = mat(B2[ix, ix+1]); c = mat(A2[ix+1, ix+1]); f = mat(B2[ix+1, ix+1])
17 wz = c_[c*e - f*b, (c*d - f*a).H]
18 xy = c_[(b*d - e*a).H, (c*d - f*a).H]
19 n = sqrt(wz*wz.H)
20 m = sqrt(xy*xy.H)
21 if n[0,0] == 0: return (Aout, Bout, Qout, Zout)
22 wz = solve(n, wz)
23 xy = solve(m, xy)
24 wz = r_[ wz, \
25 c_[-wz[:,1].H, wz[:,0].H]]
26 xy = r_[ xy, \
27 c_[-xy[:,1].H, xy[:,0].H]]
28 Aout[ix:ix+2, :] = xy * Aout[ix:ix+2, :]
29 Bout[ix:ix+2, :] = xy * Bout[ix:ix+2, :]
30 Aout[:, ix:ix+2] = Aout[:, ix:ix+2] * wz
31 Bout[:, ix:ix+2] = Bout[:, ix:ix+2] * wz
32 Zout[:, ix:ix+2] = Zout[:, ix:ix+2] * wz
33 Qout[ix:ix+2, :] = xy * Qout[ix:ix+2, :]
34 return (Aout, Bout, Qout, Zout)
35
36 -def qzdiv(stake, A2, B2, Q, Z):
37 Aout = A2.copy(); Bout = B2.copy(); Qout = Q.copy(); Zout = Z.copy()
38 n, jnk = A2.shape
39
40 root = mat(abs(c_[diag(A2)[:,newaxis], diag(B2)[:,newaxis]]))
41 root[:,1] /= where(root[:,0]<1e-13, -root[:,1], root[:,0])
42 for i in range(1,n+1)[::-1]:
43 m = None
44 for j in range(1,i+1)[::-1]:
45
46
47
48 if root[j-1,1] > stake or root[j-1,1] < -0.1:
49 m = j
50 break
51 if m == None: return (Aout, Bout, Qout, Zout)
52 for k in range(m,i):
53 (Aout, Bout, Qout, Zout) = qzswitch(k, Aout, Bout, Qout, Zout)
54 root[k-1:k+1, 1] = root[k-1:k+1, 1][::-1]
55 return (Aout, Bout, Qout, Zout)
56
57 import numpy as n
58 from subprocess import Popen, PIPE
60 '''
61 Lets octave functions calculate things, collects results as numpy-matrices.
62
63 Example usage qz decomposition with octave syntax
64 [AA,BB,Q,Z,V,W,lambda] = qz(A,B):
65
66 1) "session approach"
67 myoct = octave4numpy()
68 myoct.definemats(['A', 'B'], [a, b]) # a and b: numpy arrays/matrices
69 (AA,BB,Q,Z,V,W,lda) = myoct.execfunc('qz', ['A', 'B'], 7)
70 # (7 is the number of returned objects, must be specified here in advance!)
71 # (possibly execute other funcs after this)
72 myoct.close()
73
74 2) or the "shortcut approach", quick way for one-time use:
75 myoct = octave4numpy('qz', (a, b), 7)
76 (AA,BB,Q,Z,V,W,lda) = myoct.results
77 # (connection to octave is automatically closed in this variant)
78
79 If something else than 'octave' is needed to invoke your octave version,
80 specify the command string in optional keyword arg cmd, like so:
81 myoct = octave4numpy(cmd = 'octave2.0')
82
83 The user should not pass 1d-numpy-arrays; be explicit about row or col!
84
85 to do:
86 - test on windows
87 - allow to set precision
88 - test if it also works with complex numbers (it should)
89 ...
90 '''
91 - def __init__(self, func = None, args = None, numout = 1, cmd = 'octave'):
92 '''
93 opens the octave connection via pipes (is this really cross-platform?)
94
95 optionally already executes a function for quick use, func is the name
96 of an octave function; then assignments must match the number of return
97 objects from that specific octave function
98 '''
99 self.o = Popen([cmd, '-q'], stdin = PIPE, stdout = PIPE)
100 if type(func) == type('f'):
101 assert args != None
102 if type(args) == type([]): args = tuple(args)
103 elif type(args) != type((1,)):
104 args = (args,)
105
106 argnamelist = ['a' + str(ix) for ix in range(len(args))]
107 self.definemats(argnamelist, args)
108 self.results = self.execfunc(func, argnamelist, numout)
109 self.octreturncode = self.close()
110
112 '''
113 transfers matrices (values, can be 1x1) to octave for further use
114
115 names must be valid denominator strings
116
117 examples:
118 myoct.definemats('a', m)
119 myoct.definemats(['a', 'b'], [m1, m2])
120
121 (since octave also accepts j for imaginary parts, should also work for
122 complex numbers)
123 '''
124 if type(namelist) == type('n'):
125 namelist = [namelist]
126 mlist = [mlist]
127 assert len(namelist) == len(mlist)
128 for name in namelist:
129 m = mlist[namelist.index(name)]
130 out = ';'.join( \
131 [','.join(map(str, row)) for row in n.mat(m).tolist()] )
132 out = '[' + out + ']'
133 self.o.stdin.write(name + '=' + out + '\n')
134
135 self.getreaction()
136
138 '''
139 parse (and thereby chop off) octave's stdout
140
141 Converting the string to a numpy matrix is left to another method.
142 '''
143
144
145
146
147
148
149
150
151
152 output = ''
153 itemcount = 0
154 while itemcount < items:
155 line = self.o.stdout.readline()
156 output = output + line
157 if output.endswith('\n\n') and output[-3] != '=': itemcount += 1
158
159 return output
160
162 '''
163 creates numpy matrix from octave's matrix printout
164
165 only one matrix per call should be passed
166 '''
167
168 temp = octstring.split('=')[1].strip()
169
170 temp = temp.replace('\n', ';')
171
172
173 temp = temp.replace('i', 'j')
174
175
176 temp = temp.replace(' + ', '+')
177
178 return n.mat(temp)
179
180 - def execfunc(self, funcname, argnames, numout = 1):
181 '''
182 executes an octave function call and returns matrix results
183
184 For example, the octave function [AA,BB,Q,Z,V,W] = qz(A,B) would be
185 called by
186 (a, b, q, z, v, w) = myoctconn.exefunc('qz', ['myA', 'myB'], 6)
187
188 The arg names must be given as strings, and must have been defined in
189 octave before with definemats.
190
191 If there's only one arg, it is admissible to provide just one arg string
192 instead of an 1-element list
193 '''
194 if type(argnames) == type('a'): argnames = [argnames]
195
196 lhs = '['
197 for returnix in range(numout):
198 lhs = lhs + 'r' + str(returnix) + ','
199 lhs = lhs[:-1] + ']'
200
201 rhs = funcname + '('
202 for argname in argnames: rhs = rhs + argname + ','
203 rhs = rhs[:-1] + ')'
204
205 self.o.stdin.write(lhs + '=' + rhs + '\n')
206 outlist = []
207 for item in range(numout):
208 outlist.append(self.octstr2nmat(self.getreaction()))
209 return outlist
210
212 self.o.communicate('quit')
213 return self.o.returncode
214
215
216 if __name__ == '__main__':
217 print 'running testcode'
218
219 myo = octave4numpy()
220 a = n.hstack( [n.ones((4,2)), n.random.rand(4,2)] )
221 b = n.hstack( [n.zeros((4,2)), n.random.rand(4,2)] )
222 myo.definemats('a', a)
223 myo.definemats('b', b)
224
225 print myo.close()
226 del myo
227
228
229 print 'shortcut approach:'
230 c = a
231 d = b
232 myo2 = octave4numpy('qz', (c, d), 7)
233
234 for result in myo2.results: print result
235 print 'octreturncode: ' + str(myo2.octreturncode)
236 del myo2
237
238 print 'session approach:'
239 e = a
240 f = b
241 myoct = octave4numpy()
242 myoct.definemats(['e', 'f'], [e, f])
243 (AA,BB,Q,Z,V,W, lam) = myoct.execfunc('qz', ['e', 'f'], 7)
244 myoct.close()
245 print V
246 print W
247