/*
 * LVmatrix.java
 * @author  Michael Anderson
 *
 * Created on July 31, 2004, 11:21 PM
 */

package LotkaVolterra;
import Jama.*;

public final class LVmatrix {
    
    // Creates a new instance of LVmatrix
    private LVmatrix() {}
    
    
    // N is the Number of Species
    // numberOfConnections is the number of connections each 
    // animal will have p is the "randomness" of the network
    public static double[][] createAlphaMatrix(int N, int numConnect, double p) {
        
        double[][] alphaMatrix = createOrderedMatrix(N, numConnect, 1.0);
            
        if (p > 0.0) {
            // Mix up a percentage p number of links
            mixUpMatrix(alphaMatrix, p);
        }
        
        return alphaMatrix;
    } // end of createAlphaMatrix method
    
    
    // Given an array of animals, convert
    // that to the coresponding alpha matrix
    public static double[][] createAlphaMatrix(Animal[] animal) {
        
        int numberOfSpecies = animal.length;
        double[][] alphaMatrix = new double[numberOfSpecies][numberOfSpecies];
        
        for (int i = 0; i < numberOfSpecies; i++) {
            for (int j = 0; j < animal[i].connection.length; j++) {
                alphaMatrix[i][animal[i].connection[j]] = animal[i].conStrength[j];
            }
        }
        
        return alphaMatrix;
    }
    
    
    // Create an NxN matrix with elements within + or - k/2
    // of the diagonal set to one
    public static double[][] createOrderedMatrix(int N, int k, double strength) {
        
        double[][] returnMatrix = new double[N][N];
        int m;
        
        for (int i = 0; i < N; i++) {
            for (int j = i - k/2; j <= i + k/2; j++) {
                
                if (j < 0) {
                    m = j + N;
                } else if (j >= N) {
                    m = j - N;
                } else {
                    m = j;
                }
                
                // Put a link from animal i to animal j
                if (j == i) {
                    returnMatrix[i][m] = 1.0;
                } else {
                    returnMatrix[i][m] = strength;
                }
                
               
            } // end j loop
        } // end i loop
        
        return returnMatrix;
    }  // End of createOrderedMatrix method
    
    
    //Determine if the Lotka Volterra system is
    //totally connected or not.
    public static boolean isConnected(Animal[] animal) {
        
        int numberOfSpecies = animal.length;
        Matrix alphaMatrix = new Matrix(createAlphaMatrix(animal));
        Matrix sum = new Matrix(numberOfSpecies, numberOfSpecies, 0);
        Matrix lowerPowers = new Matrix(alphaMatrix.getArrayCopy());
        
        for (int i = 1; i < numberOfSpecies; i++) {
            sum = sum.plus(lowerPowers);
            lowerPowers = lowerPowers.times(lowerPowers);
        }
        
        double minValue = sum.getMinValue();
        
        if (minValue > 0.0) {
            return true;
        } else {
            return false;
        }
    }
    
    
    // Mix up an ordered matrix by
    // moving a percentage of points, p.
    public static void mixUpMatrix(double[][] matrix, double p) {
        
        int N = matrix.length;
        
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                
                if ((matrix[i][j] != 0) && (Math.random() <= p)) {
                    // We've found a non-zero connection
                    // and it's been randomly chosen to be moved

                    int newLocation = 0;
                    do {
                        newLocation = (int)(N * Math.random());
                    } while (matrix[i][newLocation] != 0);

                        matrix[i][newLocation] = matrix[i][j];
                        matrix[i][j] = 0;
                }
            }  // end of j loop
        }  // end of i loop

    }  // End of mixUpMatrix
    
    
    // Create an Array of integers like [1, 2, ... size]
    // then mix up the values in this array
    public static int[] randomOrderedArray(int size) {
        
        int[] randomizedArray = new int[size];
        //First create the ordered array
        for (int i = 0; i < size; i++) {
            randomizedArray[i] = i;
        }  //end of i loop
        
        int tempValue;
        int tempLocation1;
        int tempLocation2;

        //Now mix up the array
        for (int i = 0; i < size; i++) {
            
            //pick two different locations
            do {
                tempLocation1 = (int)(Math.random() * size);
                tempLocation2 = (int)(Math.random() * size);
            } while (tempLocation1 == tempLocation2);
            
            //Swap the values in the two locations in randomizedArray
            tempValue = randomizedArray[tempLocation1];
            randomizedArray[tempLocation1] = randomizedArray[tempLocation2];
            randomizedArray[tempLocation2] = tempValue;
        }
        
        return randomizedArray;
    }  // End randomOrderedArray
    
    
    // Remove element i from array
    public static double[] removeFromArray(double[] array, int q) {
        
        if ((array == null) || (q >= array.length)) {
            return array;
        }
        
        int newLength = array.length - 1;
        double[] newArray = new double[newLength];
        
        int j = 0;
        for (int i = 0; i < array.length; i++) {
            if (i != q) {
                newArray[j] = array[i];
                j = j + 1;
            }
        }
        
        return newArray;
    }  // End removeFromArray
    
} // End of LVmatrix class
