~ubuntu-branches/ubuntu/lucid/pdl/lucid

« back to all changes in this revision

Viewing changes to Basic/Complex/complex.pd

  • Committer: Bazaar Package Importer
  • Author(s): Ben Gertzfield
  • Date: 2002-04-08 18:47:16 UTC
  • Revision ID: james.westby@ubuntu.com-20020408184716-0hf64dc96kin3htp
Tags: upstream-2.3.2
ImportĀ upstreamĀ versionĀ 2.3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
$VERSION = 0.7;
 
2
 
 
3
# pp_setversion $VERSION;  # haven't worked out why it breaks my system (CS)
 
4
pp_beginwrap; # required for overload to work
 
5
 
 
6
pp_addpm {At => Top}, <<'EOD';
 
7
=head1 NAME
 
8
 
 
9
PDL::Complex - handle complex numbers
 
10
 
 
11
=head1 SYNOPSIS
 
12
 
 
13
  use PDL;
 
14
  use PDL::Complex;
 
15
 
 
16
=head1 DESCRIPTION
 
17
 
 
18
This module features a growing number of functions manipulating complex
 
19
numbers. These are usually represented as a pair C<[ real imag ]> or
 
20
C<[ angle phase ]>. If not explicitly mentioned, the functions can work
 
21
inplace (not yet implemented!!!) and require rectangular form.
 
22
 
 
23
While there is a procedural interface available (C<$a/$b*$c <=> Cmul
 
24
(Cdiv $a, $b), $c)>), you can also opt to cast your pdl's into the
 
25
C<PDL::Complex> datatype, which works just like your normal piddles, but
 
26
with all the normal perl operators overloaded.
 
27
 
 
28
The latter means that C<sin($a) + $b/$c> will be evaluated using the
 
29
normal rules of complex numbers, while other pdl functions (like C<max>)
 
30
just treat the piddle as a real-valued piddle with a lowest dimension of
 
31
size 2, so C<max> will return the maximum of all real and imaginary parts,
 
32
not the "highest" (for some definition)
 
33
 
 
34
=head1 TIPS, TRICKS & CAVEATS
 
35
 
 
36
=over 4
 
37
 
 
38
=item *
 
39
 
 
40
C<i> is a constant exported by this module, which represents
 
41
C<-1**0.5>, i.e. the imaginary unit. it can be used to quickly and
 
42
conviniently write complex constants like this: C<4+3*i>.
 
43
 
 
44
=item *
 
45
 
 
46
Use C<r2C(real-values)> to convert from real to complex, as in C<$r
 
47
= Cpow $cplx, r2C 2>. The overloaded operators automatically do that for
 
48
you, all the other functions, do not. So C<Croots 1, 5> will return all
 
49
the fifths roots of 1+1*i (due to threading).
 
50
 
 
51
=item *
 
52
 
 
53
use C<cplx(real-valued-piddle)> to cast from normal piddles intot he
 
54
complex datatype. Use C<real(complex-valued-piddle)> to cast back. This
 
55
requires a copy, though.
 
56
 
 
57
=item *
 
58
 
 
59
BEWARE: This module has not been extensively tested. Watch out and
 
60
send me bugreports!
 
61
 
 
62
=back
 
63
 
 
64
=head1 EXAMPLE WALK-THROUGH
 
65
 
 
66
The complex constant five is equal to C<pdl(1,0)>:
 
67
 
 
68
   perldl> p $x = r2C 5
 
69
   [5 0]
 
70
 
 
71
Now calculate the three roots of of five:
 
72
 
 
73
   perldl> p $r = Croots $x, 3 
 
74
 
 
75
   [
 
76
    [  1.7099759           0]
 
77
    [-0.85498797   1.4808826]
 
78
    [-0.85498797  -1.4808826]
 
79
   ]
 
80
 
 
81
Check that these really are the roots of unity:
 
82
 
 
83
   perldl> p $r ** 3
 
84
 
 
85
   [
 
86
    [             5              0]
 
87
    [             5 -3.4450524e-15]
 
88
    [             5 -9.8776239e-15]
 
89
   ]
 
90
 
 
91
Duh! Could be better. Now try by multiplying C<$r> three times with itself:
 
92
 
 
93
   perldl> p $r*$r*$r
 
94
 
 
95
   [
 
96
    [             5              0]
 
97
    [             5 -2.8052647e-15]
 
98
    [             5 -7.5369398e-15]
 
99
   ]
 
100
 
 
101
Well... maybe C<Cpow> (which is used by the C<**> operator) isn't as
 
102
bad as I thought. Now multiply by C<i> and negate, which is just a very
 
