You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
245 lines
5.4 KiB
245 lines
5.4 KiB
/*
|
|
* tests/pslq.h
|
|
*
|
|
* This work was supported by the Director, Office of Science, Division
|
|
* of Mathematical, Information, and Computational Sciences of the
|
|
* U.S. Department of Energy under contract number DE-AC03-76SF00098.
|
|
*
|
|
* Copyright (c) 2000-2001
|
|
*
|
|
*
|
|
* Implementation of PSLQ Integer Relation Detection Algorithm
|
|
* due to H. R. P. Ferguson and D. H. Bailey. See
|
|
*
|
|
* A new polynomial time algorithm for finding relations among
|
|
* real numbers, Supercomputing Research Center Tech Report
|
|
* SRC-93-093 (March 1993).
|
|
*
|
|
* This code is based in part on David Bailey's F90 version.
|
|
*/
|
|
|
|
#include <cmath>
|
|
#include <cstdio>
|
|
|
|
#include <qd/dd_real.h>
|
|
#include <qd/qd_real.h>
|
|
|
|
using std::sqrt;
|
|
using std::abs;
|
|
|
|
using namespace qd;
|
|
|
|
#define MIN(a, b) ( ((a)<(b)) ? (a) : (b) )
|
|
#define MAX(a, b) ( ((a)>(b)) ? (a) : (b) )
|
|
#define SWAP(a, b) { t = a; a = b; b = t; }
|
|
#define SQR(a) ( (a)*(a) )
|
|
|
|
/* Create an n-by-m matrix of T. Diagonal elements
|
|
are initialized to diag, while all other elements are
|
|
initialized to elem. */
|
|
template <class T>
|
|
T **new_matrix(int nr_rows, int nr_cols,
|
|
T diag = 0.0, T elem = 0.0) {
|
|
T **m = new T *[nr_rows];
|
|
int i, j;
|
|
|
|
for (i = 0; i < nr_rows; i++)
|
|
m[i] = new T[nr_cols];
|
|
for (i = 0; i < nr_rows; i++)
|
|
for (j = 0; j < nr_cols; j++)
|
|
m[i][j] = (i == j) ? diag : elem;
|
|
return m;
|
|
}
|
|
|
|
/* Create an n-vector of T. Each elements are initialized to elem. */
|
|
template <class T>
|
|
T *new_vector(int n, T elem = 0.0) {
|
|
T *v = new T[n];
|
|
for (int i = 0; i < n; i++)
|
|
v[i] = elem;
|
|
return v;
|
|
}
|
|
|
|
/* Destroys a matrix m. */
|
|
template <class T>
|
|
void delete_matrix(T **m, int nr_rows) {
|
|
for (int i = 0; i < nr_rows; i++)
|
|
delete [] m[i];
|
|
delete [] m;
|
|
}
|
|
|
|
/* Destroys a vector v. */
|
|
template <class T>
|
|
void delete_vector(T *v) {
|
|
delete [] v;
|
|
}
|
|
|
|
/* The parameter gamma used in the PSLQ algorithm. */
|
|
static const double gam = 1.2;
|
|
|
|
/* Perform PSLQ integer relation algorithm to find any
|
|
linear relation among the n numbers in the vector x.
|
|
It returns the coefficients found in the vector r.
|
|
The parameter eps provides the precision of type T. */
|
|
template <class T>
|
|
int pslq(const T *x, int n, T *r, double eps, int max_itr) {
|
|
T *s = new_vector<T>(n);
|
|
T *y = new_vector<T>(n);
|
|
T **a = new_matrix<T>(n, n, 1.0);
|
|
T **b = new_matrix<T>(n, n, 1.0);
|
|
T **h = new_matrix<T>(n, n-1, 0.0);
|
|
T t;
|
|
double teps = 16.0 * eps;
|
|
int i, j, k;
|
|
int err = 0;
|
|
|
|
/* Compute the vector s */
|
|
t = x[n-1] * x[n-1];
|
|
s[n-1] = abs(x[n-1]);
|
|
for (i = n-2; i >= 0; i--) {
|
|
t += x[i] * x[i];
|
|
s[i] = sqrt(t);
|
|
}
|
|
|
|
/* Normalize the vector x, s. */
|
|
t = s[0];
|
|
for (i = 0; i < n; i++)
|
|
y[i] = x[i] / t;
|
|
s[0] = 1.0;
|
|
for (i = 1; i < n; i++)
|
|
s[i] /= t;
|
|
|
|
/* Construct matrix H. */
|
|
for (i = 0; i < n; i++) {
|
|
for (j = 0; j <= MIN(i, n-2); j++) {
|
|
h[i][j] = (i == j) ? s[j+1]/s[j] : - y[i]*y[j] / (s[j] * s[j+1]);
|
|
}
|
|
}
|
|
|
|
/* Reduce matrix H. */
|
|
for (i = 1; i < n; i++) {
|
|
for (j = i-1; j >= 0; j--) {
|
|
t = nint(h[i][j] / h[j][j]);
|
|
y[j] += t * y[i];
|
|
for (k = 0; k <= j; k++)
|
|
h[i][k] -= t * h[j][k];
|
|
for (k = 0; k < n; k++) {
|
|
a[i][k] -= t * a[j][k];
|
|
b[k][j] += t * b[k][i];
|
|
}
|
|
}
|
|
}
|
|
|
|
int m;
|
|
int itr = 0;
|
|
bool done = false;
|
|
|
|
while(!done) {
|
|
|
|
itr++;
|
|
|
|
/* Select m such that gam^i * |H_ii| is maximal when i = m. */
|
|
T m_val = -1.0;
|
|
T g = gam;
|
|
m = -1;
|
|
|
|
for (i = 0; i < n-1; i++, g *= gam) {
|
|
t = abs(g * h[i][i]);
|
|
if (t > m_val) {
|
|
m_val = t;
|
|
m = i;
|
|
}
|
|
}
|
|
|
|
if (m < 0) {
|
|
/* This shouldn't happen. */
|
|
err = 1;
|
|
break;
|
|
}
|
|
|
|
/* Exchange entries m and m+1 of y,
|
|
rows m and m+1 of A and H,
|
|
columns m and m+1 of B. */
|
|
SWAP(y[m], y[m+1])
|
|
for (i = 0; i < n; i++) {
|
|
SWAP(a[m][i], a[m+1][i])
|
|
}
|
|
for (i = 0; i < n-1; i++) {
|
|
SWAP(h[m][i], h[m+1][i])
|
|
}
|
|
for (i = 0; i < n; i++) {
|
|
SWAP(b[i][m], b[i][m+1])
|
|
}
|
|
|
|
|
|
/* Remove the corner on H diagonal. */
|
|
if (m < n-2) {
|
|
T t0, t1, t2, t3, t4;
|
|
t0 = sqrt(SQR(h[m][m]) + SQR(h[m][m+1]));
|
|
t1 = h[m][m] / t0;
|
|
t2 = h[m][m+1] / t0;
|
|
for (i = m; i < n; i++) {
|
|
t3 = h[i][m];
|
|
t4 = h[i][m+1];
|
|
h[i][m] = t1 * t3 + t2 * t4;
|
|
h[i][m+1] = t1 * t4 - t2 * t3;
|
|
}
|
|
}
|
|
|
|
/* Reduce H. */
|
|
for (i = m+1; i < n; i++) {
|
|
for (j = MIN(i-1, m+1); j >= 0; j--) {
|
|
t = nint(h[i][j]/h[j][j]);
|
|
y[j] += t * y[i];
|
|
for (k = 0; k <= j; k++) {
|
|
h[i][k] -= t * h[j][k];
|
|
}
|
|
for (k = 0; k < n; k++) {
|
|
a[i][k] -= t * a[j][k];
|
|
b[k][j] += t * b[k][i];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Norm bound */
|
|
m_val = -1.0e308;
|
|
for (j = 0; j < n-1; j++) {
|
|
t = abs(h[j][j]);
|
|
if (t > m_val)
|
|
m_val = t;
|
|
}
|
|
|
|
/* Check the y vector for zeros. */
|
|
for (i = 0; i < n; i++) {
|
|
t = abs(y[i]);
|
|
if (t < teps) {
|
|
m = i;
|
|
done = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (itr > max_itr) {
|
|
done = true;
|
|
err = -1;
|
|
}
|
|
|
|
} /* while */
|
|
|
|
/* Get the coefficients. */
|
|
if (err == 0) {
|
|
for (i = 0; i < n; i++) {
|
|
r[i] = b[i][m];
|
|
}
|
|
}
|
|
|
|
delete_matrix<T>(h, n);
|
|
delete_matrix<T>(a, n);
|
|
delete_matrix<T>(b, n);
|
|
delete_vector<T>(y);
|
|
delete_vector<T>(s);
|
|
|
|
return err;
|
|
}
|
|
|