Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/rings/complex_interval.pyx
4048 views
1
"""
2
Arbitrary Precision Complex Intervals
3
4
This is a simple complex interval package, using intervals which are
5
axis-aligned rectangles in the complex plane. It has very few special
6
functions, and it does not use any special tricks to keep the size of
7
the intervals down.
8
9
AUTHOR:
10
These authors wrote complex_number.pyx.
11
-- William Stein (2006-01-26): complete rewrite
12
-- Joel B. Mohler (2006-12-16): naive rewrite into pyrex
13
-- William Stein(2007-01): rewrite of Mohler's rewrite
14
Then complex_number.pyx was copied to complex_interval.pyx and
15
heavily modified:
16
-- Carl Witty (2007-10-24): rewrite to become a complex interval package
17
"""
18
19
#################################################################################
20
# Copyright (C) 2006 William Stein <[email protected]>
21
#
22
# Distributed under the terms of the GNU General Public License (GPL)
23
#
24
# http://www.gnu.org/licenses/
25
#*****************************************************************************
26
27
import math
28
import operator
29
30
from sage.structure.element cimport FieldElement, RingElement, Element, ModuleElement
31
from complex_number cimport ComplexNumber
32
33
import complex_interval_field
34
from complex_field import ComplexField
35
import sage.misc.misc
36
import integer
37
import infinity
38
import real_mpfi
39
import real_mpfr
40
cimport real_mpfr
41
42
include "../ext/stdsage.pxi"
43
44
cdef double LOG_TEN_TWO_PLUS_EPSILON = 3.321928094887363 # a small overestimate of log(10,2)
45
46
def is_ComplexIntervalFieldElement(x):
47
return isinstance(x, ComplexIntervalFieldElement)
48
49
cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement):
50
"""
51
A complex interval.
52
53
EXAMPLES:
54
sage: I = CIF.gen()
55
sage: b = 1.5 + 2.5*I
56
sage: TestSuite(b).run()
57
"""
58
cdef ComplexIntervalFieldElement _new(self):
59
"""
60
Quickly creates a new initialized complex interval with the
61
same parent as self.
62
"""
63
cdef ComplexIntervalFieldElement x
64
x = PY_NEW(ComplexIntervalFieldElement)
65
x._parent = self._parent
66
x._prec = self._prec
67
mpfi_init2(x.__re, self._prec)
68
mpfi_init2(x.__im, self._prec)
69
return x
70
71
def __init__(self, parent, real, imag=None):
72
"""
73
Initialize a complex interval.
74
"""
75
cdef real_mpfi.RealIntervalFieldElement rr, ii
76
self._parent = parent
77
self._prec = self._parent._prec
78
mpfi_init2(self.__re, self._prec)
79
mpfi_init2(self.__im, self._prec)
80
81
if imag is None:
82
if PY_TYPE_CHECK(real, ComplexNumber):
83
real, imag = (<ComplexNumber>real).real(), (<ComplexNumber>real).imag()
84
elif PY_TYPE_CHECK(real, ComplexIntervalFieldElement):
85
real, imag = (<ComplexIntervalFieldElement>real).real(), (<ComplexIntervalFieldElement>real).imag()
86
elif isinstance(real, sage.libs.pari.all.pari_gen):
87
real, imag = real.real(), real.imag()
88
elif isinstance(real, list) or isinstance(real, tuple):
89
re, imag = real
90
real = re
91
elif isinstance(real, complex):
92
real, imag = real.real, real.imag
93
else:
94
imag = 0
95
try:
96
R = parent._real_field()
97
rr = R(real)
98
ii = R(imag)
99
mpfi_set(self.__re, rr.value)
100
mpfi_set(self.__im, ii.value)
101
except TypeError:
102
raise TypeError, "unable to coerce to a ComplexIntervalFieldElement"
103
104
105
def __dealloc__(self):
106
mpfi_clear(self.__re)
107
mpfi_clear(self.__im)
108
109
def _repr_(self):
110
return self.str(10)
111
112
def __hash__(self):
113
return hash(self.str())
114
115
def __getitem__(self, i):
116
if i == 0:
117
return self.real()
118
elif i == 1:
119
return self.imag()
120
raise IndexError, "i must be between 0 and 1."
121
122
def __reduce__( self ):
123
"""
124
Pickling support
125
126
EXAMPLES:
127
sage: a = CIF(1 + I)
128
sage: loads(dumps(a)) == a
129
True
130
"""
131
# TODO: This is potentially slow -- make a 1 version that
132
# is native and much faster -- doesn't use .real()/.imag()
133
return (make_ComplexIntervalFieldElement0, (self._parent, self.real(), self.imag()))
134
135
def str(self, base=10, style=None):
136
"""
137
Returns a string representation of self.
138
139
EXAMPLES::
140
141
sage: CIF(1.5).str()
142
'1.5000000000000000?'
143
sage: CIF(1.5, 2.5).str()
144
'1.5000000000000000? + 2.5000000000000000?*I'
145
sage: CIF(1.5, -2.5).str()
146
'1.5000000000000000? - 2.5000000000000000?*I'
147
sage: CIF(0, -2.5).str()
148
'-2.5000000000000000?*I'
149
sage: CIF(1.5).str(base=3)
150
'1.1111111111111111111111111111111112?'
151
sage: CIF(1, pi).str(style='brackets')
152
'[1.0000000000000000 .. 1.0000000000000000] + [3.1415926535897931 .. 3.1415926535897936]*I'
153
154
SEE ALSO:
155
156
RealIntervalFieldElement.str()
157
"""
158
s = ""
159
if not self.real().is_zero():
160
s = self.real().str(base=base, style=style)
161
if not self.imag().is_zero():
162
y = self.imag()
163
if s!="":
164
if y < 0:
165
s = s+" - "
166
y = -y
167
else:
168
s = s+" + "
169
s = s+"%s*I"%y.str(base=base, style=style)
170
if len(s) == 0:
171
s = "0"
172
return s
173
174
def plot(self, pointsize=10, **kwds):
175
"""
176
Plot a complex interval as a rectangle.
177
178
EXAMPLES::
179
180
sage: sum(plot(CIF(RIF(1/k, 1/k), RIF(-k, k))) for k in [1..10])
181
182
Exact and nearly exact points are still visible::
183
184
sage: plot(CIF(pi, 1), color='red') + plot(CIF(1, e), color='purple') + plot(CIF(-1, -1))
185
186
A demonstration that $z \mapsto z^2$ acts chaotically on $|z|=1$::
187
188
sage: z = CIF(0, 2*pi/1000).exp()
189
sage: g = Graphics()
190
sage: for i in range(40):
191
... z = z^2
192
... g += z.plot(color=(1./(40-i), 0, 1))
193
...
194
sage: g
195
"""
196
from sage.plot.polygon import polygon2d
197
x, y = self.real(), self.imag()
198
x0, y0 = x.lower(), y.lower()
199
x1, y1 = x.upper(), y.upper()
200
g = polygon2d([(x0, y0), (x1, y0), (x1, y1), (x0, y1), (x0, y0)],
201
thickness=pointsize/4, **kwds)
202
# Nearly empty polygons don't show up.
203
g += self.center().plot(pointsize= pointsize, **kwds)
204
return g
205
206
def _latex_(self):
207
"""
208
Returns a latex representation of self.
209
210
EXAMPLES::
211
212
sage: latex(CIF(1.5, -2.5))
213
1.5000000000000000? - 2.5000000000000000?i
214
sage: latex(CIF(0, 3e200))
215
3.0000000000000000? \times 10^{200}i
216
"""
217
import re
218
s = self.str().replace('*I', 'i')
219
return re.sub(r"e(-?\d+)", r" \\times 10^{\1}", s)
220
221
def bisection(self):
222
"""
223
Returns the bisection of self into four intervals whose union is
224
``self`` and intersection is ``self.center()``.
225
226
EXAMPLES::
227
228
sage: z = CIF(RIF(2, 3), RIF(-5, -4))
229
sage: z.bisection()
230
(3.? - 5.?*I, 3.? - 5.?*I, 3.? - 5.?*I, 3.? - 5.?*I)
231
sage: for z in z.bisection():
232
... print z.real().endpoints(), z.imag().endpoints()
233
(2.00000000000000, 2.50000000000000) (-5.00000000000000, -4.50000000000000)
234
(2.50000000000000, 3.00000000000000) (-5.00000000000000, -4.50000000000000)
235
(2.00000000000000, 2.50000000000000) (-4.50000000000000, -4.00000000000000)
236
(2.50000000000000, 3.00000000000000) (-4.50000000000000, -4.00000000000000)
237
238
sage: z = CIF(RIF(sqrt(2), sqrt(3)), RIF(e, pi))
239
sage: a, b, c, d = z.bisection()
240
sage: a.intersection(b).intersection(c).intersection(d) == CIF(z.center())
241
True
242
243
sage: zz = a.union(b).union(c).union(c)
244
sage: zz.real().endpoints() == z.real().endpoints()
245
True
246
sage: zz.imag().endpoints() == z.imag().endpoints()
247
True
248
"""
249
cdef ComplexIntervalFieldElement a00 = self._new()
250
mpfr_set(&a00.__re.left, &self.__re.left, GMP_RNDN)
251
mpfi_mid(&a00.__re.right, self.__re)
252
mpfr_set(&a00.__im.left, &self.__im.left, GMP_RNDN)
253
mpfi_mid(&a00.__im.right, self.__im)
254
255
cdef ComplexIntervalFieldElement a01 = self._new()
256
mpfr_set(&a01.__re.left, &a00.__re.right, GMP_RNDN)
257
mpfr_set(&a01.__re.right, &self.__re.right, GMP_RNDN)
258
mpfi_set(a01.__im, a00.__im)
259
260
cdef ComplexIntervalFieldElement a10 = self._new()
261
mpfi_set(a10.__re, a00.__re)
262
mpfi_mid(&a10.__im.left, self.__im)
263
mpfr_set(&a10.__im.right, &self.__im.right, GMP_RNDN)
264
265
cdef ComplexIntervalFieldElement a11 = self._new()
266
mpfi_set(a11.__re, a01.__re)
267
mpfi_set(a11.__im, a10.__im)
268
269
return a00, a01, a10, a11
270
271
def is_exact(self):
272
"""
273
Returns whether this real interval is exact (i.e. contains exactly one
274
complex value).
275
276
EXAMPLES::
277
278
sage: CIF(3).is_exact()
279
True
280
sage: CIF(0, 2).is_exact()
281
True
282
sage: CIF(-4, 0).sqrt().is_exact()
283
True
284
sage: CIF(-5, 0).sqrt().is_exact()
285
False
286
sage: CIF(0, 2*pi).is_exact()
287
False
288
sage: CIF(e).is_exact()
289
False
290
sage: CIF(1e100).is_exact()
291
True
292
sage: (CIF(1e100) + 1).is_exact()
293
False
294
"""
295
return mpfr_equal_p(&self.__re.left, &self.__re.right) and \
296
mpfr_equal_p(&self.__im.left, &self.__im.right)
297
298
def diameter(self):
299
"""
300
Returns a somewhat-arbitrarily defined "diameter" for this
301
interval: returns the maximum of the diameter of the real
302
and imaginary components, where diameter on a real interval
303
is defined as absolute diameter if the interval contains zero,
304
and relative diameter otherwise.
305
306
EXAMPLES:
307
sage: CIF(RIF(-1, 1), RIF(13, 17)).diameter()
308
2.00000000000000
309
sage: CIF(RIF(-0.1, 0.1), RIF(13, 17)).diameter()
310
0.266666666666667
311
sage: CIF(RIF(-1, 1), 15).diameter()
312
2.00000000000000
313
"""
314
cdef real_mpfr.RealNumber diam
315
diam = real_mpfr.RealNumber(self._parent._real_field()._middle_field(), None)
316
cdef mpfr_t tmp
317
mpfr_init2(tmp, self.prec())
318
mpfi_diam(diam.value, self.__re)
319
mpfi_diam(tmp, self.__im)
320
mpfr_max(diam.value, diam.value, tmp, GMP_RNDU)
321
mpfr_clear(tmp)
322
return diam
323
324
def overlaps(self, ComplexIntervalFieldElement other):
325
"""
326
Returns True if self and other are intervals with at least
327
one value in common.
328
329
EXAMPLES:
330
sage: CIF(0).overlaps(CIF(RIF(0, 1), RIF(-1, 0)))
331
True
332
sage: CIF(1).overlaps(CIF(1, 1))
333
False
334
"""
335
return mpfr_greaterequal_p(&self.__re.right, &other.__re.left) \
336
and mpfr_greaterequal_p(&other.__re.right, &self.__re.left) \
337
and mpfr_greaterequal_p(&self.__im.right, &other.__im.left) \
338
and mpfr_greaterequal_p(&other.__im.right, &self.__im.left)
339
340
def intersection(self, other):
341
"""
342
Returns the intersection of two complex intervals.
343
344
EXAMPLES:
345
sage: CIF(RIF(1, 3), RIF(1, 3)).intersection(CIF(RIF(2, 4), RIF(2, 4))).str(style='brackets')
346
'[2.0000000000000000 .. 3.0000000000000000] + [2.0000000000000000 .. 3.0000000000000000]*I'
347
sage: CIF(RIF(1, 2), RIF(1, 3)).intersection(CIF(RIF(3, 4), RIF(2, 4)))
348
Traceback (most recent call last):
349
...
350
ValueError: intersection of non-overlapping intervals
351
"""
352
353
cdef ComplexIntervalFieldElement x = self._new()
354
cdef ComplexIntervalFieldElement other_intv
355
if PY_TYPE_CHECK(other, ComplexIntervalFieldElement):
356
other_intv = other
357
else:
358
# Let type errors from _coerce_ propagate...
359
other_intv = self._parent(other)
360
361
mpfi_intersect(x.__re, self.__re, other_intv.__re)
362
mpfi_intersect(x.__im, self.__im, other_intv.__im)
363
if mpfr_less_p(&x.__re.right, &x.__re.left) \
364
or mpfr_less_p(&x.__im.right, &x.__im.left):
365
raise ValueError, "intersection of non-overlapping intervals"
366
367
return x
368
369
def union(self, other):
370
"""
371
Returns the smallest complex interval including the
372
two complex intervals.
373
374
EXAMPLES:
375
sage: CIF(0).union(CIF(5, 5)).str(style='brackets')
376
'[0.00000000000000000 .. 5.0000000000000000] + [0.00000000000000000 .. 5.0000000000000000]*I'
377
"""
378
cdef ComplexIntervalFieldElement x = self._new()
379
cdef ComplexIntervalFieldElement other_intv
380
if PY_TYPE_CHECK(other, ComplexIntervalFieldElement):
381
other_intv = other
382
else:
383
# Let type errors from _coerce_ propagate...
384
other_intv = self._parent(other)
385
386
mpfi_union(x.__re, self.__re, other_intv.__re)
387
mpfi_union(x.__im, self.__im, other_intv.__im)
388
return x
389
390
def center(self):
391
"""
392
Returns the closest floating-point approximation to the center
393
of the interval.
394
395
EXAMPLES:
396
sage: CIF(RIF(1, 2), RIF(3, 4)).center()
397
1.50000000000000 + 3.50000000000000*I
398
"""
399
cdef complex_number.ComplexNumber center
400
center = complex_number.ComplexNumber(self._parent._middle_field(), None)
401
mpfi_mid(center.__re, self.__re)
402
mpfi_mid(center.__im, self.__im)
403
404
return center
405
406
def __contains__(self, other):
407
"""
408
Test whether one interval is totally contained in another.
409
410
EXAMPLES:
411
sage: CIF(1, 1) in CIF(RIF(1, 2), RIF(1, 2))
412
True
413
"""
414
# This could be more efficient (and support more types for "other").
415
return (other.real() in self.real()) and (other.imag() in self.imag())
416
417
def contains_zero(self):
418
"""
419
Returns True if self is an interval containing zero.
420
421
EXAMPLES:
422
sage: CIF(0).contains_zero()
423
True
424
sage: CIF(RIF(-1, 1), 1).contains_zero()
425
False
426
"""
427
return mpfi_has_zero(self.__re) and mpfi_has_zero(self.__im)
428
429
cpdef ModuleElement _add_(self, ModuleElement right):
430
cdef ComplexIntervalFieldElement x
431
x = self._new()
432
mpfi_add(x.__re, self.__re, (<ComplexIntervalFieldElement>right).__re)
433
mpfi_add(x.__im, self.__im, (<ComplexIntervalFieldElement>right).__im)
434
return x
435
436
cpdef ModuleElement _sub_(self, ModuleElement right):
437
cdef ComplexIntervalFieldElement x
438
x = self._new()
439
mpfi_sub(x.__re, self.__re, (<ComplexIntervalFieldElement>right).__re)
440
mpfi_sub(x.__im, self.__im, (<ComplexIntervalFieldElement>right).__im)
441
return x
442
443
cpdef RingElement _mul_(self, RingElement right):
444
cdef ComplexIntervalFieldElement x
445
x = self._new()
446
cdef mpfi_t t0, t1
447
mpfi_init2(t0, self._prec)
448
mpfi_init2(t1, self._prec)
449
mpfi_mul(t0, self.__re, (<ComplexIntervalFieldElement>right).__re)
450
mpfi_mul(t1, self.__im, (<ComplexIntervalFieldElement>right).__im)
451
mpfi_sub(x.__re, t0, t1)
452
mpfi_mul(t0, self.__re, (<ComplexIntervalFieldElement>right).__im)
453
mpfi_mul(t1, self.__im, (<ComplexIntervalFieldElement>right).__re)
454
mpfi_add(x.__im, t0, t1)
455
mpfi_clear(t0)
456
mpfi_clear(t1)
457
return x
458
459
def norm(self):
460
return self.norm_c()
461
462
cdef real_mpfi.RealIntervalFieldElement norm_c(ComplexIntervalFieldElement self):
463
cdef real_mpfi.RealIntervalFieldElement x
464
x = real_mpfi.RealIntervalFieldElement(self._parent._real_field(), None)
465
466
cdef mpfi_t t0, t1
467
mpfi_init2(t0, self._prec)
468
mpfi_init2(t1, self._prec)
469
470
mpfi_sqr(t0, self.__re)
471
mpfi_sqr(t1, self.__im)
472
473
mpfi_add(x.value, t0, t1)
474
475
mpfi_clear(t0)
476
mpfi_clear(t1)
477
return x
478
479
cdef real_mpfi.RealIntervalFieldElement abs_c(ComplexIntervalFieldElement self):
480
cdef real_mpfi.RealIntervalFieldElement x
481
x = real_mpfi.RealIntervalFieldElement(self._parent._real_field(), None)
482
483
cdef mpfi_t t0, t1
484
mpfi_init2(t0, self._prec)
485
mpfi_init2(t1, self._prec)
486
487
mpfi_sqr(t0, self.__re)
488
mpfi_sqr(t1, self.__im)
489
490
mpfi_add(x.value, t0, t1)
491
mpfi_sqrt(x.value, x.value)
492
493
mpfi_clear(t0)
494
mpfi_clear(t1)
495
return x
496
497
cpdef RingElement _div_(self, RingElement right):
498
cdef ComplexIntervalFieldElement x
499
x = self._new()
500
cdef mpfi_t a, b, t0, t1, right_nm
501
mpfi_init2(t0, self._prec)
502
mpfi_init2(t1, self._prec)
503
mpfi_init2(a, self._prec)
504
mpfi_init2(b, self._prec)
505
mpfi_init2(right_nm, self._prec)
506
507
mpfi_sqr(t0, (<ComplexIntervalFieldElement>right).__re)
508
mpfi_sqr(t1, (<ComplexIntervalFieldElement>right).__im)
509
mpfi_add(right_nm, t0, t1)
510
511
mpfi_div(a, (<ComplexIntervalFieldElement>right).__re, right_nm)
512
mpfi_div(b, (<ComplexIntervalFieldElement>right).__im, right_nm)
513
514
## Do this: x.__re = a * self.__re + b * self.__im
515
mpfi_mul(t0, a, self.__re)
516
mpfi_mul(t1, b, self.__im)
517
mpfi_add(x.__re, t0, t1)
518
519
## Do this: x.__im = a * self.__im - b * self.__re
520
mpfi_mul(t0, a, self.__im)
521
mpfi_mul(t1, b, self.__re)
522
mpfi_sub(x.__im, t0, t1)
523
mpfi_clear(t0)
524
mpfi_clear(t1)
525
mpfi_clear(a)
526
mpfi_clear(b)
527
mpfi_clear(right_nm)
528
return x
529
530
def __rdiv__(self, left):
531
return ComplexIntervalFieldElement(self._parent, left)/self
532
533
def __pow__(self, right, modulus):
534
"""
535
Compute $x^y$. If y is an integer, uses multiplication;
536
otherwise, uses the standard definition exp(log(x)*y).
537
WARNING: If the interval x crosses the negative real axis,
538
then we use a non-standard definition of log() (see
539
the docstring for argument() for more details). This means
540
that we will not select the principal value of the power,
541
for part of the input interval (and that we violate the
542
interval guarantees).
543
544
EXAMPLES:
545
sage: C.<i> = ComplexIntervalField(20)
546
sage: a = i^2; a
547
-1
548
sage: a.parent()
549
Complex Interval Field with 20 bits of precision
550
sage: a = (1+i)^7; a
551
8 - 8*I
552
sage: (1+i)^(1+i)
553
0.27396? + 0.58370?*I
554
sage: a.parent()
555
Complex Interval Field with 20 bits of precision
556
sage: (2+i)^(-39)
557
1.688?e-14 + 1.628?e-14*I
558
559
If the interval crosses the negative real axis, then we don't
560
use the standard branch cut (and we violate the interval
561
guarantees):
562
sage: (CIF(-7, RIF(-1, 1)) ^ CIF(0.3)).str(style='brackets')
563
'[0.99109735947126309 .. 1.1179269966896264] + [1.4042388462787560 .. 1.4984624123369835]*I'
564
sage: CIF(-7, -1) ^ CIF(0.3)
565
1.117926996689626? - 1.408500714575360?*I
566
"""
567
if isinstance(right, (int, long, integer.Integer)):
568
return sage.rings.ring_element.RingElement.__pow__(self, right)
569
return (self.log() * self.parent()(right)).exp()
570
571
def _magma_init_(self, magma):
572
r"""
573
EXAMPLES:
574
sage: t = CIF((1, 1.1), 2.5); t
575
1.1? + 2.5000000000000000?*I
576
sage: magma(t) # optional - magma
577
1.05000000000000 + 2.50000000000000*$.1
578
sage: t = ComplexIntervalField(100)((1, 4/3), 2.5); t
579
2.? + 2.5000000000000000000000000000000?*I
580
sage: magma(t) # optional - magma
581
1.16666666666666666666666666670 + 2.50000000000000000000000000000*$.1
582
"""
583
return "%s![%s, %s]" % (self.parent()._magma_init_(magma), self.center().real(), self.center().imag())
584
585
def _interface_init_(self, I=None):
586
"""
587
Raise a TypeError.
588
589
This function would return the string representation of self
590
that makes sense as a default representation of a complex
591
interval in other computer algebra systems. But, most other
592
computer algebra systems do not support interval arithmetic,
593
so instead we just raise a TypeError.
594
595
Define the appropriate _cas_init_ function if there is a
596
computer algebra system you would like to support.
597
598
EXAMPLES::
599
600
sage: n = CIF(1.3939494594)
601
sage: n._interface_init_()
602
Traceback (most recent call last):
603
...
604
TypeError
605
606
Here a conversion to Maxima happens, which results in a type
607
error::
608
609
sage: a = CIF(2.3)
610
sage: maxima(a)
611
Traceback (most recent call last):
612
...
613
TypeError
614
"""
615
raise TypeError
616
617
618
def _sage_input_(self, sib, coerce):
619
r"""
620
Produce an expression which will reproduce this value when evaluated.
621
622
EXAMPLES:
623
sage: sage_input(CIF(RIF(e, pi), RIF(sqrt(2), sqrt(3))), verify=True)
624
# Verified
625
CIF(RIF(RR(2.7182818284590451), RR(3.1415926535897936)), RIF(RR(1.4142135623730949), RR(1.7320508075688774)))
626
sage: sage_input(ComplexIntervalField(64)(2)^I, preparse=False, verify=True)
627
# Verified
628
RIF64 = RealIntervalField(64)
629
RR64 = RealField(64)
630
ComplexIntervalField(64)(RIF64(RR64('0.769238901363972126565'), RR64('0.769238901363972126619')), RIF64(RR64('0.638961276313634801076'), RR64('0.638961276313634801184')))
631
sage: from sage.misc.sage_input import SageInputBuilder
632
sage: sib = SageInputBuilder()
633
sage: ComplexIntervalField(15)(3+I).log()._sage_input_(sib, False)
634
{call: {call: {atomic:ComplexIntervalField}({atomic:15})}({call: {call: {atomic:RealIntervalField}({atomic:15})}({call: {call: {atomic:RealField}({atomic:15})}({atomic:1.15125})}, {call: {call: {atomic:RealField}({atomic:15})}({atomic:1.15137})})}, {call: {call: {atomic:RealIntervalField}({atomic:15})}({call: {call: {atomic:RealField}({atomic:15})}({atomic:0.321655})}, {call: {call: {atomic:RealField}({atomic:15})}({atomic:0.321777})})})}
635
"""
636
# Interval printing could often be much prettier,
637
# but I'm feeling lazy :)
638
return sib(self.parent())(sib(self.real()), sib(self.imag()))
639
640
def prec(self):
641
"""
642
Return precision of this complex number.
643
644
EXAMPLES:
645
sage: i = ComplexIntervalField(2000).0
646
sage: i.prec()
647
2000
648
"""
649
return self._parent.prec()
650
651
def real(self):
652
"""
653
Return real part of self.
654
655
EXAMPLES:
656
sage: i = ComplexIntervalField(100).0
657
sage: z = 2 + 3*i
658
sage: x = z.real(); x
659
2
660
sage: x.parent()
661
Real Interval Field with 100 bits of precision
662
"""
663
cdef real_mpfi.RealIntervalFieldElement x
664
x = real_mpfi.RealIntervalFieldElement(self._parent._real_field(), None)
665
mpfi_set(x.value, self.__re)
666
return x
667
668
def imag(self):
669
"""
670
Return imaginary part of self.
671
672
EXAMPLES:
673
sage: i = ComplexIntervalField(100).0
674
sage: z = 2 + 3*i
675
sage: x = z.imag(); x
676
3
677
sage: x.parent()
678
Real Interval Field with 100 bits of precision
679
"""
680
cdef real_mpfi.RealIntervalFieldElement x
681
x = real_mpfi.RealIntervalFieldElement(self._parent._real_field(), None)
682
mpfi_set(x.value, self.__im)
683
return x
684
685
def __neg__(self):
686
cdef ComplexIntervalFieldElement x
687
x = self._new()
688
mpfi_neg(x.__re, self.__re)
689
mpfi_neg(x.__im, self.__im)
690
return x
691
692
def __pos__(self):
693
return self
694
695
def __abs__(self):
696
return self.abs_c()
697
698
def __invert__(self):
699
"""
700
Return the multiplicative inverse.
701
702
EXAMPLES:
703
sage: I = CIF.0
704
sage: a = ~(5+I)
705
sage: a * (5+I)
706
1.000000000000000? + 0.?e-16*I
707
"""
708
cdef ComplexIntervalFieldElement x
709
x = self._new()
710
711
cdef mpfi_t t0, t1
712
mpfi_init2(t0, self._prec)
713
mpfi_init2(t1, self._prec)
714
715
mpfi_sqr(t0, self.__re)
716
mpfi_sqr(t1, self.__im)
717
718
mpfi_add(t0, t0, t1) # now t0 is the norm
719
mpfi_div(x.__re, self.__re, t0) # x.__re = self.__re/norm
720
721
mpfi_neg(t1, self.__im)
722
mpfi_div(x.__im, t1, t0) # x.__im = -self.__im/norm
723
724
mpfi_clear(t0)
725
mpfi_clear(t1)
726
727
return x
728
729
def __int__(self):
730
raise TypeError, "can't convert complex interval to int"
731
732
def __long__(self):
733
raise TypeError, "can't convert complex interval to long"
734
735
def __float__(self):
736
raise TypeError, "can't convert complex interval to float"
737
738
def __complex__(self):
739
raise TypeError, "can't convert complex interval to complex"
740
741
def __richcmp__(left, right, int op):
742
"""
743
As with the real interval fields this never returns false positives.
744
Thus, `a == b` is True iff both `a` and `b` represent the same
745
one-point interval. Likewise `a != b` is True iff `x != y` for all
746
`x \in a, y \in b`.
747
748
EXAMPLES::
749
750
sage: CIF(0) == CIF(0)
751
True
752
sage: CIF(0) == CIF(1)
753
False
754
sage: CIF.gen() == CIF.gen()
755
True
756
sage: CIF(0) == CIF.gen()
757
False
758
sage: CIF(0) != CIF(1)
759
True
760
sage: -CIF(-3).sqrt() != CIF(-3).sqrt()
761
True
762
763
These intervals overlap, but contain unequal points::
764
765
sage: CIF(3).sqrt() == CIF(3).sqrt()
766
False
767
sage: CIF(3).sqrt() != CIF(3).sqrt()
768
False
769
770
In the future, complex interval elements may be unordered,
771
but or backwards compatibility we order them lexicographically::
772
773
sage: CDF(-1) < -CDF.gen() < CDF.gen() < CDF(1)
774
True
775
sage: CDF(1) >= CDF(1) >= CDF.gen() >= CDF.gen() >= 0 >= -CDF.gen() >= CDF(-1)
776
True
777
"""
778
return (<Element>left)._richcmp(right, op)
779
780
cdef _richcmp_c_impl(left, Element right, int op):
781
cdef ComplexIntervalFieldElement lt, rt
782
lt = left
783
rt = right
784
if op == 2: #==
785
# intervals a == b iff a<=b and b <= a
786
# (this gives a result with two comparisons, where the
787
# obvious approach would use three)
788
return mpfr_lessequal_p(&lt.__re.right, &rt.__re.left) \
789
and mpfr_lessequal_p(&rt.__re.right, &lt.__re.left) \
790
and mpfr_lessequal_p(&lt.__im.right, &rt.__im.left) \
791
and mpfr_lessequal_p(&rt.__im.right, &lt.__im.left)
792
elif op == 3: #!=
793
return mpfr_less_p(&lt.__re.right, &rt.__re.left) \
794
or mpfr_less_p(&rt.__re.right, &lt.__re.left) \
795
or mpfr_less_p(&lt.__im.right, &rt.__im.left) \
796
or mpfr_less_p(&rt.__im.right, &lt.__im.left)
797
else:
798
# Eventually we probably want to disable comparison of complex
799
# intervals, just like python complexes will be unordered.
800
## raise TypeError, "no ordering relation is defined for complex numbers"
801
diff = left - right
802
real_diff = diff.real()
803
imag_diff = diff.imag()
804
if op == 0: #<
805
return real_diff < 0 or (real_diff == 0 and imag_diff < 0)
806
elif op == 1: #<=
807
return real_diff < 0 or (real_diff == 0 and imag_diff <= 0)
808
elif op == 4: #>
809
return real_diff > 0 or (real_diff == 0 and imag_diff > 0)
810
elif op == 5: #>=
811
return real_diff > 0 or (real_diff == 0 and imag_diff >= 0)
812
813
def __cmp__(left, right):
814
"""
815
Intervals are compared lexicographically on the 4-tuple
816
(x.real().lower(), x.real().upper(), x.imag().lower(), x.imag().upper())
817
818
EXAMPLES::
819
820
sage: a = CIF(RIF(0,1), RIF(0,1))
821
sage: b = CIF(RIF(0,1), RIF(0,2))
822
sage: c = CIF(RIF(0,2), RIF(0,2))
823
sage: cmp(a, b)
824
-1
825
sage: cmp(b, c)
826
-1
827
sage: cmp(a, c)
828
-1
829
sage: cmp(a, a)
830
0
831
sage: cmp(b, a)
832
1
833
"""
834
return (<Element>left)._cmp(right)
835
836
837
cdef int _cmp_c_impl(left, sage.structure.element.Element right) except -2:
838
"""
839
Intervals are compared lexicographically on the 4-tuple
840
(x.real().lower(), x.real().upper(), x.imag().lower(), x.imag().upper())
841
842
TESTS:
843
sage: tests = []
844
sage: for rl in (0, 1):
845
... for ru in (rl, rl + 1):
846
... for il in (0, 1):
847
... for iu in (il, il + 1):
848
... tests.append((CIF(RIF(rl, ru), RIF(il, iu)), (rl, ru, il, iu)))
849
sage: for (i1, t1) in tests:
850
... for (i2, t2) in tests:
851
... assert(cmp(i1, i2) == cmp(t1, t2))
852
"""
853
cdef int a, b
854
a = mpfi_nan_p(left.__re)
855
b = mpfi_nan_p((<ComplexIntervalFieldElement>right).__re)
856
if a != b:
857
return -1
858
859
cdef int i
860
i = mpfr_cmp(&left.__re.left, &(<ComplexIntervalFieldElement>right).__re.left)
861
if i < 0:
862
return -1
863
elif i > 0:
864
return 1
865
i = mpfr_cmp(&left.__re.right, &(<ComplexIntervalFieldElement>right).__re.right)
866
if i < 0:
867
return -1
868
elif i > 0:
869
return 1
870
i = mpfr_cmp(&left.__im.left, &(<ComplexIntervalFieldElement>right).__im.left)
871
if i < 0:
872
return -1
873
elif i > 0:
874
return 1
875
i = mpfr_cmp(&left.__im.right, &(<ComplexIntervalFieldElement>right).__im.right)
876
if i < 0:
877
return -1
878
elif i > 0:
879
return 1
880
return 0
881
882
########################################################################
883
# Transcendental (and other) functions
884
########################################################################
885
886
def argument(self):
887
r"""
888
The argument (angle) of the complex number, normalized
889
so that $-\pi < \theta.lower() \leq \pi$.
890
891
We raise a ValueError if the interval strictly contains 0,
892
or if the interval contains only 0.
893
894
WARNING: We do not always use the standard branch cut for
895
argument! If the interval crosses the negative real axis,
896
then the argument will be an interval whose lower bound is
897
less than $\pi$ and whose upper bound is more than $\pi$; in
898
effect, we move the branch cut away from the interval.
899
900
EXAMPLES:
901
sage: i = CIF.0
902
sage: (i^2).argument()
903
3.141592653589794?
904
sage: (1+i).argument()
905
0.785398163397449?
906
sage: i.argument()
907
1.570796326794897?
908
sage: (-i).argument()
909
-1.570796326794897?
910
sage: (RR('-0.001') - i).argument()
911
-1.571796326461564?
912
sage: CIF(2).argument()
913
0
914
sage: CIF(-2).argument()
915
3.141592653589794?
916
917
Here we see that if the interval crosses the negative real
918
axis, then the argument() can exceed $\pi$, and we
919
we violate the standard interval guarantees in the process:
920
sage: CIF(-2, RIF(-0.1, 0.1)).argument().str(style='brackets')
921
'[3.0916342578678501 .. 3.1915510493117365]'
922
sage: CIF(-2, -0.1).argument()
923
-3.091634257867851?
924
"""
925
if mpfi_has_zero(self.__re) and mpfi_has_zero(self.__im):
926
927
if mpfi_is_zero(self.__re) and mpfi_is_zero(self.__im):
928
raise ValueError, "Can't take the argument of complex zero"
929
if not mpfi_is_nonpos(self.__re) and not mpfi_is_nonneg(self.__re) \
930
and not mpfi_is_nonpos(self.__im) and not mpfi_is_nonneg(self.__im):
931
raise ValueError, "Can't take the argument of interval strictly containing zero"
932
933
# Now if we exclude zero from the interval, we know that the
934
# argument of the remaining points is bounded. Check which
935
# axes the interval extends along (we can deduce information
936
# about the quadrants from information about the axes).
937
938
which_axes = [False, False, False, False]
939
if not mpfi_is_nonpos(self.__re):
940
which_axes[0] = True
941
if not mpfi_is_nonpos(self.__im):
942
which_axes[1] = True
943
if not mpfi_is_nonneg(self.__re):
944
which_axes[2] = True
945
if not mpfi_is_nonneg(self.__im):
946
which_axes[3] = True
947
948
lower = None
949
for i in range(-1, 3):
950
if which_axes[i % 4] and not which_axes[(i - 1) % 4]:
951
if lower is not None:
952
raise ValueError, "Can't take the argument of line-segment interval strictly containing zero"
953
lower = i
954
955
for i in range(lower, lower+4):
956
if which_axes[i % 4] and not which_axes[(i + 1) % 4]:
957
upper = i
958
break
959
960
fld = self.parent()._real_field()
961
return fld.pi() * fld(lower, upper) * fld(0.5)
962
963
else:
964
965
# OK, we know that the interval is bounded away from zero
966
# in either the real or the imaginary direction (or both).
967
# We'll handle the "bounded away in the imaginary direction"
968
# case first.
969
970
fld = self.parent()._real_field()
971
972
if mpfi_is_strictly_pos(self.__im):
973
return (-self.real() / self.imag()).arctan() + fld.pi()/2
974
if mpfi_is_strictly_neg(self.__im):
975
return (-self.real() / self.imag()).arctan() - fld.pi()/2
976
977
if mpfi_is_strictly_pos(self.__re):
978
return (self.imag() / self.real()).arctan()
979
980
# The only remaining case is that self.__re is strictly
981
# negative and self.__im contains 0. In that case, we
982
# return an interval containing pi.
983
984
return (self.imag() / self.real()).arctan() + fld.pi()
985
986
def arg(self):
987
"""
988
Same as argument.
989
990
EXAMPLES:
991
sage: i = CIF.0
992
sage: (i^2).arg()
993
3.141592653589794?
994
"""
995
return self.argument()
996
997
def crosses_log_branch_cut(self):
998
"""
999
Returns true if this interval crosses the standard branch cut
1000
for log() (and hence for exponentiation) and for argument.
1001
(Recall that this branch cut is infinitesimally below the
1002
negative portion of the real axis.)
1003
"""
1004
1005
if mpfi_is_nonneg(self.__re):
1006
return False
1007
if mpfi_is_nonneg(self.__im):
1008
return False
1009
if mpfi_is_neg(self.__im):
1010
return False
1011
return True
1012
1013
def conjugate(self):
1014
"""
1015
Return the complex conjugate of this complex number.
1016
1017
EXAMPLES:
1018
sage: i = CIF.0
1019
sage: (1+i).conjugate()
1020
1 - 1*I
1021
"""
1022
cdef ComplexIntervalFieldElement x
1023
x = self._new()
1024
1025
mpfi_set(x.__re, self.__re)
1026
mpfi_neg(x.__im, self.__im)
1027
return x
1028
1029
def exp(self):
1030
"""
1031
Compute exp(z).
1032
1033
EXAMPLES:
1034
sage: i = ComplexIntervalField(300).0
1035
sage: z = 1 + i
1036
sage: z.exp()
1037
1.46869393991588515713896759732660426132695673662900872279767567631093696585951213872272450? + 2.28735528717884239120817190670050180895558625666835568093865811410364716018934540926734485?*I
1038
"""
1039
mag = self.real().exp()
1040
theta = self.imag()
1041
re = theta.cos() * mag
1042
im = theta.sin() * mag
1043
return ComplexIntervalFieldElement(self._parent, re, im)
1044
1045
def log(self,base=None):
1046
"""
1047
Complex logarithm of z. WARNING: This does always not use the
1048
standard branch cut for complex log! See the docstring for
1049
argument() to see what we do instead.
1050
1051
EXAMPLES::
1052
1053
sage: a = CIF(RIF(3, 4), RIF(13, 14))
1054
sage: a.log().str(style='brackets')
1055
'[2.5908917751460420 .. 2.6782931373360067] + [1.2722973952087170 .. 1.3597029935721503]*I'
1056
sage: a.log().exp().str(style='brackets')
1057
'[2.7954667135098274 .. 4.2819545928390213] + [12.751682453911920 .. 14.237018048974635]*I'
1058
sage: a in a.log().exp()
1059
True
1060
1061
If the interval crosses the negative real axis, then we don't
1062
use the standard branch cut (and we violate the interval guarantees)::
1063
1064
sage: CIF(-3, RIF(-1/4, 1/4)).log().str(style='brackets')
1065
'[1.0986122886681095 .. 1.1020725100903968] + [3.0584514217013518 .. 3.2247338854782349]*I'
1066
sage: CIF(-3, -1/4).log()
1067
1.102072510090397? - 3.058451421701352?*I
1068
1069
Usually if an interval contains zero, we raise an exception::
1070
1071
sage: CIF(RIF(-1,1),RIF(-1,1)).log()
1072
Traceback (most recent call last):
1073
...
1074
ValueError: Can't take the argument of interval strictly containing zero
1075
1076
But we allow the exact input zero::
1077
1078
sage: CIF(0).log()
1079
[-infinity .. -infinity]
1080
1081
If a base is passed from another function, we can accommodate this::
1082
1083
sage: CIF(-1,1).log(2)
1084
0.500000000000000? + 3.399270106370396?*I
1085
"""
1086
if self == 0:
1087
from real_mpfi import RIF
1088
return RIF(0).log()
1089
theta = self.argument()
1090
rho = abs(self)
1091
if base is None or base is 'e':
1092
return ComplexIntervalFieldElement(self._parent, rho.log(), theta)
1093
else:
1094
from real_mpfr import RealNumber, RealField
1095
return ComplexIntervalFieldElement(self._parent, rho.log()/RealNumber(RealField(self.prec()),base).log(), theta/RealNumber(RealField(self.prec()),base).log())
1096
1097
def sqrt(self, bint all=False, **kwds):
1098
"""
1099
The square root function.
1100
1101
WARNING: We approximate the standard branch cut along the
1102
negative real axis, with sqrt(-r^2) = i*r for positive real r;
1103
but if the interval crosses the negative real axis, we pick
1104
the root with positive imaginary component for the entire
1105
interval.
1106
1107
INPUT:
1108
all -- bool (default: False); if True, return a list
1109
of all square roots.
1110
1111
EXAMPLES:
1112
sage: CIF(-1).sqrt()^2
1113
-1
1114
sage: sqrt(CIF(2))
1115
1.414213562373095?
1116
sage: sqrt(CIF(-1))
1117
1*I
1118
sage: sqrt(CIF(2-I))^2
1119
2.00000000000000? - 1.00000000000000?*I
1120
sage: CC(-2-I).sqrt()^2
1121
-2.00000000000000 - 1.00000000000000*I
1122
1123
Here, we select a non-principal root for part of the interval, and
1124
violate the standard interval guarantees:
1125
sage: CIF(-5, RIF(-1, 1)).sqrt().str(style='brackets')
1126
'[-0.22250788030178321 .. 0.22250788030178296] + [2.2251857651053086 .. 2.2581008643532262]*I'
1127
sage: CIF(-5, -1).sqrt()
1128
0.222507880301783? - 2.247111425095870?*I
1129
"""
1130
if self.is_zero():
1131
return [self] if all else self
1132
if mpfi_is_zero(self.__im) and not mpfi_has_zero(self.__re):
1133
if mpfr_sgn(&self.__re.left) > 0:
1134
x = ComplexIntervalFieldElement(self._parent, self.real().sqrt(), 0)
1135
else:
1136
x = ComplexIntervalFieldElement(self._parent, 0, (-self.real()).sqrt())
1137
else:
1138
theta = self.argument()/2
1139
rho = abs(self).sqrt()
1140
x = ComplexIntervalFieldElement(self._parent, rho*theta.cos(), rho*theta.sin())
1141
if all:
1142
return [x, -x]
1143
else:
1144
return x
1145
1146
1147
def is_square(self):
1148
"""
1149
This function always returns true as $\C$ is algebraically closed.
1150
"""
1151
return True
1152
1153
# def algdep(self, n, **kwds):
1154
# """
1155
# Returns a polynomial of degree at most $n$ which is approximately
1156
# satisfied by this complex number. Note that the returned polynomial
1157
# need not be irreducible, and indeed usually won't be if $z$ is a good
1158
# approximation to an algebraic number of degree less than $n$.
1159
1160
# ALGORITHM: Uses the PARI C-library algdep command.
1161
1162
# INPUT: Type algdep? at the top level prompt. All additional
1163
# parameters are passed onto the top-level algdep command.
1164
1165
# EXAMPLE:
1166
# sage: C = ComplexIntervalField()
1167
# sage: z = (1/2)*(1 + sqrt(3.0) *C.0); z
1168
# 0.500000000000000 + 0.866025403784439*I
1169
# sage: p = z.algdep(5); p
1170
# x^5 + x^2
1171
# sage: p.factor()
1172
# (x + 1) * x^2 * (x^2 - x + 1)
1173
# sage: z^2 - z + 1
1174
# 0.000000000000000111022302462516
1175
# """
1176
# import sage.rings.arith
1177
# return sage.rings.arith.algdep(self,n, **kwds)
1178
1179
# def algebraic_dependancy( self, n ):
1180
# return self.algdep( n )
1181
1182
def make_ComplexIntervalFieldElement0( fld, re, im ):
1183
x = ComplexIntervalFieldElement( fld, re, im )
1184
return x
1185
1186
1187
1188
def create_ComplexIntervalFieldElement(s_real, s_imag=None, int pad=0, min_prec=53):
1189
r"""
1190
Return the complex number defined by the strings s_real and s_imag as an element of
1191
\code{ComplexIntervalField(prec=n)}, where n potentially has slightly more
1192
(controlled by pad) bits than given by s.
1193
1194
INPUT:
1195
1196
s_real -- a string that defines a real number (or something whose
1197
string representation defines a number)
1198
s_imag -- a string that defines a real number (or something whose
1199
string representation defines a number)
1200
pad -- an integer >= 0.
1201
min_prec -- number will have at least this many bits of precision, no matter what.
1202
1203
EXAMPLES:
1204
1205
sage: ComplexIntervalFieldElement('2.3')
1206
2.300000000000000?
1207
sage: ComplexIntervalFieldElement('2.3','1.1')
1208
2.300000000000000? + 1.100000000000000?*I
1209
sage: ComplexIntervalFieldElement(10)
1210
10
1211
sage: ComplexIntervalFieldElement(10,10)
1212
10 + 10*I
1213
sage: ComplexIntervalFieldElement(1.000000000000000000000000000,2)
1214
1 + 2*I
1215
sage: ComplexIntervalFieldElement(1,2.000000000000000000000)
1216
1 + 2*I
1217
sage: ComplexIntervalFieldElement(1.234567890123456789012345, 5.4321098654321987654321)
1218
1.234567890123456789012350? + 5.432109865432198765432000?*I
1219
1220
TESTS:
1221
1222
Make sure we've rounded up log(10,2) enough to guarantee
1223
sufficient precision (trac #10164). This is a little tricky
1224
because at the time of writing, we don't support intervals long
1225
enough to trip the error. However, at least we can make sure that
1226
we either do it correctly or fail noisily::
1227
1228
sage: c_CIFE = sage.rings.complex_interval.create_ComplexIntervalFieldElement
1229
sage: for kp in range(2,6):
1230
... s = '1.' + '0'*10**kp + '1'
1231
... try:
1232
... assert c_CIFE(s,0).real()-1 != 0
1233
... assert c_CIFE(0,s).imag()-1 != 0
1234
... except TypeError:
1235
... pass
1236
1237
"""
1238
if s_imag is None:
1239
s_imag = 0
1240
1241
if not isinstance(s_real, str):
1242
s_real = str(s_real).strip()
1243
if not isinstance(s_imag, str):
1244
s_imag = str(s_imag).strip()
1245
#if base == 10:
1246
bits = max(int(LOG_TEN_TWO_PLUS_EPSILON*len(s_real)),
1247
int(LOG_TEN_TWO_PLUS_EPSILON*len(s_imag)))
1248
#else:
1249
# bits = max(int(math.log(base,2)*len(s_imag)),int(math.log(base,2)*len(s_imag)))
1250
1251
C = complex_interval_field.ComplexIntervalField(prec=max(bits+pad, min_prec))
1252
return ComplexIntervalFieldElement(C, s_real, s_imag)
1253
1254