103
expensive way of swapping real and imaginary parts.
 
104
 
 
105
   perldl> p -($r*i)
 
106
 
 
107
   [
 
108
    [         -0   1.7099759]
 
109
    [  1.4808826 -0.85498797]
 
110
    [ -1.4808826 -0.85498797]
 
111
   ]
 
112
 
 
113
Now plot the magnitude of (part of) the complex sine. First generate the
 
114
coefficients:
 
115
 
 
116
   perldl> $sin = i * zeroes(50)->xlinvals(2,4)
 
117
                    + zeroes(50)->xlinvals(0,7)
 
118
 
 
119
Now plot the imaginary part, the real part and the magnitude of the sine
 
120
into the same diagram:
 
121
 
 
122
   perldl> line im sin $sin; hold
 
123
   perldl> line re sin $sin
 
124
   perldl> line abs sin $sin
 
125
 
 
126
Sorry, but I didn't yet try to reproduce the diagram in this
 
127
text. Just run the commands yourself, making sure that you have loaded
 
128
C<PDL::Complex> (and C<PDL::Graphics::PGPLOT>).
 
129
 
 
130
 
 
131
=cut
 
132
 
 
133
EOD
 
134
 
 
135
for (qw(Ctan Catan re im i cplx real)) {
 
136
   pp_add_exported '', $_;
 
137
}
 
138
 
 
139
pp_addhdr <<'EOH';
 
140
 
 
141
#include <math.h>
 
142
 
 
143
#ifndef M_PI
 
144
# define M_PI   3.1415926535897932384626433832795029
 
145
#endif
 
146
#ifndef M_2PI
 
147
# define M_2PI  (2. * M_PI)
 
148
#endif
 
149
 
 
150
#if __GLIBC__ > 1 && (defined __USE_MISC || defined __USE_XOPEN || defined __USE_ISOC9X)
 
151
# define CABS(r,i) hypot (r, i)
 
152
#else
 
153
  static double
 
154
  CABS (double r, double i)
 
155
  {
 
156
    double t;
 
157
 
 
158
    if (r < 0) r = - r;
 
159
    if (i < 0) i = - i;
 
160
 
 
161
    if (i > r)
 
162
      {
 
163
        t = r; r = i; i = t;
 
164
      }
 
165
 
 
166
    if (r + i == r)
 
167
      return r;
 
168
 
 
169
    t = i / r;
 
170
    return r * sqrt (1 + t*t);
 
171
  }
 
172
#endif
 
173
 
 
174
#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 && defined __USE_GNU
 
175
# define SINCOS(x,s,c) sincos ((x), &(s), &(c))
 
176
#else
 
177
# define SINCOS(x,s,c)                  \
 
178
        (s) = sin (x);                  \
 
179
        (c) = cos (x);
 
180
#endif
 
181
 
 
182
 
 
183
#define CSQRT(type,ar,ai,cr,ci)                 \
 
184
        type mag = CABS ((ar), (ai));           \
 
185
        type t;                                 \
 
186
                                                \
 
187
        if (mag == 0)                           \
 
188
          (cr) = (ci) = 0;                      \
 
189
        else if ((ar) > 0)                      \
 
190
          {                                     \
 
191
            t = sqrt (0.5 * (mag + (ar)));      \
 
192
            (cr) = t;                           \
 
193
            (ci) = 0.5 * (ai) / t;              \
 
194
          }                                     \
 
195
        else                                    \
 
196
          {                                     \
 
197
            t = sqrt (0.5 * (mag - (ar)));      \
 
198
                                                \
 
199
            if ((ai) < 0)                       \
 
200
              t = -t;                           \
 
201
                                                \
 
202
            (ci) = t;                           \
 
203
            (cr) = 0.5 * (ai) / t;              \
 
204
          }
 
205
 
 
206
#define CLOG(ar,ai,cr,ci)                       \
 
207
        (cr) = log (CABS ((ar), (ai)));         \
 
208
        (ci) = atan2 ((ai), (ar));
 
209
 
 
210
EOH
 
211
 
 
212
pp_addpm <<'EOP';
 
213
 
 
214
=head2 cplx real-valued-pdl
 
215
 
 
216
Cast a real-valued piddle to the complex datatype. The first dimension of
 
217
the piddle must be of size 2. After this the usual (complex) arithmetic
 
218
operators are applied to this pdl, rather than the normal elementwise pdl
 
219
operators.  Dataflow to the complex parent works. Use C<sever> on the result
 
220
if you don't want this.
 
221
 
 
222
 
 
223
=head2 real cplx-valued-pdl
 
