blob: 0dccdbede4f681aff01c036caa42674254d79ead [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 University of Illinois at Urbana-Champaign and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* UIUC - Initial API and implementation
*******************************************************************************/
package org.eclipse.photran.internal.core.analysis.dependence;
import java.util.Arrays;
/**
* Generalized GCD Dependence Test
* <p>
* (Wolfe pp. 246-247)
* <p>
* THIS IS PRELIMINARY AND EXPERIMENTAL. IT IS NOT APPROPRIATE FOR PRODUCTION USE.
*
* @author Jeff Overbey
*/
public class GeneralizedGCDTest implements IDependenceTester
{
public Result test(int n, int[] L, int[] U, int[] a, int[] b, Direction[] direction)
{
// a: Coefficients in definition
// b: Coefficients in reference
// For each index variable
// element 2*i is definition
// element 2*i+1 is use
IntMatrix coeffs = IntMatrix.zero(2*n /* but only 1 row used */, 2*n);
for (int i = 1; i <= n; i++)
{
coeffs.set(1, 2*(i-1)+1, a[i]);
coeffs.set(1, 2*(i-1)+2, -b[i]);
}
int[] c = new int[2*n];
c[0] = b[0] - a[0];
System.out.println("Solving\n" + coeffs + " * t =\n" + Arrays.toString(c)); //$NON-NLS-1$ //$NON-NLS-2$
IntVector sol = coeffs.solve(c);
System.out.println(" t =\n" + (sol == null ? "null" : sol)); //$NON-NLS-1$ //$NON-NLS-2$
return sol != null && !sol.isZero() ? Result.POSSIBLE_DEPENDENCE : Result.NO_DEPENDENCE;
}
/**
* A mutable matrix of integers, used solely to support the Generalized GCD dependence tester.
*
* @author Jeff Overbey
*
* @see GeneralizedGCDTest
*/
public static final class IntMatrix
{
public static IntMatrix zero(int rows, int cols)
{
return new IntMatrix(rows, cols);
}
public static IntMatrix identity(int rank)
{
IntMatrix id = new IntMatrix(rank, rank);
for (int i = 1; i <= rank; i++)
id.set(i, i, 1);
return id;
}
public static IntMatrix copyFrom(IntMatrix m)
{
IntMatrix result = zero(m.rows, m.cols);
for (int col = 0; col < m.cols; col++)
System.arraycopy(m.data[col], 0, result.data[col], 0, m.rows);
return result;
}
public static IntMatrix create(int rows, int cols, int... vals)
{
if (vals.length != rows*cols) throw new IllegalArgumentException("Wrong number of values"); //$NON-NLS-1$
IntMatrix result = zero(rows, cols);
int i = 0;
for (int row = 1; row <= rows; row++)
for (int col = 1; col <= cols; col++)
result.set(row, col, vals[i++]);
return result;
}
protected final int rows, cols;
protected final int[][] data;
protected IntMatrix(int rows, int cols)
{
this.rows = rows;
this.cols = cols;
this.data = new int[cols][rows];
}
/**
* @param row (1-based)
* @param col (1-based)
* @return
*/
public int get(int row, int col)
{
check(row, col);
return data[col-1][row-1];
}
/**
* @param row (1-based)
* @param col (1-based)
* @param value
*/
public void set(int row, int col, int value)
{
check(row, col);
data[col-1][row-1] = value;
}
/**
*
* @param col1
* @param col2
*/
public void swapColumns(int col1, int col2)
{
int[] tmp = data[col1-1];
data[col1-1] = data[col2-1];
data[col2-1] = tmp;
}
protected void check(int row, int col)
{
if (row < 1 || row > rows) throw new IllegalArgumentException("Invalid row " + row); //$NON-NLS-1$
if (col < 1 || col > cols) throw new IllegalArgumentException("Invalid column " + col); //$NON-NLS-1$
}
/**
* @return
*/
public int numRows()
{
return rows;
}
/**
* @return
*/
public int numCols()
{
return cols;
}
@Override public String toString()
{
StringBuilder sb = new StringBuilder();
for (int row = 1; row <= rows; row++)
{
for (int col = 1; col <= cols; col++)
{
sb.append(String.format("%5d", get(row, col))); //$NON-NLS-1$
}
sb.append('\n');
}
return sb.toString();
}
public boolean equalsUnwrapped(int... vals)
{
if (vals.length != rows * cols) throw new IllegalArgumentException("Wrong length array"); //$NON-NLS-1$
int i = 0;
for (int row = 1; row <= rows; row++)
for (int col = 1; col <= cols; col++)
if (get(row, col) != vals[i++])
return false;
return true;
}
public Reduce reduce()
{
return new Reduce(this);
}
public IntVector solve(int... c)
{
if (!isSquare()) throw new IllegalArgumentException();
// "this" is the matrix A
// We want to find a vector x such that A x = c
// Find unimodular matrix U and column echelon form D such that A U = D
Reduce reduce = reduce();
// A x = c
// <=> (D U^-1) x = c
// <=> D (U^-1 x) = c
// <=> D t = c for some t
// Find t such that D t = c
IntMatrix d = reduce.getColumnEchelonForm();
IntVector t = d.forwardSubstitute(c);
if (t == null) return null; // No solution
// t = U^-1 x
// U t = U U^-1 x
// U t = x
IntVector x = reduce.getUnimodularMatrix().times(t);
return x;
}
/**
* @param vec
* @return
*/
private IntVector times(IntVector vec)
{
int origSize = vec.size();
if (origSize < numRows())
{
IntVector newVec = IntVector.zero(numRows());
for (int i = 1; i <= origSize; i++)
newVec.set(i, vec.get(i));
vec = newVec;
}
int size = vec.size();
if (numRows() != size) throw new IllegalArgumentException();
if (numCols() != size) throw new IllegalArgumentException();
IntVector result = IntVector.zero(size);
for (int row = 1; row <= size; row++)
{
int sum = 0;
for (int col = 1; col <= size; col++)
sum += vec.get(col) * this.get(row, col);
result.set(row, sum);
}
if (origSize != size)
{
IntVector newVec = IntVector.zero(origSize);
for (int i = 1; i <= origSize; i++)
newVec.set(i, result.get(i));
return newVec;
}
else return result;
}
/**
* Reduces a coefficient matrix D = (d, 0, 0, ..., 0) and finds an appropriate unimodular matrix
* U such that AU = D
*
* Reduces a coefficient matrix to column echelon form
*
* Wolfe p.112
*/
public static final class Reduce
{
protected IntMatrix a;
private IntMatrix d;
private IntMatrix u;
protected Reduce(IntMatrix a)
{
/** ReduceRow -- Wolfe p. 112 */
if (a.numRows() == 1)
{
this.a = a;
this.u = IntMatrix.identity(a.numCols()); // TODO
this.d = IntMatrix.copyFrom(a); // TODO
reduce(1, 1, a.numCols());
}
/** ReduceMatrix -- Wolfe p. 115 */
else
{
this.a = a;
this.u = IntMatrix.identity(a.numCols()); // TODO
this.d = IntMatrix.copyFrom(a); // TODO
int c = 1;
for (int i = 1; i <= a.numRows(); i++)
{
reduce(i, c, a.numCols());
if (d.get(i, c) != 0) c++;
}
}
}
/** Leaves only a single nonzero entry in columns j through n of row i */
protected void reduce(int i, int j, int n)
{
int k;
boolean f;
do
{
if (d.isZero(i, j, n)) return;
k = d.colWithMinimumMagnitude(i, j, d.numCols());
f = true;
for (int m = j; m <= n; m++)
{
if (m != k)
{
int q = d.get(i, m) / d.get(i, k);
if (q != 0)
{
d.addColumnMultiple(m, -q, k);
u.addColumnMultiple(m, -q, k);
if (d.get(i, m) > 0) f = false;
}
}
}
} while (!f);
if (k != 1)
{
d.swapColumns(j, k);
u.swapColumns(j, k);
}
}
/**
* @return the u
*/
public IntMatrix getUnimodularMatrix()
{
return u;
}
/**
* @return the d
*/
public IntMatrix getColumnEchelonForm()
{
return d;
}
@Override public String toString()
{
return "A =\n" + a + "\n\nD =\n" + d + "\n\nU =\n" + u; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
/**
* @param i
* @param j
* @param n
* @return
*/
public boolean isZero(int row, int colFrom, int colThru)
{
for (int col = colFrom; col <= colThru; col++)
if (get(row, col) != 0)
return false;
return true;
}
/**
* @param thruCol
* @param fromCol
* @param i
* @return
*/
public int colWithMinimumMagnitude(int row, int fromCol, int thruCol)
{
while (get(row, fromCol) == 0 && fromCol <= cols)
fromCol++;
if (fromCol > cols) throw new IllegalArgumentException();
int result = fromCol;
for (int col = fromCol; col <= thruCol; col++)
if (get(row, col) != 0 && Math.abs(get(row, col)) < Math.abs(get(row, result)))
result = col;
return result;
}
/**
* @param m
* @param i
* @param k
*/
public void addColumnMultiple(int col1, int factor, int col2)
{
for (int row = 1; row <= rows; row++)
set(row, col1, get(row, col1) + factor * get(row, col2));
}
// http://www.ecs.fullerton.edu/~mathews/n2003/BackSubstitutionMod.html
public IntVector forwardSubstitute(int... c)
{
//assert isLowerTriangular() && isColumnEchelonForm();
if (!isSquare()) throw new IllegalArgumentException();
if (c.length != numRows()) throw new IllegalArgumentException();
int size = numRows(); //Math.min(numRows(), numNonzeroCols());
IntVector x = IntVector.zero(size);
for (int i = 1; i <= size; i++)
{
int sum = 0;
for (int j = 1; j < i; j++)
sum += get(i, j) * x.get(j);
if (c[i-1] - sum == 0 && get(i, i) == 0)
x.set(i, 0); // Infinitely many solutions
else if (get(i, i) == 0)
return null; // No solution
else
x.set(i, (c[i-1] - sum) / get(i, i));
}
return x;
}
/**
* @return
*/
private boolean isSquare()
{
return numRows() == numCols();
}
}
/**
* A mutable vector of integers, used solely to support the Generalized GCD dependence tester.
*
* @author Jeff Overbey
*
* @see GeneralizedGCDTest
*/
public static final class IntVector
{
public static IntVector zero(int size)
{
return new IntVector(size);
}
public static IntVector copyFrom(IntVector m)
{
IntVector result = zero(m.data.length);
System.arraycopy(m.data, 0, result.data, 0, m.data.length);
return result;
}
public static IntVector create(int... vals)
{
IntVector result = zero(vals.length);
System.arraycopy(vals, 0, result.data, 0, vals.length);
return result;
}
protected final int[] data;
protected IntVector(int size)
{
this.data = new int[size];
}
/**
* @param element (1-based)
* @return
*/
public int get(int element)
{
check(element);
return data[element-1];
}
/**
* @param element (1-based)
* @param value
*/
public void set(int element, int value)
{
check(element);
data[element-1] = value;
}
protected void check(int element)
{
if (element < 1 || element > data.length) throw new IllegalArgumentException("Invalid element " + element); //$NON-NLS-1$
}
/**
* @return
*/
public int size()
{
return data.length;
}
@Override public String toString()
{
StringBuilder sb = new StringBuilder();
for (int row = 1; row <= size(); row++)
{
sb.append(String.format("%5d", get(row))); //$NON-NLS-1$
sb.append('\n');
}
return sb.toString();
}
public boolean equalsUnwrapped(int... vals)
{
if (vals.length != data.length) throw new IllegalArgumentException("Wrong length array"); //$NON-NLS-1$
return Arrays.equals(vals, data);
}
/**
* @return
*/
public boolean isZero()
{
for (int i = 0; i < data.length; i++)
if (data[i] != 0)
return false;
return true;
}
/**
* @param unimodularMatrix
* @return
*/
public IntVector asRowTimes(IntMatrix matrix)
{
int size = this.size();
if (matrix.numRows() != size) throw new IllegalArgumentException();
if (matrix.numCols() != size) throw new IllegalArgumentException();
IntVector result = IntVector.zero(size);
for (int col = 1; col <= size; col++)
{
int sum = 0;
for (int row = 1; row <= size; row++)
sum += this.get(row) * matrix.get(row, col);
result.set(col, sum);
}
return result;
}
}
}