Class AppMath::Vec
In: linalg.rb
Parent: Object

Vector space of arbitrary dimension. The intended usage is that the components of a vector are all either real or complex. Since

  x = Vec.new(anyArray); x[1] = anyObject

works, there is no guaranty for type-uniformity of the components of a vector.

Methods

*   +   -   -@   <=>   []   []=   abs   abs2   clone   complex?   convolution   dim   dis   each   new   prn   pseudo_inv   spr   test   to_s   tob   uv  

Included Modules

Enumerable Comparable

Attributes

x  [RW] 

Public Class methods

These are the 3 mehods to generate a vector via ‘new

  a = Vec.new(anArray)
  b = Vec.new(aVec)
  c = Vec.new(aPositiveInteger, aRealOrComplex)

[Source]

    # File linalg.rb, line 42
42:   def initialize(*arg)
43:     case arg.size
44:     when 1
45:       a0 = arg[0]
46:       if a0.is_a?(Array)
47:         @x = Array.new(a0)
48:       elsif a0.is_a?(Vec)
49:         @x = Array.new(a0.x)
50:       else
51:         fail "object can't be used to build a vector"
52:       end
53:     when 2
54:       n = arg[0]
55:       fail "first argument has to be an integer" unless n.integer?
56:       fail "first argument must be non-negative" unless n >= 0
57:       @x = Array.new(n,arg[1])
58:     end
59:   end

Consistency test of class Vec.

[Source]

     # File linalg.rb, line 289
289:   def Vec.test(n0, verbose = true , complex = false)
290:     puts "Doing Vec.test( n = #{n0}, verbose = #{verbose}, " +
291:     "complex = #{complex}) for R.prec = #{R.prec}:"
292:     puts "*************************************************"
293:     
294:     t1 = Time.now
295:     s = R.c0
296:     puts "class of s is " + s.class.to_s
297:     i = n0
298:     a = Vec.tob(n0, i, complex) 
299:     i += 1
300:     b = Vec.tob(n0, i, complex) 
301:     i += 1
302:     c = Vec.tob(n0, i, complex) 
303:     i += 1
304:     s1 = complex ? C.ran(i) : R.ran(i)
305:     i += 1
306:     s2 = complex ? C.ran(i) : R.ran(i)
307:   
308:     r = (a + b) + c
309:     l = a + (b + c)
310:     ds = r.dis(l)
311:     puts "associativity: ds = " + ds.to_s if verbose
312:     s += ds
313:   
314:     r = (a - b) + c
315:     l = a - (b - c)
316:     ds = r.dis(l)
317:     puts "associativity 2: ds = " + ds.to_s if verbose
318:     s += ds
319:   
320:     r = (a + b) * s1
321:     l = a * s1 + b * s1
322:     ds = r.dis(l)
323:     puts "distributivity: ds = " + ds.to_s if verbose
324:     s += ds
325:   
326:     r = c * (s1*s2)
327:     l = (c * s1) * s2
328:     ds = r.dis(l)
329:     puts "distributivity of multiplication by scalars: ds = " + ds.to_s if verbose
330:     s += ds
331:   
332:     r = a
333:     l = -(-a)
334:     ds = r.dis(l)
335:     puts "idempotency of unary minus: ds = " + ds.to_s if verbose
336:     s += ds
337:   
338:     r = (a + b).spr(c)
339:     l = a.spr(c) + b.spr(c)
340:     ds = r.dis(l)
341:     puts "distributivity of spr: ds = " + ds.to_s if verbose
342:     s += ds
343:     
344:     t2 = Time.now
345:   
346:     if verbose
347:       puts
348:       a.prn("a")
349:       puts
350:       b.prn("b")
351:       puts
352:       c.prn("c")
353:       puts
354:       s1.prn("s1")
355:       puts
356:       s2.prn("s2")
357:     end
358: 
359:     puts "class of s is " + s.class.to_s + " ."
360:     puts "The error sum s is " + s.to_s + " ."
361:     puts "It should be close to 0."
362:     puts "Computation time was " + (t2-t1).to_s
363:     s
364:   end

Test object.

Returns a Vec res such that res.dim == n. Vector res depends rather chaotically on the integer argument i. If the last argument is ‘false’ res will have R-typed components, and C-typed components else.

[Source]

    # File linalg.rb, line 71
71:   def Vec.tob(n,i,complex=false)
72:     vi = complex ? C.tob(i) : R.tob(i)
73:     res=Vec.new(n, vi)
74:     if complex 
75:       rg1 = Ran.new(-vi.re,vi.re)
76:       rg2 = Ran.new(-vi.im,vi.im)
77:       for j in 1..res.dim
78:         res[j] = C.new(rg1.ran,rg2.ran)
79:       end
80:     else
81:       rg = Ran.new(-vi,vi)
82:       for j in 1..res.dim
83:         res[j] = rg.ran
84:       end
85:     end
86:     res
87:   end

Public Instance methods

Returns self * s, where s has the same type as the components of self.

[Source]

     # File linalg.rb, line 160
160:   def *(s)
161:     res = clone
162:     for i in 1..dim
163:       res[i] *= s
164:     end
165:     res
166:   end

Returns self + v, where v is a Vec

[Source]

     # File linalg.rb, line 138
138:   def +(v)
139:     fail "object can't be added to a Vec" unless v.is_a?(Vec)
140:     fail "dimension mismatch" unless dim == v.dim
141:     res = clone
142:     for i in 1..dim
143:       res[i] += v[i]
144:     end
145:     res
146:   end

Returns self - v , where v is a Vec

[Source]

     # File linalg.rb, line 149