224
 
 
225
Cast a complex vlaued pdl back to the "normal" pdl datatype. Afterwards
 
226
the normal elementwise pdl operators are used in operations. Dataflow
 
227
to the real parent works. Use C<sever> on the result if you don't want this.
 
228
 
 
229
=cut
 
230
 
 
231
sub cplx($) {
 
232
   bless $_[0]->slice('');
 
233
}
 
234
 
 
235
*PDL::cplx = \&cplx;
 
236
 
 
237
sub real($) {
 
238
   bless $_[0]->slice(''), 'PDL';
 
239
}
 
240
 
 
241
EOP
 
242
 
 
243
pp_def 'r2C',
 
244
       Pars => 'r(); [o]c(m=2)',
 
245
       Doc => 'convert real to complex, assuming an imaginary part of zero',
 
246
       PMCode => 'sub PDL::r2C($) { my $r = __PACKAGE__->initialize; &PDL::_r2C_int($_[0], $r); $r }',
 
247
       Code => q!
 
248
          $c(m=>0) = $r();
 
249
          $c(m=>1) = 0;
 
250
       !
 
251
;
 
252
 
 
253
pp_def 'i2C',
 
254
       Pars => 'r(); [o]c(m=2)',
 
255
       Doc => 'convert imaginary to complex, assuming a real part of zero',
 
256
       PMCode => 'sub PDL::i2C($) { my $r = __PACKAGE__->initialize; &PDL::_i2C_int($_[0], $r); $r }',
 
257
       Code => q!
 
258
          $c(m=>0) = 0;
 
259
          $c(m=>1) = $r();
 
260
       !
 
261
;
 
262
 
 
263
pp_def 'Cr2p',
 
264
       Pars => 'r(m=2); float+ [o]p(m=2)',
 
265
       Doc => 'convert complex numbers in rectangular form to polar (mod,arg) form',
 
266
       Code => q!
 
267
          $GENERIC() x = $r(m=>0);
 
268
          $GENERIC() y = $r(m=>1);
 
269
          $p(m=>0) = CABS (x, y);
 
270
          $p(m=>1) = atan2 (y, x);
 
271
       !
 
272
;
 
273
 
 
274
pp_def 'Cp2r',
 
275
       Pars => 'r(m=2); [o]p(m=2)',
 
276
       GenericTypes => [F,D],
 
277
       Doc => 'convert complex numbers in polar (mod,arg) form to rectangular form',
 
278
       Code => q!
 
279
          $GENERIC() m = $r(m=>0);
 
280
          $GENERIC() a = $r(m=>1);
 
281
          double s, c;
 
282
 
 
283
          SINCOS (a, s, c);
 
284
          $p(m=>0) = s * m;
 
285
          $p(m=>1) = c * m;
 
286
       !
 
287
;
 
288
 
 
289
pp_def 'Cadd', # this is here for a) completeness and b) not having to mess with PDL::Ops
 
290
        Pars => 'a(m=2); b(m=2); [o]c(m=2)',
 
291
        Doc => undef,
 
292
        Code => q^
 
293
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
294
           $GENERIC() br = $b(m=>0), bi = $b(m=>1);
 
295
           $c(m=>0) = ar + br;
 
296
           $c(m=>1) = ai + bi;
 
297
        ^
 
298
;
 
299
 
 
300
pp_def 'Csub', # this is here for a) completeness and b) not having to mess with PDL::Ops
 
301
        Pars => 'a(m=2); b(m=2); [o]c(m=2)',
 
302
        Doc => undef,
 
303
        Code => q^
 
304
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
305
           $GENERIC() br = $b(m=>0), bi = $b(m=>1);
 
306
           $c(m=>0) = ar - br;
 
307
           $c(m=>1) = ai - bi;
 
308
        ^
 
309
;
 
310
 
 
311
pp_def 'Cmul',
 
312
        Pars => 'a(m=2); b(m=2); [o]c(m=2)',
 
313
        Doc => 'complex multiplication',
 
314
        Code => q^
 
315
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
316
           $GENERIC() br = $b(m=>0), bi = $b(m=>1);
 
317
           $c(m=>0) = ar*br - ai*bi;
 
318
           $c(m=>1) = ar*bi + ai*br;
 
319
        ^
 
320
;
 
321
 
 
322
pp_def 'Cscale',
 
323
        Pars => 'a(m=2); b(); [o]c(m=2)',
 
324
        Doc => 'mixed complex/real multiplication',
 
325
        Code => q^
 
326
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
327
           $c(m=>0) = ar * $b();
 
328
           $c(m=>1) = ai * $b();
 
329
        ^
 
330
;
 
