Initial commit
This commit is contained in:
commit
3cf6b0d1dc
6
Makefile.am
Normal file
6
Makefile.am
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
SUBDIRS = lib tests
|
||||||
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
|
dist-hook:
|
||||||
|
cp README.md $(distdir)
|
||||||
|
cp ZVK.py $(distdir)
|
||||||
|
cp sage-sirocco_interface.pyx $(distdir)
|
||||||
211
README.md
Normal file
211
README.md
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
# Sirocco Is a ROot Certified COntinuator
|
||||||
|
|
||||||
|
## General description.
|
||||||
|
|
||||||
|
This is a library for computing homotopy continuation of a given root of one
|
||||||
|
dimensional sections of bivariate complex polynomials. The output is a
|
||||||
|
piecewise linear aproximation of the path followed by the root, with the
|
||||||
|
property that there is a tubular neighborhood, with square transversal section,
|
||||||
|
that contains the actual path, and there is a three times thicker tubular
|
||||||
|
neigborhood guaranted to contain no other root of the polynomial. This second
|
||||||
|
property ensures that the piecewise linear approximation computed from all roots
|
||||||
|
of a polynomial form a topologically correct deformation of the actual braid,
|
||||||
|
since the inner tubular neighborhoods cannot intersect.
|
||||||
|
|
||||||
|
The first version of the library was written in C, and provided only double
|
||||||
|
precission. This is the second version, rewritten in C++, and provides the
|
||||||
|
possibility of using arbitrary precission computations. Hence, it deppends on
|
||||||
|
the [MPFR](http://www.mpfr.org/) and [GMP](https://gmplib.org/) libraries.
|
||||||
|
|
||||||
|
## Authors:
|
||||||
|
|
||||||
|
- Miguel Marco
|
||||||
|
- Marcos Rodriguez
|
||||||
|
|
||||||
|
## Usage:
|
||||||
|
|
||||||
|
After installing the library, you can call it from any .cpp program by calling
|
||||||
|
the homotopyPath or homotopyPath_mp functions. In the file test/test_example you can see a simple
|
||||||
|
example
|
||||||
|
|
||||||
|
- Double precission:
|
||||||
|
|
||||||
|
The input of the homotopyPath function is the following:
|
||||||
|
|
||||||
|
- An integer representing the total degree of the polynomial
|
||||||
|
- A malloc'ed array of double precission floats. Each four consecutive entries
|
||||||
|
of this list represent a coefficient, in the form of a rectangular complex
|
||||||
|
interval. These four numbers represent the following:
|
||||||
|
- the lower bound of the real part
|
||||||
|
- the upper bound of the real part
|
||||||
|
- the lower bound of the imaginary part
|
||||||
|
- the upper bound of the imaginary part
|
||||||
|
|
||||||
|
These coefficients are written in increasing deglex order. That is, the first
|
||||||
|
coefficients are the corresponding to the monomials $1, x, y, x^2, x y, y^2,
|
||||||
|
x^3, x^2 y, x y^2, y^3...$
|
||||||
|
|
||||||
|
- A double precission float corresponding to the real part of an approximate
|
||||||
|
solution y0
|
||||||
|
- A double precission float corresponding to the imaginary part of an
|
||||||
|
approximate solution y0
|
||||||
|
|
||||||
|
The use of complex intervals allows us to represent polynomials with non
|
||||||
|
rational coefficients (even transcendental): just give an interval that
|
||||||
|
contains it.
|
||||||
|
|
||||||
|
y0 must be an approximation of a simple root of the univariate polynomial
|
||||||
|
f(0,y).
|
||||||
|
|
||||||
|
For example, the input 1, [2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 3.2, 3.2, -4.5, -4.5,
|
||||||
|
0.7, 0.7], 6.1, -3.3 would represent the polynomial of degree 1 f(x,y)=(2) +
|
||||||
|
(3.2*i)*x + (-4.5 + 0.7)*y , and the approximate root y0= 6.1-3.3*i
|
||||||
|
|
||||||
|
The output is a malloc'ed array of double floats. The first entry represents
|
||||||
|
the number of points in the piecewise linear path. Then, each three entries
|
||||||
|
correspond to one of these points. The first entry of these triplets is the x
|
||||||
|
coordinate of the point (will be a real number between 0 and 1), the next two
|
||||||
|
are the real and imaginary parts of the y coordinate.
|
||||||
|
|
||||||
|
This path represents the movement of the root y0 of f(x,y) when x varies from 0
|
||||||
|
to 1. So for each t between 0 and 1, there is a value y_t which is the linear
|
||||||
|
interpolation of the returned values. The computation certifies that for each
|
||||||
|
t, there is a square neighborhood centered around y_t that contains one and
|
||||||
|
only one root of f(t,y). That is, there is a tube around the piecewise linear
|
||||||
|
path that contains the actual path followed by y0. Moreover, the corresponding
|
||||||
|
tubes of two different roots computed this way will not intersect.
|
||||||
|
|
||||||
|
Note that the method might fail if there is a singularity (i.e. a value xt for
|
||||||
|
which f(xt, y) has multiple roots). In that case, you will either get a NULL
|
||||||
|
value, or an infinite running time.
|
||||||
|
|
||||||
|
- Arbitrary precission
|
||||||
|
|
||||||
|
The input of the homotopyPath_mp function is the following:
|
||||||
|
|
||||||
|
- An integer representing the total degree of the polynomial
|
||||||
|
- A malloc'ed array of mpfr_t numbers. As before, each four entries
|
||||||
|
represent an (intervalar) coefficient of a polynomial, following
|
||||||
|
increasing deglex order.
|
||||||
|
- A mpfr_t number corresponding to the real part of an approximate
|
||||||
|
solution y0
|
||||||
|
- A mpfr_t number corresponding to the imaginary part of an
|
||||||
|
approximate solution y0
|
||||||
|
- An integer representing the precission to be used in the internal
|
||||||
|
computations (and the output).
|
||||||
|
|
||||||
|
The output is a malloc'ed array of mpfr_t numbers as before, being the first
|
||||||
|
equal to the length of the list of points.
|
||||||
|
|
||||||
|
|
||||||
|
### From [SageMath](https://www.sagemath.org)
|
||||||
|
|
||||||
|
If you have the library and headers installed correctly, you can call this
|
||||||
|
library from a [sagemath](https://www.sagemath.org) session. The relevant files
|
||||||
|
for that are `sage-sirocco_interface.pyx` and `ZVK.py`. The first one contains
|
||||||
|
the interface code, and the second one several functions to compute the
|
||||||
|
fundamental group of the complement of a curve in the complex plane, using this
|
||||||
|
library. Reffer to the comments in `ZVK.py` for a more detailed explanation of
|
||||||
|
the functions available there.
|
||||||
|
|
||||||
|
An example of session using this library can be the following
|
||||||
|
|
||||||
|
```
|
||||||
|
sage: load("sage-sirocco_interface.pyx")
|
||||||
|
Compiling ./sage-sirocco_interface.pyx...
|
||||||
|
sage: load("ZVK.py")
|
||||||
|
sage: R.<x,y>=QQ[]
|
||||||
|
sage: f = x^4*y - x^2*y - y^2 + y
|
||||||
|
sage: followstrand(f, 0, 2, 1)
|
||||||
|
[(0.0, 1.0, 0.0),
|
||||||
|
(0.08838834764831845, 0.9697265625, 0.0),
|
||||||
|
(0.18495073095668707, 0.8818945614497176, 0.0),
|
||||||
|
(0.2830354627446311, 0.7822431249849692, 0.0),
|
||||||
|
(0.36442245301616083, 0.7509743697977961, 0.0),
|
||||||
|
(0.4162134713480532, 0.7872237656367932, 0.0),
|
||||||
|
(0.460346631682259, 0.8708786602233393, 0.0),
|
||||||
|
(0.5011524089991131, 1.0046362459291838, 0.0),
|
||||||
|
(0.5406631526749315, 1.1979177532866128, 0.0),
|
||||||
|
(0.5801060727487398, 1.465872049076292, 0.0),
|
||||||
|
(0.6203344167290801, 1.830059589826348, 0.0),
|
||||||
|
(0.6620003579483648, 2.319953607100401, 0.0),
|
||||||
|
(0.7056383582405797, 2.975174768739414, 0.0),
|
||||||
|
(0.7517106691371234, 3.848570611753438, 0.0),
|
||||||
|
(0.8006345979664276, 5.010356224191542, 0.0),
|
||||||
|
(0.8528001455202311, 6.553629601012362, 0.0),
|
||||||
|
(0.908582197461905, 8.601688407025646, 0.0),
|
||||||
|
(0.9683494644216709, 11.317718460782247, 0.0),
|
||||||
|
(1.0, 13.0, 0.0)]
|
||||||
|
sage: fundamental_group(f)
|
||||||
|
Finitely presented group < x0, x1 | x1*x0*x1^-1*x0^-1 >
|
||||||
|
```
|
||||||
|
|
||||||
|
The command followstrand shows the path followed y the root y0=1 of f(x,y) when
|
||||||
|
x varies from 0 o 2. It accepts an optional argument called `prec`, for the precission
|
||||||
|
to use. By default it is set to 53 (and uses the double precission implementation). If
|
||||||
|
the computation fails, it falls back to a bigger precission until it succeeds).
|
||||||
|
The command fundamental_group uses this approach to
|
||||||
|
compute the braid monodromy associated to this polynomial, and then uses it to
|
||||||
|
compute the fundamental group of its complement, using Zariski-VanKampen method.
|
||||||
|
|
||||||
|
At some point we expect to have this included in SageMath as an optional (or
|
||||||
|
maybe even standard) package. When that happens, we will probably provide a
|
||||||
|
more natural interface for the fundamental group and/or braid monodromy
|
||||||
|
computation.
|
||||||
|
|
||||||
|
## Dependencies:
|
||||||
|
|
||||||
|
The deppendencies are:
|
||||||
|
|
||||||
|
- autotools/libtools/autoconf if you want to generate the configuration
|
||||||
|
scripts (only needed if you get the source code from a git repository)
|
||||||
|
- /make/gcc for the build process (you need them to build from a source
|
||||||
|
tarball)
|
||||||
|
- standard c libraries (math, io and std)
|
||||||
|
- mpfr
|
||||||
|
- gmp
|
||||||
|
|
||||||
|
|
||||||
|
## Installation:
|
||||||
|
|
||||||
|
### From the git repository
|
||||||
|
|
||||||
|
You can get the git repository by running
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone https://github.com/miguelmarco/SIROCCO2.git
|
||||||
|
```
|
||||||
|
|
||||||
|
And then cd in the directory and run
|
||||||
|
|
||||||
|
```
|
||||||
|
autoreconf --install
|
||||||
|
```
|
||||||
|
|
||||||
|
to create the configure script then from there you can continue as usual:
|
||||||
|
|
||||||
|
```
|
||||||
|
./configure
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
|
This last line might require superuser privileges for writing in system folders
|
||||||
|
|
||||||
|
### From a tar.gz package
|
||||||
|
|
||||||
|
If you got a tarball produced by a `make dist`command, just unpack it and run
|
||||||
|
|
||||||
|
```
|
||||||
|
./configure
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
|
as before.
|
||||||
|
|
||||||
|
## To do:
|
||||||
|
|
||||||
|
- include an option for passing the factors of the polynomial, for the cases
|
||||||
|
where the original polynomial is reducible. This might speed up the computations
|
||||||
|
|
||||||
426
ZVK.py
Normal file
426
ZVK.py
Normal file
@ -0,0 +1,426 @@
|
|||||||
|
"""
|
||||||
|
Zariski-Van Kampen method implementation
|
||||||
|
|
||||||
|
This file contains functions to compute the fundamental group of
|
||||||
|
the complement of a curve in the complex affine plane, using
|
||||||
|
Zariski-Van Kampen approach. It deppends on the package...
|
||||||
|
|
||||||
|
AUTHORS:
|
||||||
|
|
||||||
|
- Miguel Marco (2015-09-30): Initial version
|
||||||
|
|
||||||
|
|
||||||
|
EXAMPLES::
|
||||||
|
|
||||||
|
sage: R.<x,y> = QQ[]
|
||||||
|
sage: f = y^3 + x^3 -1
|
||||||
|
sage: fundamental_group(f)
|
||||||
|
Finitely presented group < x0 | >
|
||||||
|
"""
|
||||||
|
|
||||||
|
#*****************************************************************************
|
||||||
|
# Copyright (C) 2015 Miguel Marco <mmarco@unizar.es>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
# http://www.gnu.org/licenses/
|
||||||
|
#*****************************************************************************
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
from sage.groups.braid import BraidGroup
|
||||||
|
from sage.groups.perm_gps.permgroup_named import SymmetricGroup
|
||||||
|
from sage.rings.rational_field import QQ
|
||||||
|
from sage.rings.qqbar import QQbar
|
||||||
|
from scipy.spatial import Voronoi
|
||||||
|
from numpy import array, vstack
|
||||||
|
from sage.rings.all import CC, CIF
|
||||||
|
from sage.rings.complex_field import ComplexField
|
||||||
|
from sage.rings.complex_interval_field import ComplexIntervalField
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def braid_from_piecewise(strands):
|
||||||
|
"""
|
||||||
|
Compute the braid corresponding to the piecewise linear curves strands.
|
||||||
|
strands is a list whose elements are a list of pairs (x,y), where x is
|
||||||
|
a real number between 0 and 1, and y is a complex number.
|
||||||
|
|
||||||
|
INPUT:
|
||||||
|
|
||||||
|
- A list of lists of tuples (t, c), where t is a number bewteen 0 and 1,
|
||||||
|
and c is a complex number.
|
||||||
|
|
||||||
|
OUTPUT:
|
||||||
|
|
||||||
|
The braid formed by the piecewise linear strands.
|
||||||
|
|
||||||
|
EXAMPLES::
|
||||||
|
|
||||||
|
sage: paths = [[(0, I), (0.2, -1 - 0.5*I), (0.8, -1), (1, -I)], [(0, -1), (0.5, -I), (1, 1)], [(0, 1), (0.5, 1 + I), (1, I)]]
|
||||||
|
sage: braid_from_piecewise(paths)
|
||||||
|
s0*s1
|
||||||
|
|
||||||
|
"""
|
||||||
|
L = strands
|
||||||
|
i = min([L[k][1][0] for k in range(len(L))])
|
||||||
|
totalpoints = [[[a[0][1].real(), a[0][1].imag()]] for a in L]
|
||||||
|
indices = [1 for a in range(len(L))]
|
||||||
|
while i < 1:
|
||||||
|
for j in range(len(L)):
|
||||||
|
if L[j][indices[j]][0] > i:
|
||||||
|
xaux = L[j][indices[j] - 1][1]
|
||||||
|
yaux = L[j][indices[j]][1]
|
||||||
|
aaux = L[j][indices[j] - 1][0]
|
||||||
|
baux = L[j][indices[j]][0]
|
||||||
|
interpola = xaux + (yaux - xaux)*(i - aaux)/(baux - aaux)
|
||||||
|
totalpoints[j].append([interpola.real(), interpola.imag()])
|
||||||
|
else:
|
||||||
|
totalpoints[j].append([L[j][indices[j]][1].real(), L[j][indices[j]][1].imag()])
|
||||||
|
indices[j] = indices[j] + 1
|
||||||
|
i = min([L[k][indices[k]][0] for k in range(len(L))])
|
||||||
|
for j in range(len(L)):
|
||||||
|
totalpoints[j].append([L[j][-1][1].real(), L[j][-1][1].imag()])
|
||||||
|
braid = []
|
||||||
|
G = SymmetricGroup(len(totalpoints))
|
||||||
|
for i in range(len(totalpoints[0]) - 1):
|
||||||
|
l1 = [totalpoints[j][i] for j in range(len(L))]
|
||||||
|
l2 = [totalpoints[j][i+1] for j in range(len(L))]
|
||||||
|
M = [[l1[s], l2[s]] for s in range(len(l1))]
|
||||||
|
M.sort()
|
||||||
|
l1 = [a[0] for a in M]
|
||||||
|
l2 = [a[1] for a in M]
|
||||||
|
cruces = []
|
||||||
|
for j in range(len(l2)):
|
||||||
|
for k in range(j):
|
||||||
|
if l2[j] < l2[k]:
|
||||||
|
t = (l1[j][0] - l1[k][0])/(l2[k][0] - l1[k][0] + l1[j][0] - l2[j][0])
|
||||||
|
s = cmp(l1[k][1]*(1 - t) + t*l2[k][1], l1[j][1]*(1 - t) + t*l2[j][1])
|
||||||
|
cruces.append([t, k, j, -s])
|
||||||
|
if len(cruces) > 0:
|
||||||
|
cruces.sort()
|
||||||
|
P = G(Permutation([]))
|
||||||
|
while cruces:
|
||||||
|
# we select the crosses in the same t
|
||||||
|
crucesl = [c for c in cruces if c[0]==cruces[0][0]]
|
||||||
|
crossesl = [(P(c[2]+1) - P(c[1]+1),c[1],c[2],c[3]) for c in crucesl]
|
||||||
|
cruces = cruces[len(crucesl):]
|
||||||
|
while crossesl:
|
||||||
|
crossesl.sort()
|
||||||
|
c = crossesl.pop(0)
|
||||||
|
braid.append(c[3]*min(map(P, [c[1] + 1, c[2] + 1])))
|
||||||
|
P = G(Permutation([(c[1] + 1, c[2] + 1)]))*P
|
||||||
|
crossesl = [(P(c[2]+1) - P(c[1]+1),c[1],c[2],c[3]) for c in crossesl]
|
||||||
|
B = BraidGroup(len(L))
|
||||||
|
return B(braid)
|
||||||
|
|
||||||
|
|
||||||
|
def discrim(f):
|
||||||
|
"""
|
||||||
|
Return the points in the discriminant of f. f must be a polynomial in two variables with coefficients in a
|
||||||
|
number field with a fixed embedding in QQbar. The result is the set of values of the first variable for which
|
||||||
|
two roots in the second variable coincide.
|
||||||
|
|
||||||
|
INPUT:
|
||||||
|
|
||||||
|
- ``f`` -- a polynomial in two variables, with coefficients in a number field with a fixed embedding in QQbar.
|
||||||
|
|
||||||
|
OUTPUT:
|
||||||
|
|
||||||
|
A list with the values of the discriminant in QQbar
|
||||||
|
|
||||||
|
EXAMPLES::
|
||||||
|
|
||||||
|
sage: R.<x,y> = QQ[]
|
||||||
|
sage: f = (y^3 + x^3 -1) * (x+y)
|
||||||
|
sage: discrim(f)
|
||||||
|
[1,
|
||||||
|
-0.500000000000000? - 0.866025403784439?*I,
|
||||||
|
-0.500000000000000? + 0.866025403784439?*I]
|
||||||
|
|
||||||
|
"""
|
||||||
|
x, y = f.variables()
|
||||||
|
F = f.base_ring()
|
||||||
|
disc = F[x](f.discriminant(y).resultant(f, y)).roots(QQbar, multiplicities = False)
|
||||||
|
return disc
|
||||||
|
|
||||||
|
|
||||||
|
def segments(points):
|
||||||
|
"""
|
||||||
|
Return the bounded segments of the Voronoi diagram of the given points.
|
||||||
|
|
||||||
|
INPUT:
|
||||||
|
|
||||||
|
- A list of complex points.
|
||||||
|
|
||||||
|
OUTPUT:
|
||||||
|
|
||||||
|
A list of pairs (p1, p2) where p1 and p2 are the endpoints of the segments in the Voronoi diagram
|
||||||
|
|
||||||
|
EXAMPLES::
|
||||||
|
|
||||||
|
sage: R.<x,y> = QQ[]
|
||||||
|
sage: f = y^3 + x^3 -1
|
||||||
|
sage: disc = discrim(f)
|
||||||
|
sage: segments(disc)
|
||||||
|
[(-2.84740787203333 - 2.84740787203333*I,
|
||||||
|
-2.14285714285714 + 1.11022302462516e-16*I),
|
||||||
|
(-2.84740787203333 + 2.84740787203333*I,
|
||||||
|
-2.14285714285714 + 1.11022302462516e-16*I),
|
||||||
|
(2.50000000000000 + 2.50000000000000*I,
|
||||||
|
1.26513881334184 + 2.19128470333546*I),
|
||||||
|
(2.50000000000000 + 2.50000000000000*I,
|
||||||
|
2.50000000000000 - 2.50000000000000*I),
|
||||||
|
(1.26513881334184 + 2.19128470333546*I, 0.000000000000000),
|
||||||
|
(0.000000000000000, 1.26513881334184 - 2.19128470333546*I),
|
||||||
|
(2.50000000000000 - 2.50000000000000*I,
|
||||||
|
1.26513881334184 - 2.19128470333546*I),
|
||||||
|
(-2.84740787203333 + 2.84740787203333*I,
|
||||||
|
1.26513881334184 + 2.19128470333546*I),
|
||||||
|
(-2.14285714285714 + 1.11022302462516e-16*I, 0.000000000000000),
|
||||||
|
(-2.84740787203333 - 2.84740787203333*I,
|
||||||
|
1.26513881334184 - 2.19128470333546*I)]
|
||||||
|
|
||||||
|
"""
|
||||||
|
discpoints = array([(CC(a).real(), CC(a).imag()) for a in points])
|
||||||
|
added_points = 3*abs(discpoints).max() + 1.0
|
||||||
|
configuration = vstack([discpoints, array([[added_points, 0], [-added_points, 0], [0, added_points],[0, -added_points]])])
|
||||||
|
V = Voronoi(configuration)
|
||||||
|
res = []
|
||||||
|
for rv in V.ridge_vertices:
|
||||||
|
if not -1 in rv:
|
||||||
|
p1 = CC(list(V.vertices[rv[0]]))
|
||||||
|
p2 = CC(list(V.vertices[rv[1]]))
|
||||||
|
res.append((p1, p2))
|
||||||
|
return res
|
||||||
|
|
||||||
|
def followstrand(f, x0, x1, y0a, prec=53):
|
||||||
|
"""
|
||||||
|
Return a piecewise linear aproximation of the homotopy continuation of the root y0a
|
||||||
|
from x0 to x1
|
||||||
|
|
||||||
|
INPUT:
|
||||||
|
|
||||||
|
- ``f`` -- a polynomial in two variables
|
||||||
|
- ``x0`` -- a complex value, where the homotopy starts
|
||||||
|
- ``x1`` -- a complex value, where the homotopy ends
|
||||||
|
- ``y0a`` -- an approximate solution of the polynomial $F(y)=f(x_0,y)$
|
||||||
|
- ``prec`` -- the precission to use
|
||||||
|
|
||||||
|
OUTPUT:
|
||||||
|
|
||||||
|
A list of values (t, ytr, yti) such that:
|
||||||
|
- ``t`` is a real number between zero and one
|
||||||
|
- $f(t\cdot x_1+(1-t)\cdot x_0, y_{tr} + I\cdot y_{ti})$ is zero (or a good enough aproximation)
|
||||||
|
- the piecewise linear path determined by the points has a tubular
|
||||||
|
neighborhood where the actual homotopy continuation path lies, and
|
||||||
|
no other root intersects it.
|
||||||
|
|
||||||
|
EXAMPLES::
|
||||||
|
|
||||||
|
sage: R.<x,y> = QQ[]
|
||||||
|
sage: f = x^2 + y^3
|
||||||
|
sage: x0 = CC(1, 0)
|
||||||
|
sage: x1 = CC(1, 0.5)
|
||||||
|
sage: followstrand(f, x0, x1, -1.0) # optional
|
||||||
|
[(0.0, -1.0, 0.0),
|
||||||
|
(0.063125, -1.0001106593601545, -0.02104011456212618),
|
||||||
|
(0.12230468750000001, -1.0004151100003031, -0.04075695242737829),
|
||||||
|
(0.17778564453125, -1.0008762007617709, -0.059227299979315154),
|
||||||
|
(0.28181243896484376, -1.0021948141328698, -0.09380038023464156),
|
||||||
|
(0.3728358840942383, -1.0038270754728402, -0.123962953123039),
|
||||||
|
(0.4524813985824585, -1.005613540368227, -0.15026634875747985),
|
||||||
|
(0.5221712237596512, -1.0074443351354077, -0.17320066690539515),
|
||||||
|
(0.5831498207896948, -1.009246118007067, -0.1931978258913501),
|
||||||
|
(0.636506093190983, -1.0109719597443307, -0.21063630045261386),
|
||||||
|
(0.6831928315421101, -1.0125937110987449, -0.2258465242053158),
|
||||||
|
(0.7648946236565826, -1.0156754074572174, -0.2523480191006915),
|
||||||
|
(0.8261709677424369, -1.0181837235093538, -0.2721208327884435),
|
||||||
|
(0.8721282258068277, -1.0201720738092597, -0.2868892148703381),
|
||||||
|
(0.9410641129034139, -1.0233210275568283, -0.3089391941950436),
|
||||||
|
(1.0, -1.026166099551513, -0.3276894025360433)]
|
||||||
|
|
||||||
|
"""
|
||||||
|
CIF = ComplexIntervalField(prec)
|
||||||
|
CC = ComplexField(prec)
|
||||||
|
G = f.change_ring(QQbar).change_ring(CIF)
|
||||||
|
(x, y) = G.variables()
|
||||||
|
g = G.subs({x: (1-x)*CIF(x0) + x*CIF(x1)})
|
||||||
|
coefs = []
|
||||||
|
deg = g.total_degree()
|
||||||
|
for d in range(deg + 1):
|
||||||
|
for i in range(d + 1):
|
||||||
|
c = CIF(g.coefficient({x: d-i, y: i}))
|
||||||
|
cr = c.real()
|
||||||
|
ci = c.imag()
|
||||||
|
coefs += list(cr.endpoints())
|
||||||
|
coefs += list(ci.endpoints())
|
||||||
|
yr = CC(y0a).real()
|
||||||
|
yi = CC(y0a).imag()
|
||||||
|
try:
|
||||||
|
if prec == 53:
|
||||||
|
points = contpath(deg, coefs, yr, yi)
|
||||||
|
else:
|
||||||
|
points = contpath_mp(deg, coefs, yr, yi, prec)
|
||||||
|
return points
|
||||||
|
except:
|
||||||
|
return followstrand(f, x0, x1, y0a, 2*prec)
|
||||||
|
|
||||||
|
@parallel
|
||||||
|
def braid_in_segment(f, x0, x1):
|
||||||
|
"""
|
||||||
|
Return the braid formed by the y roots of f when x moves from
|
||||||
|
x0 to x1
|
||||||
|
|
||||||
|
INPUT:
|
||||||
|
|
||||||
|
- ``f`` -- a polynomial in two variables
|
||||||
|
- ``x0`` -- a complex number
|
||||||
|
- ``x1`` -- a complex number
|
||||||
|
|
||||||
|
- OUTPUT:
|
||||||
|
|
||||||
|
A braid
|
||||||
|
|
||||||
|
EXAMPLES::
|
||||||
|
|
||||||
|
sage: R.<x,y> = QQ[]
|
||||||
|
sage: f = x^2 + y^3
|
||||||
|
sage: x0 = CC(1,0)
|
||||||
|
sage: x1 = CC(1, 0.5)
|
||||||
|
sage: braid_in_segment(f, x0, x1) # optional -
|
||||||
|
s1
|
||||||
|
|
||||||
|
"""
|
||||||
|
CC = ComplexField(64)
|
||||||
|
(x, y) = f.variables()
|
||||||
|
I = QQbar.gen()
|
||||||
|
X0 = QQ(x0.real()) + I*QQ(x0.imag())
|
||||||
|
X1 = QQ(x1.real()) + I*QQ(x1.imag())
|
||||||
|
F0 = QQbar[y](f(x=X0))
|
||||||
|
y0s = F0.roots(multiplicities=False)
|
||||||
|
strands = [followstrand(f, x0, x1, CC(a)) for a in y0s]
|
||||||
|
complexstrands = [[(a[0], CC(a[1], a[2])) for a in b] for b in strands]
|
||||||
|
centralbraid = braid_from_piecewise(complexstrands)
|
||||||
|
initialstrands = []
|
||||||
|
y0aps = [c[0][1] for c in complexstrands]
|
||||||
|
used = []
|
||||||
|
for y0ap in y0aps:
|
||||||
|
distances = [((y0ap - y0).norm(), y0) for y0 in y0s]
|
||||||
|
y0 = sorted(distances)[0][1]
|
||||||
|
if y0 in used:
|
||||||
|
raise ValueError("different roots are too close")
|
||||||
|
used.append(y0)
|
||||||
|
initialstrands.append([(0, CC(y0)), (1, y0ap)])
|
||||||
|
initialbraid = braid_from_piecewise(initialstrands)
|
||||||
|
F1 = QQbar[y](f(x=X1))
|
||||||
|
y1s = F1.roots(multiplicities=False)
|
||||||
|
finalstrands = []
|
||||||
|
y1aps = [c[-1][1] for c in complexstrands]
|
||||||
|
used = []
|
||||||
|
for y1ap in y1aps:
|
||||||
|
distances = [((y1ap - y1).norm(), y1) for y1 in y1s]
|
||||||
|
y1 = sorted(distances)[0][1]
|
||||||
|
if y1 in used:
|
||||||
|
raise ValueError("different roots are too close")
|
||||||
|
used.append(y1)
|
||||||
|
finalstrands.append([(0, y1ap), (1, CC(y1))])
|
||||||
|
finallbraid = braid_from_piecewise(finalstrands)
|
||||||
|
return initialbraid*centralbraid*finallbraid
|
||||||
|
|
||||||
|
def fundamental_group(f, simplified=True, projective = False):
|
||||||
|
"""
|
||||||
|
Return a presentation of the fundamental group of the complement of the algebraic
|
||||||
|
set defined by the polynomial f.
|
||||||
|
|
||||||
|
INPUT:
|
||||||
|
|
||||||
|
- ``f`` -- a polynomial in two variables, with coefficients in either the rationals
|
||||||
|
or a number field with a fixed embedding in QQbar.
|
||||||
|
|
||||||
|
- ``simplified`` -- boolean (default: True). If set to True the presentation will be
|
||||||
|
simplified. Otherwise, the returned presentation has as many generators
|
||||||
|
as degree of the polynomial times the points in the base used to create
|
||||||
|
the segments that surround the discriminant. In this case, the generators
|
||||||
|
are granted to be meridians of the curve.
|
||||||
|
|
||||||
|
-- ``projective`` -- boolean (default: False). If set to True, the fundamental group of
|
||||||
|
the complement of the projective completion of the curve will be computed.
|
||||||
|
Otherwise, the fundamental group of the complement in the affine plane will
|
||||||
|
be computed.
|
||||||
|
|
||||||
|
OUTPUT:
|
||||||
|
|
||||||
|
A presentation of the fundamental group of the complement of the curve defined by ``f``.
|
||||||
|
|
||||||
|
EXAMPLES::
|
||||||
|
|
||||||
|
sage: R.<x,y> = QQ[]
|
||||||
|
sage: f = x^2 + y^3
|
||||||
|
sage: fundamental_group(f) # optional -
|
||||||
|
Finitely presented group < x0, x1 | x0^-1*x1*x0*x1*x0^-1*x1^-1 >
|
||||||
|
sage: fundamental_group(f, simplified=False) # optional
|
||||||
|
Finitely presented group < x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11 | x3*x9^-1, x4*x5*x4^-1*x10^-1, x4*x11^-1, x0*x1*x0^-1*x3^-1, x0*x4^-1, x2*x5^-1, x0*x6^-1, x2*x7^-1, x2^-1*x1*x2*x8^-1, x7*x9^-1, x7^-1*x6*x7*x10^-1, x8*x11^-1 >
|
||||||
|
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
sage: R.<x,y> = QQ[]
|
||||||
|
sage: f = y^3 + x^3
|
||||||
|
sage: fundamental_group(f) # optional
|
||||||
|
Finitely presented group < x0, x1, x2 | x1*x2*x1^-1*x0^-1*x2^-1*x0, x2*x0*x1*x0^-1*x2^-1*x1^-1 >
|
||||||
|
|
||||||
|
It is also possible to have coefficients in a number field with a fixed embedding in QQbar::
|
||||||
|
|
||||||
|
sage: zeta = QQbar['x']('x^2+x+1').roots(multiplicities = False)[0]
|
||||||
|
sage: zeta
|
||||||
|
-0.50000000000000000? - 0.866025403784439?*I
|
||||||
|
sage: F = NumberField(zeta.minpoly(), 'zeta', embedding = zeta)
|
||||||
|
sage: F.inj
|
||||||
|
F.inject_variables F.injvar
|
||||||
|
sage: F.inject_variables()
|
||||||
|
Defining zeta
|
||||||
|
sage: R.<x,y> = F[]
|
||||||
|
sage: f = y^3 + x^3 +zeta *x + 1
|
||||||
|
sage: fundamental_group(f)
|
||||||
|
Finitely presented group < x0 | >
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
(x, y) = f.variables()
|
||||||
|
F = f.base_ring()
|
||||||
|
g = f.factor().radical().prod()
|
||||||
|
d = g.degree(y)
|
||||||
|
while not g.coefficient(y**d) in F or (projective and g.total_degree() > d):
|
||||||
|
g = g.subs({x: x + y})
|
||||||
|
d = g.degree(y)
|
||||||
|
disc = discrim(g)
|
||||||
|
segs = segments(disc)
|
||||||
|
vertices = list(set(flatten(segs)))
|
||||||
|
Faux = FreeGroup(d)
|
||||||
|
F = FreeGroup(d * len(vertices))
|
||||||
|
rels = []
|
||||||
|
if projective:
|
||||||
|
rels.append(prod(F.gen(i) for i in range(d)))
|
||||||
|
braidscomputed = braid_in_segment([(g, seg[0], seg[1]) for seg in segs])
|
||||||
|
#braidscomputed = [(((g, seg[0], seg[1]), ), braid_in_segment(g,seg[0], seg[1])) for seg in segs]
|
||||||
|
for braidcomputed in braidscomputed:
|
||||||
|
seg = (braidcomputed[0][0][1], braidcomputed[0][0][2])
|
||||||
|
b = braidcomputed[1]
|
||||||
|
i = vertices.index(seg[0])
|
||||||
|
j = vertices.index(seg[1])
|
||||||
|
for k in range(d):
|
||||||
|
el1 = Faux([k + 1]) * b.inverse()
|
||||||
|
el2 = k + 1
|
||||||
|
w1 = F([sign(a)*d*i + a for a in el1.Tietze()])
|
||||||
|
w2 = F([d*j + el2])
|
||||||
|
rels.append(w1/w2)
|
||||||
|
G = F/rels
|
||||||
|
if simplified:
|
||||||
|
return G.simplified()
|
||||||
|
else:
|
||||||
|
return G
|
||||||
10
configure.ac
Normal file
10
configure.ac
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
AC_INIT([libsirocco], [2.0], [mmarco@unizar.es])
|
||||||
|
AC_CONFIG_AUX_DIR([build-aux])
|
||||||
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
|
: ${CXXFLAGS=-O0 -g}
|
||||||
|
AM_INIT_AUTOMAKE([foreign -Wall])
|
||||||
|
AM_PROG_AR
|
||||||
|
AC_PROG_CXX
|
||||||
|
LT_INIT
|
||||||
|
AC_CONFIG_FILES([Makefile lib/Makefile tests/Makefile])
|
||||||
|
AC_OUTPUT
|
||||||
104
include/icomplex.hpp
Normal file
104
include/icomplex.hpp
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
#ifndef _ICOMPLEX_HPP
|
||||||
|
#define _ICOMPLEX_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <complex>
|
||||||
|
#include <interval.hpp>
|
||||||
|
|
||||||
|
class IComplex {
|
||||||
|
public:
|
||||||
|
|
||||||
|
Interval r;
|
||||||
|
Interval i;
|
||||||
|
|
||||||
|
// CONSTRUCTORS
|
||||||
|
IComplex (double = 0);
|
||||||
|
IComplex (const Interval &, const Interval &);
|
||||||
|
IComplex (double, double, double, double);
|
||||||
|
IComplex (const std::complex<double> &);
|
||||||
|
IComplex (const IComplex &);
|
||||||
|
~IComplex ();
|
||||||
|
|
||||||
|
// ASSIGNMENT
|
||||||
|
IComplex & operator= (const IComplex &);
|
||||||
|
IComplex & operator= (const Interval &);
|
||||||
|
IComplex & operator= (const std::complex<double> &);
|
||||||
|
IComplex & operator= (double);
|
||||||
|
|
||||||
|
// COMPARISON
|
||||||
|
int operator== (const IComplex &) const;
|
||||||
|
int operator== (const std::complex<double> &) const;
|
||||||
|
int operator== (double) const;
|
||||||
|
int operator!= (const IComplex &) const;
|
||||||
|
int operator!= (const std::complex<double> &) const;
|
||||||
|
int operator!= (double) const;
|
||||||
|
|
||||||
|
// ARITHMETIC
|
||||||
|
IComplex operator+ (const IComplex &) const;
|
||||||
|
IComplex operator+ (const Interval &) const;
|
||||||
|
IComplex operator+ (const std::complex<double> &) const;
|
||||||
|
IComplex operator+ (double) const;
|
||||||
|
|
||||||
|
IComplex operator- () const;
|
||||||
|
IComplex operator- (const IComplex &) const;
|
||||||
|
IComplex operator- (const std::complex<double> &) const;
|
||||||
|
IComplex operator- (const Interval &) const;
|
||||||
|
IComplex operator- (double) const;
|
||||||
|
|
||||||
|
IComplex operator* (const IComplex &) const;
|
||||||
|
IComplex operator* (const std::complex<double> &) const;
|
||||||
|
IComplex operator* (const Interval &) const;
|
||||||
|
IComplex operator* (double) const;
|
||||||
|
|
||||||
|
IComplex operator/ (const IComplex &) const;
|
||||||
|
IComplex operator/ (const std::complex<double> &) const;
|
||||||
|
IComplex operator/ (const Interval &) const;
|
||||||
|
IComplex operator/ (double) const;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// MISC
|
||||||
|
IComplex inverse () const;
|
||||||
|
|
||||||
|
int containsZero () const;
|
||||||
|
int contains (double) const;
|
||||||
|
int contains (const std::complex<double> &);
|
||||||
|
int subset (const IComplex &) const;
|
||||||
|
int subsetEq (const IComplex &) const;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// NON MEMBER FUNCTIONS
|
||||||
|
|
||||||
|
std::ostream & operator<< (std::ostream &, const IComplex &);
|
||||||
|
|
||||||
|
|
||||||
|
IComplex operator+ (const Interval &, const IComplex &);
|
||||||
|
IComplex operator+ (const std::complex<double> &, const IComplex &);
|
||||||
|
IComplex operator+ (double, const IComplex &);
|
||||||
|
|
||||||
|
IComplex operator- (const Interval &, const IComplex &);
|
||||||
|
IComplex operator- (const std::complex<double> &, const IComplex &);
|
||||||
|
IComplex operator- (double, const IComplex &);
|
||||||
|
|
||||||
|
IComplex operator* (const Interval &, const IComplex &);
|
||||||
|
IComplex operator* (const std::complex<double> &, const IComplex &);
|
||||||
|
IComplex operator* (double, const IComplex &);
|
||||||
|
|
||||||
|
IComplex operator/ (const Interval &, const IComplex &);
|
||||||
|
IComplex operator/ (const std::complex<double> &, const IComplex &);
|
||||||
|
IComplex operator/ (double, const IComplex &);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// MISCELLANEOUS FUNCTIONS FOR INVERT COMPLEX INTERVALS
|
||||||
|
IComplex inverse_horizontal (double, double, double);
|
||||||
|
IComplex inverse_vertical (double, double, double);
|
||||||
|
double f (double, double);
|
||||||
|
double g (double, double);
|
||||||
|
|
||||||
|
#endif
|
||||||
71
include/interval.hpp
Normal file
71
include/interval.hpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#ifndef _INTERVAL_HPP
|
||||||
|
#define _INTERVAL_HPP
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
// IMPLEMENTS [a,b],
|
||||||
|
// a,b double
|
||||||
|
|
||||||
|
class Interval {
|
||||||
|
// FRIEND CLASS
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
double a;
|
||||||
|
double b;
|
||||||
|
|
||||||
|
|
||||||
|
// CONSTRUCTORS
|
||||||
|
// DEFAULT CONSTRUCTOR
|
||||||
|
Interval (double = 0);
|
||||||
|
// CONSTRUCTOR BY ELEMENTS
|
||||||
|
Interval (double, double);
|
||||||
|
// COPY CONSTRUCTOR
|
||||||
|
Interval (const Interval &);
|
||||||
|
// DESTRUCTOR
|
||||||
|
~Interval ();
|
||||||
|
|
||||||
|
// ASSIGNMENT
|
||||||
|
Interval & operator= (const Interval &);
|
||||||
|
Interval & operator= (double);
|
||||||
|
|
||||||
|
// COMPARISON
|
||||||
|
int operator== (const Interval &) const;
|
||||||
|
int operator!= (const Interval &) const;
|
||||||
|
|
||||||
|
// ARITHMETIC
|
||||||
|
Interval operator+ (const Interval &) const;
|
||||||
|
Interval operator+ (double) const;
|
||||||
|
|
||||||
|
Interval operator- () const;
|
||||||
|
Interval operator- (const Interval &) const;
|
||||||
|
Interval operator- (double) const;
|
||||||
|
|
||||||
|
Interval operator* (const Interval &) const;
|
||||||
|
Interval operator* (double) const;
|
||||||
|
|
||||||
|
Interval operator/ (const Interval &) const;
|
||||||
|
Interval operator/ (double) const;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// MISC
|
||||||
|
Interval inverse () const;
|
||||||
|
|
||||||
|
int containsZero () const;
|
||||||
|
int contains (double) const;
|
||||||
|
int subset (const Interval &) const;
|
||||||
|
int subsetEq (const Interval &) const;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// EXTERNAL FUNCTIONS
|
||||||
|
std::ostream & operator<< (std::ostream &, const Interval &);
|
||||||
|
|
||||||
|
Interval operator+ (double, const Interval &);
|
||||||
|
Interval operator- (double, const Interval &);
|
||||||
|
Interval operator* (double, const Interval &);
|
||||||
|
Interval operator/ (double, const Interval &);
|
||||||
|
#endif
|
||||||
80
include/list.hpp
Normal file
80
include/list.hpp
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
#ifndef _LIST_HPP
|
||||||
|
#define _LIST_HPP
|
||||||
|
|
||||||
|
#include <mpfr.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class Cell {
|
||||||
|
T x[3];
|
||||||
|
Cell () {}
|
||||||
|
Cell (T data[3]) {}
|
||||||
|
Cell (T x0, T y0R, T y0I) {}
|
||||||
|
~Cell () {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class Cell<double> {
|
||||||
|
public:
|
||||||
|
double x[3];
|
||||||
|
Cell () {}
|
||||||
|
Cell (double data[3]) {x[0] = data[0]; x[1] = data[1], x[2] = data[2];}
|
||||||
|
Cell (double x0, double y0R, double y0I) {x[0] = x0; x[1] = y0R; x[2] = y0I;}
|
||||||
|
~Cell () {}
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
class Cell<mpfr_t> {
|
||||||
|
public:
|
||||||
|
mpfr_t x[3];
|
||||||
|
Cell () {}
|
||||||
|
Cell (mpfr_t x0, mpfr_t y0R, mpfr_t y0I) {
|
||||||
|
mpfr_inits (x[0], x[1], x[2], NULL);
|
||||||
|
mpfr_set (x[0], x0, MPFR_RNDN);
|
||||||
|
mpfr_set (x[1], y0R, MPFR_RNDN);
|
||||||
|
mpfr_set (x[2], y0I, MPFR_RNDN);
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell (const Cell<mpfr_t> &op) {
|
||||||
|
mpfr_inits (x[0], x[1], x[2], NULL);
|
||||||
|
mpfr_set (x[0], op.x[0], MPFR_RNDN);
|
||||||
|
mpfr_set (x[1], op.x[1], MPFR_RNDN);
|
||||||
|
mpfr_set (x[2], op.x[2], MPFR_RNDN);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Cell () {
|
||||||
|
mpfr_clears (x[0], x[1], x[2], NULL);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream & operator<< (std::ostream &output, const Cell<double> &op) {
|
||||||
|
output << op.x[0] << " ";
|
||||||
|
output << op.x[1] << " ";
|
||||||
|
output << op.x[2];
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream & operator<< (std::ostream &output, const Cell<mpfr_t> &op) {
|
||||||
|
output << op.x[0] << " ";
|
||||||
|
output << op.x[1] << " ";
|
||||||
|
output << op.x[2];
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream & operator<< (std::ostream &output, const std::vector<Cell<double> > &op) {
|
||||||
|
for (int i=0; i<op.size(); ++i)
|
||||||
|
output << op[i];
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream & operator<< (std::ostream &output, const std::vector<Cell<mpfr_t> > &op) {
|
||||||
|
for (int i=0; i<op.size(); ++i)
|
||||||
|
output << op[i];
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
86
include/mp_complex.hpp
Normal file
86
include/mp_complex.hpp
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#ifndef MP_COMPLEX_HPP
|
||||||
|
#define MP_COMPLEX_HPP
|
||||||
|
|
||||||
|
#include <complex>
|
||||||
|
#include <iostream>
|
||||||
|
#include <mpfr.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class MPComplex {
|
||||||
|
public:
|
||||||
|
|
||||||
|
mpfr_t r;
|
||||||
|
mpfr_t i;
|
||||||
|
|
||||||
|
MPComplex (double = 0);
|
||||||
|
MPComplex (double, double);
|
||||||
|
MPComplex (const std::complex<double> &);
|
||||||
|
MPComplex (const mpfr_t);
|
||||||
|
MPComplex (const mpfr_t, const mpfr_t);
|
||||||
|
~MPComplex ();
|
||||||
|
|
||||||
|
// ASSIGNMENT
|
||||||
|
MPComplex & operator= (double);
|
||||||
|
MPComplex & operator= (const std::complex<double> &);
|
||||||
|
MPComplex & operator= (const mpfr_t );
|
||||||
|
MPComplex & operator= (const MPComplex &);
|
||||||
|
|
||||||
|
// COMPARISON
|
||||||
|
int operator == (double) const;
|
||||||
|
int operator == (const std::complex<double> &) const;
|
||||||
|
int operator == (const MPComplex &) const;
|
||||||
|
int operator != (double) const;
|
||||||
|
int operator != (const std::complex<double> &) const;
|
||||||
|
int operator != (const MPComplex &) const;
|
||||||
|
|
||||||
|
// ARITHMETIC
|
||||||
|
MPComplex operator+ (double) const;
|
||||||
|
MPComplex operator+ (const std::complex<double> &) const;
|
||||||
|
MPComplex operator+ (const mpfr_t ) const;
|
||||||
|
MPComplex operator+ (const MPComplex &) const;
|
||||||
|
|
||||||
|
MPComplex operator- () const;
|
||||||
|
MPComplex operator- (double) const;
|
||||||
|
MPComplex operator- (const std::complex<double> &) const;
|
||||||
|
MPComplex operator- (const mpfr_t ) const;
|
||||||
|
MPComplex operator- (const MPComplex &) const;
|
||||||
|
|
||||||
|
MPComplex operator* (double) const;
|
||||||
|
MPComplex operator* (const std::complex<double> &) const;
|
||||||
|
MPComplex operator* (const mpfr_t ) const;
|
||||||
|
MPComplex operator* (const MPComplex &) const;
|
||||||
|
|
||||||
|
MPComplex operator/ (double) const;
|
||||||
|
MPComplex operator/ (const std::complex<double> &) const;
|
||||||
|
MPComplex operator/ (const mpfr_t ) const;
|
||||||
|
MPComplex operator/ (const MPComplex &) const;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// NON MEMBER FUNCTIONS
|
||||||
|
|
||||||
|
std::ostream & operator<< (std::ostream &, const MPComplex &);
|
||||||
|
|
||||||
|
MPComplex operator+ (double, const MPComplex &);
|
||||||
|
MPComplex operator+ (const std::complex<double> &, const MPComplex &);
|
||||||
|
MPComplex operator+ (const mpfr_t , const MPComplex &);
|
||||||
|
|
||||||
|
MPComplex operator- (double, const MPComplex &);
|
||||||
|
MPComplex operator- (const std::complex<double> &, const MPComplex &);
|
||||||
|
MPComplex operator- (const mpfr_t , const MPComplex &);
|
||||||
|
|
||||||
|
MPComplex operator* (double, const MPComplex &);
|
||||||
|
MPComplex operator* (const std::complex<double> &, const MPComplex &);
|
||||||
|
MPComplex operator* (const mpfr_t , const MPComplex &);
|
||||||
|
|
||||||
|
MPComplex operator/ (double, const MPComplex &);
|
||||||
|
MPComplex operator/ (const std::complex<double> &, const MPComplex &);
|
||||||
|
MPComplex operator/ (const mpfr_t , const MPComplex &);
|
||||||
|
|
||||||
|
|
||||||
|
void abs (mpfr_t rop, const MPComplex &op);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
134
include/mp_icomplex.hpp
Normal file
134
include/mp_icomplex.hpp
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
#ifndef _MP_ICOMPLEX_HPP
|
||||||
|
#define _MP_ICOMPLEX_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <mpfr.h>
|
||||||
|
#include <mp_complex.hpp>
|
||||||
|
#include <interval.hpp>
|
||||||
|
#include <icomplex.hpp>
|
||||||
|
#include <mp_interval.hpp>
|
||||||
|
|
||||||
|
class MPIComplex {
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
// CONSTRUCTORS
|
||||||
|
MPIComplex (double = 0);
|
||||||
|
MPIComplex (double, double, double, double);
|
||||||
|
MPIComplex (const mpfr_t);
|
||||||
|
MPIComplex (const MPComplex &);
|
||||||
|
MPIComplex (const mpfr_t, const mpfr_t, const mpfr_t, const mpfr_t);
|
||||||
|
MPIComplex (const Interval &, const Interval &);
|
||||||
|
MPIComplex (const MPInterval &, const MPInterval &);
|
||||||
|
MPIComplex (const IComplex &);
|
||||||
|
MPIComplex (const MPIComplex &);
|
||||||
|
~MPIComplex ();
|
||||||
|
|
||||||
|
// ASSIGNMENT
|
||||||
|
MPIComplex & operator= (const MPIComplex &);
|
||||||
|
MPIComplex & operator= (const IComplex &);
|
||||||
|
MPIComplex & operator= (const MPInterval &);
|
||||||
|
MPIComplex & operator= (const Interval &);
|
||||||
|
MPIComplex & operator= (const mpfr_t);
|
||||||
|
MPIComplex & operator= (double);
|
||||||
|
|
||||||
|
// COMPARISON
|
||||||
|
int operator== (double) const;
|
||||||
|
int operator== (const std::complex<double> &) const;
|
||||||
|
int operator== (const Interval &) const;
|
||||||
|
int operator== (const MPInterval &) const;
|
||||||
|
int operator== (const MPIComplex &) const;
|
||||||
|
int operator!= (double) const;
|
||||||
|
int operator!= (const std::complex<double> &) const;
|
||||||
|
int operator!= (const Interval &) const;
|
||||||
|
int operator!= (const MPInterval &) const;
|
||||||
|
int operator!= (const MPIComplex &) const;
|
||||||
|
|
||||||
|
// ARITHMETIC
|
||||||
|
MPIComplex operator+ (const MPIComplex &) const;
|
||||||
|
MPIComplex operator+ (const IComplex &) const;
|
||||||
|
MPIComplex operator+ (const MPInterval &) const;
|
||||||
|
MPIComplex operator+ (const Interval &) const;
|
||||||
|
MPIComplex operator+ (const mpfr_t) const;
|
||||||
|
MPIComplex operator+ (double) const;
|
||||||
|
|
||||||
|
MPIComplex operator- () const;
|
||||||
|
MPIComplex operator- (const MPIComplex &) const;
|
||||||
|
MPIComplex operator- (const IComplex &) const;
|
||||||
|
MPIComplex operator- (const MPInterval &) const;
|
||||||
|
MPIComplex operator- (const Interval &) const;
|
||||||
|
MPIComplex operator- (const mpfr_t) const;
|
||||||
|
MPIComplex operator- (double) const;
|
||||||
|
|
||||||
|
MPIComplex operator* (const MPIComplex &) const;
|
||||||
|
MPIComplex operator* (const IComplex &) const;
|
||||||
|
MPIComplex operator* (const MPInterval &) const;
|
||||||
|
MPIComplex operator* (const Interval &) const;
|
||||||
|
MPIComplex operator* (const mpfr_t) const;
|
||||||
|
MPIComplex operator* (double) const;
|
||||||
|
|
||||||
|
|
||||||
|
MPIComplex operator/ (const MPIComplex &) const;
|
||||||
|
MPIComplex operator/ (const IComplex &) const;
|
||||||
|
MPIComplex operator/ (const MPInterval &) const;
|
||||||
|
MPIComplex operator/ (const Interval &) const;
|
||||||
|
MPIComplex operator/ (const mpfr_t) const;
|
||||||
|
MPIComplex operator/ (double) const;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// MISC
|
||||||
|
MPIComplex inverse () const;
|
||||||
|
|
||||||
|
int containsZero () const;
|
||||||
|
int contains (double) const;
|
||||||
|
int contains (const mpfr_t) const;
|
||||||
|
int subset (const MPIComplex &) const;
|
||||||
|
// int subsetEq (const MPIComplex &) const;
|
||||||
|
|
||||||
|
|
||||||
|
MPInterval r;
|
||||||
|
MPInterval i;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// NON MEMBER FUNCTIONS
|
||||||
|
|
||||||
|
std::ostream & operator<< (std::ostream &, const MPIComplex &);
|
||||||
|
|
||||||
|
|
||||||
|
MPIComplex operator+ (const IComplex &, const MPIComplex &);
|
||||||
|
MPIComplex operator+ (const MPInterval &, const MPIComplex &);
|
||||||
|
MPIComplex operator+ (const Interval &, const MPIComplex &);
|
||||||
|
MPIComplex operator+ (const mpfr_t, const MPIComplex &);
|
||||||
|
MPIComplex operator+ (double, const MPIComplex &);
|
||||||
|
|
||||||
|
MPIComplex operator- (const IComplex &, const MPIComplex &);
|
||||||
|
MPIComplex operator- (const MPInterval &, const MPIComplex &);
|
||||||
|
MPIComplex operator- (const Interval &, const MPIComplex &);
|
||||||
|
MPIComplex operator- (const mpfr_t, const MPIComplex &);
|
||||||
|
MPIComplex operator- (double, const MPIComplex &);
|
||||||
|
|
||||||
|
MPIComplex operator* (const IComplex &, const MPIComplex &);
|
||||||
|
MPIComplex operator* (const MPInterval &, const MPIComplex &);
|
||||||
|
MPIComplex operator* (const Interval &, const MPIComplex &);
|
||||||
|
MPIComplex operator* (const mpfr_t, const MPIComplex &);
|
||||||
|
MPIComplex operator* (double, const MPIComplex &);
|
||||||
|
|
||||||
|
MPIComplex operator/ (const IComplex &, const MPIComplex &);
|
||||||
|
MPIComplex operator/ (const MPInterval &, const MPIComplex &);
|
||||||
|
MPIComplex operator/ (const Interval &, const MPIComplex &);
|
||||||
|
MPIComplex operator/ (const mpfr_t, const MPIComplex &);
|
||||||
|
MPIComplex operator/ (double, const MPIComplex &);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// MISCELLANEOUS FUNCTIONS FOR INVERT COMPLEX INTERVALS
|
||||||
|
MPIComplex inverse_horizontal (const mpfr_t, const mpfr_t, const mpfr_t);
|
||||||
|
MPIComplex inverse_vertical (const mpfr_t, const mpfr_t, const mpfr_t);
|
||||||
|
void f (mpfr_t, const mpfr_t, const mpfr_t, mpfr_rnd_t);
|
||||||
|
void g (mpfr_t, const mpfr_t, const mpfr_t, mpfr_rnd_t);
|
||||||
|
|
||||||
|
#endif
|
||||||
108
include/mp_interval.hpp
Normal file
108
include/mp_interval.hpp
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#ifndef _MP_INTERVAL_HPP
|
||||||
|
#define _MP_INTERVAL_HPP
|
||||||
|
|
||||||
|
#include <interval.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <mpfr.h>
|
||||||
|
|
||||||
|
|
||||||
|
// IMPLEMENTS [a,b],
|
||||||
|
// a,b mpfr
|
||||||
|
|
||||||
|
class MPInterval {
|
||||||
|
// FRIEND CLASS
|
||||||
|
public:
|
||||||
|
|
||||||
|
mpfr_t a;
|
||||||
|
mpfr_t b;
|
||||||
|
|
||||||
|
|
||||||
|
// CONSTRUCTORS
|
||||||
|
// DEFAULT CONSTRUCTOR
|
||||||
|
MPInterval (double = 0);
|
||||||
|
// CONSTRUCTOR BY double ELEMENTS
|
||||||
|
MPInterval (double, double);
|
||||||
|
// CONSTRUCTOR BY string VALUE
|
||||||
|
MPInterval (const char *);
|
||||||
|
// CONSTRUCTOR BY string PAIR OF VALUES
|
||||||
|
MPInterval (const char *, const char *);
|
||||||
|
// CONSTRUCTOR BY mpfr ELEMENT
|
||||||
|
MPInterval (const mpfr_t);
|
||||||
|
// CONSTRUCTOR BY mpfr PAIR OF ELEMENTS
|
||||||
|
MPInterval (const mpfr_t, const mpfr_t);
|
||||||
|
// CONSTRUCTOR BY double Invterval
|
||||||
|
MPInterval (const Interval &);
|
||||||
|
// COPY CONSTRUCTOR
|
||||||
|
MPInterval (const MPInterval &);
|
||||||
|
// DESTRUCTOR
|
||||||
|
~MPInterval ();
|
||||||
|
|
||||||
|
// COMPARISON
|
||||||
|
int operator== (double) const;
|
||||||
|
int operator== (const Interval &) const;
|
||||||
|
int operator== (const MPInterval &) const;
|
||||||
|
int operator!= (double) const;
|
||||||
|
int operator!= (const Interval &) const;
|
||||||
|
int operator!= (const MPInterval &) const;
|
||||||
|
|
||||||
|
// ASSIGNMENT
|
||||||
|
MPInterval & operator= (const MPInterval &);
|
||||||
|
MPInterval & operator= (const Interval &);
|
||||||
|
MPInterval & operator= (const mpfr_t);
|
||||||
|
MPInterval & operator= (double);
|
||||||
|
|
||||||
|
// ARITHMETIC
|
||||||
|
MPInterval operator+ (const MPInterval &) const;
|
||||||
|
MPInterval operator+ (const Interval &) const;
|
||||||
|
MPInterval operator+ (const mpfr_t) const;
|
||||||
|
MPInterval operator+ (double) const;
|
||||||
|
|
||||||
|
MPInterval operator- () const;
|
||||||
|
MPInterval operator- (const MPInterval &) const;
|
||||||
|
MPInterval operator- (const Interval &) const;
|
||||||
|
MPInterval operator- (const mpfr_t) const;
|
||||||
|
MPInterval operator- (double) const;
|
||||||
|
|
||||||
|
MPInterval operator* (const MPInterval &) const;
|
||||||
|
MPInterval operator* (const Interval &) const;
|
||||||
|
MPInterval operator* (const mpfr_t) const;
|
||||||
|
MPInterval operator* (double) const;
|
||||||
|
|
||||||
|
MPInterval operator/ (const MPInterval &) const;
|
||||||
|
MPInterval operator/ (const Interval &) const;
|
||||||
|
MPInterval operator/ (const mpfr_t) const;
|
||||||
|
MPInterval operator/ (double) const;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// MISC
|
||||||
|
MPInterval inverse () const;
|
||||||
|
|
||||||
|
int containsZero () const;
|
||||||
|
int contains (double) const;
|
||||||
|
int contains (const mpfr_t) const;
|
||||||
|
int subset (const MPInterval &) const;
|
||||||
|
int subset (const Interval &) const;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// EXTERNAL FUNCTIONS
|
||||||
|
std::ostream & operator<< (std::ostream &, const MPInterval &);
|
||||||
|
|
||||||
|
MPInterval operator+ (double, const MPInterval &);
|
||||||
|
MPInterval operator+ (const mpfr_t, const MPInterval &);
|
||||||
|
MPInterval operator+ (const Interval &, const MPInterval &);
|
||||||
|
|
||||||
|
MPInterval operator- (double, const MPInterval &);
|
||||||
|
MPInterval operator- (const mpfr_t, const MPInterval &);
|
||||||
|
MPInterval operator- (const Interval &, const MPInterval &);
|
||||||
|
|
||||||
|
MPInterval operator* (double, const MPInterval &);
|
||||||
|
MPInterval operator* (const mpfr_t, const MPInterval &);
|
||||||
|
MPInterval operator* (const Interval &, const MPInterval &);
|
||||||
|
|
||||||
|
MPInterval operator/ (double, const MPInterval &);
|
||||||
|
MPInterval operator/ (const mpfr_t, const MPInterval &);
|
||||||
|
MPInterval operator/ (const Interval &, const MPInterval &);
|
||||||
|
#endif
|
||||||
475
include/polynomial.hpp
Normal file
475
include/polynomial.hpp
Normal file
@ -0,0 +1,475 @@
|
|||||||
|
#ifndef _POLYNOMIAL_HPP
|
||||||
|
#define _POLYNOMIAL_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <complex> // std::complex
|
||||||
|
#include <mp_complex.hpp>
|
||||||
|
#include <icomplex.hpp>
|
||||||
|
#include <mp_icomplex.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
#define MIN(a,b) (((a) < (b))? (a) : (b))
|
||||||
|
#define MAX(a,b) (((a) > (b))? (a) : (b))
|
||||||
|
|
||||||
|
class _Polynomial {
|
||||||
|
public:
|
||||||
|
_Polynomial() {}
|
||||||
|
~_Polynomial() {}
|
||||||
|
|
||||||
|
static unsigned int *combinatorial;
|
||||||
|
static void startCombinatorialNumbers (int degree);
|
||||||
|
static void releaseCombinatorialNumbers () {
|
||||||
|
delete [] _Polynomial::combinatorial;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class Polynomial : _Polynomial {
|
||||||
|
public:
|
||||||
|
|
||||||
|
// CONSTRUCTOR
|
||||||
|
Polynomial (int = 0);
|
||||||
|
Polynomial (int, const T *);
|
||||||
|
Polynomial (const Polynomial<T> &);
|
||||||
|
~Polynomial () {delete [] coef;}
|
||||||
|
|
||||||
|
// ASSIGNMENT
|
||||||
|
Polynomial & operator= (const Polynomial<T> &);
|
||||||
|
Polynomial & operator= (const T &);
|
||||||
|
Polynomial & operator= (double);
|
||||||
|
|
||||||
|
T operator() (const T &, const T &) const;
|
||||||
|
T diffX (const T &, const T &) const;
|
||||||
|
T diffY (const T &, const T &) const;
|
||||||
|
T diffXX (const T &, const T &) const;
|
||||||
|
T diffXY (const T &, const T &) const;
|
||||||
|
T diffYY (const T &, const T &) const;
|
||||||
|
|
||||||
|
|
||||||
|
// MISC FUNCTIONS FOR HORNER
|
||||||
|
T evalPolClassic (const T &, const T &) const;
|
||||||
|
T evalIPolHornerXY (const T &, const T &) const {return T();}
|
||||||
|
T evalIPolHornerYX (const T &, const T &) const {return T();}
|
||||||
|
|
||||||
|
T evalPolYClassic (const T &, const T &) const;
|
||||||
|
T evalIPolYHornerXY (const T &, const T &) const {return T();}
|
||||||
|
T evalIPolYHornerYX (const T &, const T &) const {return T();}
|
||||||
|
|
||||||
|
|
||||||
|
// CHANGE OF VARIABLE
|
||||||
|
Polynomial<T> IlinearVarChange (const T &a) const;
|
||||||
|
Polynomial<T> IlinearVarChange2 (const T &x0) const;
|
||||||
|
|
||||||
|
// MEMBERS
|
||||||
|
T *coef;
|
||||||
|
int degree;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
std::ostream & operator<< (std::ostream &output, const Polynomial<T> &op) {
|
||||||
|
int allZero = 1;
|
||||||
|
for (int i=0; i<=op.degree; ++i)
|
||||||
|
for (int j=0; j<=i; ++j){
|
||||||
|
if (op.coef[i*(i+1)/2 + j] == 0.0) continue;
|
||||||
|
allZero = 0;
|
||||||
|
if (op.coef[i*(i+1)/2 + j] == -1.0)
|
||||||
|
output << "-";
|
||||||
|
else if (op.coef[i*(i+1)/2 + j] != 1.0)
|
||||||
|
output << "+(" << op.coef[i*(i+1)/2 + j] << ")*";
|
||||||
|
else
|
||||||
|
output << "+";
|
||||||
|
if (i == 0)
|
||||||
|
if (op.coef[0] == T(1))
|
||||||
|
output << "1";
|
||||||
|
if (i != 0)
|
||||||
|
if (i-j == 0)
|
||||||
|
if (j == 1)
|
||||||
|
output << "y";
|
||||||
|
else
|
||||||
|
output << "y^" << j;
|
||||||
|
else if (i-j == 1)
|
||||||
|
if (j == 0)
|
||||||
|
output << "x";
|
||||||
|
else if (j == 1)
|
||||||
|
output << "x*y";
|
||||||
|
else
|
||||||
|
output << "x*y^" << j;
|
||||||
|
else
|
||||||
|
if (j == 0)
|
||||||
|
output << "x^" << i;
|
||||||
|
else if (j == 1)
|
||||||
|
output << "x^" << (i-j) << "*y";
|
||||||
|
else
|
||||||
|
output << "x^" << (i-j) << "*y^" << j;
|
||||||
|
}
|
||||||
|
if (allZero) output << "0";
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CONSTRUCTOR
|
||||||
|
|
||||||
|
// DEFAULT CONSTRUCTOR FOR ZERO POLYNOMIAL
|
||||||
|
template <class T>
|
||||||
|
Polynomial<T>::Polynomial (int op) {
|
||||||
|
degree = op;
|
||||||
|
coef = new T [((op+1)*(op+2))/2];
|
||||||
|
for (int i=0; i<((op+1)*(op+2))/2; ++i)
|
||||||
|
coef[i] = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CONSTRUCTOR FROM ARRAY OF COMPLEX or ICOMPLEX
|
||||||
|
template <class T>
|
||||||
|
Polynomial<T>::Polynomial (int op1, const T *op2) {
|
||||||
|
degree = op1;
|
||||||
|
int nCoef = ((degree+1)*(degree+2)) / 2;
|
||||||
|
coef = new T [nCoef];
|
||||||
|
for (int i=0; i<nCoef; ++i)
|
||||||
|
coef[i] = op2[i];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// COPY CONSTRUCTOR
|
||||||
|
template <class T>
|
||||||
|
Polynomial<T>::Polynomial (const Polynomial<T> &op) {
|
||||||
|
degree = op.degree;
|
||||||
|
int nCoef = ((degree+1)*(degree+2)) / 2;
|
||||||
|
coef = new T [nCoef];
|
||||||
|
for (int i=0; i<nCoef; ++i)
|
||||||
|
coef[i] = op.coef[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ASSIGNMENT
|
||||||
|
template <class T>
|
||||||
|
Polynomial<T> & Polynomial<T>::operator= (const Polynomial<T> &op) {
|
||||||
|
// CHECKS WHETHER ASSIGNED POL IS TARGET POL
|
||||||
|
if (this == &op) return (*this);
|
||||||
|
|
||||||
|
// GETS FINAL NUMBER OF COEFICIENTS
|
||||||
|
int nCoef = ((op.degree+1)*(op.degree+2)) / 2;
|
||||||
|
// IF NUMBER OF COEFFICIENTS ARE THE SAME, NO NEED TO REALLOCATE
|
||||||
|
if (this->degree != op.degree) {
|
||||||
|
delete [] this->coef;
|
||||||
|
this->coef = new T[nCoef];
|
||||||
|
this->degree = op.degree;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UPDATE VALUES OF COEFICIENTS
|
||||||
|
for (int i=0; i<nCoef; ++i)
|
||||||
|
this->coef[i] = op.coef[i];
|
||||||
|
|
||||||
|
|
||||||
|
return (*this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Polynomial<T> & Polynomial<T>::operator= (const T &op) {
|
||||||
|
// CHECKS IF TARGET POL IS ALSO A CONSTANT POL
|
||||||
|
// IN THAT CASE THERE IS NO NEED TO REALLOCATE MEMORY
|
||||||
|
if (this->degree != 0) {
|
||||||
|
delete [] this->coef;
|
||||||
|
this->coef = new T[1];
|
||||||
|
this->degree = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UPDATE INDEPENDENT TERM
|
||||||
|
this->coef[0] = op;
|
||||||
|
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Polynomial<T> & Polynomial<T>::operator= (double op) {
|
||||||
|
// USE PREVIOUS DEFINITION
|
||||||
|
return ((*this) = T(op));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// EVALUATION
|
||||||
|
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T Polynomial<T>::evalPolClassic (const T &x, const T &y) const {
|
||||||
|
// coef[(i*(i+1))/2 + j] is coeficient of monomial of degree 'i',
|
||||||
|
// with degree of second variable 'j' -> coef of x^(i-j) y^j
|
||||||
|
// i; // counter along degree of polynomial
|
||||||
|
// j; // counter for monomials of equal degree
|
||||||
|
|
||||||
|
// sets output to 0+0i
|
||||||
|
T rop;
|
||||||
|
|
||||||
|
// compute all powers of x and y (from 0 to degree)
|
||||||
|
T xPower[this->degree+1], yPower[this->degree+1];
|
||||||
|
xPower[0] = yPower[0] = 1.0;
|
||||||
|
xPower[1] = x; yPower[1] = y;
|
||||||
|
for (int j=1; j<this->degree; ++j) {
|
||||||
|
xPower[j+1] = xPower[j] * x;
|
||||||
|
yPower[j+1] = yPower[j] * y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop for each monomial of each degree
|
||||||
|
for (int i=0; i<=this->degree; ++i)
|
||||||
|
for (int j=0; j<=i; ++j)
|
||||||
|
rop = rop +
|
||||||
|
((this->coef)[(i*(i+1))/2 + j]) * xPower[i-j] * yPower[j];
|
||||||
|
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T Polynomial<T>::operator() (const T &x, const T &y) const {
|
||||||
|
return this->evalPolClassic (x,y);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T Polynomial<T>::diffX (const T &x, const T &y) const {
|
||||||
|
// coef[(i*(i+1))/2 + j] is coeficient of monomial of degree 'i',
|
||||||
|
// with degree of second variable 'j' -> coef of x^(i-j) y^j
|
||||||
|
// i; // counter along degree of polynomial
|
||||||
|
// j; // counter for monomials of equal degree
|
||||||
|
|
||||||
|
// sets output to 0+0i
|
||||||
|
T rop;
|
||||||
|
|
||||||
|
// compute all powers of x and y
|
||||||
|
// (from 0 to degree-1) (from 0 to degree) resp
|
||||||
|
T xPower[this->degree], yPower[this->degree+1];
|
||||||
|
xPower[0] = yPower[0] = 1.0;
|
||||||
|
xPower[1] = x; yPower[1] = y;
|
||||||
|
for (int j=1; j<this->degree-1; ++j) {
|
||||||
|
xPower[j+1] = xPower[j] * x;
|
||||||
|
yPower[j+1] = yPower[j] * y;
|
||||||
|
}
|
||||||
|
yPower[this->degree] = yPower[this->degree-1] * y;
|
||||||
|
|
||||||
|
// loop for each monomial of each degree
|
||||||
|
for (int i=1; i<=this->degree; ++i)
|
||||||
|
for (int j=0; j<i; ++j)
|
||||||
|
rop = rop +
|
||||||
|
T(i-j)*((this->coef)[(i*(i+1))/2 + j]) *
|
||||||
|
xPower[i-j-1] * yPower[j];
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T Polynomial<T>::evalPolYClassic (const T &x, const T &y) const {
|
||||||
|
// coef[(i*(i+1))/2 + j] is coeficient of monomial of degree 'i',
|
||||||
|
// with degree of second variable 'j' -> coef of x^(i-j) y^j
|
||||||
|
// i; // counter along degree of polynomial
|
||||||
|
// j; // counter for monomials of equal degree
|
||||||
|
|
||||||
|
// sets output to 0+0i
|
||||||
|
T rop;
|
||||||
|
|
||||||
|
// compute all powers of x and y
|
||||||
|
// (from 0 to degree) (from 0 to degree-1) resp
|
||||||
|
T xPower[this->degree], yPower[this->degree];
|
||||||
|
xPower[0] = yPower[0] = 1.0;
|
||||||
|
xPower[1] = x; yPower[1] = y;
|
||||||
|
for (int j=1; j<this->degree-1; ++j) {
|
||||||
|
xPower[j+1] = xPower[j] * x;
|
||||||
|
yPower[j+1] = yPower[j] * y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop for each monomial of each degree
|
||||||
|
for (int i=1; i<=this->degree; ++i)
|
||||||
|
for (int j=1; j<=i; ++j)
|
||||||
|
rop = rop +
|
||||||
|
T(j)*((this->coef)[(i*(i+1))/2 + j]) *
|
||||||
|
xPower[i-j] * yPower[j-1];
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T Polynomial<T>::diffY (const T &x, const T &y) const {
|
||||||
|
return this->evalPolYClassic (x,y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T Polynomial<T>::diffXX (const T &x, const T &y) const {
|
||||||
|
// coef[(i*(i+1))/2 + j] is coeficient of monomial of degree 'i',
|
||||||
|
// with degree of second variable 'j' -> coef of x^(i-j) y^j
|
||||||
|
// i; // counter along degree of polynomial
|
||||||
|
// j; // counter for monomials of equal degree
|
||||||
|
|
||||||
|
// sets output to 0+0i
|
||||||
|
T rop;
|
||||||
|
|
||||||
|
// compute all powers of x and y
|
||||||
|
// (from 0 to degree-2) (from 0 to degree-2) resp
|
||||||
|
T xPower[this->degree-1], yPower[this->degree-1];
|
||||||
|
xPower[0] = yPower[0] = 1.0;
|
||||||
|
xPower[1] = x; yPower[1] = y;
|
||||||
|
for (int j=1; j<this->degree-2; ++j) {
|
||||||
|
xPower[j+1] = xPower[j] * x;
|
||||||
|
yPower[j+1] = yPower[j] * y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop for each monomial of each degree
|
||||||
|
for (int i=2; i<=this->degree; ++i)
|
||||||
|
for (int j=0; j<i-1; ++j)
|
||||||
|
rop = rop +
|
||||||
|
T(i-j)*(i-j-1.0)*((this->coef)[(i*(i+1))/2 + j]) *
|
||||||
|
xPower[i-j-2] * yPower[j];
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T Polynomial<T>::diffXY (const T &x, const T &y) const {
|
||||||
|
// coef[(i*(i+1))/2 + j] is coeficient of monomial of degree 'i',
|
||||||
|
// with degree of second variable 'j' -> coef of x^(i-j) y^j
|
||||||
|
// i; // counter along degree of polynomial
|
||||||
|
// j; // counter for monomials of equal degree
|
||||||
|
|
||||||
|
// sets output to 0+0i
|
||||||
|
T rop;
|
||||||
|
|
||||||
|
// compute all powers of x and y
|
||||||
|
// (from 0 to degree-2) (from 0 to degree-2) resp
|
||||||
|
T xPower[this->degree-1], yPower[this->degree-1];
|
||||||
|
xPower[0] = yPower[0] = 1.0;
|
||||||
|
xPower[1] = x; yPower[1] = y;
|
||||||
|
for (int j=1; j<this->degree-2; ++j) {
|
||||||
|
xPower[j+1] = xPower[j] * x;
|
||||||
|
yPower[j+1] = yPower[j] * y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop for each monomial of each degree
|
||||||
|
for (int i=2; i<=this->degree; ++i)
|
||||||
|
for (int j=1; j<i; ++j)
|
||||||
|
rop = rop +
|
||||||
|
T(j)*T(i-j)*((this->coef)[(i*(i+1))/2 + j]) *
|
||||||
|
xPower[i-j-1] * yPower[j-1];
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T Polynomial<T>::diffYY (const T &x, const T &y) const {
|
||||||
|
// coef[(i*(i+1))/2 + j] is coeficient of monomial of degree 'i',
|
||||||
|
// with degree of second variable 'j' -> coef of x^(i-j) y^j
|
||||||
|
// i; // counter along degree of polynomial
|
||||||
|
// j; // counter for monomials of equal degree
|
||||||
|
|
||||||
|
// sets output to 0+0i
|
||||||
|
T rop;
|
||||||
|
|
||||||
|
// compute all powers of x and y
|
||||||
|
// (from 0 to degree-2) (from 0 to degree-2) resp
|
||||||
|
T xPower[this->degree-1];
|
||||||
|
T yPower[this->degree-1];
|
||||||
|
xPower[0] = yPower[0] = 1.0;
|
||||||
|
xPower[1] = x; yPower[1] = y;
|
||||||
|
for (int j=1; j<this->degree-2; ++j) {
|
||||||
|
xPower[j+1] = xPower[j] * x;
|
||||||
|
yPower[j+1] = yPower[j] * y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop for each monomial of each degree
|
||||||
|
for (int i=2; i<=this->degree; ++i)
|
||||||
|
for (int j=2; j<=i; ++j)
|
||||||
|
rop = rop +
|
||||||
|
T(j)*T(j-1)*((this->coef)[(i*(i+1))/2 + j]) *
|
||||||
|
xPower[i-j] * yPower[j-2];
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// CHANGE OF VARIABLE
|
||||||
|
|
||||||
|
// RETURNS q = p(x, y + ax);
|
||||||
|
// q = sum D(i,j)x^(i-j)y^j
|
||||||
|
template <class T>
|
||||||
|
Polynomial<T> Polynomial<T>::IlinearVarChange (const T &a) const {
|
||||||
|
|
||||||
|
|
||||||
|
int i; // counter for degree
|
||||||
|
int j; // counter for exponent of y
|
||||||
|
int k; // counter for elements modifying x^(i-j) y^j
|
||||||
|
|
||||||
|
// for each degree i, only coefficients of monomials with j in {0, ..., i-1} are changed
|
||||||
|
// for each j, only monomials with degree i and k in {j+1, ..., i} modify it
|
||||||
|
// for each k, coef[(i*(i+1))/2+k] x^(i-k) (y+ax)^k
|
||||||
|
// from binomial expansion, the term with x^(i-j) y^j has multiplier:
|
||||||
|
// coef[(i*(i+1))/2+k] a^(k-j) (k over j)
|
||||||
|
T aPower[this->degree+1];
|
||||||
|
aPower[0] = 1;
|
||||||
|
aPower[1] = a;
|
||||||
|
for (i=1; i<this->degree; ++i)
|
||||||
|
aPower[i+1] = aPower[i] * a;
|
||||||
|
|
||||||
|
unsigned int *combinatorial = _Polynomial::combinatorial;
|
||||||
|
|
||||||
|
Polynomial<T> rop(this->degree);
|
||||||
|
|
||||||
|
// rop = sum_{i=0}^{degree} sum_{j=0}^{i} D(i,j)x^{i-j}y^j
|
||||||
|
// D(i,j) = sum_{k=j}^{i} C(i,k)(k over j) a^{k-j}
|
||||||
|
for (i=0; i<=this->degree; ++i) for (j=0; j<=i; ++j) {
|
||||||
|
rop.coef[(i*(i+1))/2 + j] = this->coef[(i*(i+1))/2 + j];
|
||||||
|
for (k=j+1; k<=i; ++k)
|
||||||
|
rop.coef[(i*(i+1))/2 + j] = rop.coef[(i*(i+1))/2 + j] +
|
||||||
|
combinatorial[(k*(k+1))/2+j] * aPower[k-j] * this->coef[(i*(i+1))/2+k];
|
||||||
|
}
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
// RETURNS q = p(x+x0, y);
|
||||||
|
template <class T>
|
||||||
|
Polynomial<T> Polynomial<T>::IlinearVarChange2 (const T &x0) const {
|
||||||
|
int i; // counter for degree
|
||||||
|
int j; // counter for exponent of y
|
||||||
|
int k; // counter for elements modifying x^(i-j) y^j
|
||||||
|
|
||||||
|
// for each degree i, only coefficients of monomials with j in {0, ..., i-1} are changed
|
||||||
|
// for each j, only monomials with degree i and k in {j+1, ..., i} modify it
|
||||||
|
// for each k, coef[(i*(i+1))/2+k] x^(i-k) (y+ax)^k
|
||||||
|
// from binomial expansion, the term with x^(i-j) y^j has multiplier:
|
||||||
|
// coef[(i*(i+1))/2+k] a^(k-j) (k over j)
|
||||||
|
T x0Power[this->degree+1];
|
||||||
|
x0Power[0] = 1;
|
||||||
|
x0Power[1] = x0;
|
||||||
|
for (i=1; i<this->degree; ++i)
|
||||||
|
x0Power[i+1] = x0Power[i] * x0;
|
||||||
|
|
||||||
|
unsigned int *combinatorial = _Polynomial::combinatorial;
|
||||||
|
|
||||||
|
Polynomial<T> rop(this->degree);
|
||||||
|
|
||||||
|
// rop = sum_{i=0}^{degree} sum_{j=0}^{i} D(i,j)x^{i-j}y^j
|
||||||
|
// D(i,j) = sum_{k=i}^{degree} (k-j over i-j) C(k,j) x0^(k-i)
|
||||||
|
for (i=0; i<=this->degree; ++i) for (j=0; j<=i; ++j) {
|
||||||
|
rop.coef[(i*(i+1))/2+j] = this->coef[(i*(i+1))/2+j];
|
||||||
|
for (k=i+1; k<=this->degree; ++k)
|
||||||
|
rop.coef[(i*(i+1))/2+j] = rop.coef[(i*(i+1))/2+j] +
|
||||||
|
combinatorial[((k-j)*(k-j+1))/2 + i-j] * this->coef[(k*(k+1))/2+j] * x0Power[k-i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
14
include/sirocco.h
Normal file
14
include/sirocco.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef __SIROCCO_H__
|
||||||
|
#define __SIROCCO_H__
|
||||||
|
|
||||||
|
#include <fenv.h>
|
||||||
|
#include <mpfr.h>
|
||||||
|
|
||||||
|
// ACTIVATE ROUND MODE CONTROL
|
||||||
|
#pragma STDC FENV_ACCESS on
|
||||||
|
|
||||||
|
|
||||||
|
double * homotopyPath (int degree, double *_coef, double _y0R, double _y0I);
|
||||||
|
mpfr_t * homotopyPath_mp (int degree, mpfr_t *_coef, mpfr_t _y0R, mpfr_t _y0I, int prec);
|
||||||
|
|
||||||
|
#endif
|
||||||
73
include/sirocco.hpp
Normal file
73
include/sirocco.hpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#ifndef _SIROCCO_HPP_
|
||||||
|
#define _SIROCCO_HPP_
|
||||||
|
|
||||||
|
#include <complex>
|
||||||
|
#include <fenv.h>
|
||||||
|
#include <mp_complex.hpp>
|
||||||
|
#include <polynomial.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
// ACTIVATE ROUND MODE CONTROL
|
||||||
|
#pragma STDC FENV_ACCESS on
|
||||||
|
|
||||||
|
typedef std::complex<double> Complex;
|
||||||
|
|
||||||
|
double * homotopyPath (int degree, double *_coef, double _y0R, double _y0I);
|
||||||
|
mpfr_t * homotopyPath_mp (int degree, mpfr_t *_coef, mpfr_t _y0R, mpfr_t _y0I, int prec);
|
||||||
|
|
||||||
|
|
||||||
|
template <class T> // T -> Complex, IComplex, MPComplex or MPIComplex
|
||||||
|
void correctRoot (const Polynomial<T>, const T &x0, T &y0) {}
|
||||||
|
|
||||||
|
|
||||||
|
template <class T> // T -> Complex or MPComplex
|
||||||
|
T getA (const Polynomial<T> f, const T &x0, const T &y0) {
|
||||||
|
return -(f.diffX (x0, y0) / f.diffY (x0, y0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <class T> // T -> IComplex or MPIComplex
|
||||||
|
int newtonTest (const Polynomial<T> &If, const T &Ix0, const T &Iy0, const T &IY0) {
|
||||||
|
|
||||||
|
T N, aux;
|
||||||
|
|
||||||
|
N = If(Ix0, Iy0);
|
||||||
|
|
||||||
|
|
||||||
|
aux = If.diffY (Ix0, IY0);
|
||||||
|
|
||||||
|
// check we do not perform division by an interval containing 0.
|
||||||
|
// in this case, return fail the test
|
||||||
|
if (aux.containsZero ()) return 0;
|
||||||
|
|
||||||
|
N = Iy0 - (N / aux);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (N.subset (IY0))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// // RETURNS WHETHER NEWTON EVALUATION N IS CONTAINED IN THE INTERVAL ENCLOSURE IY0 OF Iy0.
|
||||||
|
// // BESIDES REPEATS WITH A ENCLOSURE THREE TIMES BIGER. RETURNS SUCCESS IF BOTH ARE SATISFIED
|
||||||
|
template <class T> // T -> IComplex or MPIComplex
|
||||||
|
int validate (const Polynomial<T> &If, const T &Ix0, const T &Iy0, const T &IY0) {
|
||||||
|
|
||||||
|
|
||||||
|
T IY1;
|
||||||
|
if (!newtonTest<T> (If, Ix0, Iy0, IY0)) return 0;
|
||||||
|
|
||||||
|
|
||||||
|
// COMPUTES AN ENCLOSURE THREE TIMES BIGGER FOR N2
|
||||||
|
// CREATE A 3-TIMES BIGGER ENCLOSURE (ROUNDING TO BIGGER)
|
||||||
|
IY1 = IY0 + IY0;
|
||||||
|
IY1 = IY1 - IY0;
|
||||||
|
|
||||||
|
if (!newtonTest<T> (If, Ix0, Iy0, IY1)) return 0;
|
||||||
|
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
5
lib/Makefile.am
Normal file
5
lib/Makefile.am
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
lib_LTLIBRARIES = libsirocco.la
|
||||||
|
libsirocco_la_SOURCES = icomplex.cpp interval.cpp $(top_srcdir)/include/list.hpp $(top_srcdir)/include/mp_complex.hpp $(top_srcdir)/include/mp_icomplex.hpp $(top_srcdir)/include/mp_interval.hpp $(top_srcdir)/include/polynomial.hpp $(top_srcdir)/include/sirocco.hpp $(top_srcdir)/include/icomplex.hpp $(top_srcdir)/include/interval.hpp mp_complex.cpp mp_icomplex.cpp mp_interval.cpp polynomial.cpp sirocco.cpp
|
||||||
|
libsirocco_la_LDFLAGS = -lm -lmpfr -lgmp
|
||||||
|
AM_CPPFLAGS = -I$(top_srcdir)/include
|
||||||
|
include_HEADERS = $(top_srcdir)/include/sirocco.h
|
||||||
389
lib/icomplex.cpp
Normal file
389
lib/icomplex.cpp
Normal file
@ -0,0 +1,389 @@
|
|||||||
|
#include <fenv.h>
|
||||||
|
#include <cmath>
|
||||||
|
#include "icomplex.hpp"
|
||||||
|
|
||||||
|
#define MIN(a,b) (((a) < (b))? (a) : (b))
|
||||||
|
#define MAX(a,b) (((a) > (b))? (a) : (b))
|
||||||
|
|
||||||
|
#pragma STDC FENV_ACCESS on
|
||||||
|
|
||||||
|
|
||||||
|
// CONSTRUCTORS
|
||||||
|
IComplex::IComplex (double op)
|
||||||
|
: r(op, op), i() {}
|
||||||
|
IComplex::IComplex (double op1, double op2, double op3, double op4)
|
||||||
|
: r(op1, op2), i(op3, op4) {}
|
||||||
|
IComplex::IComplex (const Interval &op1, const Interval &op2)
|
||||||
|
: r(op1), i(op2) {}
|
||||||
|
|
||||||
|
IComplex::IComplex (const std::complex<double> &op)
|
||||||
|
: r(op.real()), i(op.imag()) {}
|
||||||
|
// COPY CONSTRUCTOR
|
||||||
|
IComplex::IComplex (const IComplex &op)
|
||||||
|
: r(op.r), i(op.i) {}
|
||||||
|
IComplex::~IComplex () {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// // ASSIGNMENT
|
||||||
|
IComplex & IComplex::operator= (const IComplex &op) {
|
||||||
|
// CHECK WHETER WE ARE ASIGNING SOMETHING OVER ITSELF
|
||||||
|
if (this == &op) return (*this);
|
||||||
|
// UPDATE ELEMENTS
|
||||||
|
this->r = op.r; this->i = op.i;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
IComplex & IComplex::operator= (const std::complex<double> &op) {
|
||||||
|
// UPDATE ELEMENTS
|
||||||
|
this->r = op.real (); this->i = op.imag ();
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
IComplex & IComplex::operator= (const Interval &op) {
|
||||||
|
// UPDATE ELEMENTS
|
||||||
|
this->r = op; this->i = 0.0;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
IComplex & IComplex::operator= (double op) {
|
||||||
|
// UPDATE ELEMENTS
|
||||||
|
this->r = op; this->i = 0.0;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// // COMPARISON
|
||||||
|
int IComplex::operator== (const IComplex &op) const {
|
||||||
|
return (this->r == op.r) && (this->i == op.i);
|
||||||
|
}
|
||||||
|
int IComplex::operator== (const std::complex<double> &op) const {
|
||||||
|
return (this->r == op.real ()) && (this->i == op.imag ());
|
||||||
|
}
|
||||||
|
int IComplex::operator== (double op) const {
|
||||||
|
return (this->r == op) && (this->i == 0);
|
||||||
|
}
|
||||||
|
int IComplex::operator!= (const IComplex &op) const {
|
||||||
|
return !((*this) == op);
|
||||||
|
}
|
||||||
|
int IComplex::operator!= (const std::complex<double> &op) const {
|
||||||
|
return !((*this) == op);
|
||||||
|
}
|
||||||
|
int IComplex::operator!= (double op) const {
|
||||||
|
return !((*this) == op);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// // ARITHMETIC
|
||||||
|
// A INTERVAL REAL PART
|
||||||
|
// B INTERNAL IMAG PART
|
||||||
|
// (A + iB) + (C + iD) = (A+C) + i(B+D)
|
||||||
|
IComplex IComplex::operator+ (const IComplex &op) const {
|
||||||
|
return IComplex (this->r + op.r, this->i + op.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) + (C + iD) = (A+C) + i(B+D)
|
||||||
|
IComplex IComplex::operator+ (const std::complex<double> &op) const {
|
||||||
|
return IComplex (this->r + op.real (), this->i + op.imag ());
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) + C = (A+C) + iB
|
||||||
|
IComplex IComplex::operator+ (const Interval &op) const {
|
||||||
|
return IComplex (this->r + op, this->i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) + C = (A+C) + iB
|
||||||
|
IComplex IComplex::operator+ (double op) const {
|
||||||
|
return IComplex (this->r + op, this->i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -(A + iB) = (-A) + i(-B)
|
||||||
|
IComplex IComplex::operator- () const {
|
||||||
|
return IComplex (-(this->r), -(this->i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) - (C + iD) = (A-C) + i(B-D)
|
||||||
|
IComplex IComplex::operator- (const IComplex &op) const {
|
||||||
|
return IComplex (this->r - op.r, this->i - op.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) - (C + iD) = (A-C) + i(B-D)
|
||||||
|
IComplex IComplex::operator- (const std::complex<double> &op) const {
|
||||||
|
return IComplex (this->r - op.real (), this->i - op.imag ());
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) - (C + iD) = (A-C) + i(B-D)
|
||||||
|
IComplex IComplex::operator- (const Interval &op) const {
|
||||||
|
return IComplex (this->r - op, this->i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) - C = (A-C) + iB
|
||||||
|
IComplex IComplex::operator- (double op) const {
|
||||||
|
return IComplex (this->r - op, this->i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// (A + iB) * (C + iD) = (A*C - B*D) + i(A*D + B*C)
|
||||||
|
IComplex IComplex::operator* (const IComplex &op) const {
|
||||||
|
return IComplex (this->r * op.r - this->i * op.i,
|
||||||
|
this->r * op.i + this->i * op.r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) * (C + iD) = (A*C - B*D) + i(A*D + B*C)
|
||||||
|
IComplex IComplex::operator* (const std::complex<double> &op) const {
|
||||||
|
return IComplex (this->r * op.real () - this->i * op.imag (),
|
||||||
|
this->r * op.imag () + this->i * op.real ());
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) * C = (A*C) + i(B*C)
|
||||||
|
IComplex IComplex::operator* (const Interval &op) const {
|
||||||
|
return IComplex (this->r * op, this->i * op);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) * C = (A*C) + i(B*C)
|
||||||
|
IComplex IComplex::operator* (double op) const {
|
||||||
|
return IComplex (this->r * op, this->i * op);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
IComplex IComplex::operator/ (const IComplex &op) const {
|
||||||
|
return (*this) * (op.inverse ());
|
||||||
|
}
|
||||||
|
IComplex IComplex::operator/ (const std::complex<double> &op) const {
|
||||||
|
return (*this) * (IComplex(op).inverse ());
|
||||||
|
}
|
||||||
|
IComplex IComplex::operator/ (const Interval &op) const {
|
||||||
|
return IComplex (this->r / op, this->i / op);
|
||||||
|
}
|
||||||
|
IComplex IComplex::operator/ (double op) const {
|
||||||
|
return IComplex (this->r / op, this->i / op);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// // MISC
|
||||||
|
IComplex IComplex::inverse () const {
|
||||||
|
if (this->containsZero())
|
||||||
|
return IComplex (NAN, NAN, NAN, NAN);
|
||||||
|
IComplex inv_edge[4], rop;
|
||||||
|
inv_edge[0] = inverse_horizontal (this->r.a, this->r.b, this->i.a);
|
||||||
|
inv_edge[1] = inverse_horizontal (this->r.a, this->r.b, this->i.b);
|
||||||
|
inv_edge[2] = inverse_vertical (this->i.a, this->i.b, this->r.a);
|
||||||
|
inv_edge[3] = inverse_vertical (this->i.a, this->i.b, this->r.b);
|
||||||
|
|
||||||
|
rop.r.a = MIN (MIN (MIN (inv_edge[0].r.a,
|
||||||
|
inv_edge[1].r.a), inv_edge[2].r.a), inv_edge[3].r.a);
|
||||||
|
rop.r.b = MAX (MAX (MAX (inv_edge[0].r.b,
|
||||||
|
inv_edge[1].r.b), inv_edge[2].r.b), inv_edge[3].r.b);
|
||||||
|
rop.i.a = MIN (MIN (MIN (inv_edge[0].i.a,
|
||||||
|
inv_edge[1].i.a), inv_edge[2].i.a), inv_edge[3].i.a);
|
||||||
|
rop.i.b = MAX (MAX (MAX (inv_edge[0].i.b,
|
||||||
|
inv_edge[1].i.b), inv_edge[2].i.b), inv_edge[3].i.b);
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECKS WHETHER 0 IS IN A + iB
|
||||||
|
int IComplex::containsZero () const {
|
||||||
|
return ((this->r).containsZero () && (this->i).containsZero());
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECKS WHETHER A VALUE IS in A + iB
|
||||||
|
int IComplex::contains (double op) const {
|
||||||
|
return ((this->r).contains (op) && (this->i).contains(op));
|
||||||
|
}
|
||||||
|
int IComplex::contains (const std::complex<double> &op) {
|
||||||
|
return ((this->r).contains(op.real()) && (this->i).contains(op.imag ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// CHECK WHETHER A COMPLEX INTERVAL IS INSIDE ANOTHER WITHOUT TOUCHING THE EDGES
|
||||||
|
int IComplex::subset (const IComplex &op) const {
|
||||||
|
return (this->r).subset (op.r) && (this->i).subset (op.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK WHETHER A COMPLEX INTERVAL IS INSIDE ANOTHER
|
||||||
|
int IComplex::subsetEq (const IComplex &op) const {
|
||||||
|
return (this->r).subsetEq (op.r) && (this->i).subsetEq (op.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// // NON MEMBER FUNCTIONS
|
||||||
|
|
||||||
|
// OVERLOAD OUTPUT STREAM
|
||||||
|
std::ostream & operator<< (std::ostream &output, const IComplex &op) {
|
||||||
|
output << op.r << " + i*" << op.i;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// C + (A + iB) = (A+C) + iB
|
||||||
|
IComplex operator+ (const std::complex<double> &op1, const IComplex &op2) {
|
||||||
|
return IComplex (op1.real () + op2.r, op1.imag () + op2.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// C + (A + iB) = (A+C) + iB
|
||||||
|
IComplex operator+ (const Interval &op1, const IComplex &op2) {
|
||||||
|
return IComplex (op1 + op2.r, op2.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// C + (A + iB) = (A+C) + iB
|
||||||
|
IComplex operator+ (double op1, const IComplex &op2) {
|
||||||
|
return IComplex (op1 + op2.r, op2.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// C - (A + iB) = (C-A) + i(-B)
|
||||||
|
IComplex operator- (const std::complex<double> &op1, const IComplex &op2) {
|
||||||
|
return IComplex (op1.real () - op2.r, op1.imag () -op2.i);
|
||||||
|
}
|
||||||
|
// C - (A + iB) = (C-A) + i(-B)
|
||||||
|
IComplex operator- (const Interval &op1, const IComplex &op2) {
|
||||||
|
return IComplex (op1 - op2.r, -op2.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// C - (A + iB) = (C-A) + i(-B)
|
||||||
|
IComplex operator- (double op1, const IComplex &op2) {
|
||||||
|
return IComplex (op1 - op2.r, -op2.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// C * (A + iB) = (C*A) + i(C*B)
|
||||||
|
IComplex operator* (const std::complex<double> &op1, const IComplex &op2) {
|
||||||
|
return (IComplex (op1.real () * op2.r - op1.imag () * op2.i,
|
||||||
|
op1.real () * op2.i + op1.imag () * op2.r));
|
||||||
|
}
|
||||||
|
|
||||||
|
// C * (A + iB) = (C*A) + i(C*B)
|
||||||
|
IComplex operator* (const Interval &op1, const IComplex &op2) {
|
||||||
|
return (IComplex (op1 * op2.r, op1 * op2.i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// C * (A + iB) = (C*A) + i(C*B)
|
||||||
|
IComplex operator* (double op1, const IComplex &op2) {
|
||||||
|
return (IComplex (op1 * op2.r, op1 * op2.i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// C / (A + iB) = C * (A + iB)^-1
|
||||||
|
IComplex operator/ (const std::complex<double> &op1, const IComplex &op2) {
|
||||||
|
return op1 * (op2.inverse ());
|
||||||
|
}
|
||||||
|
|
||||||
|
// C / (A + iB) = C * (A + iB)^-1
|
||||||
|
IComplex operator/ (const Interval &op1, const IComplex &op2) {
|
||||||
|
return op1 * (op2.inverse ());
|
||||||
|
}
|
||||||
|
|
||||||
|
// C / (A + iB) = C * (A + iB)^-1
|
||||||
|
IComplex operator/ (double op1, const IComplex &op2) {
|
||||||
|
return op1 * (op2.inverse ());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MISC METHODS FOR INVERSION
|
||||||
|
|
||||||
|
// returns inverse of horizontal segment [a,b] + ci
|
||||||
|
IComplex inverse_horizontal (double a, double b, double c) {
|
||||||
|
IComplex rop;
|
||||||
|
int oldRoundingMode = fegetround ();
|
||||||
|
// case c = 0
|
||||||
|
if (c == 0) {
|
||||||
|
if (a < 0 && b > 0) {
|
||||||
|
rop.r.a = rop.r.b = rop.i.a = rop.i.b = NAN;
|
||||||
|
} else {
|
||||||
|
rop.i.a = rop.i.b = 0.0;
|
||||||
|
fesetround (FE_DOWNWARD);
|
||||||
|
rop.r.a = 1.0 / b;
|
||||||
|
fesetround (FE_UPWARD);
|
||||||
|
rop.r.b = 1.0 / a;
|
||||||
|
}
|
||||||
|
// case c > 0
|
||||||
|
} else if (c > 0) {
|
||||||
|
// case a<0<b
|
||||||
|
if (a < 0 && 0 < b) {
|
||||||
|
fesetround (FE_DOWNWARD);
|
||||||
|
|
||||||
|
if (a < -c)
|
||||||
|
rop.r.a = -0.5 / c;
|
||||||
|
else
|
||||||
|
rop.r.a = f (a, c);
|
||||||
|
|
||||||
|
rop.i.a = -1.0 / c;
|
||||||
|
|
||||||
|
fesetround (FE_UPWARD);
|
||||||
|
|
||||||
|
if (c < b)
|
||||||
|
rop.r.b = 0.5 / c;
|
||||||
|
else
|
||||||
|
rop.r.b = f (b, c);
|
||||||
|
|
||||||
|
if (b > (-a))
|
||||||
|
rop.i.b = g (b, c);
|
||||||
|
else
|
||||||
|
rop.i.b = g (a, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 0<=a<b
|
||||||
|
else if (0 <= a) {
|
||||||
|
fesetround (FE_DOWNWARD);
|
||||||
|
|
||||||
|
rop.r.a = MIN (f (a, c), f(b, c));
|
||||||
|
rop.i.a = g (a, c);
|
||||||
|
|
||||||
|
fesetround (FE_UPWARD);
|
||||||
|
|
||||||
|
if (b < c)
|
||||||
|
rop.r.b = f (b, c);
|
||||||
|
else if (c < a)
|
||||||
|
rop.r.b = f (a, c);
|
||||||
|
else
|
||||||
|
rop.r.b = 0.5 / c;
|
||||||
|
|
||||||
|
rop.i.b = g (b, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// case a<b<=0
|
||||||
|
else if (b <= 0) {
|
||||||
|
fesetround (FE_DOWNWARD);
|
||||||
|
|
||||||
|
if (-c < a)
|
||||||
|
rop.r.a = f (a, c);
|
||||||
|
else if (b < -c)
|
||||||
|
rop.r.a = f (b, c);
|
||||||
|
else
|
||||||
|
rop.r.a = -0.5 / c;
|
||||||
|
|
||||||
|
rop.i.a = g (b, c);
|
||||||
|
|
||||||
|
fesetround (FE_UPWARD);
|
||||||
|
|
||||||
|
rop.r.b = MAX (f (a, c), f (b, c));
|
||||||
|
rop.i.b = g (a, c);
|
||||||
|
}
|
||||||
|
// case c < 0
|
||||||
|
} else {
|
||||||
|
rop = inverse_horizontal (a, b, -c);
|
||||||
|
rop.i = -rop.i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fesetround (oldRoundingMode);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns inverse of verticla segment c + [a,b]i
|
||||||
|
IComplex inverse_vertical (double a, double b, double c) {
|
||||||
|
IComplex rop;
|
||||||
|
rop = inverse_horizontal (-b, -a, c);
|
||||||
|
Interval aux (rop.i);
|
||||||
|
rop.i = rop.r;
|
||||||
|
rop.r = -aux;
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
double f (double x, double c) {
|
||||||
|
return x / (x*x + c*c);
|
||||||
|
}
|
||||||
|
double g (double x, double c) {
|
||||||
|
return -c / (x*x + c*c);
|
||||||
|
}
|
||||||
368
lib/interval.cpp
Normal file
368
lib/interval.cpp
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
#include "interval.hpp"
|
||||||
|
#include <fenv.h>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ACTIVATE ROUND MODE CONTROL
|
||||||
|
#pragma STDC FENV_ACCESS on
|
||||||
|
|
||||||
|
// MACROS FOR MIN AND MAX
|
||||||
|
#define MIN(a,b) (((a) < (b))? (a) : (b))
|
||||||
|
#define MAX(a,b) (((a) > (b))? (a) : (b))
|
||||||
|
|
||||||
|
// DEFAULT CONSTRUCTOR
|
||||||
|
Interval::Interval (double op) {
|
||||||
|
a = b = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CONSTRUCTOR BY ELEMENT
|
||||||
|
Interval::Interval (double op1, double op2) {
|
||||||
|
a = op1; b = op2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// COPY CONSTRUCTOR
|
||||||
|
Interval::Interval (const Interval &op) {
|
||||||
|
a = op.a; b = op.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DESTRUCTOR. NOTHING TO DO...
|
||||||
|
Interval::~Interval () {}
|
||||||
|
|
||||||
|
|
||||||
|
// ASSIGNMENT
|
||||||
|
Interval & Interval::operator= (const Interval &op) {
|
||||||
|
// CHECK WHETER WE ARE ASIGNING SOMETHING OVER ITSELF
|
||||||
|
if (this == &op) return (*this);
|
||||||
|
// UPDATE VALUES
|
||||||
|
this->a = op.a; this->b = op.b;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Interval & Interval::operator= (double op) {
|
||||||
|
// UPDATE VALUES
|
||||||
|
this->a = op; this->b = op;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// COMPARISON
|
||||||
|
int Interval::operator== (const Interval &op) const {
|
||||||
|
// BOTH END POINTS MUST BE THE SAME TO BE EQUAL
|
||||||
|
if (this->a == op.a && this->b == op.b) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int Interval::operator!= (const Interval &op) const {
|
||||||
|
// BOTH END POINTS MUST BE THE SAME TO BE NOT DIFFERENT
|
||||||
|
if (this->a == op.a && this->b == op.b) return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ARITHMETIC
|
||||||
|
|
||||||
|
// [a,b] + [c,d] = [a+c, b+d]
|
||||||
|
Interval Interval::operator+ (const Interval &op) const {
|
||||||
|
Interval rop;
|
||||||
|
|
||||||
|
// STORE OLD ROUNDING MODE
|
||||||
|
int oldRound = fegetround ();
|
||||||
|
|
||||||
|
fesetround (FE_DOWNWARD);
|
||||||
|
rop.a = this->a + op.a;
|
||||||
|
|
||||||
|
fesetround (FE_UPWARD);
|
||||||
|
rop.b = this->b + op.b;
|
||||||
|
|
||||||
|
// RESTORE OLD ROUNDING MODE
|
||||||
|
fesetround (oldRound);
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
// [a,b] + c = [a+c, b+c]
|
||||||
|
Interval Interval::operator+ (double op) const {
|
||||||
|
Interval rop;
|
||||||
|
|
||||||
|
// STORE OLD ROUNDING MODE
|
||||||
|
int oldRound = fegetround ();
|
||||||
|
|
||||||
|
fesetround (FE_DOWNWARD);
|
||||||
|
rop.a = this->a + op;
|
||||||
|
|
||||||
|
fesetround (FE_UPWARD);
|
||||||
|
rop.b = this->b + op;
|
||||||
|
|
||||||
|
// RESTORE OLD ROUNDING MODE
|
||||||
|
fesetround (oldRound);
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHANGE OF SIGN OF AN INTERVAL
|
||||||
|
// -[a,b] = [-b,a]
|
||||||
|
Interval Interval::operator- () const {
|
||||||
|
Interval rop;
|
||||||
|
rop.a = -this->b;
|
||||||
|
rop.b = -this->a;
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [a,b] - [c,d] = [a-d, b-c]
|
||||||
|
Interval Interval::operator- (const Interval &op) const {
|
||||||
|
Interval rop;
|
||||||
|
|
||||||
|
// STORE OLD ROUNDING MODE
|
||||||
|
int oldRound = fegetround ();
|
||||||
|
|
||||||
|
fesetround (FE_DOWNWARD);
|
||||||
|
rop.a = this->a - op.b;
|
||||||
|
|
||||||
|
fesetround (FE_UPWARD);
|
||||||
|
rop.b = this->b - op.a;
|
||||||
|
|
||||||
|
// RESTORE OLD ROUNDING MODE
|
||||||
|
fesetround (oldRound);
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [a,b] - c = [a-c, b-c]
|
||||||
|
Interval Interval::operator- (double op) const {
|
||||||
|
Interval rop;
|
||||||
|
|
||||||
|
// STORE OLD ROUNDING MODE
|
||||||
|
int oldRound = fegetround ();
|
||||||
|
|
||||||
|
fesetround (FE_DOWNWARD);
|
||||||
|
rop.a = this->a - op;
|
||||||
|
|
||||||
|
fesetround (FE_UPWARD);
|
||||||
|
rop.b = this->b - op;
|
||||||
|
|
||||||
|
// RESTORE OLD ROUNDING MODE
|
||||||
|
fesetround (oldRound);
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [a,b]*[c,d] = [min(a*c,a*d,b*c,b*d), max(a*c,a*d,b*c,b*d)]
|
||||||
|
Interval Interval::operator* (const Interval &op) const {
|
||||||
|
Interval rop;
|
||||||
|
|
||||||
|
// STORE OLD ROUNDING MODE
|
||||||
|
int oldRound = fegetround ();
|
||||||
|
|
||||||
|
|
||||||
|
fesetround (FE_DOWNWARD);
|
||||||
|
rop.a = MIN(MIN(MIN(this->a*op.a, this->a*op.b), this->b*op.a), this->b*op.b);
|
||||||
|
|
||||||
|
fesetround (FE_UPWARD);
|
||||||
|
rop.b = MAX(MAX(MAX(this->a*op.a, this->a*op.b), this->b*op.a), this->b*op.b);
|
||||||
|
|
||||||
|
// RESTORE OLD ROUNDING MODE
|
||||||
|
fesetround (oldRound);
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// [a,b]*c = [min(a*c,b*c), max(a*c,b*c)]
|
||||||
|
Interval Interval::operator* (double op) const {
|
||||||
|
Interval rop;
|
||||||
|
|
||||||
|
// STORE OLD ROUNDING MODE
|
||||||
|
int oldRound = fegetround ();
|
||||||
|
|
||||||
|
|
||||||
|
fesetround (FE_DOWNWARD);
|
||||||
|
rop.a = MIN(this->a*op, this->b*op);
|
||||||
|
|
||||||
|
fesetround (FE_UPWARD);
|
||||||
|
rop.b = MAX(this->a*op, this->b*op);
|
||||||
|
|
||||||
|
// RESTORE OLD ROUNDING MODE
|
||||||
|
fesetround (oldRound);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// [a,b]/[c,d] = [min(a/c,a/d,b/c,b/d), max(a/c,a/d,b/c,b/d)]
|
||||||
|
Interval Interval::operator/ (const Interval &op) const {
|
||||||
|
if (op.containsZero()) return Interval (NAN);
|
||||||
|
|
||||||
|
Interval rop;
|
||||||
|
|
||||||
|
// STORE OLD ROUNDING MODE
|
||||||
|
int oldRound = fegetround ();
|
||||||
|
|
||||||
|
fesetround (FE_DOWNWARD);
|
||||||
|
rop.a = MIN(MIN(MIN(this->a/op.a, this->a/op.b), this->b/op.a), this->b/op.b);
|
||||||
|
|
||||||
|
fesetround (FE_UPWARD);
|
||||||
|
rop.b = MAX(MAX(MAX(this->a/op.a, this->a/op.b), this->b/op.a), this->b/op.b);
|
||||||
|
|
||||||
|
// RESTORE OLD ROUNDING MODE
|
||||||
|
fesetround (oldRound);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [a,b]/c = [min(a/c,b/c), max(a/c,b/c)]
|
||||||
|
Interval Interval::operator/ (double op) const {
|
||||||
|
if (op == 0.0) return Interval (NAN);
|
||||||
|
|
||||||
|
Interval rop;
|
||||||
|
|
||||||
|
// STORE OLD ROUNDING MODE
|
||||||
|
int oldRound = fegetround ();
|
||||||
|
|
||||||
|
|
||||||
|
fesetround (FE_DOWNWARD);
|
||||||
|
rop.a = MIN(this->a/op, this->b/op);
|
||||||
|
|
||||||
|
fesetround (FE_UPWARD);
|
||||||
|
rop.b = MAX(this->a/op, this->b/op);
|
||||||
|
|
||||||
|
// RESTORE OLD ROUNDING MODE
|
||||||
|
fesetround (oldRound);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// MISC
|
||||||
|
Interval Interval::inverse () const {
|
||||||
|
Interval rop;
|
||||||
|
|
||||||
|
// STORE OLD ROUNDING MODE
|
||||||
|
int oldRound = fegetround ();
|
||||||
|
|
||||||
|
if (0<this->a || this->b<0) {
|
||||||
|
fesetround (FE_DOWNWARD);
|
||||||
|
rop.a = 1.0 / (this->b);
|
||||||
|
fesetround (FE_UPWARD);
|
||||||
|
rop.b = 1.0 / (this->a);
|
||||||
|
} else {
|
||||||
|
rop.a = rop.b = NAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// RESTORE OLD ROUNDING MODE
|
||||||
|
fesetround (oldRound);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECKS WHETHER 0 in [a,b]
|
||||||
|
int Interval::containsZero () const {
|
||||||
|
if (this->a <= 0 && this->b >= 0) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// CHECKS WHETHER a value is in [a,b]
|
||||||
|
int Interval::contains (double op) const {
|
||||||
|
if (this->a <= op && this->b >= op) return 1;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
// CHECKS WHETHER [a,b] subset of [c,d] with a!=c and b!=d
|
||||||
|
int Interval::subset (const Interval &op) const {
|
||||||
|
if (this->a > op.a && this->b < op.b) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECKS WHETHER [a,b] subseteq of [c,d]
|
||||||
|
int Interval::subsetEq (const Interval &op) const {
|
||||||
|
if (this->a >= op.a && this->b <= op.b) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//EXTERNAL FUNCTIONS
|
||||||
|
// OVERLOAD OUTPUT STREAM
|
||||||
|
std::ostream & operator<< (std::ostream &output, const Interval &op) {
|
||||||
|
output << "[" << op.a << ", " << op.b << "]";
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// c + [a,b] = [a+c, b+c]
|
||||||
|
Interval operator+ (double op1, const Interval &op2) {
|
||||||
|
Interval rop;
|
||||||
|
|
||||||
|
// STORE OLD ROUNDING MODE
|
||||||
|
int oldRound = fegetround ();
|
||||||
|
|
||||||
|
fesetround (FE_DOWNWARD);
|
||||||
|
rop.a = op1 + op2.a;
|
||||||
|
|
||||||
|
fesetround (FE_UPWARD);
|
||||||
|
rop.b = op1 + op2.b;
|
||||||
|
|
||||||
|
// RESTORE OLD ROUNDING MODE
|
||||||
|
fesetround (oldRound);
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// c - [a,b] = [c-b, c-a]
|
||||||
|
Interval operator- (double op1, const Interval &op2) {
|
||||||
|
Interval rop;
|
||||||
|
|
||||||
|
// STORE OLD ROUNDING MODE
|
||||||
|
int oldRound = fegetround ();
|
||||||
|
|
||||||
|
fesetround (FE_DOWNWARD);
|
||||||
|
rop.a = op1 - op2.b;
|
||||||
|
|
||||||
|
fesetround (FE_UPWARD);
|
||||||
|
rop.b = op1 - op2.a;
|
||||||
|
|
||||||
|
// RESTORE OLD ROUNDING MODE
|
||||||
|
fesetround (oldRound);
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// c*[a,b] = [min(a*c,b*c), max(a*c,b*c)]
|
||||||
|
Interval operator* (double op1, const Interval &op2) {
|
||||||
|
Interval rop;
|
||||||
|
|
||||||
|
// STORE OLD ROUNDING MODE
|
||||||
|
int oldRound = fegetround ();
|
||||||
|
|
||||||
|
|
||||||
|
fesetround (FE_DOWNWARD);
|
||||||
|
rop.a = MIN(op2.a*op1, op2.b*op1);
|
||||||
|
|
||||||
|
fesetround (FE_UPWARD);
|
||||||
|
rop.b = MAX(op2.a*op1, op2.b*op1);
|
||||||
|
|
||||||
|
// RESTORE OLD ROUNDING MODE
|
||||||
|
fesetround (oldRound);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// c/[a,b] = [min(c/a,c/b), max(c/a,c/b)]
|
||||||
|
Interval operator/ (double op1, const Interval &op2) {
|
||||||
|
if (op2.containsZero ()) return Interval (NAN);
|
||||||
|
|
||||||
|
Interval rop;
|
||||||
|
|
||||||
|
// STORE OLD ROUNDING MODE
|
||||||
|
int oldRound = fegetround ();
|
||||||
|
|
||||||
|
|
||||||
|
fesetround (FE_DOWNWARD);
|
||||||
|
rop.a = MIN(op1 / op2.a, op1 / op2.b);
|
||||||
|
|
||||||
|
fesetround (FE_UPWARD);
|
||||||
|
rop.b = MAX(op1 / op2.a, op1 / op2.b);
|
||||||
|
|
||||||
|
// RESTORE OLD ROUNDING MODE
|
||||||
|
fesetround (oldRound);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
389
lib/mp_complex.cpp
Normal file
389
lib/mp_complex.cpp
Normal file
@ -0,0 +1,389 @@
|
|||||||
|
#include "mp_complex.hpp"
|
||||||
|
|
||||||
|
MPComplex::MPComplex (double op) {
|
||||||
|
mpfr_init (r);
|
||||||
|
mpfr_set_d (r, op, MPFR_RNDN);
|
||||||
|
mpfr_init_set_si (i, 0, MPFR_RNDN);
|
||||||
|
}
|
||||||
|
MPComplex::MPComplex (double op1, double op2) {
|
||||||
|
mpfr_init_set_d (r, op1, MPFR_RNDN);
|
||||||
|
mpfr_init_set_d (i, op2, MPFR_RNDN);
|
||||||
|
}
|
||||||
|
MPComplex::MPComplex (const std::complex<double> &op) {
|
||||||
|
mpfr_init_set_d (r, op.real (), MPFR_RNDN);
|
||||||
|
mpfr_init_set_d (i, op.imag (), MPFR_RNDN);
|
||||||
|
}
|
||||||
|
MPComplex::MPComplex (const mpfr_t op) {
|
||||||
|
mpfr_init_set (r, op, MPFR_RNDN);
|
||||||
|
mpfr_init_set_si (i, 0, MPFR_RNDN);
|
||||||
|
}
|
||||||
|
MPComplex::MPComplex (const mpfr_t op1, const mpfr_t op2) {
|
||||||
|
mpfr_init_set (r, op1, MPFR_RNDN);
|
||||||
|
mpfr_init_set (i, op2, MPFR_RNDN);
|
||||||
|
}
|
||||||
|
MPComplex::~MPComplex () {
|
||||||
|
mpfr_clears (r, i, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ASSIGNMENT
|
||||||
|
MPComplex & MPComplex::operator= (double op) {
|
||||||
|
mpfr_set_d (this->r, op, MPFR_RNDN);
|
||||||
|
mpfr_set_si (this->i, 0, MPFR_RNDN);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
MPComplex & MPComplex::operator= (const std::complex<double> &op) {
|
||||||
|
mpfr_set_d (this->r, op.real (), MPFR_RNDN);
|
||||||
|
mpfr_set_d (this->i, op.imag (), MPFR_RNDN);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
MPComplex & MPComplex::operator= (const mpfr_t op) {
|
||||||
|
mpfr_set (this->r, op, MPFR_RNDN);
|
||||||
|
mpfr_set_si (this->i, 0, MPFR_RNDN);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
MPComplex & MPComplex::operator= (const MPComplex &op) {
|
||||||
|
mpfr_set (this->r, op.r, MPFR_RNDN);
|
||||||
|
mpfr_set (this->i, op.i, MPFR_RNDN);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// COMPARISON
|
||||||
|
|
||||||
|
int MPComplex::operator == (double op) const {
|
||||||
|
return (mpfr_cmp_d (this->r, op) == 0) && (mpfr_cmp_si (this->i, 0) == 0);
|
||||||
|
}
|
||||||
|
int MPComplex::operator == (const std::complex<double> &op) const {
|
||||||
|
return (mpfr_cmp_d (this->r, op.real ()) == 0) && (mpfr_cmp_d (this->i, op.imag ()) == 0);
|
||||||
|
}
|
||||||
|
int MPComplex::operator == (const MPComplex &op) const {
|
||||||
|
return (mpfr_cmp (this->r, op.r) == 0) && (mpfr_cmp (this->i, op.i) == 0);
|
||||||
|
}
|
||||||
|
int MPComplex::operator != (double op) const {
|
||||||
|
return (mpfr_cmp_d (this->r, op) != 0) || (mpfr_cmp_si (this->i, 0) != 0);
|
||||||
|
}
|
||||||
|
int MPComplex::operator != (const std::complex<double> &op) const {
|
||||||
|
return (mpfr_cmp_d (this->r, op.real ()) != 0) || (mpfr_cmp_d (this->i, op.imag ()) != 0);
|
||||||
|
}
|
||||||
|
int MPComplex::operator != (const MPComplex &op) const {
|
||||||
|
return (mpfr_cmp (this->r, op.r) != 0) || (mpfr_cmp (this->i, op.i) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ARITHMETIC
|
||||||
|
MPComplex MPComplex::operator+ (double op) const {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_add_d (rop.r, this->r, op, MPFR_RNDN);
|
||||||
|
mpfr_set (rop.i, this->i, MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
MPComplex MPComplex::operator+ (const std::complex<double> &op) const {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_add_d (rop.r, this->r, op.real (), MPFR_RNDN);
|
||||||
|
mpfr_add_d (rop.i, this->i, op.imag (), MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
MPComplex MPComplex::operator+ (const mpfr_t op) const {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_add (rop.r, this->r, op, MPFR_RNDN);
|
||||||
|
mpfr_set (rop.i, this->i, MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
MPComplex MPComplex::operator+ (const MPComplex &op) const {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_add (rop.r, this->r, op.r, MPFR_RNDN);
|
||||||
|
mpfr_add (rop.i, this->i, op.i, MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPComplex MPComplex::operator- () const {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_neg (rop.r, this->r, MPFR_RNDN);
|
||||||
|
mpfr_neg (rop.i, this->i, MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
MPComplex MPComplex::operator- (double op) const {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_sub_d (rop.r, this->r, op, MPFR_RNDN);
|
||||||
|
mpfr_set (rop.i, this->i, MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
MPComplex MPComplex::operator- (const std::complex<double> &op) const {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_sub_d (rop.r, this->r, op.real (), MPFR_RNDN);
|
||||||
|
mpfr_sub_d (rop.i, this->i, op.imag (), MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
MPComplex MPComplex::operator- (const mpfr_t op) const {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_sub (rop.r, this->r, op, MPFR_RNDN);
|
||||||
|
mpfr_set (rop.i, this->i, MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
MPComplex MPComplex::operator- (const MPComplex &op) const {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_sub (rop.r, this->r, op.r, MPFR_RNDN);
|
||||||
|
mpfr_sub (rop.i, this->i, op.i, MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPComplex MPComplex::operator* (double op) const {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_mul_d (rop.r, this->r, op, MPFR_RNDN);
|
||||||
|
mpfr_mul_d (rop.i, this->i, op, MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
MPComplex MPComplex::operator* (const std::complex<double> &op) const {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_t aux; mpfr_init (aux);
|
||||||
|
mpfr_mul_d (rop.r, this->r, op.real (), MPFR_RNDN);
|
||||||
|
mpfr_mul_d (aux, this->i, op.imag (), MPFR_RNDN);
|
||||||
|
mpfr_sub (rop.r, rop.r, aux, MPFR_RNDN);
|
||||||
|
mpfr_mul_d (rop.i, this->r, op.imag (), MPFR_RNDN);
|
||||||
|
mpfr_mul_d (aux, this->i, op.real (), MPFR_RNDN);
|
||||||
|
mpfr_add (rop.i, rop.i, aux, MPFR_RNDN);
|
||||||
|
|
||||||
|
mpfr_clear (aux);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
MPComplex MPComplex::operator* (const mpfr_t op) const {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_mul (rop.r, this->r, op, MPFR_RNDN);
|
||||||
|
mpfr_mul (rop.i, this->i, op, MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
MPComplex MPComplex::operator* (const MPComplex &op) const {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_t aux; mpfr_init (aux);
|
||||||
|
mpfr_mul (rop.r, this->r, op.r, MPFR_RNDN);
|
||||||
|
mpfr_mul (aux, this->i, op.i, MPFR_RNDN);
|
||||||
|
mpfr_sub (rop.r, rop.r, aux, MPFR_RNDN);
|
||||||
|
mpfr_mul (rop.i, this->r, op.i, MPFR_RNDN);
|
||||||
|
mpfr_mul (aux, this->i, op.r, MPFR_RNDN);
|
||||||
|
mpfr_add (rop.i, rop.i, aux, MPFR_RNDN);
|
||||||
|
|
||||||
|
mpfr_clear (aux);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MPComplex MPComplex::operator/ (double op) const {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_div_d (rop.r, this->r, op, MPFR_RNDN);
|
||||||
|
mpfr_div_d (rop.i, this->i, op, MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
MPComplex MPComplex::operator/ (const std::complex<double> &op) const {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_t aux; mpfr_init (aux);
|
||||||
|
double factor = 1.0 / ((op.real() * op.real()) + (op.imag() * op.imag()));
|
||||||
|
mpfr_mul_d (rop.r, this->r, op.real (), MPFR_RNDN);
|
||||||
|
mpfr_mul_d (aux, this->i, op.imag (), MPFR_RNDN);
|
||||||
|
mpfr_add (rop.r, rop.r, aux, MPFR_RNDN);
|
||||||
|
mpfr_mul_d (rop.r, rop.r, factor, MPFR_RNDN);
|
||||||
|
mpfr_mul_d (rop.i, this->i, op.real (), MPFR_RNDN);
|
||||||
|
mpfr_mul_d (aux, this->r, op.imag (), MPFR_RNDN);
|
||||||
|
mpfr_sub (rop.i, rop.i, aux, MPFR_RNDN);
|
||||||
|
mpfr_mul_d (rop.i, rop.i, factor, MPFR_RNDN);
|
||||||
|
mpfr_clear (aux);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
MPComplex MPComplex::operator/ (const mpfr_t op) const {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_div (rop.r, this->r, op, MPFR_RNDN);
|
||||||
|
mpfr_div (rop.i, this->i, op, MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
MPComplex MPComplex::operator/ (const MPComplex &op) const {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_t aux, factor; mpfr_inits (aux, factor, NULL);
|
||||||
|
|
||||||
|
mpfr_mul (factor, op.r, op.r, MPFR_RNDN);
|
||||||
|
mpfr_mul (aux, op.i, op.i, MPFR_RNDN);
|
||||||
|
mpfr_add (factor, factor, aux, MPFR_RNDN);
|
||||||
|
mpfr_si_div (factor, 1, factor, MPFR_RNDN);
|
||||||
|
|
||||||
|
mpfr_mul (rop.r, this->r, op.r, MPFR_RNDN);
|
||||||
|
mpfr_mul (aux, this->i, op.i, MPFR_RNDN);
|
||||||
|
mpfr_add (rop.r, rop.r, aux, MPFR_RNDN);
|
||||||
|
mpfr_mul (rop.r, rop.r, factor, MPFR_RNDN);
|
||||||
|
mpfr_mul (rop.i, this->i, op.r, MPFR_RNDN);
|
||||||
|
mpfr_mul (aux, this->r, op.i, MPFR_RNDN);
|
||||||
|
mpfr_sub (rop.i, rop.i, aux, MPFR_RNDN);
|
||||||
|
mpfr_mul (rop.i, rop.i, factor, MPFR_RNDN);
|
||||||
|
|
||||||
|
mpfr_clears (aux, factor, NULL);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NON MEMBER FUNCTIONS
|
||||||
|
|
||||||
|
std::ostream & operator<< (std::ostream &output, const MPComplex &op) {
|
||||||
|
|
||||||
|
mpfr_exp_t exponent;
|
||||||
|
char *string = mpfr_get_str (NULL, &exponent, 10, 0, op.r, MPFR_RNDD);
|
||||||
|
if (mpfr_signbit (op.r) != 0)
|
||||||
|
output << "-" << string[1] << "." << string+2 << "e" << exponent-1;
|
||||||
|
else
|
||||||
|
output << string[0] << "." << string+1 << "e" << exponent-1;
|
||||||
|
mpfr_free_str (string);
|
||||||
|
|
||||||
|
string = mpfr_get_str (NULL, &exponent, 10, 0, op.i, MPFR_RNDU);
|
||||||
|
if (mpfr_signbit (op.i) != 0)
|
||||||
|
output << "-" << string[1] << "." << string+2 << "e" << exponent-1 << "i";
|
||||||
|
else
|
||||||
|
output << "+" << string[0] << "." << string+1 << "e" << exponent-1 << "i";
|
||||||
|
|
||||||
|
mpfr_free_str (string);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
MPComplex operator+ (double op1, const MPComplex &op2) {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_add_d (rop.r, op2.r, op1, MPFR_RNDN);
|
||||||
|
mpfr_set (rop.i, op2.i, MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
MPComplex operator+ (const std::complex<double> &op1, const MPComplex &op2) {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_add_d (rop.r, op2.r, op1.real (), MPFR_RNDN);
|
||||||
|
mpfr_add_d (rop.i, op2.i, op1.imag (), MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
MPComplex operator+ (const mpfr_t op1, const MPComplex &op2) {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_add (rop.r, op2.r, op1, MPFR_RNDN);
|
||||||
|
mpfr_set (rop.i, op2.i, MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MPComplex operator- (double op1, const MPComplex &op2) {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_d_sub (rop.r, op1, op2.r, MPFR_RNDN);
|
||||||
|
mpfr_neg (rop.i, op2.i, MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
MPComplex operator- (const std::complex<double> &op1, const MPComplex &op2) {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_d_sub (rop.r, op1.real (), op2.r, MPFR_RNDN);
|
||||||
|
mpfr_d_sub (rop.i, op1.imag (), op2.i, MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
MPComplex operator- (const mpfr_t op1, const MPComplex &op2) {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_sub (rop.r, op1, op2.r, MPFR_RNDN);
|
||||||
|
mpfr_neg (rop.i, op2.i, MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
MPComplex operator* (double op1, const MPComplex &op2) {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_mul_d (rop.r, op2.r, op1, MPFR_RNDN);
|
||||||
|
mpfr_mul_d (rop.i, op2.i, op1, MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
MPComplex operator* (const std::complex<double> &op1, const MPComplex &op2) {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_t aux; mpfr_init (aux);
|
||||||
|
mpfr_mul_d (rop.r, op2.r, op1.real (), MPFR_RNDN);
|
||||||
|
mpfr_mul_d (aux, op2.i, op1.imag (), MPFR_RNDN);
|
||||||
|
mpfr_sub (rop.r, rop.r, aux, MPFR_RNDN);
|
||||||
|
mpfr_mul_d (rop.i, op2.r, op1.imag (), MPFR_RNDN);
|
||||||
|
mpfr_mul_d (aux, op2.r, op1.real (), MPFR_RNDN);
|
||||||
|
mpfr_add (rop.i, rop.i, aux, MPFR_RNDN);
|
||||||
|
|
||||||
|
mpfr_clear (aux);
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
MPComplex operator* (const mpfr_t op1, const MPComplex &op2) {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_mul (rop.r, op2.r, op1, MPFR_RNDN);
|
||||||
|
mpfr_mul (rop.i, op2.i, op1, MPFR_RNDN);
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
MPComplex operator/ (double op1, const MPComplex &op2) {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_t factor;
|
||||||
|
mpfr_init (factor);
|
||||||
|
mpfr_mul (factor, op2.r, op2.r, MPFR_RNDN);
|
||||||
|
mpfr_mul (rop.r, op2.i, op2.i, MPFR_RNDN);
|
||||||
|
mpfr_add (factor, factor, rop.r, MPFR_RNDN);
|
||||||
|
mpfr_si_div (factor, 1, factor, MPFR_RNDN);
|
||||||
|
|
||||||
|
mpfr_mul_d (rop.r, op2.r, op1, MPFR_RNDN);
|
||||||
|
mpfr_mul (rop.r, rop.r, factor, MPFR_RNDN);
|
||||||
|
mpfr_mul_d (rop.i, op2.i, op1, MPFR_RNDN);
|
||||||
|
mpfr_neg (rop.i, rop.i, MPFR_RNDN);
|
||||||
|
mpfr_mul (rop.i, rop.i, factor, MPFR_RNDN);
|
||||||
|
|
||||||
|
mpfr_clear (factor);
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
MPComplex operator/ (const std::complex<double> &op1, const MPComplex &op2) {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_t factor, aux;
|
||||||
|
mpfr_inits (factor, aux, NULL);
|
||||||
|
mpfr_mul (factor, op2.r, op2.r, MPFR_RNDN);
|
||||||
|
mpfr_mul (aux, op2.i, op2.i, MPFR_RNDN);
|
||||||
|
mpfr_add (factor, factor, aux, MPFR_RNDN);
|
||||||
|
mpfr_si_div (factor, 1, factor, MPFR_RNDN);
|
||||||
|
|
||||||
|
mpfr_mul_d (rop.r, op2.r, op1.real (), MPFR_RNDN);
|
||||||
|
mpfr_mul_d (aux, op2.i, op1.imag (), MPFR_RNDN);
|
||||||
|
mpfr_add (rop.r, rop.r, aux, MPFR_RNDN);
|
||||||
|
mpfr_mul (rop.r, rop.r, factor, MPFR_RNDN);
|
||||||
|
mpfr_mul_d (rop.i, op2.r, op1.imag (), MPFR_RNDN);
|
||||||
|
mpfr_mul_d (aux, op2.i, op1.real (), MPFR_RNDN);
|
||||||
|
mpfr_sub (rop.i, rop.i, aux, MPFR_RNDN);
|
||||||
|
mpfr_neg (rop.i, rop.i, MPFR_RNDN);
|
||||||
|
mpfr_mul (rop.i, rop.i, factor, MPFR_RNDN);
|
||||||
|
|
||||||
|
mpfr_clears (factor, aux, NULL);
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
MPComplex operator/ (const mpfr_t op1, const MPComplex &op2) {
|
||||||
|
MPComplex rop;
|
||||||
|
mpfr_t factor;
|
||||||
|
mpfr_init (factor);
|
||||||
|
mpfr_mul (factor, op2.r, op2.r, MPFR_RNDN);
|
||||||
|
mpfr_mul (rop.r, op2.i, op2.i, MPFR_RNDN);
|
||||||
|
mpfr_add (factor, factor, rop.r, MPFR_RNDN);
|
||||||
|
mpfr_si_div (factor, 1, factor, MPFR_RNDN);
|
||||||
|
|
||||||
|
mpfr_mul (rop.r, op2.r, op1, MPFR_RNDN);
|
||||||
|
mpfr_mul (rop.r, rop.r, factor, MPFR_RNDN);
|
||||||
|
mpfr_mul (rop.i, op2.i, op1, MPFR_RNDN);
|
||||||
|
mpfr_neg (rop.i, rop.i, MPFR_RNDN);
|
||||||
|
mpfr_mul (rop.i, rop.i, factor, MPFR_RNDN);
|
||||||
|
|
||||||
|
mpfr_clear (factor);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
void abs (mpfr_t rop, const MPComplex &op) {
|
||||||
|
mpfr_t aux;
|
||||||
|
mpfr_init (aux);
|
||||||
|
mpfr_mul (rop, op.r, op.r, MPFR_RNDN);
|
||||||
|
mpfr_mul (aux, op.i, op.i, MPFR_RNDN);
|
||||||
|
mpfr_add (rop, rop, aux, MPFR_RNDN);
|
||||||
|
mpfr_sqrt (rop, rop, MPFR_RNDN);
|
||||||
|
|
||||||
|
|
||||||
|
mpfr_clear (aux);
|
||||||
|
return;
|
||||||
|
}
|
||||||
483
lib/mp_icomplex.cpp
Normal file
483
lib/mp_icomplex.cpp
Normal file
@ -0,0 +1,483 @@
|
|||||||
|
#include "mp_icomplex.hpp"
|
||||||
|
|
||||||
|
// CONSTRUCTORS
|
||||||
|
MPIComplex::MPIComplex (double op)
|
||||||
|
: r (op), i (0.0) {}
|
||||||
|
MPIComplex::MPIComplex (double op1, double op2, double op3, double op4)
|
||||||
|
: r (op1, op2), i (op3, op4) {}
|
||||||
|
MPIComplex::MPIComplex (const mpfr_t op)
|
||||||
|
: r (op), i (0.0) {}
|
||||||
|
MPIComplex::MPIComplex (const MPComplex &op)
|
||||||
|
: r (op.r), i (op.i) {}
|
||||||
|
MPIComplex::MPIComplex (const mpfr_t op1, const mpfr_t op2, const mpfr_t op3, const mpfr_t op4)
|
||||||
|
: r (op1, op2), i (op3, op4) {}
|
||||||
|
MPIComplex::MPIComplex (const Interval &op1, const Interval &op2)
|
||||||
|
: r (op1), i (op2) {}
|
||||||
|
MPIComplex::MPIComplex (const MPInterval &op1, const MPInterval &op2)
|
||||||
|
: r (op1), i (op2) {}
|
||||||
|
MPIComplex::MPIComplex (const IComplex &op)
|
||||||
|
: r (op.r), i (op.i) {}
|
||||||
|
// COPY CONSTRUCTOR
|
||||||
|
MPIComplex::MPIComplex (const MPIComplex &op)
|
||||||
|
: r (op.r), i (op.i) {}
|
||||||
|
MPIComplex::~MPIComplex () {}
|
||||||
|
|
||||||
|
// ASSIGNMENT
|
||||||
|
MPIComplex & MPIComplex::operator= (const MPIComplex &op) {
|
||||||
|
// CHECK WHETER WE ARE ASIGNING SOMETHING OVER ITSELF
|
||||||
|
if (this == &op) return (*this);
|
||||||
|
// UPDATE ELEMENTS
|
||||||
|
this->r = op.r; this->i = op.i;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
MPIComplex & MPIComplex::operator= (const IComplex &op) {
|
||||||
|
// UPDATE ELEMENTS
|
||||||
|
this->r = op.r; this->i = op.i;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
MPIComplex & MPIComplex::operator= (const MPInterval &op) {
|
||||||
|
// UPDATE ELEMENTS
|
||||||
|
this->r = op; this->i = 0.0;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
MPIComplex & MPIComplex::operator= (const Interval &op) {
|
||||||
|
// UPDATE ELEMENTS
|
||||||
|
this->r = op; this->i = 0.0;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
MPIComplex & MPIComplex::operator= (const mpfr_t op) {
|
||||||
|
// UPDATE ELEMENTS
|
||||||
|
this->r = op; this->i = 0.0;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
MPIComplex & MPIComplex::operator= (double op) {
|
||||||
|
// UPDATE ELEMENTS
|
||||||
|
this->r = op; this->i = 0.0;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// // COMPARISON
|
||||||
|
|
||||||
|
int MPIComplex::operator== (double op) const {
|
||||||
|
return (this->r == op) && (this->i == 0);
|
||||||
|
}
|
||||||
|
int MPIComplex::operator== (const std::complex<double> &op) const {
|
||||||
|
return (this->r == op.real() && this->i == op.imag ());
|
||||||
|
}
|
||||||
|
int MPIComplex::operator== (const Interval &op) const {
|
||||||
|
return (this->r == op) && (this->i == 0);
|
||||||
|
}
|
||||||
|
int MPIComplex::operator== (const MPInterval &op) const {
|
||||||
|
return (this->r == op) && (this->i == 0);
|
||||||
|
}
|
||||||
|
int MPIComplex::operator== (const MPIComplex &op) const {
|
||||||
|
return (this->r == op.r) && (this->i == op.i);
|
||||||
|
}
|
||||||
|
int MPIComplex::operator!= (double op) const {
|
||||||
|
return (this->r != op) || (this->i != 0);
|
||||||
|
}
|
||||||
|
int MPIComplex::operator!= (const std::complex<double> &op) const {
|
||||||
|
return (this->r != op.real() || this->i != op.imag ());
|
||||||
|
}
|
||||||
|
int MPIComplex::operator!= (const Interval &op) const {
|
||||||
|
return (this->r != op) || (this->i != 0);
|
||||||
|
}
|
||||||
|
int MPIComplex::operator!= (const MPInterval &op) const {
|
||||||
|
return (this->r != op) || (this->i != 0);
|
||||||
|
}
|
||||||
|
int MPIComplex::operator!= (const MPIComplex &op) const {
|
||||||
|
return (this->r != op.r) || (this->i != op.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// // ARITHMETIC
|
||||||
|
// A INTERVAL REAL PART
|
||||||
|
// B INTERNAL IMAG PART
|
||||||
|
// (A + iB) + (C + iD) = (A+C) + i(B+D)
|
||||||
|
MPIComplex MPIComplex::operator+ (const MPIComplex &op) const {
|
||||||
|
return MPIComplex (this->r + op.r, this->i + op.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) + (C + iD) = (A+C) + i(B+D)
|
||||||
|
MPIComplex MPIComplex::operator+ (const IComplex &op) const {
|
||||||
|
return MPIComplex (this->r + op.r, this->i + op.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) + C = (A+C) + iB
|
||||||
|
MPIComplex MPIComplex::operator+ (const MPInterval &op) const {
|
||||||
|
return MPIComplex (this->r + op, this->i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) + C = (A+C) + iB
|
||||||
|
MPIComplex MPIComplex::operator+ (const Interval &op) const {
|
||||||
|
return MPIComplex (this->r + op, this->i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) + C = (A+C) + iB
|
||||||
|
MPIComplex MPIComplex::operator+ (const mpfr_t op) const {
|
||||||
|
return MPIComplex (this->r + op, this->i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) + C = (A+C) + iB
|
||||||
|
MPIComplex MPIComplex::operator+ (double op) const {
|
||||||
|
return MPIComplex (this->r + op, this->i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// -(A + iB) = (-A) + i(-B)
|
||||||
|
MPIComplex MPIComplex::operator- () const {
|
||||||
|
return MPIComplex (-(this->r), -(this->i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) - (C + iD) = (A-C) + i(B-D)
|
||||||
|
MPIComplex MPIComplex::operator- (const MPIComplex &op) const {
|
||||||
|
return MPIComplex (this->r - op.r, this->i - op.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) - (C + iD) = (A-C) + i(B-D)
|
||||||
|
MPIComplex MPIComplex::operator- (const IComplex &op) const {
|
||||||
|
return MPIComplex (this->r - op.r, this->i - op.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) - C = (A-C) + iB
|
||||||
|
MPIComplex MPIComplex::operator- (const MPInterval &op) const {
|
||||||
|
return MPIComplex (this->r - op, this->i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) - C = (A-C) + iB
|
||||||
|
MPIComplex MPIComplex::operator- (const Interval &op) const {
|
||||||
|
return MPIComplex (this->r - op, this->i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) - C = (A-C) + iB
|
||||||
|
MPIComplex MPIComplex::operator- (const mpfr_t op) const {
|
||||||
|
return MPIComplex (this->r - op, this->i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) - C = (A-C) + iB
|
||||||
|
MPIComplex MPIComplex::operator- (double op) const {
|
||||||
|
return MPIComplex (this->r - op, this->i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// (A + iB) * (C + iD) = (A*C - B*D) + i(A*D + B*C)
|
||||||
|
MPIComplex MPIComplex::operator* (const MPIComplex &op) const {
|
||||||
|
return MPIComplex (this->r * op.r - this->i * op.i,
|
||||||
|
this->r * op.i + this->i * op.r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) * (C + iD) = (A*C - B*D) + i(A*D + B*C)
|
||||||
|
MPIComplex MPIComplex::operator* (const IComplex &op) const {
|
||||||
|
return MPIComplex (this->r * op.r - this->i * op.i,
|
||||||
|
this->r * op.i + this->i * op.r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) * C = (A*C) + i(B*C)
|
||||||
|
MPIComplex MPIComplex::operator* (const MPInterval &op) const {
|
||||||
|
return MPIComplex (this->r * op, this->i * op);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) * C = (A*C) + i(B*C)
|
||||||
|
MPIComplex MPIComplex::operator* (const Interval &op) const {
|
||||||
|
return MPIComplex (this->r * op, this->i * op);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) * C = (A*C) + i(B*C)
|
||||||
|
MPIComplex MPIComplex::operator* (const mpfr_t op) const {
|
||||||
|
return MPIComplex (this->r * op, this->i * op);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A + iB) * C = (A*C) + i(B*C)
|
||||||
|
MPIComplex MPIComplex::operator* (double op) const {
|
||||||
|
return MPIComplex (this->r * op, this->i * op);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MPIComplex MPIComplex::operator/ (const MPIComplex &op) const {
|
||||||
|
return (*this) * (op.inverse ());
|
||||||
|
}
|
||||||
|
MPIComplex MPIComplex::operator/ (const IComplex &op) const {
|
||||||
|
return (*this) * (op.inverse ());
|
||||||
|
}
|
||||||
|
MPIComplex MPIComplex::operator/ (const MPInterval &op) const {
|
||||||
|
return (*this) * (op.inverse ());
|
||||||
|
}
|
||||||
|
MPIComplex MPIComplex::operator/ (const Interval &op) const {
|
||||||
|
return (*this) * (op.inverse ());
|
||||||
|
}
|
||||||
|
MPIComplex MPIComplex::operator/ (const mpfr_t op) const {
|
||||||
|
return (*this) * (MPIComplex(op).inverse ());
|
||||||
|
}
|
||||||
|
MPIComplex MPIComplex::operator/ (double op) const {
|
||||||
|
return (*this) * (IComplex(op).inverse ());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// // MISC
|
||||||
|
MPIComplex MPIComplex::inverse () const {
|
||||||
|
if (this->containsZero()) {
|
||||||
|
mpfr_t aux;
|
||||||
|
mpfr_init (aux);
|
||||||
|
mpfr_set_nan (aux);
|
||||||
|
MPIComplex rop (aux);
|
||||||
|
mpfr_clear (aux);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPIComplex inv_edge[4], rop;
|
||||||
|
inv_edge[0] = inverse_horizontal (this->r.a, this->r.b, this->i.a);
|
||||||
|
inv_edge[1] = inverse_horizontal (this->r.a, this->r.b, this->i.b);
|
||||||
|
inv_edge[2] = inverse_vertical (this->i.a, this->i.b, this->r.a);
|
||||||
|
inv_edge[3] = inverse_vertical (this->i.a, this->i.b, this->r.b);
|
||||||
|
|
||||||
|
mpfr_min (rop.r.a, inv_edge[0].r.a, inv_edge[1].r.a, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.r.a, rop.r.a, inv_edge[2].r.a, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.r.a, rop.r.a, inv_edge[3].r.a, MPFR_RNDD);
|
||||||
|
|
||||||
|
|
||||||
|
mpfr_max (rop.r.b, inv_edge[0].r.b, inv_edge[1].r.b, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.r.b, rop.r.b, inv_edge[2].r.b, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.r.b, rop.r.b, inv_edge[3].r.b, MPFR_RNDU);
|
||||||
|
|
||||||
|
mpfr_min (rop.i.a, inv_edge[0].i.a, inv_edge[1].i.a, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.i.a, rop.i.a, inv_edge[2].i.a, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.i.a, rop.i.a, inv_edge[3].i.a, MPFR_RNDD);
|
||||||
|
|
||||||
|
|
||||||
|
mpfr_max (rop.i.b, inv_edge[0].i.b, inv_edge[1].i.b, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.i.b, rop.i.b, inv_edge[2].i.b, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.i.b, rop.i.b, inv_edge[3].i.b, MPFR_RNDU);
|
||||||
|
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int MPIComplex::containsZero () const {
|
||||||
|
return ((this->r).containsZero () && (this->i).containsZero());
|
||||||
|
}
|
||||||
|
int MPIComplex::contains (double op) const {
|
||||||
|
return ((this->r).contains (op) && (this->i).contains(op));
|
||||||
|
}
|
||||||
|
int MPIComplex::contains (const mpfr_t op) const {
|
||||||
|
return ((this->r).contains (op) && (this->i).contains(op));
|
||||||
|
}
|
||||||
|
int MPIComplex::subset (const MPIComplex &op) const {
|
||||||
|
return (this->r).subset (op.r) && (this->i).subset (op.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// // NON MEMBER FUNCTIONS
|
||||||
|
|
||||||
|
std::ostream & operator<< (std::ostream &output, const MPIComplex &op) {
|
||||||
|
output << op.r << " + i" << op.i;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MPIComplex operator+ (const IComplex &op1, const MPIComplex &op2) {
|
||||||
|
return MPIComplex (op1.r + op2.r, op1.i + op2.i);
|
||||||
|
}
|
||||||
|
MPIComplex operator+ (const MPInterval &op1, const MPIComplex &op2) {
|
||||||
|
return MPIComplex (op2.r, op1 + op2.i);
|
||||||
|
}
|
||||||
|
MPIComplex operator+ (const Interval &op1, const MPIComplex &op2) {
|
||||||
|
return MPIComplex (op1 + op2.r, op2.i);
|
||||||
|
}
|
||||||
|
MPIComplex operator+ (const mpfr_t op1, const MPIComplex &op2) {
|
||||||
|
return MPIComplex (op1 + op2.r, op2.i);
|
||||||
|
}
|
||||||
|
MPIComplex operator+ (double op1, const MPIComplex &op2) {
|
||||||
|
return MPIComplex (op1 + op2.r, op2.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
MPIComplex operator- (const IComplex &op1, const MPIComplex &op2) {
|
||||||
|
return MPIComplex (op1.r - op2.r, op1.i - op2.i);
|
||||||
|
}
|
||||||
|
MPIComplex operator- (const MPInterval &op1, const MPIComplex &op2) {
|
||||||
|
return MPIComplex (op1 - op2.r, -op2.i);
|
||||||
|
}
|
||||||
|
MPIComplex operator- (const Interval &op1, const MPIComplex &op2) {
|
||||||
|
return MPIComplex (op1 - op2.r, -op2.i);
|
||||||
|
}
|
||||||
|
MPIComplex operator- (const mpfr_t op1, const MPIComplex &op2) {
|
||||||
|
return MPIComplex (op1 - op2.r, -op2.i);
|
||||||
|
}
|
||||||
|
MPIComplex operator- (double op1, const MPIComplex &op2) {
|
||||||
|
return MPIComplex (op1 - op2.r, -op2.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
MPIComplex operator* (const IComplex &op1, const MPIComplex &op2) {
|
||||||
|
return MPIComplex (op1.r * op2.r - op1.i * op2.i,
|
||||||
|
op1.r * op2.i + op1.i * op2.r);
|
||||||
|
}
|
||||||
|
MPIComplex operator* (const MPInterval &op1, const MPIComplex &op2) {
|
||||||
|
return MPIComplex (op1 * op2.r, op1 * op2.i);
|
||||||
|
}
|
||||||
|
MPIComplex operator* (const Interval &op1, const MPIComplex &op2) {
|
||||||
|
return MPIComplex (op1 * op2.r, op1 * op2.i);
|
||||||
|
}
|
||||||
|
MPIComplex operator* (const mpfr_t op1, const MPIComplex &op2) {
|
||||||
|
return MPIComplex (op1 * op2.r, op1 * op2.i);
|
||||||
|
}
|
||||||
|
MPIComplex operator* (double op1, const MPIComplex &op2) {
|
||||||
|
return MPIComplex (op1 * op2.r, op1 * op2.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
MPIComplex operator/ (const IComplex &op1, const MPIComplex &op2) {
|
||||||
|
return op1 * (op2.inverse ());
|
||||||
|
}
|
||||||
|
MPIComplex operator/ (const MPInterval &op1, const MPIComplex &op2) {
|
||||||
|
return op1 * (op2.inverse ());
|
||||||
|
}
|
||||||
|
MPIComplex operator/ (const Interval &op1, const MPIComplex &op2) {
|
||||||
|
return op1 * (op2.inverse ());
|
||||||
|
}
|
||||||
|
MPIComplex operator/ (const mpfr_t op1, const MPIComplex &op2) {
|
||||||
|
return op1 * (op2.inverse ());
|
||||||
|
}
|
||||||
|
MPIComplex operator/ (double op1, const MPIComplex &op2) {
|
||||||
|
return op1 * (op2.inverse ());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// // MISCELLANEOUS FUNCTIONS FOR INVERT COMPLEX INTERVALS
|
||||||
|
|
||||||
|
// returns inverse of horizontal segment [a,b] + ci
|
||||||
|
MPIComplex inverse_horizontal (const mpfr_t a, const mpfr_t b, const mpfr_t c) {
|
||||||
|
MPIComplex rop;
|
||||||
|
mpfr_t aux;
|
||||||
|
mpfr_init (aux);
|
||||||
|
// case c = 0
|
||||||
|
if (mpfr_cmp_si (c, 0) == 0) {
|
||||||
|
if (mpfr_cmp_si (a, 0) < 0 && mpfr_cmp_si (b, 0) > 0) {
|
||||||
|
mpfr_set_nan (rop.r.a);
|
||||||
|
mpfr_set_nan (rop.r.b);
|
||||||
|
mpfr_set_nan (rop.i.a);
|
||||||
|
mpfr_set_nan (rop.i.b);
|
||||||
|
} else {
|
||||||
|
mpfr_si_div (rop.r.a, 1, b, MPFR_RNDD);
|
||||||
|
mpfr_si_div (rop.r.b, 1, a, MPFR_RNDU);
|
||||||
|
mpfr_set_si (rop.i.a, 0, MPFR_RNDD);
|
||||||
|
mpfr_set_si (rop.i.b, 0, MPFR_RNDU);
|
||||||
|
}
|
||||||
|
// case c > 0
|
||||||
|
} else if (mpfr_cmp_si (c, 0) > 0) {
|
||||||
|
// case a<0<b
|
||||||
|
if (mpfr_cmp_si (a, 0) < 0 && mpfr_cmp_si (b, 0) > 0) {
|
||||||
|
mpfr_si_div (rop.i.a, -1, c, MPFR_RNDD);
|
||||||
|
|
||||||
|
if (mpfr_cmpabs (b, a) > 0)
|
||||||
|
g (rop.i.b, b, c, MPFR_RNDU);
|
||||||
|
else
|
||||||
|
g (rop.i.b, a, c, MPFR_RNDU);
|
||||||
|
|
||||||
|
|
||||||
|
if (mpfr_cmpabs (a, c) > 0) {
|
||||||
|
mpfr_mul_si (aux, c, 2, MPFR_RNDD);
|
||||||
|
mpfr_si_div (rop.r.a, -1, aux, MPFR_RNDD);
|
||||||
|
} else
|
||||||
|
f (rop.r.a, a, c, MPFR_RNDD);
|
||||||
|
|
||||||
|
|
||||||
|
if (mpfr_cmp (c, b) < 0) {
|
||||||
|
mpfr_mul_si (aux, c, 2, MPFR_RNDU);
|
||||||
|
mpfr_si_div (rop.r.b, 1, aux, MPFR_RNDU);
|
||||||
|
} else {
|
||||||
|
f (rop.r.b, b, c, MPFR_RNDU);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 0<=a<b
|
||||||
|
else if (mpfr_cmp_si (a, 0) >= 0) {
|
||||||
|
g (rop.i.a, a, c, MPFR_RNDD);
|
||||||
|
|
||||||
|
g (rop.i.b, b, c, MPFR_RNDU);
|
||||||
|
|
||||||
|
f (aux, a, c, MPFR_RNDD);
|
||||||
|
f (rop.r.a, b, c, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.r.a, rop.r.a, aux, MPFR_RNDD);
|
||||||
|
|
||||||
|
if (mpfr_cmp (b, c) < 0) {
|
||||||
|
f (rop.r.b, b, c, MPFR_RNDU);
|
||||||
|
} else if (mpfr_cmp (c, a) < 0) {
|
||||||
|
f (rop.r.b, a, c, MPFR_RNDU);
|
||||||
|
} else {
|
||||||
|
mpfr_mul_si (rop.r.b, c, 2, MPFR_RNDU);
|
||||||
|
mpfr_si_div (rop.r.b, 1, rop.r.b, MPFR_RNDU);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// case a<b<=0
|
||||||
|
else if (mpfr_cmp_si (b, 0) <= 0) {
|
||||||
|
g (rop.i.a, b, c, MPFR_RNDD);
|
||||||
|
g (rop.i.b, a, c, MPFR_RNDU);
|
||||||
|
f (aux, a, c, MPFR_RNDU);
|
||||||
|
f (rop.r.b, b, c, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.r.b, rop.r.b, aux, MPFR_RNDU);
|
||||||
|
|
||||||
|
if (mpfr_cmpabs (c, a) > 0) {
|
||||||
|
f (rop.r.a, a, c, MPFR_RNDD);
|
||||||
|
} else if (mpfr_cmpabs (b, c) > 0) {
|
||||||
|
f (rop.r.a, b, c, MPFR_RNDD);
|
||||||
|
} else {
|
||||||
|
mpfr_mul_si (rop.r.a, c, 2, MPFR_RNDD);
|
||||||
|
mpfr_si_div (rop.r.a, -1, rop.r.a, MPFR_RNDD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// case c < 0
|
||||||
|
} else {
|
||||||
|
mpfr_neg (aux, c, MPFR_RNDN); // ???
|
||||||
|
rop = inverse_horizontal (a, b, aux);
|
||||||
|
rop.i = -rop.i;
|
||||||
|
}
|
||||||
|
mpfr_clear (aux);
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns inverse of verticla segment c + [a,b]i
|
||||||
|
MPIComplex inverse_vertical (const mpfr_t a, const mpfr_t b, const mpfr_t c) {
|
||||||
|
mpfr_t aux1, aux2;
|
||||||
|
mpfr_inits (aux1, aux2, NULL);
|
||||||
|
mpfr_neg (aux1, b, MPFR_RNDD);
|
||||||
|
mpfr_neg (aux2, a, MPFR_RNDU);
|
||||||
|
MPIComplex rop;
|
||||||
|
rop = inverse_horizontal (aux1, aux2, c);
|
||||||
|
|
||||||
|
MPInterval aux (rop.i);
|
||||||
|
rop.i = rop.r;
|
||||||
|
rop.r = -aux;
|
||||||
|
|
||||||
|
mpfr_clears (aux1, aux2, NULL);
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
void f (mpfr_t rop, const mpfr_t x, const mpfr_t c, mpfr_rnd_t roundMode) {
|
||||||
|
mpfr_t aux;
|
||||||
|
mpfr_init(aux);
|
||||||
|
mpfr_mul (aux, c, c, roundMode);
|
||||||
|
mpfr_mul (rop, x, x, roundMode);
|
||||||
|
mpfr_add (rop, rop, aux, roundMode);
|
||||||
|
mpfr_div (rop, x, rop, roundMode);
|
||||||
|
mpfr_clear (aux);
|
||||||
|
}
|
||||||
|
void g (mpfr_t rop, const mpfr_t x, const mpfr_t c, mpfr_rnd_t roundMode) {
|
||||||
|
mpfr_t aux;
|
||||||
|
mpfr_init (aux);
|
||||||
|
mpfr_mul (aux, c, c, roundMode);
|
||||||
|
mpfr_mul (rop, x, x, roundMode);
|
||||||
|
mpfr_add (rop, rop, aux, roundMode);
|
||||||
|
mpfr_neg (aux, c, roundMode);
|
||||||
|
mpfr_div (rop, aux, rop, roundMode);
|
||||||
|
mpfr_clear (aux);
|
||||||
|
}
|
||||||
559
lib/mp_interval.cpp
Normal file
559
lib/mp_interval.cpp
Normal file
@ -0,0 +1,559 @@
|
|||||||
|
#include "mp_interval.hpp"
|
||||||
|
|
||||||
|
// MACROS FOR MIN AND MAX
|
||||||
|
|
||||||
|
#define MIN(a,b) (((a) < (b))? (a) : (b))
|
||||||
|
#define MAX(a,b) (((a) > (b))? (a) : (b))
|
||||||
|
|
||||||
|
// DEFAULT CONSTRUCTOR
|
||||||
|
MPInterval::MPInterval (double op) {
|
||||||
|
mpfr_init_set_d (a, op, MPFR_RNDD);
|
||||||
|
mpfr_init_set_d (b, op, MPFR_RNDU);
|
||||||
|
}
|
||||||
|
// CONSTRUCTOR BY double ELEMENTS
|
||||||
|
MPInterval::MPInterval (double op1, double op2) {
|
||||||
|
mpfr_init_set_d (a, op1, MPFR_RNDD);
|
||||||
|
mpfr_init_set_d (b, op2, MPFR_RNDU);
|
||||||
|
}
|
||||||
|
// CONSTRUCTOR BY string VALUE
|
||||||
|
MPInterval::MPInterval (const char *op) {
|
||||||
|
mpfr_init_set_str (a, op, 10, MPFR_RNDD);
|
||||||
|
mpfr_init_set_str (b, op, 10, MPFR_RNDU);
|
||||||
|
}
|
||||||
|
// CONSTRUCTOR BY string PAIR OF VALUES
|
||||||
|
MPInterval::MPInterval (const char *op1, const char *op2) {
|
||||||
|
mpfr_init_set_str (a, op1, 10, MPFR_RNDD);
|
||||||
|
mpfr_init_set_str (b, op2, 10, MPFR_RNDU);
|
||||||
|
|
||||||
|
}
|
||||||
|
// CONSTRUCTOR BY mpfr ELEMENT
|
||||||
|
MPInterval::MPInterval (const mpfr_t op) {
|
||||||
|
mpfr_init_set (a, op, MPFR_RNDD);
|
||||||
|
mpfr_init_set (b, op, MPFR_RNDU);
|
||||||
|
}
|
||||||
|
// CONSTRUCTOR BY mpfr PAIR OF ELEMENTS
|
||||||
|
MPInterval::MPInterval (const mpfr_t op1, const mpfr_t op2) {
|
||||||
|
mpfr_init_set (a, op1, MPFR_RNDD);
|
||||||
|
mpfr_init_set (b, op2, MPFR_RNDU);
|
||||||
|
}
|
||||||
|
// CONSTRUCTOR BY double Invterval
|
||||||
|
MPInterval::MPInterval (const Interval &op) {
|
||||||
|
mpfr_init_set_d (a, op.a, MPFR_RNDD);
|
||||||
|
mpfr_init_set_d (b, op.b, MPFR_RNDU);
|
||||||
|
}
|
||||||
|
// COPY CONSTRUCTOR
|
||||||
|
MPInterval::MPInterval (const MPInterval &op) {
|
||||||
|
mpfr_init_set (a, op.a, MPFR_RNDD);
|
||||||
|
mpfr_init_set (b, op.b, MPFR_RNDU);
|
||||||
|
}
|
||||||
|
// DESTRUCTOR
|
||||||
|
MPInterval::~MPInterval () {
|
||||||
|
mpfr_clears (a, b, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int MPInterval::operator== (double op) const {
|
||||||
|
return (mpfr_cmp_d(this->a, op) == 0) && (mpfr_cmp_d(this->b, op) == 0);
|
||||||
|
}
|
||||||
|
int MPInterval::operator== (const Interval &op) const {
|
||||||
|
return (mpfr_cmp_d (this->a, op.a) == 0) && (mpfr_cmp_d (this->b, op.b) == 0);
|
||||||
|
}
|
||||||
|
int MPInterval::operator== (const MPInterval &op) const {
|
||||||
|
return (mpfr_cmp(this->a, op.a) == 0) && (mpfr_cmp(this->b, op.b) == 0);
|
||||||
|
}
|
||||||
|
int MPInterval::operator!= (double op) const {
|
||||||
|
return (mpfr_cmp_d(this->a, op) != 0) || (mpfr_cmp_d(this->b, op) != 0);
|
||||||
|
}
|
||||||
|
int MPInterval::operator!= (const Interval &op) const {
|
||||||
|
return (mpfr_cmp_d (this->a, op.a) != 0) || (mpfr_cmp_d (this->b, op.b) != 0);
|
||||||
|
}
|
||||||
|
int MPInterval::operator!= (const MPInterval &op) const {
|
||||||
|
return (mpfr_cmp(this->a, op.a) != 0) || (mpfr_cmp(this->a, op.b) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ASSIGNMENT
|
||||||
|
MPInterval & MPInterval::operator= (const MPInterval &op) {
|
||||||
|
// CHECK WHETER WE ARE ASIGNING SOMETHING OVER ITSELF
|
||||||
|
if (this == &op) return (*this);
|
||||||
|
// UPDATE VALUES
|
||||||
|
mpfr_set (this->a, op.a, MPFR_RNDD);
|
||||||
|
mpfr_set (this->b, op.b, MPFR_RNDU);
|
||||||
|
}
|
||||||
|
MPInterval & MPInterval::operator= (const Interval &op) {
|
||||||
|
// UPDATE VALUES
|
||||||
|
mpfr_set_d (this->a, op.a, MPFR_RNDD);
|
||||||
|
mpfr_set_d (this->b, op.b, MPFR_RNDU);
|
||||||
|
}
|
||||||
|
MPInterval & MPInterval::operator= (const mpfr_t op) {
|
||||||
|
// UPDATE VALUES
|
||||||
|
mpfr_set (this->a, op, MPFR_RNDD);
|
||||||
|
mpfr_set (this->b, op, MPFR_RNDU);
|
||||||
|
}
|
||||||
|
MPInterval & MPInterval::operator= (double op) {
|
||||||
|
// UPDATE VALUES
|
||||||
|
mpfr_set_d (this->a, op, MPFR_RNDD);
|
||||||
|
mpfr_set_d (this->b, op, MPFR_RNDU);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ARITHMETIC
|
||||||
|
|
||||||
|
// [a,b] + [c,d] = [a+c, b+d]
|
||||||
|
MPInterval MPInterval::operator+ (const MPInterval &op) const {
|
||||||
|
MPInterval rop (*this);
|
||||||
|
mpfr_add (rop.a, rop.a, op.a, MPFR_RNDD);
|
||||||
|
mpfr_add (rop.b, rop.b, op.b, MPFR_RNDU);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [a,b] + [c,d] = [a+c, b+d]
|
||||||
|
MPInterval MPInterval::operator+ (const Interval &op) const {
|
||||||
|
MPInterval rop (*this);
|
||||||
|
mpfr_add_d (rop.a, rop.a, op.a, MPFR_RNDD);
|
||||||
|
mpfr_add_d (rop.b, rop.b, op.b, MPFR_RNDU);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [a,b] + c = [a+c, b+c]
|
||||||
|
MPInterval MPInterval::operator+ (const mpfr_t op) const {
|
||||||
|
MPInterval rop (*this);
|
||||||
|
mpfr_add (rop.a, rop.a, op, MPFR_RNDD);
|
||||||
|
mpfr_add (rop.b, rop.b, op, MPFR_RNDU);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [a,b] + c = [a+c, b+c]
|
||||||
|
MPInterval MPInterval::operator+ (double op) const {
|
||||||
|
MPInterval rop (*this);
|
||||||
|
mpfr_add_d (rop.a, rop.a, op, MPFR_RNDD);
|
||||||
|
mpfr_add_d (rop.b, rop.b, op, MPFR_RNDU);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHANGE OF SIGN OF AN INTERVAL
|
||||||
|
// -[a,b] = [-b,a]
|
||||||
|
MPInterval MPInterval::operator- () const {
|
||||||
|
MPInterval rop;
|
||||||
|
mpfr_neg (rop.a, this->b, MPFR_RNDD);
|
||||||
|
mpfr_neg (rop.b, this->a, MPFR_RNDU);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [a,b] - [c,d] = [a-d, b-c]
|
||||||
|
MPInterval MPInterval::operator- (const MPInterval &op) const {
|
||||||
|
MPInterval rop(*this);
|
||||||
|
mpfr_sub (rop.a, rop.a, op.b, MPFR_RNDD);
|
||||||
|
mpfr_sub (rop.b, rop.b, op.a, MPFR_RNDU);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
// [a,b] - [c,d] = [a-d, b-c]
|
||||||
|
MPInterval MPInterval::operator- (const Interval &op) const {
|
||||||
|
MPInterval rop(*this);
|
||||||
|
mpfr_sub_d (rop.a, rop.a, op.b, MPFR_RNDD);
|
||||||
|
mpfr_sub_d (rop.b, rop.b, op.a, MPFR_RNDU);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [a,b] - c = [a-c, b-c]
|
||||||
|
MPInterval MPInterval::operator- (const mpfr_t op) const {
|
||||||
|
MPInterval rop(*this);
|
||||||
|
mpfr_sub (rop.a, rop.a, op, MPFR_RNDD);
|
||||||
|
mpfr_sub (rop.b, rop.b, op, MPFR_RNDU);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [a,b] - c = [a-c, b-c]
|
||||||
|
MPInterval MPInterval::operator- (double op) const {
|
||||||
|
MPInterval rop(*this);
|
||||||
|
mpfr_sub_d (rop.a, rop.a, op, MPFR_RNDD);
|
||||||
|
mpfr_sub_d (rop.b, rop.b, op, MPFR_RNDU);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [a,b]*[c,d] = [min(a*c,a*d,b*c,b*d), max(a*c,a*d,b*c,b*d)]
|
||||||
|
MPInterval MPInterval::operator* (const MPInterval &op) const {
|
||||||
|
mpfr_t aux;
|
||||||
|
mpfr_init (aux);
|
||||||
|
MPInterval rop;
|
||||||
|
|
||||||
|
mpfr_mul (rop.a, this->a, op.a, MPFR_RNDD);
|
||||||
|
mpfr_mul (aux, this->a, op.b, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
mpfr_mul (aux, this->b, op.a, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
mpfr_mul (aux, this->b, op.b, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
|
||||||
|
|
||||||
|
mpfr_mul (rop.b, this->a, op.a, MPFR_RNDU);
|
||||||
|
mpfr_mul (aux, this->a, op.b, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
mpfr_mul (aux, this->b, op.a, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
mpfr_mul (aux, this->b, op.b, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
|
||||||
|
mpfr_clear (aux);
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// [a,b]*[c,d] = [min(a*c,a*d,b*c,b*d), max(a*c,a*d,b*c,b*d)]
|
||||||
|
MPInterval MPInterval::operator* (const Interval &op) const {
|
||||||
|
mpfr_t aux;
|
||||||
|
mpfr_init (aux);
|
||||||
|
MPInterval rop;
|
||||||
|
|
||||||
|
mpfr_mul_d (rop.a, this->a, op.a, MPFR_RNDD);
|
||||||
|
mpfr_mul_d (aux, this->a, op.b, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
mpfr_mul_d (aux, this->b, op.a, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
mpfr_mul_d (aux, this->b, op.b, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
|
||||||
|
|
||||||
|
mpfr_mul_d (rop.b, this->a, op.a, MPFR_RNDU);
|
||||||
|
mpfr_mul_d (aux, this->a, op.b, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
mpfr_mul_d (aux, this->b, op.a, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
mpfr_mul_d (aux, this->b, op.b, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
|
||||||
|
mpfr_clear (aux);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// [a,b]*c = [min(a*c,b*c), max(a*c,b*c)]
|
||||||
|
MPInterval MPInterval::operator* (const mpfr_t op) const {
|
||||||
|
mpfr_t aux;
|
||||||
|
mpfr_init (aux);
|
||||||
|
MPInterval rop;
|
||||||
|
|
||||||
|
mpfr_mul (rop.a, this->a, op, MPFR_RNDD);
|
||||||
|
mpfr_mul (aux, this->b, op, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
|
||||||
|
|
||||||
|
mpfr_mul (rop.b, this->a, op, MPFR_RNDU);
|
||||||
|
mpfr_mul (aux, this->b, op, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
|
||||||
|
mpfr_clear (aux);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [a,b]*c = [min(a*c,b*c), max(a*c,b*c)]
|
||||||
|
MPInterval MPInterval::operator* (double op) const {
|
||||||
|
mpfr_t aux;
|
||||||
|
mpfr_init (aux);
|
||||||
|
MPInterval rop;
|
||||||
|
|
||||||
|
mpfr_mul_d (rop.a, this->a, op, MPFR_RNDD);
|
||||||
|
mpfr_mul_d (aux, this->b, op, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
|
||||||
|
|
||||||
|
mpfr_mul_d (rop.b, this->a, op, MPFR_RNDU);
|
||||||
|
mpfr_mul_d (aux, this->b, op, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
|
||||||
|
mpfr_clear (aux);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// [a,b]/[c,d] = [min(a/c,a/d,b/c,b/d), max(a/c,a/d,b/c,b/d)]
|
||||||
|
MPInterval MPInterval::operator/ (const MPInterval &op) const {
|
||||||
|
mpfr_t aux;
|
||||||
|
mpfr_init (aux);
|
||||||
|
MPInterval rop;
|
||||||
|
|
||||||
|
mpfr_div (rop.a, this->a, op.a, MPFR_RNDD);
|
||||||
|
mpfr_div (aux, this->a, op.b, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
mpfr_div (aux, this->b, op.a, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
mpfr_div (aux, this->b, op.b, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
|
||||||
|
|
||||||
|
mpfr_div (rop.b, this->a, op.a, MPFR_RNDU);
|
||||||
|
mpfr_div (aux, this->a, op.b, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
mpfr_div (aux, this->b, op.a, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
mpfr_div (aux, this->b, op.b, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
|
||||||
|
mpfr_clear (aux);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [a,b]/[c,d] = [min(a/c,a/d,b/c,b/d), max(a/c,a/d,b/c,b/d)]
|
||||||
|
MPInterval MPInterval::operator/ (const Interval &op) const {
|
||||||
|
mpfr_t aux;
|
||||||
|
mpfr_init (aux);
|
||||||
|
MPInterval rop;
|
||||||
|
|
||||||
|
mpfr_div_d (rop.a, this->a, op.a, MPFR_RNDD);
|
||||||
|
mpfr_div_d (aux, this->a, op.b, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
mpfr_div_d (aux, this->b, op.a, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
mpfr_div_d (aux, this->b, op.b, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
|
||||||
|
|
||||||
|
mpfr_div_d (rop.b, this->a, op.a, MPFR_RNDU);
|
||||||
|
mpfr_div_d (aux, this->a, op.b, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
mpfr_div_d (aux, this->b, op.a, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
mpfr_div_d (aux, this->b, op.b, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
|
||||||
|
mpfr_clear (aux);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [a,b]/c = [min(a/c,b/c), max(a/c,b/c)]
|
||||||
|
MPInterval MPInterval::operator/ (const mpfr_t op) const {
|
||||||
|
mpfr_t aux;
|
||||||
|
mpfr_init (aux);
|
||||||
|
MPInterval rop;
|
||||||
|
|
||||||
|
mpfr_div (rop.a, this->a, op, MPFR_RNDD);
|
||||||
|
mpfr_div (aux, this->b, op, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
|
||||||
|
|
||||||
|
mpfr_div (rop.b, this->a, op, MPFR_RNDU);
|
||||||
|
mpfr_div (aux, this->b, op, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
|
||||||
|
mpfr_clear (aux);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [a,b]/c = [min(a/c,b/c), max(a/c,b/c)]
|
||||||
|
MPInterval MPInterval::operator/ (double op) const {
|
||||||
|
mpfr_t aux;
|
||||||
|
mpfr_init (aux);
|
||||||
|
MPInterval rop;
|
||||||
|
|
||||||
|
mpfr_div_d (rop.a, this->a, op, MPFR_RNDD);
|
||||||
|
mpfr_div_d (aux, this->b, op, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
|
||||||
|
|
||||||
|
mpfr_div_d (rop.b, this->a, op, MPFR_RNDU);
|
||||||
|
mpfr_div_d (aux, this->b, op, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
|
||||||
|
mpfr_clear (aux);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// MISC
|
||||||
|
// [a,b] ^ -1 = [1/b, 1/a]
|
||||||
|
MPInterval MPInterval::inverse () const {
|
||||||
|
MPInterval rop;
|
||||||
|
|
||||||
|
// CHECK WHETER 0 IS IN THE INTERVAL
|
||||||
|
if (this->containsZero ()) {
|
||||||
|
mpfr_si_div (rop.a, 1, this->b, MPFR_RNDD);
|
||||||
|
mpfr_si_div (rop.b, 1, this->a, MPFR_RNDU);
|
||||||
|
} else {
|
||||||
|
mpfr_set_nan (rop.a);
|
||||||
|
mpfr_set_nan (rop.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK WHETER 0 IS IN THE INTERVAL
|
||||||
|
int MPInterval::containsZero () const {
|
||||||
|
if (mpfr_cmp_si (this->a, 0) <= 0 && mpfr_cmp_si (this->b, 0) >= 0)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK WHETER A VALUE IS IN THE INTERVAL
|
||||||
|
int MPInterval::contains (double op) const {
|
||||||
|
if (mpfr_cmp_d (this->a, op) <= 0 && mpfr_cmp_d (this->b, op) >= 0)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// CHECK WHETER A VALUE IS IN THE INTERVAL
|
||||||
|
int MPInterval::contains (const mpfr_t op) const {
|
||||||
|
if (mpfr_cmp (this->a, op) <= 0 && mpfr_cmp (this->b, op) >= 0)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECKS WHETER THE INTERVAL [a,b] IS SUBSET OF ANOTHER [c,d].
|
||||||
|
// c<a<b<d
|
||||||
|
int MPInterval::subset (const MPInterval &op) const {
|
||||||
|
if (mpfr_cmp (this->a, op.a) > 0 && mpfr_cmp (this->b, op.b) < 0)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECKS WHETER THE INTERVAL [a,b] IS SUBSET OF ANOTHER [c,d].
|
||||||
|
// c<a<b<d
|
||||||
|
int MPInterval::subset (const Interval &op) const {
|
||||||
|
if (mpfr_cmp_d (this->a, op.a) > 0 && mpfr_cmp_d (this->b, op.b) < 0)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// EXTERNAL FUNCTIONS
|
||||||
|
// OVERLOAD OUTPUT STREAM
|
||||||
|
std::ostream & operator<< (std::ostream &output, const MPInterval &op) {
|
||||||
|
mpfr_exp_t exponent;
|
||||||
|
char *string = mpfr_get_str (NULL, &exponent, 10, 0, op.a, MPFR_RNDD);
|
||||||
|
if (mpfr_signbit (op.a) != 0)
|
||||||
|
output << "[-" << string[1] << "." << string+2 << "e" << exponent-1 << ", ";
|
||||||
|
else
|
||||||
|
output << "[" << string[0] << "." << string+1 << "e" << exponent-1 << ", ";
|
||||||
|
mpfr_free_str (string);
|
||||||
|
|
||||||
|
string = mpfr_get_str (NULL, &exponent, 10, 0, op.b, MPFR_RNDU);
|
||||||
|
if (mpfr_signbit (op.b) != 0)
|
||||||
|
output << "-" << string[1] << "." << string+2 << "e" << exponent-1 << "]";
|
||||||
|
else
|
||||||
|
output << string[0] << "." << string+1 << "e" << exponent-1 << "]";
|
||||||
|
mpfr_free_str (string);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
// c + [a,b] = [a+c, b+c] = [a,b] + c
|
||||||
|
MPInterval operator+ (double op1, const MPInterval &op2) {
|
||||||
|
return op2 + op1;
|
||||||
|
}
|
||||||
|
// c + [a,b] = [a+c, b+c] = [a,b] + c
|
||||||
|
MPInterval operator+ (const mpfr_t op1, const MPInterval &op2) {
|
||||||
|
return op2 + op1;
|
||||||
|
}
|
||||||
|
// [c,d] + [a,b] = [a+c, b+c] = [a,b] + [c,d]
|
||||||
|
MPInterval operator+ (const Interval &op1, const MPInterval &op2) {
|
||||||
|
return op2 + op1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// c - [a,b] = [c-b, c-a]
|
||||||
|
MPInterval operator- (double op1, const MPInterval &op2) {
|
||||||
|
MPInterval rop;
|
||||||
|
mpfr_d_sub (rop.a, op1, op2.b, MPFR_RNDD);
|
||||||
|
mpfr_d_sub (rop.b, op1, op2.a, MPFR_RNDU);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// c - [a,b] = [c-b, c-a]
|
||||||
|
MPInterval operator- (const mpfr_t op1, const MPInterval &op2) {
|
||||||
|
MPInterval rop;
|
||||||
|
mpfr_sub (rop.a, op1, op2.b, MPFR_RNDD);
|
||||||
|
mpfr_sub (rop.b, op1, op2.a, MPFR_RNDU);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [c,d]- [a,b] = [c-b, d-a]
|
||||||
|
MPInterval operator- (const Interval &op1, const MPInterval &op2) {
|
||||||
|
MPInterval rop;
|
||||||
|
mpfr_d_sub (rop.a, op1.a, op2.b, MPFR_RNDD);
|
||||||
|
mpfr_d_sub (rop.b, op1.b, op2.a, MPFR_RNDU);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// c*[a,b] = [a,b]*c
|
||||||
|
MPInterval operator* (double op1, const MPInterval &op2) {
|
||||||
|
return op2 * op1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// c*[a,b] = [a,b]*c
|
||||||
|
MPInterval operator* (const mpfr_t op1, const MPInterval &op2) {
|
||||||
|
return op2 * op1;
|
||||||
|
}
|
||||||
|
// [c,d] * [a,b] = [a,b] * [c,d]
|
||||||
|
MPInterval operator* (const Interval &op1, const MPInterval &op2) {
|
||||||
|
return op2 * op1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// c / [a,b] = [min (c/a, c/b), max (c/a, c/b)]
|
||||||
|
MPInterval operator/ (double op1, const MPInterval &op2) {
|
||||||
|
mpfr_t aux;
|
||||||
|
mpfr_init (aux);
|
||||||
|
MPInterval rop;
|
||||||
|
|
||||||
|
mpfr_d_div (rop.a, op1, op2.a, MPFR_RNDD);
|
||||||
|
mpfr_d_div (aux, op1, op2.b, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
|
||||||
|
|
||||||
|
mpfr_d_div (rop.b, op1, op2.a, MPFR_RNDU);
|
||||||
|
mpfr_d_div (aux, op1, op2.b, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
|
||||||
|
mpfr_clear (aux);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// c / [a,b] = [min (c/a, c/b), max (c/a, c/b)]
|
||||||
|
MPInterval operator/ (const mpfr_t op1, const MPInterval &op2) {
|
||||||
|
mpfr_t aux;
|
||||||
|
mpfr_init (aux);
|
||||||
|
MPInterval rop;
|
||||||
|
|
||||||
|
mpfr_div (rop.a, op1, op2.a, MPFR_RNDD);
|
||||||
|
mpfr_div (aux, op1, op2.b, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
|
||||||
|
|
||||||
|
mpfr_div (rop.b, op1, op2.a, MPFR_RNDU);
|
||||||
|
mpfr_div (aux, op1, op2.b, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
|
||||||
|
mpfr_clear (aux);
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [a,b]/[c,d] = [min(a/c,a/d,b/c,b/d), max(a/c,a/d,b/c,b/d)]
|
||||||
|
MPInterval operator/ (const Interval &op1, const MPInterval &op2) {
|
||||||
|
mpfr_t aux;
|
||||||
|
mpfr_init (aux);
|
||||||
|
MPInterval rop;
|
||||||
|
|
||||||
|
mpfr_d_div (rop.a, op1.a, op2.a, MPFR_RNDD);
|
||||||
|
mpfr_d_div (aux, op1.a, op2.b, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
mpfr_d_div (aux, op1.b, op2.a, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
mpfr_d_div (aux, op1.b, op2.b, MPFR_RNDD);
|
||||||
|
mpfr_min (rop.a, rop.a, aux, MPFR_RNDD);
|
||||||
|
|
||||||
|
|
||||||
|
mpfr_d_div (rop.b, op1.a, op2.a, MPFR_RNDU);
|
||||||
|
mpfr_d_div (aux, op1.a, op2.b, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
mpfr_d_div (aux, op1.b, op2.a, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
mpfr_d_div (aux, op1.b, op2.b, MPFR_RNDU);
|
||||||
|
mpfr_max (rop.b, rop.b, aux, MPFR_RNDU);
|
||||||
|
|
||||||
|
mpfr_clear (aux);
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
297
lib/polynomial.cpp
Normal file
297
lib/polynomial.cpp
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
#include "polynomial.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int *_Polynomial::combinatorial;
|
||||||
|
|
||||||
|
|
||||||
|
void _Polynomial::startCombinatorialNumbers (int degree) {
|
||||||
|
_Polynomial::combinatorial = new unsigned int [((degree+2)*(degree+1))/2];
|
||||||
|
unsigned int *combinatorial = _Polynomial::combinatorial;
|
||||||
|
unsigned int i; // counter for m
|
||||||
|
unsigned int j; // counter for n
|
||||||
|
|
||||||
|
for (i=0; i<=degree; i++) {
|
||||||
|
combinatorial[(i*(i+1))/2] = combinatorial[(i*(i+3))/2] = 1; // FIRST AND LAST = 1
|
||||||
|
|
||||||
|
// THE REST IS COMPUTED FROM THE RECURRENCE OF COMBINATORIAL NUMBERS.
|
||||||
|
for (j=1; j<i; j++)
|
||||||
|
combinatorial[(i*(i+1))/2+j] = combinatorial[((i-1)*i)/2+j-1] + combinatorial[((i-1)*i)/2+j];
|
||||||
|
combinatorial[((i+1)*(i+2))/2-1] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
IComplex Polynomial<IComplex>::evalIPolHornerXY (const IComplex &x, const IComplex &y) const {
|
||||||
|
|
||||||
|
//evaluate polynomial as an element of K[x][y] in Horner form
|
||||||
|
//that is, each coefficient of y is a polynomial on x
|
||||||
|
int i; //i will represent the on x
|
||||||
|
int j; //j will represent the degree on y
|
||||||
|
int d = this->degree;
|
||||||
|
IComplex coef;
|
||||||
|
IComplex rop;
|
||||||
|
rop = (this->coef)[(d+2)*(d+1)/2-1];
|
||||||
|
for (j=d-1; j>=0; --j){
|
||||||
|
coef = (this->coef)[d*(d+1)/2+j];
|
||||||
|
for (i=d-1-j; i>=0; --i){
|
||||||
|
coef = x * coef + (this->coef)[(j+i)*(j+i+1)/2+j];
|
||||||
|
}
|
||||||
|
rop = rop * y + coef;
|
||||||
|
}
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
IComplex Polynomial<IComplex>::evalIPolHornerYX (const IComplex &x, const IComplex &y) const {
|
||||||
|
//evaluate polynomial as an element of K[y][x] in Horner form
|
||||||
|
//that is, each coefficient of x is a polynomial on y
|
||||||
|
int i; //i will represent the degree on x
|
||||||
|
int j; //j will represent the on y
|
||||||
|
int d = this->degree;
|
||||||
|
IComplex coef;
|
||||||
|
IComplex rop;
|
||||||
|
rop = (this->coef)[(d)*(d+1)/2];
|
||||||
|
for (i=d-1; i>=0; --i){
|
||||||
|
coef = (this->coef)[d*(d+1)/2+d-i];
|
||||||
|
for (j=d-i-1; j>=0; --j) {
|
||||||
|
coef = coef * y + (this->coef)[(i+j)*(i+j+1)/2+j];
|
||||||
|
}
|
||||||
|
rop = rop * x + coef;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
IComplex Polynomial<IComplex>::operator () (const IComplex &x, const IComplex &y) const{
|
||||||
|
IComplex rop, ropx, ropy;
|
||||||
|
|
||||||
|
ropx = this->evalIPolHornerXY (x, y);
|
||||||
|
ropy = this->evalIPolHornerYX (x, y);
|
||||||
|
rop = this->evalPolClassic (x, y);
|
||||||
|
|
||||||
|
|
||||||
|
rop.r.a = MAX(MAX(ropx.r.a, ropy.r.a), rop.r.a);
|
||||||
|
rop.r.b = MIN(MIN(ropx.r.b, ropy.r.b), rop.r.b);
|
||||||
|
rop.i.a = MAX(MAX(ropx.i.a, ropy.i.a), rop.i.a);
|
||||||
|
rop.i.b = MIN(MIN(ropx.i.b, ropy.i.b), rop.i.b);
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
IComplex Polynomial<IComplex>::evalIPolYHornerXY (const IComplex &x, const IComplex &y) const {
|
||||||
|
//evaluate polynomial as an element of K[x][y] in Horner form
|
||||||
|
//that is, each coefficient of y is a polynomial on x
|
||||||
|
int i; //i will represent the on x
|
||||||
|
int j; //j will represent the degree on y
|
||||||
|
int d = this->degree;
|
||||||
|
IComplex coef;
|
||||||
|
IComplex rop;
|
||||||
|
rop = (d) * (this->coef)[(d+2)*(d+1)/2-1];
|
||||||
|
|
||||||
|
for (j=d-2; j>=0; --j){
|
||||||
|
coef = (this->coef)[d*(d+1)/2+j+1];
|
||||||
|
for (i=d-1; i>=j+1; --i){
|
||||||
|
coef = x * coef + (this->coef)[(i*(i+1))/2+j+1];
|
||||||
|
}
|
||||||
|
rop = rop * y + (j+1.0) * coef;
|
||||||
|
}
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
IComplex Polynomial<IComplex>::evalIPolYHornerYX (const IComplex &x, const IComplex &y) const {
|
||||||
|
|
||||||
|
//evaluate polynomial as an element of K[x][y] in Horner form
|
||||||
|
//that is, each coefficient of y is a polynomial on x
|
||||||
|
int i; //i will represent the on x
|
||||||
|
int j; //j will represent the degree on y
|
||||||
|
int d = this->degree;
|
||||||
|
IComplex coef;
|
||||||
|
IComplex rop;
|
||||||
|
rop = (this->coef)[(d)*(d+1)/2+1];
|
||||||
|
|
||||||
|
for (i=d-2; i>=0; --i){
|
||||||
|
coef = ((double) d-i)*(this->coef)[(d*(d+1))/2+d-i];
|
||||||
|
for (j=d-1; j>=i+1; --j){
|
||||||
|
coef = y * coef + (j-i)*(this->coef)[(j*(j+1))/2+j-i];
|
||||||
|
}
|
||||||
|
rop = rop * x + coef;
|
||||||
|
}
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
IComplex Polynomial<IComplex>::diffY (const IComplex &x, const IComplex &y) const{
|
||||||
|
IComplex rop, ropx, ropy;
|
||||||
|
|
||||||
|
ropx = this->evalIPolYHornerXY (x, y);
|
||||||
|
ropy = this->evalIPolYHornerYX (x, y);
|
||||||
|
rop = this->evalPolYClassic (x, y);
|
||||||
|
|
||||||
|
|
||||||
|
rop.r.a = MAX(MAX(ropx.r.a, ropy.r.a), rop.r.a);
|
||||||
|
rop.r.b = MIN(MIN(ropx.r.b, ropy.r.b), rop.r.b);
|
||||||
|
rop.i.a = MAX(MAX(ropx.i.a, ropy.i.a), rop.i.a);
|
||||||
|
rop.i.b = MIN(MIN(ropx.i.b, ropy.i.b), rop.i.b);
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
MPIComplex Polynomial<MPIComplex>::evalIPolHornerXY (const MPIComplex &x, const MPIComplex &y) const {
|
||||||
|
|
||||||
|
//evaluate polynomial as an element of K[x][y] in Horner form
|
||||||
|
//that is, each coefficient of y is a polynomial on x
|
||||||
|
int i; //i will represent the on x
|
||||||
|
int j; //j will represent the degree on y
|
||||||
|
int d = this->degree;
|
||||||
|
MPIComplex coef;
|
||||||
|
MPIComplex rop;
|
||||||
|
rop = (this->coef)[(d+2)*(d+1)/2-1];
|
||||||
|
for (j=d-1; j>=0; --j){
|
||||||
|
coef = (this->coef)[d*(d+1)/2+j];
|
||||||
|
for (i=d-1-j; i>=0; --i){
|
||||||
|
coef = x * coef + (this->coef)[(j+i)*(j+i+1)/2+j];
|
||||||
|
}
|
||||||
|
rop = rop * y + coef;
|
||||||
|
}
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
MPIComplex Polynomial<MPIComplex>::evalIPolHornerYX (const MPIComplex &x, const MPIComplex &y) const {
|
||||||
|
//evaluate polynomial as an element of K[y][x] in Horner form
|
||||||
|
//that is, each coefficient of x is a polynomial on y
|
||||||
|
int i; //i will represent the degree on x
|
||||||
|
int j; //j will represent the on y
|
||||||
|
int d = this->degree;
|
||||||
|
MPIComplex coef;
|
||||||
|
MPIComplex rop;
|
||||||
|
rop = (this->coef)[(d)*(d+1)/2];
|
||||||
|
for (i=d-1; i>=0; --i){
|
||||||
|
coef = (this->coef)[d*(d+1)/2+d-i];
|
||||||
|
for (j=d-i-1; j>=0; --j) {
|
||||||
|
coef = coef * y + (this->coef)[(i+j)*(i+j+1)/2+j];
|
||||||
|
}
|
||||||
|
rop = rop * x + coef;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
MPIComplex Polynomial<MPIComplex>::operator () (const MPIComplex &x, const MPIComplex &y) const{
|
||||||
|
MPIComplex rop, ropx, ropy;
|
||||||
|
|
||||||
|
ropx = this->evalIPolHornerXY (x, y);
|
||||||
|
ropy = this->evalIPolHornerYX (x, y);
|
||||||
|
rop = this->evalPolClassic (x, y);
|
||||||
|
|
||||||
|
|
||||||
|
mpfr_max (rop.r.a, rop.r.a, ropx.r.a, MPFR_RNDD);
|
||||||
|
mpfr_max (rop.r.a, rop.r.a, ropy.r.a, MPFR_RNDD);
|
||||||
|
mpfr_max (rop.i.a, rop.i.a, ropx.i.a, MPFR_RNDD);
|
||||||
|
mpfr_max (rop.i.a, rop.i.a, ropy.i.a, MPFR_RNDD);
|
||||||
|
|
||||||
|
mpfr_min (rop.r.b, rop.r.b, ropx.r.b, MPFR_RNDU);
|
||||||
|
mpfr_min (rop.r.b, rop.r.b, ropy.r.b, MPFR_RNDU);
|
||||||
|
mpfr_min (rop.i.b, rop.i.b, ropx.i.b, MPFR_RNDU);
|
||||||
|
mpfr_min (rop.i.b, rop.i.b, ropy.i.b, MPFR_RNDU);
|
||||||
|
|
||||||
|
// rop.r.a = MAX(MAX(ropx.r.a, ropy.r.a), rop.r.a);
|
||||||
|
// rop.r.b = MIN(MIN(ropx.r.b, ropy.r.b), rop.r.b);
|
||||||
|
// rop.i.a = MAX(MAX(ropx.i.a, ropy.i.a), rop.i.a);
|
||||||
|
// rop.i.b = MIN(MIN(ropx.i.b, ropy.i.b), rop.i.b);
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
MPIComplex Polynomial<MPIComplex>::evalIPolYHornerXY (const MPIComplex &x, const MPIComplex &y) const {
|
||||||
|
//evaluate polynomial as an element of K[x][y] in Horner form
|
||||||
|
//that is, each coefficient of y is a polynomial on x
|
||||||
|
int i; //i will represent the on x
|
||||||
|
int j; //j will represent the degree on y
|
||||||
|
int d = this->degree;
|
||||||
|
MPIComplex coef;
|
||||||
|
MPIComplex rop;
|
||||||
|
rop = (d) * (this->coef)[(d+2)*(d+1)/2-1];
|
||||||
|
|
||||||
|
for (j=d-2; j>=0; --j){
|
||||||
|
coef = (this->coef)[d*(d+1)/2+j+1];
|
||||||
|
for (i=d-1; i>=j+1; --i){
|
||||||
|
coef = x * coef + (this->coef)[(i*(i+1))/2+j+1];
|
||||||
|
}
|
||||||
|
rop = rop * y + (j+1.0) * coef;
|
||||||
|
}
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
MPIComplex Polynomial<MPIComplex>::evalIPolYHornerYX (const MPIComplex &x, const MPIComplex &y) const {
|
||||||
|
|
||||||
|
//evaluate polynomial as an element of K[x][y] in Horner form
|
||||||
|
//that is, each coefficient of y is a polynomial on x
|
||||||
|
int i; //i will represent the on x
|
||||||
|
int j; //j will represent the degree on y
|
||||||
|
int d = this->degree;
|
||||||
|
MPIComplex coef;
|
||||||
|
MPIComplex rop;
|
||||||
|
rop = (this->coef)[(d)*(d+1)/2+1];
|
||||||
|
|
||||||
|
for (i=d-2; i>=0; --i){
|
||||||
|
coef = ((double) d-i)*(this->coef)[(d*(d+1))/2+d-i];
|
||||||
|
for (j=d-1; j>=i+1; --j){
|
||||||
|
coef = y * coef + (j-i)*(this->coef)[(j*(j+1))/2+j-i];
|
||||||
|
}
|
||||||
|
rop = rop * x + coef;
|
||||||
|
}
|
||||||
|
return rop;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
MPIComplex Polynomial<MPIComplex>::diffY (const MPIComplex &x, const MPIComplex &y) const{
|
||||||
|
MPIComplex rop, ropx, ropy;
|
||||||
|
|
||||||
|
ropx = this->evalIPolYHornerXY (x, y);
|
||||||
|
ropy = this->evalIPolYHornerYX (x, y);
|
||||||
|
rop = this->evalPolYClassic (x, y);
|
||||||
|
|
||||||
|
|
||||||
|
/*rop.r.a = MAX(MAX(ropx.r.a, ropy.r.a), rop.r.a);
|
||||||
|
rop.r.b = MIN(MIN(ropx.r.b, ropy.r.b), rop.r.b);
|
||||||
|
rop.i.a = MAX(MAX(ropx.i.a, ropy.i.a), rop.i.a);
|
||||||
|
rop.i.b = MIN(MIN(ropx.i.b, ropy.i.b), rop.i.b);*/
|
||||||
|
mpfr_max (rop.r.a, rop.r.a, ropx.r.a, MPFR_RNDD);
|
||||||
|
mpfr_max (rop.r.a, rop.r.a, ropy.r.a, MPFR_RNDD);
|
||||||
|
mpfr_max (rop.i.a, rop.i.a, ropx.i.a, MPFR_RNDD);
|
||||||
|
mpfr_max (rop.i.a, rop.i.a, ropy.i.a, MPFR_RNDD);
|
||||||
|
|
||||||
|
mpfr_min (rop.r.b, rop.r.b, ropx.r.b, MPFR_RNDU);
|
||||||
|
mpfr_min (rop.r.b, rop.r.b, ropy.r.b, MPFR_RNDU);
|
||||||
|
mpfr_min (rop.i.b, rop.i.b, ropx.i.b, MPFR_RNDU);
|
||||||
|
mpfr_min (rop.i.b, rop.i.b, ropy.i.b, MPFR_RNDU);
|
||||||
|
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
556
lib/sirocco.cpp
Normal file
556
lib/sirocco.cpp
Normal file
@ -0,0 +1,556 @@
|
|||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <sirocco.hpp>
|
||||||
|
#include <list.hpp>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
// unsigned int *_Polynomial::combinatorial;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
// f(z1,z2) = z1^3+2*z1*z2-3*z2-z1;
|
||||||
|
// COEFS = {{1,0,0,0}, {0,2,0}, {-1,3}, {0}}
|
||||||
|
// z1 = x + iy
|
||||||
|
// z2 = t(1+0.01i)
|
||||||
|
******************************************/
|
||||||
|
|
||||||
|
#pragma STDC FENV_ACCESS ON
|
||||||
|
|
||||||
|
// PERFORM A MINIMUM OF 5 ITERATIONS OF NEWTON METHOD TO CORRECT THE APPROXIMATION OF THE ROOT (SUPPOSED TO BE GOOD ENOUGH)
|
||||||
|
template <>
|
||||||
|
void correctRoot<Complex> (const Polynomial<Complex> f, const Complex &x0, Complex &y0) {
|
||||||
|
Complex increment;
|
||||||
|
int count = 0;
|
||||||
|
double last_increment, new_increment; // sizes of corrections
|
||||||
|
new_increment = 9999.0;
|
||||||
|
do {
|
||||||
|
last_increment = new_increment;
|
||||||
|
increment = f(x0,y0) / (f.diffY(x0,y0));
|
||||||
|
new_increment = abs (increment);
|
||||||
|
y0 = y0 - increment;
|
||||||
|
++count;
|
||||||
|
} while ((fabs(last_increment - new_increment) > 1.0e-14 || count < 6 ) && count < 50);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
template <>
|
||||||
|
void correctRoot<MPComplex> (const Polynomial<MPComplex> f, const MPComplex &x0, MPComplex &y0) {
|
||||||
|
MPComplex increment;
|
||||||
|
int count = 0;
|
||||||
|
mpfr_t last_increment, new_increment, tol; // sizes of corrections and tolerance
|
||||||
|
mpfr_inits (last_increment, new_increment, tol, NULL);
|
||||||
|
|
||||||
|
mpfr_set_d (tol, mpfr_get_default_prec(), MPFR_RNDN);
|
||||||
|
mpfr_sub_si (tol, tol, 5, MPFR_RNDN);
|
||||||
|
mpfr_neg (tol, tol, MPFR_RNDN);
|
||||||
|
mpfr_exp2 (tol, tol, MPFR_RNDN);
|
||||||
|
// std::cout << "tol = ";
|
||||||
|
// mpfr_out_str (stdout, 10, 20, tol, MPFR_RNDN);
|
||||||
|
// std::cout << std::endl;
|
||||||
|
|
||||||
|
mpfr_set_d (new_increment, 9999.0, MPFR_RNDN);
|
||||||
|
do {
|
||||||
|
mpfr_set (last_increment, new_increment, MPFR_RNDN);
|
||||||
|
increment = f(x0,y0) / (f.diffY(x0,y0));
|
||||||
|
abs (new_increment, increment);
|
||||||
|
y0 = y0 - increment;
|
||||||
|
++count;
|
||||||
|
|
||||||
|
// compute difference of increments and store in "last_increment"
|
||||||
|
mpfr_sub (last_increment, last_increment, new_increment, MPFR_RNDN);
|
||||||
|
mpfr_abs (last_increment, last_increment, MPFR_RNDN);
|
||||||
|
} while ((mpfr_cmp (last_increment, tol) > 0 || count < 6 ) && count < 50);
|
||||||
|
|
||||||
|
mpfr_clears (last_increment, new_increment, tol, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double * homotopyPath (int degree, double *_coef, double _y0R, double _y0I) {
|
||||||
|
|
||||||
|
_Polynomial::startCombinatorialNumbers (degree);
|
||||||
|
|
||||||
|
// /************************************************/
|
||||||
|
// /* VARIABLE DECLARATION AND DATA INITIALIZATION */
|
||||||
|
// /************************************************/
|
||||||
|
Complex aux; // Complex aux variable.
|
||||||
|
|
||||||
|
double stepsize = 0.0001; // step size
|
||||||
|
double eps; // radius of the box
|
||||||
|
|
||||||
|
|
||||||
|
int nCoef = ((degree+1)*(degree+2)) / 2; // number of monomials
|
||||||
|
Complex coef[nCoef]; // coefficient list for floating point representation of
|
||||||
|
// the polynomial.
|
||||||
|
IComplex Icoef[nCoef]; // coefficient list for Interval representation of
|
||||||
|
// the polynomial.
|
||||||
|
|
||||||
|
std::vector<Cell<double> > outputList;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// INITIALIZE COEFICIENT DATA FROM ARGUMENT INTO APPROPIATE DATA STRUCTURES
|
||||||
|
for (int i=0; i<nCoef; ++i) {
|
||||||
|
Icoef[i] = IComplex (_coef[4*i] ,_coef[4*i+1] ,_coef[4*i+2] ,_coef[4*i+3]);
|
||||||
|
coef[i] = Complex ((_coef[4*i] + _coef[4*i+1])/2.0 ,
|
||||||
|
(_coef[4*i+2] + _coef[4*i+3])/2.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Polynomial<Complex> f (degree, coef); // complex polynomials (with fp arithmetic)
|
||||||
|
// to be used in Newton method correction
|
||||||
|
Polynomial<IComplex> If (degree, Icoef); // complex polynomials (with Interval arithmetic)
|
||||||
|
Polynomial<IComplex> Ig (degree); // to be used in validated homotopy
|
||||||
|
Polynomial<IComplex> Ih (degree);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// INITIALIZE FLOATING POINT COMPLEX APPROXIMATION OF THE ROOT
|
||||||
|
Complex x0 (0.0); // x0 of the root (x0.imag = 0)
|
||||||
|
Complex y0 (_y0R, _y0I); // approximated y0 of the root
|
||||||
|
IComplex Ix0; // Interval representation for x0
|
||||||
|
IComplex Iy0; // Interval representation for y0
|
||||||
|
IComplex IY0; // Interval enclosure for y0 for Newton Method
|
||||||
|
IComplex Iy1, IY1; // Interval representation of zeros for rotated polynomial
|
||||||
|
IComplex Ix1;
|
||||||
|
|
||||||
|
Complex a; // y'(x0) as Complex
|
||||||
|
IComplex Ia; // y'(x0) as IComplex
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef PROFILING
|
||||||
|
int nsteps = 0; // number of steps performed
|
||||||
|
int nrejectedEps = 0; // number of rejected validations of boxes
|
||||||
|
int nrejectedSteps = 0; // number of rejected validations of tubes
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
outputList.push_back (Cell<double> (0.0, y0.real (), y0.imag ()));
|
||||||
|
|
||||||
|
/*******************/
|
||||||
|
/* CORRECT ROOT */
|
||||||
|
/*******************/
|
||||||
|
|
||||||
|
|
||||||
|
correctRoot<Complex> (f, x0, y0);
|
||||||
|
|
||||||
|
|
||||||
|
/*******************/
|
||||||
|
/** MAIN LOOP */
|
||||||
|
/*******************/
|
||||||
|
while (x0.real () < 1.0) {
|
||||||
|
|
||||||
|
#ifdef PROFILING
|
||||||
|
nsteps++; // used for profiling only
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/***********************************************************/
|
||||||
|
/*** BOX SIZE ESTIMATION. F RESTRICTED TO X0 IS INJECTIVE. */
|
||||||
|
/***********************************************************/
|
||||||
|
aux = f.diffYY (x0, y0);
|
||||||
|
if (abs (aux) < 1.0e-10) {
|
||||||
|
eps = 0.5;
|
||||||
|
} else {
|
||||||
|
eps = (abs (f.diffY(x0,y0) / aux)) / 8.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
eps /= 2.0;
|
||||||
|
// cout << "estima eps = " << eps << endl;
|
||||||
|
|
||||||
|
/**************************/
|
||||||
|
/*** VALIDATE y0 AS POINT.*/
|
||||||
|
/**************************/
|
||||||
|
Ix0 = x0;
|
||||||
|
Iy0 = y0;
|
||||||
|
IY0 = y0 + IComplex (-eps, eps, -eps, eps);
|
||||||
|
|
||||||
|
|
||||||
|
while (!validate<IComplex> (If, Ix0, Iy0, IY0)) {
|
||||||
|
#ifdef PROFILING
|
||||||
|
nrejectedEps++; // used for profiling
|
||||||
|
#endif
|
||||||
|
if (eps < 1.0e-13) {
|
||||||
|
printf ("Singularity detected. Abort Sirocco\n");
|
||||||
|
/*******************/
|
||||||
|
/* CLEAN VARIABLES */
|
||||||
|
/*******************/
|
||||||
|
|
||||||
|
_Polynomial::releaseCombinatorialNumbers ();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
eps *= 0.5;
|
||||||
|
IY0 = Iy0;
|
||||||
|
IY0 = y0 + IComplex (-eps, eps, -eps, eps);
|
||||||
|
}
|
||||||
|
// cout << "acepta eps = " << eps << endl;
|
||||||
|
|
||||||
|
// COMPUTE a = -fx(x0,y0) / fy(x0.y0)
|
||||||
|
// both fp and Interval
|
||||||
|
a = getA<Complex> (f, x0, y0);
|
||||||
|
Ia = a;
|
||||||
|
|
||||||
|
|
||||||
|
/************************/
|
||||||
|
/* ESTIMATE STEP SIZE ***/
|
||||||
|
/************************/
|
||||||
|
// we have: aux = fyy
|
||||||
|
// store all in aux2
|
||||||
|
|
||||||
|
aux = a*a*aux + 2.0*a*f.diffXY(x0,y0) + f.diffXX (x0, y0);
|
||||||
|
|
||||||
|
// DETECT INFLEXION POINT
|
||||||
|
if (abs(aux) < 1.0e-10)
|
||||||
|
stepsize=1.0;
|
||||||
|
else
|
||||||
|
stepsize = sqrt(abs((eps * f.diffY (x0, y0) )/ aux));
|
||||||
|
if (stepsize + x0.real () > 1.0) stepsize = 1.000001 - x0.real ();
|
||||||
|
|
||||||
|
|
||||||
|
/*******************/
|
||||||
|
/** VALIDATE STEP */
|
||||||
|
/*******************/
|
||||||
|
Ix1 = Interval(0,stepsize);
|
||||||
|
|
||||||
|
|
||||||
|
// PERFORM TRANSLATION AND ROTATION OF THE POLYNOMIAL
|
||||||
|
Ig = If.IlinearVarChange2 (Ix0);
|
||||||
|
Ih = Ig.IlinearVarChange (Ia);
|
||||||
|
|
||||||
|
|
||||||
|
while (!validate<IComplex> (Ih, Ix1, Iy0, IY0)) {
|
||||||
|
#ifdef PROFILING
|
||||||
|
nrejectedSteps++; // used for profiling
|
||||||
|
#endif
|
||||||
|
stepsize *= 0.5;
|
||||||
|
eps*=0.95;
|
||||||
|
IY0 = y0 + IComplex (-eps, eps, -eps, eps);
|
||||||
|
Ix1 = Interval (0, stepsize);
|
||||||
|
|
||||||
|
if (stepsize < 1.0e-13) {
|
||||||
|
/*******************/
|
||||||
|
/* CLEAN VARIABLES */
|
||||||
|
/*******************/
|
||||||
|
_Polynomial::releaseCombinatorialNumbers ();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#ifdef DEVELOPER
|
||||||
|
std::cout << "x0 = " << x0.real () << " step = " << stepsize << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// /**************************/
|
||||||
|
// /** VALIDATE FINAL STEP */
|
||||||
|
// /**************************/
|
||||||
|
if (x0.real () + stepsize > 1.0) {
|
||||||
|
stepsize = 1.0 - x0.real ();
|
||||||
|
Ix1.r.b = stepsize;
|
||||||
|
|
||||||
|
#ifdef DEVELOPER
|
||||||
|
std::cout << "final step = " << stepsize << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (!validate<IComplex> (Ih, Ix1, Iy0, IY0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// /********************/
|
||||||
|
// /* UPDATE VARIABLES */
|
||||||
|
// /********************/
|
||||||
|
x0 = Complex (Ix0.r.a + stepsize, 0.0);
|
||||||
|
y0 = Complex (y0.real () + Ia.r.a * stepsize,
|
||||||
|
y0.imag () + Ia.i.a * stepsize);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// /*******************/
|
||||||
|
// /* CORRECT ROOT */
|
||||||
|
// /*******************/
|
||||||
|
correctRoot<Complex> (f, x0, y0);
|
||||||
|
|
||||||
|
/**********************************************/
|
||||||
|
/* CHECK WE HAVE NOT JUMPED TO ANOTHER ROOT */
|
||||||
|
/**********************************************/
|
||||||
|
if (!(IY0+Ia*stepsize).contains (y0)) {
|
||||||
|
printf ("error! Jumped to other thread!\n");
|
||||||
|
_Polynomial::releaseCombinatorialNumbers ();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
outputList.push_back (Cell<double> (x0.real (), y0.real (), y0.imag ()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// /***********************************************/
|
||||||
|
/* PREPARE OUTPUT AS A BINARY ARRAY OF DOUBLES */
|
||||||
|
/***********************************************/
|
||||||
|
|
||||||
|
double *rop = new double [((3 * outputList.size () + 1))];
|
||||||
|
rop[0] = outputList.size ();
|
||||||
|
for (int i=0; i<outputList.size (); i++) {
|
||||||
|
rop[3*i+1] = outputList[i].x[0];
|
||||||
|
rop[3*i+2] = outputList[i].x[1];
|
||||||
|
rop[3*i+3] = outputList[i].x[2];
|
||||||
|
}
|
||||||
|
_Polynomial::releaseCombinatorialNumbers ();
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mpfr_t * homotopyPath_mp (int degree, mpfr_t *_coef, mpfr_t _y0R, mpfr_t _y0I, int prec) {
|
||||||
|
mpfr_prec_t oldprec = mpfr_get_default_prec();
|
||||||
|
mpfr_set_default_prec(prec);
|
||||||
|
|
||||||
|
_Polynomial::startCombinatorialNumbers (degree);
|
||||||
|
|
||||||
|
// // /************************************************/
|
||||||
|
// // /* VARIABLE DECLARATION AND DATA INITIALIZATION */
|
||||||
|
// // /************************************************/
|
||||||
|
MPComplex aux; // Complex aux variable.
|
||||||
|
|
||||||
|
mpfr_t stepsize , eps, calc, tol;
|
||||||
|
mpfr_inits (stepsize, eps, calc, tol, NULL); // step size and radius of the box
|
||||||
|
mpfr_set_d (stepsize, 0.0001, MPFR_RNDN);
|
||||||
|
mpfr_set_d (tol, mpfr_get_default_prec(), MPFR_RNDN);
|
||||||
|
mpfr_sub_si (tol, tol, 10, MPFR_RNDN);
|
||||||
|
mpfr_neg (tol, tol, MPFR_RNDN);
|
||||||
|
mpfr_exp2 (tol, tol, MPFR_RNDN);
|
||||||
|
|
||||||
|
|
||||||
|
int nCoef = ((degree+1)*(degree+2)) / 2; // number of monomials
|
||||||
|
MPComplex coef[nCoef]; // coefficient list for floating point representation of
|
||||||
|
// the polynomial.
|
||||||
|
MPIComplex Icoef[nCoef]; // coefficient list for Interval representation of
|
||||||
|
// the polynomial.
|
||||||
|
|
||||||
|
std::vector<Cell<mpfr_t> > outputList;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// INITIALIZE COEFICIENT DATA FROM ARGUMENT INTO APPROPRIATE DATA STRUCTURES
|
||||||
|
for (int i=0; i<nCoef; ++i) {
|
||||||
|
Icoef[i] = MPIComplex (_coef[4*i] ,_coef[4*i+1] ,_coef[4*i+2] ,_coef[4*i+3]);
|
||||||
|
coef[i] = 0.5*(MPComplex (_coef[4*i] , _coef[4*i+2]) +
|
||||||
|
MPComplex (_coef[4*i+1] , _coef[4*i+3]));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Polynomial<MPComplex> f (degree, coef); // complex polynomials (with fp arithmetic)
|
||||||
|
// to be used in Newton method correction
|
||||||
|
Polynomial<MPIComplex> If (degree, Icoef); // complex polynomials (with Interval arithmetic)
|
||||||
|
Polynomial<MPIComplex> Ig (degree); // to be used in validated homotopy
|
||||||
|
Polynomial<MPIComplex> Ih (degree);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// // INITIALIZE FLOATING POINT COMPLEX APPROXIMATION OF THE ROOT
|
||||||
|
MPComplex x0 (0.0); // x0 of the root (x0.imag = 0)
|
||||||
|
MPComplex y0 (_y0R, _y0I); // approximated y0 of the root
|
||||||
|
MPIComplex Ix0; // Interval representation for x0
|
||||||
|
MPIComplex Iy0; // Interval representation for y0
|
||||||
|
MPIComplex IY0; // Interval enclosure for y0 for Newton Method
|
||||||
|
MPIComplex Iy1, IY1; // Interval representation of zeros for rotated polynomial
|
||||||
|
MPIComplex Ix1;
|
||||||
|
|
||||||
|
MPComplex a; // y'(x0) as Complex
|
||||||
|
MPIComplex Ia; // y'(x0) as MPIComplex
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef PROFILING
|
||||||
|
int nsteps = 0; // number of steps performed
|
||||||
|
int nrejectedEps = 0; // number of rejected validations of boxes
|
||||||
|
int nrejectedSteps = 0; // number of rejected validations of tubes
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
outputList.push_back (Cell<mpfr_t> (x0.r, y0.r, y0.i));
|
||||||
|
|
||||||
|
// /*******************/
|
||||||
|
// /* CORRECT ROOT */
|
||||||
|
// /*******************/
|
||||||
|
|
||||||
|
|
||||||
|
correctRoot<MPComplex> (f, x0, y0);
|
||||||
|
|
||||||
|
|
||||||
|
// /*******************/
|
||||||
|
// /** MAIN LOOP */
|
||||||
|
// /*******************/
|
||||||
|
while (mpfr_cmp_si(x0.r, 1.0) < 0) {
|
||||||
|
|
||||||
|
#ifdef PROFILING
|
||||||
|
nsteps++; // used for profiling only
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/***********************************************************/
|
||||||
|
/*** BOX SIZE ESTIMATION. F RESTRICTED TO X0 IS INJECTIVE. */
|
||||||
|
/***********************************************************/
|
||||||
|
aux = f.diffYY (x0, y0);
|
||||||
|
abs (calc, aux);
|
||||||
|
if (mpfr_cmp_d (calc, 1.0e-10) < 0) {
|
||||||
|
mpfr_set_d (eps, 0.5, MPFR_RNDN);
|
||||||
|
} else {
|
||||||
|
abs (eps, (f.diffY(x0,y0) / aux));
|
||||||
|
mpfr_div_si (eps, eps, 8, MPFR_RNDN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************/
|
||||||
|
/*** VALIDATE y0 AS POINT.*/
|
||||||
|
/**************************/
|
||||||
|
Ix0 = x0;
|
||||||
|
Iy0 = y0;
|
||||||
|
IY0 = MPIComplex(y0) + eps*MPIComplex (-1.0, 1.0, -1.0, 1.0);
|
||||||
|
|
||||||
|
|
||||||
|
while (!validate<MPIComplex> (If, Ix0, Iy0, IY0)) {
|
||||||
|
#ifdef PROFILING
|
||||||
|
nrejectedEps++; // used for profiling
|
||||||
|
#endif
|
||||||
|
if (mpfr_cmp (eps ,tol) < 0) {
|
||||||
|
printf ("Singularity detected. Abort Sirocco\n");
|
||||||
|
/*******************/
|
||||||
|
/* CLEAN VARIABLES */
|
||||||
|
/*******************/
|
||||||
|
mpfr_clears (stepsize, eps, calc, tol, NULL);
|
||||||
|
|
||||||
|
mpfr_set_default_prec(oldprec);
|
||||||
|
|
||||||
|
_Polynomial::releaseCombinatorialNumbers ();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
mpfr_div_si (eps, eps, 2, MPFR_RNDN);
|
||||||
|
IY0 = Iy0;
|
||||||
|
IY0 = MPIComplex(y0) + eps*MPIComplex (-1.0, 1.0, -1.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// COMPUTE a = -fx(x0,y0) / fy(x0.y0)
|
||||||
|
// both fp and Interval
|
||||||
|
a = getA<MPComplex> (f, x0, y0);
|
||||||
|
Ia = a;
|
||||||
|
|
||||||
|
|
||||||
|
/************************/
|
||||||
|
/* ESTIMATE STEP SIZE ***/
|
||||||
|
/************************/
|
||||||
|
// we have: aux = fyy
|
||||||
|
// store all in aux2
|
||||||
|
|
||||||
|
aux = a*a*aux + 2.0*a*f.diffXY(x0,y0) + f.diffXX (x0, y0);
|
||||||
|
|
||||||
|
// DETECT INFLEXION POINT
|
||||||
|
abs (calc, aux);
|
||||||
|
if (mpfr_cmp_d(calc, 1.0e-10) < 0) {
|
||||||
|
mpfr_set_si (stepsize, 1, MPFR_RNDN);
|
||||||
|
} else {
|
||||||
|
abs (calc, (eps * f.diffY (x0, y0) )/ aux);
|
||||||
|
mpfr_sqrt (stepsize, calc, MPFR_RNDN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (stepsize + x0.real () > 1.0) stepsize = 1.000001 - x0.real ();
|
||||||
|
mpfr_add (calc, x0.r, stepsize, MPFR_RNDU);
|
||||||
|
if (mpfr_cmp_si (calc, 1) > 0) {
|
||||||
|
mpfr_si_sub (stepsize, 1, x0.r, MPFR_RNDU);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************/
|
||||||
|
/** VALIDATE STEP */
|
||||||
|
/*******************/
|
||||||
|
mpfr_set_si (calc, 0, MPFR_RNDN);
|
||||||
|
Ix1 = MPInterval(calc,stepsize);
|
||||||
|
|
||||||
|
|
||||||
|
// PERFORM TRANSLATION AND ROTATION OF THE POLYNOMIAL
|
||||||
|
Ig = If.IlinearVarChange2 (Ix0);
|
||||||
|
Ih = Ig.IlinearVarChange (Ia);
|
||||||
|
|
||||||
|
|
||||||
|
while (!validate<MPIComplex> (Ih, Ix1, Iy0, IY0)) {
|
||||||
|
#ifdef PROFILING
|
||||||
|
nrejectedSteps++; // used for profiling
|
||||||
|
#endif
|
||||||
|
mpfr_div_si (stepsize, stepsize, 2, MPFR_RNDN);
|
||||||
|
mpfr_mul_d (eps, eps, 0.95, MPFR_RNDN);
|
||||||
|
|
||||||
|
IY0 = MPIComplex(y0) + eps*MPIComplex (-1.0, 1.0, -1.0, 1.0);
|
||||||
|
Ix1 = MPInterval (calc, stepsize);
|
||||||
|
|
||||||
|
if (mpfr_cmp_d (stepsize, 1.0e-13) < 0) {
|
||||||
|
/*******************/
|
||||||
|
/* CLEAN VARIABLES */
|
||||||
|
/*******************/
|
||||||
|
mpfr_clears (stepsize, eps, calc, tol, NULL);
|
||||||
|
|
||||||
|
mpfr_set_default_prec(oldprec);
|
||||||
|
_Polynomial::releaseCombinatorialNumbers ();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#ifdef DEVELOPER
|
||||||
|
std::cout << "x0 = " << x0.r << " step = " << stepsize << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// // /********************/
|
||||||
|
// // /* UPDATE VARIABLES */
|
||||||
|
// // /********************/
|
||||||
|
x0 = MPComplex (Ix0.r.a) + MPComplex (stepsize);
|
||||||
|
y0 = y0 + stepsize*a;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// /*******************/
|
||||||
|
// /* CORRECT ROOT */
|
||||||
|
// /*******************/
|
||||||
|
correctRoot<MPComplex> (f, x0, y0);
|
||||||
|
|
||||||
|
/**********************************************/
|
||||||
|
/* CHECK WE HAVE NOT JUMPED TO ANOTHER ROOT */
|
||||||
|
/**********************************************/
|
||||||
|
if (!(MPIComplex(y0).subset (IY0+Ia*stepsize))) {
|
||||||
|
mpfr_clears (stepsize, eps, calc, tol, NULL);
|
||||||
|
printf ("error! Jumped to other thread!\n");
|
||||||
|
mpfr_set_default_prec(oldprec);
|
||||||
|
_Polynomial::releaseCombinatorialNumbers ();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
outputList.push_back (Cell<mpfr_t> (x0.r, y0.r, y0.i));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// /***********************************************/
|
||||||
|
/* PREPARE OUTPUT AS A BINARY ARRAY OF DOUBLES */
|
||||||
|
/***********************************************/
|
||||||
|
|
||||||
|
mpfr_t *rop = new mpfr_t [((3 * outputList.size () + 1))];
|
||||||
|
mpfr_init(rop[0]);
|
||||||
|
mpfr_set_si(rop[0], outputList.size(), MPFR_RNDN);
|
||||||
|
for (int i=0; i<outputList.size (); i++) {
|
||||||
|
mpfr_init(rop[3*i+1]);
|
||||||
|
mpfr_init(rop[3*i+2]);
|
||||||
|
mpfr_init(rop[3*i+3]);
|
||||||
|
mpfr_set(rop[3*i+1], outputList[i].x[0], MPFR_RNDN);
|
||||||
|
mpfr_set(rop[3*i+2], outputList[i].x[1], MPFR_RNDN);
|
||||||
|
mpfr_set(rop[3*i+3], outputList[i].x[2], MPFR_RNDN);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mpfr_clears (stepsize, eps, calc, tol, NULL);
|
||||||
|
|
||||||
|
mpfr_set_default_prec(oldprec);
|
||||||
|
_Polynomial::releaseCombinatorialNumbers ();
|
||||||
|
return rop;
|
||||||
|
}
|
||||||
99
sage-sirocco_interface.pyx
Normal file
99
sage-sirocco_interface.pyx
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
|
||||||
|
#### magic comment that tells Cython to link to libsirocco.so
|
||||||
|
#clang C++
|
||||||
|
#clib sirocco
|
||||||
|
|
||||||
|
include 'cysignals/signals.pxi'
|
||||||
|
|
||||||
|
from sage.libs.mpfr cimport *
|
||||||
|
from sage.rings.real_mpfr cimport RealNumber
|
||||||
|
from sage.rings.real_mpfr import RealField
|
||||||
|
|
||||||
|
|
||||||
|
cdef extern from "stdlib.h":
|
||||||
|
void free(void* ptr)
|
||||||
|
|
||||||
|
|
||||||
|
cdef extern from "sirocco.hpp":
|
||||||
|
mpfr_t* homotopyPath_mp (int degree, mpfr_t *_coef, mpfr_t _y0R, mpfr_t _y0I, int prec)
|
||||||
|
double * homotopyPath (int degree, double *_coef, double _y0R, double _y0I)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def devuelve(RealNumber a):
|
||||||
|
cdef mpfr_prec_t ap = mpfr_get_prec(a.value)
|
||||||
|
cdef RealNumber my_number = RealField(ap)()
|
||||||
|
mpfr_set(my_number.value, a.value, MPFR_RNDN)
|
||||||
|
return my_number
|
||||||
|
|
||||||
|
|
||||||
|
def contpath_mp(deg, values, RealNumber y0r, RealNumber y0i, int prec):
|
||||||
|
cdef int cdeg = deg
|
||||||
|
cdef mpfr_t* cvalues = <mpfr_t*> sage_malloc(sizeof(mpfr_t)*len(values))
|
||||||
|
cdef mpfr_t* rop
|
||||||
|
cdef int j
|
||||||
|
for i in range(len(values)):
|
||||||
|
j = <int>i
|
||||||
|
sig_on()
|
||||||
|
mpfr_init2(cvalues[j], prec)
|
||||||
|
mpfr_set(cvalues[j], (<RealNumber>values[j]).value, MPFR_RNDN)
|
||||||
|
sig_off()
|
||||||
|
cdef mpfr_t y0R
|
||||||
|
cdef mpfr_t y0I
|
||||||
|
sig_on()
|
||||||
|
mpfr_init2(y0R, prec)
|
||||||
|
mpfr_set(y0R, (<RealNumber>y0r).value, MPFR_RNDN)
|
||||||
|
mpfr_init2(y0I, prec)
|
||||||
|
mpfr_set(y0I, (<RealNumber>y0i).value, MPFR_RNDN)
|
||||||
|
rop = homotopyPath_mp(cdeg, cvalues, y0R, y0I, prec)
|
||||||
|
sig_off()
|
||||||
|
for i in range(len(values)):
|
||||||
|
j = <int>i
|
||||||
|
sig_on()
|
||||||
|
mpfr_clear(cvalues[j])
|
||||||
|
sig_off()
|
||||||
|
free(cvalues)
|
||||||
|
if rop == NULL:
|
||||||
|
raise ValueError("libsirocco could not guarantee one step")
|
||||||
|
cdef int n = mpfr_get_si(rop[0], MPFR_RNDN)
|
||||||
|
|
||||||
|
#cdef RealNumber res = RealField(53)()
|
||||||
|
cdef double res
|
||||||
|
l = []
|
||||||
|
|
||||||
|
for i in range(1, 3*n+1):
|
||||||
|
RN = RealField(prec)()
|
||||||
|
sig_on()
|
||||||
|
res = mpfr_set((<RealNumber>RN).value, rop[i], MPFR_RNDN)
|
||||||
|
mpfr_clear(rop[i])
|
||||||
|
sig_off()
|
||||||
|
l.append(RN)
|
||||||
|
free(rop)
|
||||||
|
return [(l[3*i], l[3*i+1], l[3*i+2]) for i in range(len(l)/3)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def contpath(deg,values,y0r,y0i):
|
||||||
|
cdef double* rop
|
||||||
|
cdef double* c_values = <double*> sage_malloc(sizeof(double)*len(values))
|
||||||
|
cdef int clen = <int> len(values)
|
||||||
|
for i,v in enumerate(values):
|
||||||
|
c_values[i] = values[i]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cdef double y0R = y0r
|
||||||
|
cdef double y0I = y0i
|
||||||
|
sig_on()
|
||||||
|
rop = homotopyPath (int(deg), c_values, y0R, y0I)
|
||||||
|
sig_off()
|
||||||
|
if rop == NULL:
|
||||||
|
raise ValueError("libsirocco could not guarantee one step")
|
||||||
|
n=int(rop[0])
|
||||||
|
l=[0 for i in range(n)]
|
||||||
|
for i in range(n):
|
||||||
|
l[i]=(rop[3*i+1],rop[3*i+2],rop[3*i+3])
|
||||||
|
free(rop)
|
||||||
|
free(c_values)
|
||||||
|
return l
|
||||||
11
tests/Makefile.am
Normal file
11
tests/Makefile.am
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
check_PROGRAMS = sirocco_test sirocco_minimal_test
|
||||||
|
sirocco_test_SOURCES = sirocco_test.cpp
|
||||||
|
sirocco_test_LDADD = @top_builddir@/lib/libsirocco.la
|
||||||
|
sirocco_test_DEPENDENCIES = @top_builddir@/lib/libsirocco.la
|
||||||
|
sirocco_test_LDFLAGS = -lm -lmpfr -lgmp
|
||||||
|
sirocco_minimal_test_SOURCES = sirocco_minimal_test.cpp
|
||||||
|
sirocco_minimal_test_LDADD = @top_builddir@/lib/libsirocco.la
|
||||||
|
sirocco_minimal_test_DEPENDENCIES = @top_builddir@/lib/libsirocco.la
|
||||||
|
sirocco_minimal_test_LDFLAGS = -lm -lmpfr -lgmp
|
||||||
|
TESTS = sirocco_test sirocco_minimal_test
|
||||||
|
AM_CPPFLAGS = -I$(top_srcdir)/include
|
||||||
67
tests/sirocco_minimal_test.cpp
Normal file
67
tests/sirocco_minimal_test.cpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <sirocco.h>
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char const *argv[]) {
|
||||||
|
mpfr_set_default_prec (162);
|
||||||
|
|
||||||
|
|
||||||
|
double testCoefs[] = {0.000000000000000, -0.000000000000000, 0.000000000000000,
|
||||||
|
-0.000000000000000, 0.000000000000000, -0.000000000000000,
|
||||||
|
0.000000000000000, -0.000000000000000, -128.000000000000,
|
||||||
|
-128.000000000000, -96.0000000000000, -96.0000000000000,
|
||||||
|
0.000000000000000, -0.000000000000000, 0.000000000000000,
|
||||||
|
-0.000000000000000, 72.0000000000000, 72.0000000000000,
|
||||||
|
304.000000000000, 304.000000000000, 12.0000000000000,
|
||||||
|
12.0000000000000, 180.000000000000, 180.000000000000,
|
||||||
|
0.000000000000000, -0.000000000000000, 0.000000000000000,
|
||||||
|
-0.000000000000000, 90.0000000000000, 90.0000000000000,
|
||||||
|
-182.500000000000, -182.500000000000, 133.500000000000,
|
||||||
|
133.500000000000, -190.500000000000, -190.500000000000,
|
||||||
|
42.0000000000000, 42.0000000000000, -44.0000000000000,
|
||||||
|
-44.0000000000000, 0.000000000000000, -0.000000000000000,
|
||||||
|
0.000000000000000, -0.000000000000000, -40.2500000000000,
|
||||||
|
-40.2500000000000, 18.2500000000000, 18.2500000000000,
|
||||||
|
-72.0000000000000, -72.0000000000000, 21.0000000000000,
|
||||||
|
21.0000000000000, -38.5000000000000, -38.5000000000000,
|
||||||
|
5.50000000000000, 5.50000000000000, -6.00000000000000,
|
||||||
|
-6.00000000000000, -0.000000000000000, 0.000000000000000};
|
||||||
|
|
||||||
|
double y0R = 4.0;
|
||||||
|
double y0I = -4.0;
|
||||||
|
double *rop = homotopyPath (4, testCoefs, y0R, y0I);
|
||||||
|
|
||||||
|
int len = (int) rop[0];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
delete [] rop;
|
||||||
|
|
||||||
|
mpfr_t mp_testCoefs[60];
|
||||||
|
for (int i=0; i<60; ++i) {
|
||||||
|
mpfr_init_set_d (mp_testCoefs[i], testCoefs[i],
|
||||||
|
(i%2)? MPFR_RNDU : MPFR_RNDD);
|
||||||
|
}
|
||||||
|
mpfr_t mp_y0R, mp_y0I;
|
||||||
|
mpfr_init_set_d (mp_y0R, y0R, MPFR_RNDN);
|
||||||
|
mpfr_init_set_d (mp_y0I, y0I, MPFR_RNDN);
|
||||||
|
|
||||||
|
mpfr_t *mp_rop = homotopyPath_mp (4, mp_testCoefs, mp_y0R, mp_y0I, 5300);
|
||||||
|
|
||||||
|
int size = mpfr_get_si (mp_rop[0], MPFR_RNDN);
|
||||||
|
|
||||||
|
for (int i=0; i<3*size+1; ++i)
|
||||||
|
mpfr_clear(mp_rop[i]);
|
||||||
|
delete [] mp_rop;
|
||||||
|
|
||||||
|
|
||||||
|
for (int i=0; i<60; ++i) {
|
||||||
|
mpfr_clear (mp_testCoefs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mpfr_clear (mp_y0R);
|
||||||
|
mpfr_clear (mp_y0I);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
95
tests/sirocco_test.cpp
Normal file
95
tests/sirocco_test.cpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <sirocco.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
|
std::ostream & operator<< (std::ostream &output, const std::complex<double> op) {
|
||||||
|
if (op == 0.0)
|
||||||
|
output << "0";
|
||||||
|
else if (op.imag() > 0)
|
||||||
|
if (op.real () != 0.0)
|
||||||
|
output << op.real () << "+" << op.imag() << "i";
|
||||||
|
else
|
||||||
|
output << op.imag() << "i";
|
||||||
|
else if (op.imag() == 0)
|
||||||
|
output << op.real ();
|
||||||
|
else
|
||||||
|
if (op.real () != 0.0)
|
||||||
|
output << op.real () << op.imag() << "i";
|
||||||
|
else
|
||||||
|
output << op.imag() << "i";
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char const *argv[]) {
|
||||||
|
mpfr_set_default_prec (162);
|
||||||
|
|
||||||
|
|
||||||
|
double testCoefs[] = {0.000000000000000, -0.000000000000000, 0.000000000000000,
|
||||||
|
-0.000000000000000, 0.000000000000000, -0.000000000000000,
|
||||||
|
0.000000000000000, -0.000000000000000, -128.000000000000,
|
||||||
|
-128.000000000000, -96.0000000000000, -96.0000000000000,
|
||||||
|
0.000000000000000, -0.000000000000000, 0.000000000000000,
|
||||||
|
-0.000000000000000, 72.0000000000000, 72.0000000000000,
|
||||||
|
304.000000000000, 304.000000000000, 12.0000000000000,
|
||||||
|
12.0000000000000, 180.000000000000, 180.000000000000,
|
||||||
|
0.000000000000000, -0.000000000000000, 0.000000000000000,
|
||||||
|
-0.000000000000000, 90.0000000000000, 90.0000000000000,
|
||||||
|
-182.500000000000, -182.500000000000, 133.500000000000,
|
||||||
|
133.500000000000, -190.500000000000, -190.500000000000,
|
||||||
|
42.0000000000000, 42.0000000000000, -44.0000000000000,
|
||||||
|
-44.0000000000000, 0.000000000000000, -0.000000000000000,
|
||||||
|
0.000000000000000, -0.000000000000000, -40.2500000000000,
|
||||||
|
-40.2500000000000, 18.2500000000000, 18.2500000000000,
|
||||||
|
-72.0000000000000, -72.0000000000000, 21.0000000000000,
|
||||||
|
21.0000000000000, -38.5000000000000, -38.5000000000000,
|
||||||
|
5.50000000000000, 5.50000000000000, -6.00000000000000,
|
||||||
|
-6.00000000000000, -0.000000000000000, 0.000000000000000};
|
||||||
|
|
||||||
|
double y0R = 4.0;
|
||||||
|
double y0I = -4.0;
|
||||||
|
double *rop = homotopyPath (4, testCoefs, y0R, y0I);
|
||||||
|
|
||||||
|
int len = (int) rop[0];
|
||||||
|
int i;
|
||||||
|
for (i=0; i<len; ++i)
|
||||||
|
printf ("%.5e %.5e %.5e\n", rop[1+3*i], rop[2+3*i], rop[3+3*i]);
|
||||||
|
|
||||||
|
delete [] rop;
|
||||||
|
|
||||||
|
mpfr_t mp_testCoefs[60];
|
||||||
|
for (int i=0; i<60; ++i) {
|
||||||
|
mpfr_init_set_d (mp_testCoefs[i], testCoefs[i],
|
||||||
|
(i%2)? MPFR_RNDU : MPFR_RNDD);
|
||||||
|
}
|
||||||
|
mpfr_t mp_y0R, mp_y0I;
|
||||||
|
mpfr_init_set_d (mp_y0R, y0R, MPFR_RNDN);
|
||||||
|
mpfr_init_set_d (mp_y0I, y0I, MPFR_RNDN);
|
||||||
|
|
||||||
|
|
||||||
|
mpfr_t *mp_rop = homotopyPath_mp (4, mp_testCoefs, mp_y0R, mp_y0I, 5300);
|
||||||
|
|
||||||
|
int size = mpfr_get_si (mp_rop[0], MPFR_RNDN);
|
||||||
|
for (i=0; i<size; ++i)
|
||||||
|
std::cout << MPComplex(mp_rop[1+3*i]) << ", " << MPComplex(mp_rop[2+3*i], mp_rop[3+3*i]) << std::endl;
|
||||||
|
for (int i=0; i<3*size+1; ++i)
|
||||||
|
mpfr_clear(mp_rop[i]);
|
||||||
|
delete [] mp_rop;
|
||||||
|
|
||||||
|
|
||||||
|
for (int i=0; i<60; ++i) {
|
||||||
|
mpfr_clear (mp_testCoefs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mpfr_clear (mp_y0R);
|
||||||
|
mpfr_clear (mp_y0I);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user