149:   def -(v)
150:     fail "object can't be subtracted from a Vec" unless v.is_a?(Vec)
151:     fail "dimension mismatch" unless dim == v.dim
152:     res = clone
153:     for i in 1..dim
154:       res[i] -= v[i]
155:     end
156:     res
157:   end

Returns -self.

[Source]

     # File linalg.rb, line 169
169:   def -@
170:     res = clone
171:     for i in 1..dim
172:       res[i] = -res[i]
173:     end
174:     res
175:   end

The order relation is here lexicographic ordering of lists. Needed only for book-keeping purposes. Defines the functionality of self as a Comparable.

[Source]

     # File linalg.rb, line 197
197:   def <=> (v)
198:     d1 = dim; d2 = v.dim
199:     if d1 < d2
200:       return -1
201:     elsif d1 > d2 
202:       return 1
203:     else
204:       for i in 0...d1
205:         ci = x[i] <=> v.x[i]
206:         return ci unless ci == 0
207:       end
208:     end
209:     return 0
210:   end

Valid indexes start with 1 not with 0. Read access to the components also works via indexes such as

  y = x[3]

[Source]

     # File linalg.rb, line 126
126:   def [](i)
127:     @x[i-1]
128:   end

Valid indexes start with 1 not with 0. Write access to the components also works via indexes such as

  x[1] = 3.14

[Source]

     # File linalg.rb, line 133
133:   def []=(i,a)
134:     @x[i-1] = a
135:   end

Returns the absolute value of self. This is also known as the L2-norm.

[Source]

     # File linalg.rb, line 249
249:   def abs
250:     if complex?
251:       abs2.re.sqrt
252:     else
253:       abs2.sqrt
254:     end
255:   end

Returns the square of absolute value of self.

[Source]

     # File linalg.rb, line 243
243:   def abs2
244:     spr(self)
245:   end

Returns an independent copy of self.

[Source]

    # File linalg.rb, line 62
62:   def clone
63:     Vec.new(self)
64:   end

Returns ‘true’ if the first component is complex. Notice that the normal usage of Vec is to have all components of the same type.

[Source]

     # File linalg.rb, line 283
283:   def complex? 
284:     return nil if dim.zero?
285:     @x[0].complex?
286:   end

Returns a ‘modified scalar product’ in which no complex conjugation is involved.

[Source]

     # File linalg.rb, line 232
232:   def convolution(v)
233:     fail "dimension mismatch" unless dim == v.dim
234:     return nil if dim.zero?
235:     s = self[1] * v[1] 
236:     for i in 2..dim
237:       s += self[i] * v[i] 
238:     end
239:     s
240:   end

Returns the ‘dimension’ of the vector, i.e. the number of its components.

[Source]

    # File linalg.rb, line 36
36:   def dim; @x.size; end

Returns a relative distance between self and v.

[Source]

     # File linalg.rb, line 270
270:   def dis(v)
271:     a = abs
272:     b = v.abs
273:     d = (self - v).abs
274:     s = a + b
275:     return R.c0 if s.zero?
276:     d1 = d/s
277:     Basics.inf(d,d1)
278:   end

Defines the functionality of self as an Enumerable.

[Source]

     # File linalg.rb, line 213
213:   def each
214:     @x.each{ |c| yield c}
215:   end

Prints the content of self and naming the output.

[Source]

     # File linalg.rb, line 188
188:   def prn(name)
189:     for i in 1..dim 
190:       puts " #{name}[#{i}] = " + self[i].to_s
191:     end
192:   end

Gives the pseudoinverse of the vector self. This means that all components get inverted except those that are close to zero in comparison to the component with the largest absolute value. For small components c ( |c| ~ acc * sup |self[i]| ) a continuous transition between the inverse and zero becomes operational.

[Source]

     # File linalg.rb, line 96
 96:   def pseudo_inv(acc=0)
 97:     n = dim
 98:     fail "dim = 0" if n.zero?
 99:     res = clone
100:     if acc.zero? # most common case, thus first and without ordering 
101:      # overhead
102:       for i in 1..n 
103:         si = self[i]
104:         res[i] = si.zero? ? si.to_0 : si.inv
105:       end
106:     else
107:       arr = @x.clone
108:       arr.each{ |v| v = v.abs }
109:       arr.sort!
110:       a_max = arr.last
111:       eta = a_max * acc
112:       eta *= 0.5
113:       eta *= eta
114:       for i in 1..n 
115:         si = self[i]
116:         ni = si * si + eta
117:         res[i] = si / ni
118:       end
119:     end
120:     res
121:   end

Returns the scalar product (self|v). The complex conjugation (which acts trivially on R) affects here the first factor. This is the convention preferred in physics.

[Source]

     # File linalg.rb, line 220
220:   def spr(v)
221:     fail "dimension mismatch" unless dim == v.dim
222:     return nil if dim.zero?
223:     s = self[1].conj * v[1] 
224:     for i in 2..dim
225:       s += self[i].conj * v[i] 
226:     end
227:     s
228:   end

Returns a string which consists of a list of the strings which represent the components.

[Source]

     # File linalg.rb, line 179
179:   def to_s
180:     res = "\n Vec"
181:     for i in 0...dim
182:       res += "\n    " + x[i].to_s
183:     end
184:     res + "\n end Vec"
185:   end

Returns a unit vector which has the same direction as self, (or self if this is the zero-vector).

[Source]

     # File linalg.rb, line 259
259:   def uv
260:     r = abs
261:     if r.zero?
262:       clone
263:     else 
264:       ri = r.inv
265:       self * ri
266:     end
267:   end

[Validate]