331
 
 
332
pp_def 'Cdiv',
 
333
        Pars => 'a(m=2); b(m=2); [o]c(m=2)',
 
334
        GenericTypes => [F,D],
 
335
        Doc => 'complex division',
 
336
        Code => q^
 
337
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
338
           $GENERIC() br = $b(m=>0), bi = $b(m=>1);
 
339
 
 
340
           if (fabs (br) > fabs (bi))
 
341
             {
 
342
               $GENERIC() tt = bi / br;
 
343
               $GENERIC() dn = br + tt * bi;
 
344
               $c(m=>0) = (ar + tt * ai) / dn;
 
345
               $c(m=>1) = (ai - tt * ar) / dn;
 
346
             }
 
347
           else
 
348
             {
 
349
               $GENERIC() tt = br / bi;
 
350
               $GENERIC() dn = br * tt + bi;
 
351
               $c(m=>0) = (ar * tt + ai) / dn;
 
352
               $c(m=>1) = (ai * tt - ar) / dn;
 
353
             }
 
354
        ^
 
355
;
 
356
 
 
357
pp_def 'Ccmp',
 
358
        Pars => 'a(m=2); b(m=2); [o]c()',
 
359
        GenericTypes => [F,D],
 
360
        Doc => 'Complex comparison oeprator (spaceship). It orders by real first, then by imaginary.',
 
361
        Code => q^
 
362
           $GENERIC() a, b;
 
363
           
 
364
           a = $a(m=>0), b = $b(m=>0);
 
365
           if (a != b)
 
366
             $c() = (a > b) * 2 - 1;
 
367
           else
 
368
             {
 
369
               a = $a(m=>1), b = $b(m=>1);
 
370
               $c() = a == b ? 0
 
371
                             : (a > b) * 2 - 1;
 
372
             }
 
373
        ^
 
374
;
 
375
 
 
376
pp_def 'Cconj',
 
377
        Pars => 'a(m=2); [o]c(m=2)',
 
378
        Doc => 'complex conjugation',
 
379
        Code => q^
 
380
           $c(m=>0) =  $a(m=>0);
 
381
           $c(m=>1) = -$a(m=>1);
 
382
        ^
 
383
;
 
384
 
 
385
pp_def 'Cabs',
 
386
        Pars => 'a(m=2); [o]c()',
 
387
        GenericTypes => [F,D],
 
388
        Doc => 'complex C<abs()> (also known as I<modulus>)',
 
389
        Code => q^
 
390
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
391
           $c() = CABS (ar, ai);
 
392
        ^
 
393
;
 
394
 
 
395
pp_def 'Cabs2',
 
396
        Pars => 'a(m=2); [o]c()',
 
397
        Doc => 'complex squared C<abs()> (also known I<squared modulus>)',
 
398
        Code => q^
 
399
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
400
           $c() = ar*ar + ai*ai;
 
401
        ^
 
402
;
 
403
 
 
404
pp_def 'Carg',
 
405
        Pars => 'a(m=2); [o]c()',
 
406
        GenericTypes => [F,D],
 
407
        Doc => 'complex argument function ("angle")',
 
408
        Code => q^
 
409
           $c() = atan2 ($a(m=>1), $a(m=>0));
 
410
        ^
 
411
;
 
412
 
 
413
pp_def 'Csin',
 
414
        Pars => 'a(m=2); [o]c(m=2)',
 
415
        GenericTypes => [F,D],
 
416
        Doc => '  sin (a) = 1/(2*i) * (exp (a*i) - exp (-a*i))',
 
417
        Code => q^
 
418
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
419
           double s, c;
 
420
 
 
421
           SINCOS (ar, s, c);
 
422
           $c(m=>0) = s * cosh (ai);
 
423
           $c(m=>1) = c * sinh (ai);
 
424
        ^
 
425
;
 
426
 
 
427
pp_def 'Ccos',
 
428
        Pars => 'a(m=2); [o]c(m=2)',
 
429
        GenericTypes => [F,D],
 
430
        Doc => '  cos (a) = 1/2 * (exp (a*i) + exp (-a*i))',
 
431
        Code => q^
 
432
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
433
           double s, c;
 
434
 
 
435
           SINCOS (ar, s, c);
 
436
           $c(m=>0) =   c * cosh (ai);
 
437
           $c(m=>1) = - s * sinh (ai);
 
438
        ^
 
439
;
 
440
 
 
441
pp_addpm <<'EOD';
 
442
 
 
443
=head2 Ctan a [not inplace]
 
444
 
 
445
  tan (a) = -i * (exp (a*i) - exp (-a*i)) / (exp (a*i) + exp (-a*i))
 
446
 
 
447
=cut
 
448
 
 
449
sub Ctan($) { Csin($_[0]) / Ccos($_[0]) }
 
450
 
 
451
EOD
 
452
 
 
453
pp_def 'Cexp',
 
454
        Pars => 'a(m=2); [o]c(m=2)',
 
455
        GenericTypes => [F,D],
 
456
        Doc => 'exp (a) = exp (real (a)) * (cos (imag (a)) + i * sin (imag (a)))',
 
457
        Code => q^
 
458
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
459
           $GENERIC() ex = exp (ar);
 
460
           double s, c;
 
461
 
 
462
           SINCOS (ai, s, c);
 
463
           $c(m=>0) = ex * c;
 
464
           $c(m=>1) = ex * s;
 
465
        ^
 
466
;
 
467
 
 
468
pp_def 'Clog',
 
469
        Pars => 'a(m=2); [o]c(m=2)',
 
470
        GenericTypes => [F,D],
 
471
        Doc => 'log (a) = log (cabs (a)) + i * carg (a)',
 
472
        Code => q^
 
473
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
474
 
 
475
           CLOG (ar, ai, $c(m=>0), $c(m=>1));
 
476
        ^
 
477
;
 
478
 
 
479
pp_def 'Cpow',
 
480
        Pars => 'a(m=2); b(m=2); [o]c(m=2)',
 
481
        GenericTypes => [F,D],
 
482
        Doc => 'complex C<pow()> (C<**>-operator)',
 
483
        Code => q^
 
484
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
485
           $GENERIC() br = $b(m=>0), bi = $b(m=>1);
 
486
 
 
487
           double logr, logi, x, y;
 
488
           double  s, c;
 
489
 
 
490
           CLOG (ar, ai, logr, logi);
 
491
           x = exp (logr*br - logi*bi);
 
492
           y =      logr*bi + logi*br;
 
493
 
 
494
           SINCOS (y, s, c);
 
495
           $c(m=>0) = x * c;
 
496
           $c(m=>1) = x * s;
 
497
        ^
 
498
;
 
499
 
 
500
pp_def 'Csqrt',
 
501
        Pars => 'a(m=2); [o]c(m=2)',
 
502
        GenericTypes => [F,D],
 
503
        Doc => '',
 
504
        Code => q^
 
505
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
506
 
 
507
           CSQRT ($GENERIC(), ar, ai, $c(m=>0), $c(m=>1));
 
508
        ^
 
509
;
 
510
 
 
511
pp_def 'Casin',
 
512
        Pars => 'a(m=2); [o]c(m=2)',
 
513
        GenericTypes => [F,D],
 
514
        Doc => '',
 
515
        Code => q^
 
516
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
517
 
 
518
           $GENERIC() t1 = sqrt ((ar+1)*(ar+1) + ai*ai);
 
519
           $GENERIC() t2 = sqrt ((ar-1)*(ar-1) + ai*ai);
 
520
           $GENERIC() alpha = (t1+t2)*0.5;
 
521
           $GENERIC() beta  = (t1-t2)*0.5;
 
522
 
 
523
           if      (alpha < 1) alpha = 1;
 
524
           if      (beta >  1) beta =  1;
 
525
           else if (beta < -1) beta = -1;
 
526
 
 
527
           $c(m=>0) =   atan2 (beta, sqrt (1-beta*beta));
 
528
           $c(m=>1) = - log (alpha + sqrt (alpha*alpha-1));
 
529
           if (ai > 0 || (ai == 0 && ar < -1))
 
530
              $c(m=>1) = - $c(m=>1);
 
531
        ^
 
532
;
 
533
 
 
534
pp_def 'Cacos',
 
535
        Pars => 'a(m=2); [o]c(m=2)',
 
536
        GenericTypes => [F,D],
 
537
        Doc => '',
 
538
        Code => q^
 
539
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
540
 
 
541
           $GENERIC() t1 = sqrt ((ar+1)*(ar+1) + ai*ai);
 
542
           $GENERIC() t2 = sqrt ((ar-1)*(ar-1) + ai*ai);
 
543
           $GENERIC() alpha = (t1+t2)*0.5;
 
544
           $GENERIC() beta  = (t1-t2)*0.5;
 
545
 
 
546
           if      (alpha < 1) alpha = 1;
 
547
           if      (beta >  1) beta =  1;
 
548
           else if (beta < -1) beta = -1;
 
549
 
 
550
           $c(m=>0) = atan2 (sqrt (1-beta*beta), beta);
 
551
           $c(m=>1) = log (alpha + sqrt (alpha*alpha-1));
 
552
           if (ai > 0 || (ai == 0 && ar < -1))
 
553
              $c(m=>1) = - $c(m=>1);
 
554
        ^
 
555
;
 
556
 
 
557
pp_addpm <<'EOD';
 
558
 
 
559
=head2 Catan cplx [not inplace]
 
560
 
 
561
Return the complex C<atan()>.
 
562
 
 
563
=cut
 
564
 
 
565
sub Catan($) {
 
566
   my $z = shift;
 
567
   Cmul pdl(0, 0.5), Clog Cdiv PDL::Complex::i+$z, PDL::Complex::i-$z;
 
568
}
 
569
 
 
570
EOD
 
571
 
 
572
pp_def 'Csinh',
 
573
        Pars => 'a(m=2); [o]c(m=2)',
 
574
        GenericTypes => [F,D],
 
575
        Doc => '  sinh (a) = (exp (a) - exp (-a)) / 2',
 
576
        Code => q^
 
577
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
578
           double s, c;
 
579
 
 
580
           SINCOS (ai, s, c);
 
581
           $c(m=>0) = sinh (ar) * c;
 
582
           $c(m=>0) = cosh (ar) * s;
 
583
        ^
 
584
;
 
585
 
 
586
pp_def 'Ccosh',
 
587
        Pars => 'a(m=2); [o]c(m=2)',
 
588
        GenericTypes => [F,D],
 
589
        Doc => '  cosh (a) = (exp (a) + exp (-a)) / 2',
 
590
        Code => q^
 
591
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
592
           double s, c;
 
593
 
 
594
           SINCOS (ai, s, c);
 
595
           $c(m=>0) = cosh (ar) * c;
 
596
           $c(m=>0) = sinh (ar) * s;
 
597
        ^
 
598
;
 
599
 
 
600
pp_def 'Ctanh',
 
601
        Pars => 'a(m=2); [o]c(m=2)',
 
602
        GenericTypes => [F,D],
 
603
        Doc => '',
 
604
        Code => q^
 
605
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
606
           double den;
 
607
           double s, c;
 
608
 
 
609
           SINCOS (2*ai, s, c);
 
610
           den = cosh (2*ar) + c;
 
611
 
 
612
           $c(m=>0) = sinh (2*ar) / den;
 
613
           $c(m=>0) = s           / den;
 
614
        ^
 
615
;
 
616
 
 
617
pp_def 'Casinh',
 
618
        Pars => 'a(m=2); [o]c(m=2)',
 
619
        GenericTypes => [F,D],
 
620
        Doc => '',
 
621
        Code => q^
 
622
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
623
 
 
624
           $GENERIC() yr = (ar-ai) * (ar+ai) + 1;
 
625
           $GENERIC() yi = 2*ar*ai;
 
626
 
 
627
           CSQRT ($GENERIC(), yr, yi, yr, yi)
 
628
 
 
629
           yr += ar;
 
630
           yi += ai;
 
631
 
 
632
           CLOG (yr, yi, $c(m=>0), $c(m=>1));
 
633
        ^
 
634
;
 
635
 
 
636
pp_def 'Cacosh',
 
637
        Pars => 'a(m=2); [o]c(m=2)',
 
638
        GenericTypes => [F,D],
 
639
        Doc => '',
 
640
        Code => q^
 
641
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
642
 
 
643
           $GENERIC() yr = (ar-ai) * (ar+ai) - 1;
 
644
           $GENERIC() yi = 2*ar*ai;
 
645
 
 
646
           CSQRT ($GENERIC(), yr, yi, yr, yi)
 
647
 
 
648
           yr += ar;
 
649
           yi += ai;
 
650
 
 
651
           CLOG (yr, yi, $c(m=>0), $c(m=>1));
 
652
        ^
 
653
;
 
654
 
 
655
pp_def 'Catanh',
 
656
        Pars => 'a(m=2); [o]c(m=2)',
 
657
        GenericTypes => [F,D],
 
658
        Doc => '',
 
659
        Code => q^
 
660
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
661
 
 
662
           double i2 = ar*ar;
 
663
           double num = i2 + (1+ar) * (1+ar);
 
664
           double den = i2 + (1-ar) * (1-ar);
 
665
 
 
666
           $c(m=>0) = 0.25 * (log(num) - log(den));
 
667
           $c(m=>1) = 0.5 * atan2 (2*ai, 1 - ar*ar - i2);
 
668
        ^
 
669
;
 
670
 
 
671
pp_def 'Cproj',
 
672
        Pars => 'a(m=2); [o]c(m=2)',
 
673
        GenericTypes => [F,D],
 
674
        Doc => 'compute the projection of a complex number to the riemann sphere',
 
675
        Code => q^
 
676
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);
 
677
 
 
678
           double den = ar*ar + ai*ai + 1;
 
679
 
 
680
           $c(m=>0) = 2*ar / den;
 
681
           $c(m=>1) = 2*ai / den;
 
682
        ^
 
683
;
 
684
 
 
685
pp_def 'Croots',
 
686
        Pars => 'a(m=2); [o]c(m=2,n)',
 
687
        OtherPars => 'int n => n',
 
688
        GenericTypes => [F,D],
 
689
        Doc => 'Compute the C<n> roots of C<a>. C<n> must be a positive integer. The result will always be a complex type!',
 
690
        PMCode => q^sub PDL::Croots($$) {
 
691
           my ($pdl, $n) = @_;
 
692
           my $r = PDL->null;
 
693
           &PDL::_Croots_int($pdl, $r, $n);
 
694
           bless $r;
 
695
        }^,
 
696
        Code => q^
 
697
           double ar = $a(m=>0), ai = $a(m=>1),
 
698
                  n1 = 1 / (double)$COMP(n),
 
699
                  rr = pow (CABS (ar, ai), n1), /* do not optimize the sqrt out of this expr! */
 
700
                  at = atan2 (ai, ar),
 
701
                  ti = M_2PI * n1;
 
702
 
 
703
           loop(n) %{
 
704
               double s, c;
 
705
 
 
706
               SINCOS (at, s, c);
 
707
 
 
708
               $c(m=>0) = rr * c;
 
709
               $c(m=>1) = rr * s;
 
710
 
 
711
               at += ti;
 
712
            %}
 
713
        ^
 
714
;
 
715
 
 
716
pp_addpm <<'EOD';
 
717
 
 
718
=head2 re cplx, im cplx
 
719
 
 
720
Return the real or imaginary part of the complex number(s) given. These
 
721
are slicing operators, so data flow works. The real and imaginary parts
 
722
are returned as piddles (ref eq PDL).
 
723
 
 
724
=cut
 
725
 
 
726
sub re($) { bless $_[0]->slice("(0)"), 'PDL' }
 
727
sub im($) { bless $_[0]->slice("(1)"), 'PDL' }
 
728
 
 
729
EOD
 
730
 
 
731
pp_def 'rCpolynomial',
 
732
       Pars => 'coeffs(n); x(c=2,m); [o]out(c=2,m)',
 
733
       Doc => 'evaluate the polynomial with (real) coefficients C<coeffs> at the (complex) position(s) C<x>. C<coeffs[0]> is the constant term.',
 
734
       GenericTypes => [F,D],
 
735
       Code => q!
 
736
          loop(m) %{
 
737
             double xr = 1;
 
738
             double xi = 0;
 
739
             double or = 0;
 
740
             double oi = 0;
 
741
             double Xr;
 
742
 
 
743
             loop(n) %{
 
744
                or += $coeffs() * xr;
 
745
                oi += $coeffs() * xi;
 
746
 
 
747
                Xr = xr;
 
748
                xr = Xr * $x(c=>0) - xi * $x(c=>1);
 
749
                xi = xi * $x(c=>0) + Xr * $x(c=>1);
 
750
             %}
 
751
 
 
752
             $out(c=>0) = or;
 
753
             $out(c=>1) = oi;
 
754
          %}
 
755
       !
 
756
;
 
757
 
 
758
pp_add_isa 'PDL';
 
759
 
 
760
pp_addpm {At => Bot}, <<'EOD';
 
761
 
 
762
# overload must be here, so that all the functions can be seen
 
763
 
 
764
# undocumented compatibility functions
 
765
sub Catan2($$) { Catan Cdiv $_[1], $_[0] }
 
766
sub atan2($$)  { Catan Cdiv $_[1], $_[0] }
 
767
 
 
768
sub _gen_biop {
 
769
   local $_ = shift;
 
770
   my $sub;
 
771
   if (/(\S+)\+(\w+)/) {
 
772
      $sub = eval 'sub { '.$2.' $_[0], ref $_[1] eq __PACKAGE__ ? $_[1] : r2C $_[1] }';
 
773
   } elsif (/(\S+)\-(\w+)/) {
 
774
      $sub = eval 'sub { my $b = ref $_[1] eq __PACKAGE__ ? $_[1] : r2C $_[1];
 
775
                       $_[2] ? '.$2.' $b, $_[0] : '.$2.' $_[0], $b }';
 
776
   } else {
 
777
      die;
 
778
   }
 
779
   return ($1, $sub) if $1 eq "atan2";
 
780
   ($1, $sub, "$1=", $sub);
 
781
}
 
782
 
 
783
sub _gen_unop {
 
784
   my ($op, $func) = ($_[0] =~ /(.+)@(\w+)/);
 
785
   *$op = \&$func if $op =~ /\w+/; # create an alias
 
786
   ($op, eval 'sub { '.$func.' $_[0] }');
 
787
}
 
788
 
 
789
sub _gen_cpop {
 
790
   ($_[0], eval 'sub { my $b = ref $_[1] eq __PACKAGE__ ? $_[1] : r2C $_[1];
 
791
                 ($_[2] ? $b <=> $_[0] : $_[0] <=> $b) '.$_[0].' 0 }');
 
792
}
 
793
 
 
794
sub initialize {
 
795
   bless PDL->null, $_[0];
 
796
}
 
797
 
 
798
BEGIN { $i = bless pdl 0,1 }
 
799
sub i () { $i->copy };
 
800
 
 
801
use overload
 
802
   (map _gen_biop($_), qw(++Cadd --Csub *+Cmul /-Cdiv **-Cpow atan2-Catan2 <=>-Ccmp)),
 
803
   (map _gen_unop($_), qw(sin@Csin cos@Ccos exp@Cexp abs@Cabs log@Clog sqrt@Csqrt abs@Cabs)),
 
804
   (map _gen_cpop($_), qw(< <= == != => >)),
 
805
   '++' => sub { $_[0] += 1 },
 
806
   '--' => sub { $_[0] -= 1 },
 
807
;
 
808
 
 
809
# overwrite PDL's overloading to honour subclass methods in + - * /
 
810
{ package PDL;
 
811
        my $warningFlag;
 
812
        # This strange usage of BEGINs is to ensure the
 
813
        # warning messages get disabled and enabled in the
 
814
        # proper order. Without the BEGIN's the 'use overload'
 
815
        #  would be called first.
 
816
        BEGIN {$warningFlag = $^W; # Temporarily disable warnings caused by 
 
817
               $^W = 0;            # redefining PDL's subs
 
818
              }
 
819
 
 
820
 
 
821
sub cp(;@) {
 
822
        my $foo; 
 
823
        if (ref $_[1]
 
824
                && (ref $_[1] ne 'PDL')
 
825
                && defined ($foo = overload::Method($_[1],'+')))
 
826
                { &$foo($_[1], $_[0], !$_[2])}
 
827
        else { PDL::plus (@_)}
 
828
}
 
829
 
 
830
sub cm(;@) {
 
831
        my $foo; 
 
832
        if (ref $_[1]
 
833
                && (ref $_[1] ne 'PDL')
 
834
                && defined ($foo = overload::Method($_[1],'*')))
 
835
                { &$foo($_[1], $_[0], !$_[2])}
 
836
        else { PDL::mult (@_)}
 
837
}
 
838
 
 
839
sub cmi(;@) {
 
840
        my $foo; 
 
841
        if (ref $_[1]
 
842
                && (ref $_[1] ne 'PDL')
 
843
                && defined ($foo = overload::Method($_[1],'-')))
 
844
                { &$foo($_[1], $_[0], !$_[2])}
 
845
        else { PDL::minus (@_)}
 
846
}
 
847
 
 
848
sub cd(;@) {
 
849
        my $foo; 
 
850
        if (ref $_[1]
 
851
                && (ref $_[1] ne 'PDL')
 
852
                && defined ($foo = overload::Method($_[1],'/')))
 
853
                { &$foo($_[1], $_[0], !$_[2])}
 
854
        else { PDL::divide (@_)}
 
855
}
 
856
 
 
857
 
 
858
  # Used in overriding standard PDL +, -, *, / ops in the complex subclass.
 
859
  use overload (
 
860
                 '+' => \&cp,
 
861
                 '*' => \&cm,
 
862
                 '-' => \&cmi,
 
863
                 '/' => \&cd,
 
864
                );
 
865
 
 
866
 
 
867
 
 
868
        BEGIN{ $^W = $warningFlag;} # Put Back Warnings  
 
869
};
 
870
 
 
871
=head1 AUTHOR
 
872
 
 
873
Copyright (C) 2000 Marc Lehmann <pcg@goof.com>. 
 
874
All rights reserved. There is no warranty. You are allowed
 
875
to redistribute this software / documentation as described
 
876
in the file COPYING in the PDL distribution.
 
877
 
 
878
=head1 SEE ALSO
 
879
 
 
880
perl(1), L<PDL>.
 
881
 
 
882
=cut
 
883
EOD
 
884
 
 
885
pp_done;
 
886