• fullscreen
  • Adventurer.pde
  • Algebraicist.pde
  • Arithmetician.pde
  • AspektWorld.pde
  • Graph.pde
  • Line.pde
  • Matrix.pde
  • Visionary.pde
  • // The inimmitable graph visualization explorer
    public class Adventurer {
    	public Graph g;
    	public Adventurer( Graph base ) {
    		g = base;
    		make_all_basic_matrices();
    	}
    
    	public void make_all_basic_matrices() {
    		int max = g.numbering.size();
    		g.matrix = new Matrix[Graph.MatrixTypeIndex.MATRIX_FIELD_COUNT];
    		float[] threeArgs = new float[] { (float)Math.random()*max, (float)Math.random()*max, (float)Math.random()*max };
    		for(int i = 0; i < Graph.MatrixTypeIndex.MATRIX_FIELD_COUNT;i++) {
    			Algebraicist.form(g, i);
    		}
    	}
    
    	public Matrix make_random_filter(int rand_base_matrix1, int rand_base_matrix2, int rand_power, int rand_binary ) {
    		//System.out.println("RF: " + rand_base_matrix1 + "," + rand_base_matrix2 + "," + rand_power + "," + rand_binary);
    		Matrix f = new Matrix(g.matrix[rand_base_matrix1]);
    		int max = g.numbering.size();
    		float[] threeArgs = new float[] { (float)Math.random()*max, (float)Math.random()*max, (float)Math.random()*max };
    		f = Arithmetician.fastMultiproduct(f, rand_power);
    		f = Arithmetician.ApplyBinary(rand_binary, f, g.matrix[rand_base_matrix2], threeArgs);
    		return f;
    	}
    
    	public Matrix make_random_Matrix_filter(int mod_or_not, int[] param_Base_Matrix, int[] param_Unary_Ops, int[] param_Binary_Combinators, int[] zeroOne, float[] threeArgs) {
    		// We choose a filter length of max 5 matrices
    		// We choose five matrices, and five unary filters to apply to each matrix
    		// We choose 4 binary combinator ops to combine these 5 matrices
    		// We collapse these ops right to left to construct a random filter
    		// But it is only random in the sense that we choose our exploration of the filterspace randomly (or using a basic GA)
    		// It is deterministic on the parameters passed in here
    		// Which in GA are 'genetic code' / feature vector
    		Matrix[] theFive = new Matrix[5];
    		int i = 5;
    		while(--i >= 0)
    			theFive[i] = g.matrix[param_Base_Matrix[i]];
    		if(mod_or_not == 0) {
    			i = 5;
    			while(--i >= 0)
    				theFive[i] = Arithmetician.ApplyUnary(param_Unary_Ops[i], theFive[i], threeArgs, zeroOne );
    			i = 4;
    			Matrix result = theFive[4];
    			while(--i >= 0)
    				result = Arithmetician.ApplyBinary(param_Binary_Combinators[i], theFive[i], result, threeArgs);
    			return result;
    		}
    		else {
    			i = 5;
    			while(--i >= 0)
    				theFive[i] = Arithmetician.ApplyModUnary(param_Unary_Ops[i], theFive[i], threeArgs, zeroOne );
    			i = 4;
    			Matrix result = theFive[4];
    			while(--i >= 0)
    				result = Arithmetician.ApplyModBinary(param_Binary_Combinators[i], theFive[i], result, threeArgs);
    			return result;
    		}
    	}
    }
    
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Set;
    
    // He makes stuff
    public class Algebraicist {
    	// 5 primitive matrices
    
    	public static Matrix form( Graph g, int matrixType ) {
    		switch(matrixType) {
    		case(Graph.MatrixTypeIndex.ADJACENCY):
    			return g.matrix[Graph.MatrixTypeIndex.ADJACENCY] = adjacency(g);
    		case(Graph.MatrixTypeIndex.DEGREE):
    			return g.matrix[Graph.MatrixTypeIndex.DEGREE] = degree(g);
    		case(Graph.MatrixTypeIndex.LAPLACIAN):
    			return g.matrix[Graph.MatrixTypeIndex.LAPLACIAN] = laplacian(g.matrix[Graph.MatrixTypeIndex.DEGREE], g.matrix[Graph.MatrixTypeIndex.ADJACENCY], 0.5f);
    		case(Graph.MatrixTypeIndex.COLLOCATION):
    			return g.matrix[Graph.MatrixTypeIndex.COLLOCATION] = collocation(g.matrix[Graph.MatrixTypeIndex.ADJACENCY]);
    		default:
    			return new Matrix(Matrix.IDENTITY,g.numbering.size(),g.numbering.size());
    		}
    	}
    
    	public static Matrix adjacency( Graph g ) {
    		int vertices = g.edgesByVertexA.size();
    		Set<Graph.Vertex> verticeSet = g.edgesByVertexA.keySet();
    		Iterator<Graph.Vertex> vertexIterator = verticeSet.iterator();
    		Matrix am = new Matrix(Matrix.NONE, vertices, vertices);
    		HashMap<Graph.Vertex,Integer> numbering = g.numbering();
    		while(vertexIterator.hasNext()) {
    			Graph.Vertex v = vertexIterator.next();
    			int vnum = numbering.get(v);
    			Set<Graph.Edge> vOutEdges = g.edgesByVertexA.get(v);
    			Set<Graph.Edge> vInEdges = g.edgesByVertexB.get(v);
    			Iterator<Graph.Edge> vOutIterator = vOutEdges.iterator();
    			while(vOutIterator.hasNext()) {
    				Graph.Edge e = vOutIterator.next();
    				Graph.Vertex b = e.b;
    				int bnum = numbering.get(b);
    				am.entry[vnum][bnum] = 1.0f;
    			}
    			Iterator<Graph.Edge> vInIterator = vInEdges.iterator();
    			while(vInIterator.hasNext()) {
    				Graph.Edge e = vInIterator.next();
    				Graph.Vertex a = e.a;
    				int anum = numbering.get(a);
    				am.entry[anum][vnum] = 1.0f;
    			}
    		}
    		am.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return am;
    	}
    
    	public static Matrix collocation( Matrix a ) {
    		int i = a.rows;
    		int j = a.columns;
    		Matrix h = new Matrix(Matrix.COLLOCATION, i, j);
    		while(--i >= 0) {
    			h.hentry[i][i] = neighbourintersection(i,i,a);
    			while(--j > i) {
    				h.hentry[i][j] = neighbourintersection(i,j,a);
    				h.hentry[j ][i] = h.hentry[i][j];
    			}  
    			j = a.columns;                
    		}
    		return h;
    	}
    
    	public static HashSet neighbourintersection(int row1, int row2, Matrix a) {
    		int column = a.columns;
    		HashSet<Integer> ni = new HashSet<Integer>();
    		while(--column >= 0) {
    			float a1c = a.entry[row1][column];
    			float a2c = a.entry[row2][column];
    			if(a1c == 1.0f && a2c == 1.0f)
    				ni.add(new Integer(column));  
    		}
    		return ni;
    	}
    
    	public static Matrix incidence( Graph g ) { // VxE
    		int vertices = g.numbering.size();
    	int edges = g.edgeNumbering.size();
    	Matrix im = new Matrix(Matrix.NONE, vertices, edges );
    	Set<Graph.Edge> edgeSet = g.edgeNumbering.keySet();
    	Iterator<Graph.Edge> edgeIterator = edgeSet.iterator();
    	while(edgeIterator.hasNext()) {
    		Graph.Edge e = edgeIterator.next();
    		int edgnum = g.edgeNumbering.get(e);
    		Graph.Vertex a = e.a;
    		Graph.Vertex b = e.b;
    		int anum = g.numbering.get(a);
    		int bnum = g.numbering.get(b);
    		im.entry[anum][edgnum] = 1.0f;
    		im.entry[bnum][edgnum] = 1.0f;
    	}
    	return im;
    	}
    
    	public static Matrix SignedIncidence( Graph g ) { // VxE
    		int vertices = g.numbering.size();
    		int edges = g.edgeNumbering.size();
    		Matrix im = new Matrix(Matrix.NONE, vertices, edges );
    		Set<Graph.Edge> edgeSet = g.edgeNumbering.keySet();
    		Iterator<Graph.Edge> edgeIterator = edgeSet.iterator();
    		while(edgeIterator.hasNext()) {
    			Graph.Edge e = edgeIterator.next();
    			int edgnum = g.edgeNumbering.get(e);
    			Graph.Vertex a = e.a;
    			Graph.Vertex b = e.b;
    			int anum = g.numbering.get(a);
    			int bnum = g.numbering.get(b);
    			im.entry[anum][edgnum] = 1.0f;
    			im.entry[bnum][edgnum] = -1.0f;
    		}
    		return im;
    	}
    
    	public static Matrix degree( Graph g ) {
    		int vertices = g.edgesByVertexA.size();
    		Matrix dg = new Matrix(Matrix.NONE, vertices, vertices);
    		HashMap<Graph.Vertex,Integer> numbering = g.numbering();
    		Set<Graph.Vertex> verticeSet = g.edgesByVertexA.keySet();
    		Iterator<Graph.Vertex> vertexIterator = verticeSet.iterator();
    		g.volume = 0.0f;
    		while(vertexIterator.hasNext()) {
    			Graph.Vertex v = vertexIterator.next();
    			int vnum = numbering.get(v);
    			Set<Graph.Edge> vOutEdges = g.edgesByVertexA.get(v);
    			Set<Graph.Edge> vInEdges = g.edgesByVertexB.get(v);
    			g.volume += dg.entry[vnum][vnum] = vOutEdges.size() + vInEdges.size();
    		}
    		dg.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return dg;
    	}
    
    	public static Matrix edgeAdjacency( Graph g ) { // ExE
    		Set<Graph.Vertex> verticeSet = g.edgesByVertexA.keySet();
    		Iterator<Graph.Vertex> vertexIterator = verticeSet.iterator();
    		int edges = g.edgeNumbering.size();
    		Matrix eda = new Matrix(Matrix.NONE, edges, edges);
    		while(vertexIterator.hasNext()) {
    			Graph.Vertex stupidFuckFace = vertexIterator.next();
    			Set<Graph.Edge> fuckingMoron = g.edgesByVertexA.get(stupidFuckFace);
    			Iterator<Graph.Edge> edgeIterator = fuckingMoron.iterator();
    			while(edgeIterator.hasNext()) {
    				Graph.Edge e = edgeIterator.next();
    				int edgnum = g.edgeNumbering.get(e);
    				Graph.Vertex a = e.a;
    				Set<Graph.Edge> heIsStillAFuckFace = g.edgesByVertexA.get(a);
    				Iterator<Graph.Edge> fuckIterator = heIsStillAFuckFace.iterator();
    				while(fuckIterator.hasNext()) {
    					Graph.Edge eneighbour = fuckIterator.next();
    					int eneighbournum = g.edgeNumbering.get(eneighbour);
    					if(edgnum != eneighbournum)
    						eda.entry[edgnum][eneighbournum] = 1.0f;
    				}
    				if(a!=e.b) {
    					Graph.Vertex b = e.b;
    					heIsStillAFuckFace = g.edgesByVertexA.get(b);
    					fuckIterator = heIsStillAFuckFace.iterator();
    					while(fuckIterator.hasNext()) {
    						Graph.Edge eneighbour = fuckIterator.next();
    						int eneighbournum = g.edgeNumbering.get(eneighbour);
    						if(edgnum != eneighbournum)
    							eda.entry[edgnum][eneighbournum] = 1.0f;
    					}	
    				}
    			}
    		}
    		eda.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return eda;
    	}
    
    	public static Matrix edgeDegree( Graph g ) { // ExE
    		Set<Graph.Vertex> verticeSet = g.edgesByVertexA.keySet();
    		Iterator<Graph.Vertex> vertexIterator = verticeSet.iterator();
    		int edges = g.edgeNumbering.size();
    		Matrix edd = new Matrix(Matrix.NONE, edges, edges);
    		while(vertexIterator.hasNext()) {
    			Graph.Vertex stupidFuckFace = vertexIterator.next();
    			Set<Graph.Edge> fuckingMoron = g.edgesByVertexA.get(stupidFuckFace);
    			Iterator<Graph.Edge> edgeIterator = fuckingMoron.iterator();
    			while(edgeIterator.hasNext()) {
    				Graph.Edge e = edgeIterator.next();
    				int edgnum = g.edgeNumbering.get(e);
    				Graph.Vertex a = e.a;
    				Set<Graph.Edge> heIsStillAFuckFace = g.edgesByVertexA.get(a);
    				Iterator<Graph.Edge> fuckIterator = heIsStillAFuckFace.iterator();
    				while(fuckIterator.hasNext()) {
    					Graph.Edge eneighbour = fuckIterator.next();
    					int eneighbournum = g.edgeNumbering.get(eneighbour);
    					if(edgnum != eneighbournum)
    						edd.entry[edgnum][edgnum] += 1.0f;
    				}
    				if(a!=e.b) {
    					Graph.Vertex b = e.b;
    					heIsStillAFuckFace = g.edgesByVertexA.get(b);
    					fuckIterator = heIsStillAFuckFace.iterator();
    					while(fuckIterator.hasNext()) {
    						Graph.Edge eneighbour = fuckIterator.next();
    						int eneighbournum = g.edgeNumbering.get(eneighbour);
    						if(edgnum != eneighbournum)
    							edd.entry[edgnum][edgnum] += 1.0f;
    					}	
    				}
    			}
    		}
    		edd.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return edd;
    	}
    
    
    	// 5 secondary matrix operators
    
    	public static Matrix complement( Matrix a ) {
    		int i = a.rows;
    		int j = a.columns;
    		Matrix c = new Matrix(Matrix.NONE, i, j);
    		while( --i >= 0 ) {
    			while( --j >= 0 ) {
    				if( a.entry[i][j] != 0.0f) 
    					c.entry[i][j] = 0.0f;
    				else
    					c.entry[i][j] = 1.0f;
    			}
    			j = a.columns;
    		}
    		return c;
    	}
    
    	public static Matrix exactlyTwoStepAdjacency( Matrix a ) {
    		int i = a.rows;
    		int j = a.columns;
    		int shortest = a.shortest;
    		Matrix a2 = new Matrix(Matrix.NONE, i, j);
    		while( --i >= 0 ) {
    			while( --j >= 0 ) {
    				int k = shortest;
    				while ( --k >= 0 ) {
    					if( a.entry[i][k] != 0.0f && a.entry[k][j] != 0.0f )
    						a2.entry[i][j] = a.entry[i][k] + a.entry[k][j];
    				}
    			}
    			j = a.columns;
    		}
    		return a2;
    	}
    
    	public static Matrix exactlyOneStepDegree( Matrix d, Matrix a ) {
    		int i = a.rows;
    		int j = a.columns;
    		Matrix d1 = new Matrix(Matrix.NONE, i, j);
    		while( --i >= 0 ) {
    			while( --j >= 0 ) {
    				if( a.entry[i][j] != 0.0f) 
    					d1.entry[i][i] += d.entry[j][j];
    			}
    			j = a.columns;
    		}
    		return d1;
    	}
    
    	public static Matrix exactlyTwoStepDegree( Matrix d, Matrix a2 ) {
    		int i = a2.rows;
    		int j = a2.columns;
    		Matrix d2 = new Matrix(Matrix.NONE, i, j);
    		while( --i >= 0 ) {
    			while( --j >= 0 ) {
    				if( a2.entry[i][j] != 0.0f) 
    					d2.entry[i][i] += d.entry[j][j];
    			}
    			j = a2.columns;
    		}
    		return d2;
    	}
    
    	public static Matrix seidelAdjacency( Matrix a ) {
    		int i = a.rows;
    		int j = a.columns;
    		Matrix sa = new Matrix(Matrix.NONE, i, j);
    		while( --i >= 0 ) {
    			while( --j >= 0 ) {
    				if(i==j)
    					sa.entry[i][i] = 0.0f;
    				else if(a.entry[i][j] != 0.0f)
    					sa.entry[i][j] = -1.0f;
    				else
    					sa.entry[i][j] = 1.0f;
    			}
    			j = a.columns;
    		}
    		return sa;
    	}
    
    	// 22 Matrix combinators 
    
    	public static Matrix augmentedAdjacencyMatrix( Matrix incidence ) {
    		return Arithmetician.productResult(incidence, incidence.transpose());
    	}
    
    	public static Matrix FanChungBoundaryOperator( Matrix SignedIncidence, Matrix degree ) {
    		int i = SignedIncidence.rows;
    		int j = SignedIncidence.columns;
    		Matrix sd = Arithmetician.entrywiseSquareRootResult(degree);
    		Matrix b = new Matrix(Matrix.NONE, j, i);
    		while( --i >= 0 ) {
    			while( --j >= 0 ) {
    				b.entry[j][i] = SignedIncidence.entry[i][j]/sd.entry[i][i];
    			}
    			j = SignedIncidence.columns;
    		}
    		return b;
    	}
    
    	public static Matrix shareOfDegree( Graph g, Matrix degree ) {
    		int i = degree.rows;
    		int j = degree.columns;
    		Matrix sd = new Matrix(Matrix.NONE, i, j);
    		while( --i >= 0 ) {
    			while( --j >= 0 ) {
    				sd.entry[i][j] = degree.entry[i][j]/g.volume;
    			}
    			j = degree.columns;
    		}
    		return sd;
    	}
    
    	public static Matrix minimumDistanceMatrix(Matrix connectivityMetric) {
    		return Arithmetician.FloydWarshall(connectivityMetric, 1.0f, 50.0f, connectivityMetric.shortest*4.0f*50.0f, 0, Arithmetician.MIN );
    	}
    
    
    	public static Matrix minimumDistanceMatrixParameterized(Matrix connectivityMetric, float conMetParam) {
    		// connectivityMetric.show();       
    		return Arithmetician.FloydWarshall(connectivityMetric, conMetParam, 50.0f, connectivityMetric.shortest*4.0f*50.0f, 0, Arithmetician.MIN );
    	}
    
    	public static Matrix generalizedAdjacency( float x, float y, float z, Matrix a ) {
    		//(xI +yA + z(J-I-A))
    		return Arithmetician.pairwiseSumResult(
    				Arithmetician.scalarMultiplyResult( 
    						new Matrix(Matrix.IDENTITY, a.rows, a.columns), x), 
    						Arithmetician.pairwiseSumResult(
    								Arithmetician.scalarMultiplyResult(a, y),
    								Arithmetician.scalarMultiplyResult(
    										Arithmetician.pairwiseSubtractResult(
    												new Matrix(Matrix.COUNTERIDENTITY, a.rows, a.columns),
    												Arithmetician.pairwiseSumResult(new Matrix(Matrix.IDENTITY, a.rows, a.columns), a)),
    												z)
    								));
    
    	}
    
    	public static Matrix weightedDegree( Matrix degree, float weight ) {
    		return Arithmetician.scalarMultiplyResult(degree, weight);
    	}
    
    	public static Matrix weightedAdjacency( Matrix adjacency, float weight ) {
    		return Arithmetician.scalarMultiplyResult(adjacency, weight);
    	}
    
    	public static Matrix SpielmanLazywalkMatrix(Matrix degree, Matrix adjacency) {
    		return Arithmetician.scalarMultiplyResult(
    				Arithmetician.pairwiseSumResult(
    						new Matrix(Matrix.IDENTITY, adjacency.rows, adjacency.columns),
    						Arithmetician.productResult(adjacency, 
    								Arithmetician.Inverse(degree))), 
    								0.5f);
    	}
    
    	public static Matrix lazywalkMatrixSoftInverse(Matrix degree, Matrix adjacency) {
    		return Arithmetician.scalarMultiplyResult(
    				Arithmetician.pairwiseSumResult(
    						new Matrix(Matrix.IDENTITY, adjacency.rows, adjacency.columns),
    						Arithmetician.productResult(degree, 
    								Arithmetician.Inverse(adjacency))), 
    								2.0f);
    	}
    
    	public static Matrix nStepWalks( Matrix adjacency, int nsteps ) {
    		return Arithmetician.fastMultiproduct(adjacency, nsteps);
    	}
    
    	public static Matrix transitionMatrixRandomWalk( Matrix a, Matrix degree ) {
    		int i = a.rows;
    		int j = a.columns;
    		Matrix t = new Matrix(Matrix.NONE, i, j);
    		while( --i >= 0 ) {
    			while( --j >= 0 ) {
    				if( a.entry[i][j] != 0.0f )
    					t.entry[i][j] = 1.0f/degree.entry[i][i];
    			}
    			j = a.columns;
    		}
    		return t;
    	}
    
    	public static Matrix laplacian(Matrix degree, Matrix adjacency, float weight) {
    		if(weight != 1.0f)
    			//return weightByDegree(degree, Arithmetician.pairwiseSubtractResult(degree,Arithmetician.scalarMultiplyResult(
    			//		 adjacency,
    			//		weight)));
    			return Arithmetician.pairwiseSubtractResult(degree,Arithmetician.scalarMultiplyResult(
    					adjacency,
    					weight));
    		else
    			return 	Arithmetician.pairwiseSubtractResult(degree, adjacency);
    		//return 	weightByDegree(degree, Arithmetician.pairwiseSubtractResult(degree, adjacency));
    	}
    
    	public static Matrix laplaceOperator( Matrix d ) {
    		int i = d.rows;
    		int j = d.columns;
    		Matrix lo = new Matrix(Matrix.NONE, i, j);
    		while( --i >= 0 ) {
    			while( --j >= 0 ) {
    				if(i==j)
    					lo.entry[i][i] = 1.0f;
    				else
    					lo.entry[i][j] = -1.0f/d.entry[i][j]; 
    			}
    			j = d.columns;
    		}
    		return lo;
    	}
    
    	public static Matrix weightByDegree(Matrix degree, Matrix base) {
    		int i = base.rows;
    		int j = base.columns;
    		Matrix pm = new Matrix(Matrix.NONE, i, j);
    		while( --i >= 0 ) {
    			float degi = degree.entry[i][i];
    			while( --j >= 0 ) {
    				if(i==j)
    					pm.entry[i][i] = base.entry[i][i];
    				else
    					pm.entry[i][j] = base.entry[i][j]*degi*degree.entry[j][j]; 
    			}
    			j = base.columns;
    		}  
    		return pm;
    	}
    
    	public static Matrix SoftNormalizedLaplacian(Matrix degree, Matrix laplacian, float weight ) {
    		Matrix entryWiseRoot = Arithmetician.entrywiseSquareRootResult(degree);
    		Matrix entryWiseRootInverse = Arithmetician.entrywiseInversionResult(entryWiseRoot);
    		if(weight != 1.0f)
    			return Arithmetician.productResult(
    					Arithmetician.productResult(entryWiseRootInverse, Arithmetician.scalarMultiplyResult(laplacian, weight)),
    					entryWiseRoot);
    		else
    			return Arithmetician.productResult(
    					Arithmetician.productResult(entryWiseRootInverse, laplacian),
    					entryWiseRoot);
    	}
    
    
    
    	public static Matrix HardNormalizedLaplacian(Matrix degree, Matrix laplacian, float weight ) {
    		Matrix[] rootAndInverse = Arithmetician.squareRootInverseSquareRootResult(degree);
    		if(weight != 1.0f)
    			return Arithmetician.productResult(
    					Arithmetician.productResult(rootAndInverse[1], Arithmetician.scalarMultiplyResult(laplacian, weight)),
    					rootAndInverse[0]);
    
    		else
    			return Arithmetician.productResult(
    					Arithmetician.productResult(rootAndInverse[1], laplacian),
    					rootAndInverse[0]);
    	}
    
    	public static Matrix eigenvectors( Matrix m ) { 
    		Arithmetician.PowerIterationDeflate(m, m.shortest, 0.000000001, 0 );
    		Matrix e = new Matrix(m.eigenvector);
    		System.arraycopy(m.eigenvalue, 0, e.eigenvalue, 0, m.eigenvalue.length);
    		return e;
    	}
    
    	public static void show_v (float[] v) {
    		int i = v.length;
    		while(--i >= 0)
    			System.out.print(v[i] + " ");
    		System.out.println();
    	}
    
    
    	public static Matrix commuteTime( Graph g ) {  
    		Matrix nl = g.matrix[Graph.MatrixTypeIndex.LAPLACIAN];
    		Matrix d = Arithmetician.entrywiseSquareRootResult(g.matrix[Graph.MatrixTypeIndex.DEGREE]);
    		Matrix eigns = eigenvectors(nl);
    		Matrix ct = new Matrix(Matrix.NONE, d.rows, d.columns);
    		float vol = g.volume;
    		int k = nl.shortest;
    		while(--k >= 0 ) {
    			int i = d.rows;
    			while(--i >= 0) {
    				int j = d.columns;
    				while(--j >= 0) {
    					float eki = eigns.entry[k][i]/d.entry[i][i];
    					float ekj = eigns.entry[k][j]/d.entry[j][j];
    					ct.entry[i][j] += vol*(eki-ekj)*(eki-ekj)/eigns.eigenvalue[k];
    				}
    			}
    		}
    		return ct;
    	}
    
    	public static Matrix deformedLaplacian(Matrix d, Matrix a, float deformation ) {
    		//I - sA + s2(D - I)
    		return Arithmetician.pairwiseSumResult(
    				Arithmetician.pairwiseSubtractResult(
    						new Matrix(Matrix.IDENTITY, a.rows, a.columns ),
    						Arithmetician.scalarMultiplyResult(a, deformation)),
    						Arithmetician.scalarMultiplyResult(
    								Arithmetician.pairwiseSubtractResult(d, new Matrix(Matrix.IDENTITY, d.rows, d.columns)),
    								deformation*deformation));
    
    	}
    
    	public static Matrix projectionMatrix( int rows, int columns ) {
    		float ns = (float)Math.sqrt(rows*columns);
    		float diag = (ns-1.0f)/ns;
    		float nondiag = -1.0f/ns;
    		int i = rows;
    		int j = columns;
    		Matrix pm = new Matrix(Matrix.NONE, i, j);
    		while( --i >= 0 ) {
    			while( --j >= 0 ) {
    				if(i==j)
    					pm.entry[i][i] = diag;
    				else
    					pm.entry[i][j] = nondiag; 
    			}
    			j = columns;
    		}
    		return pm;
    	}
    
    	public static Matrix projectedMatrix(Matrix embeddingMetric, float projectionCoefficient ) { // 0.5f
    		// p = 0.5PEP
    		return Arithmetician.productResult(
    				Arithmetician.scalarMultiplyResult(projectionMatrix(embeddingMetric.rows, embeddingMetric.columns), projectionCoefficient),
    				Arithmetician.productResult( embeddingMetric, projectionMatrix(embeddingMetric.rows, embeddingMetric.columns)));
    	}
    
    	public static Matrix RPaugmentedDegreeMatrix(Matrix d, Matrix mindistance) {
    		Matrix mindistanceRoot = Arithmetician.entrywiseSquareRootResult(mindistance);
    		int i = d.rows;
    		int j = d.columns;
    		Matrix augd = new Matrix(Matrix.NONE, i, j);
    		while( --i >= 0 ) {
    			while( --j >= 0 ) {
    				if(i==j)
    					augd.entry[i][i] = d.entry[i][i];
    				else if ((1 << (int)(mindistanceRoot.entry[i][j])) != 0.0f )
    					augd.entry[i][j] = d.entry[j][j] / (1 << (int)(mindistanceRoot.entry[i][j])) ;
    			}
    			j = d.columns;
    		}
    		return augd;
    	}
    
    	public static Matrix maximumDistanceMatrix(Matrix connectivityMetric) {
    		return Arithmetician.FloydWarshall(connectivityMetric, 1.0f, 50.0f, connectivityMetric.shortest*4.0f*50.0f, 1, Arithmetician.MAX );
    	}
    
    
    
    
    
    
    
    
    
    
    
    
    }
    
    import java.util.Arrays;
    
    public final class Arithmetician {
    	public static final int MIN = 0;
    	public static final int MAX = 1;
    	public int parametrization = (2*3*10*18*9*32);
    
    	public class MatrixOperation {
    		public static final int UNARY = 0;
    		public static final int SCALAR = 1;
    		public static final int BINARY = 2;
    		public static final int MOD = 3;
    
    		public class MatrixBinary {
    			public static final int PAIRWISESUM = 0;
    			public static final int PAIRWISESUBTRACT = 1;
    			public static final int HADARMARDPRODUCT = 2;
    			public static final int PRODUCTPROPAGATED = 3;
    			public static final int PRODUCT = 4;
    			public static final int HADAMARDDIVISION = 5;
    			public static final int AND = 6;
    			public static final int OR = 7;
    			public static final int XOR = 8;
    			public static final int KOR = 9;
    			public static final int FROBENIUSINNERPRODUCT = 10;
    			public static final int BINARY_FIELD_COUNT = 11;
    
    		}
    		public class MatrixUnary {
    			public static final int ENTRYWISEINVERSION = 1;
    			public static final int EXPONENTIALTRACE = 2;
    			public static final int SQUAREROOTINVERSESQUAREROOT = 3;
    			public static final int SOFTSQUAREROOT = 4;
    			public static final int ENTRYWISENATURALLOG = 5;
    			public static final int RANDOMFILL = 6;
    			public static final int L0NORMALIZE = 7;
    			public static final int L1NORMALIZE = 8;
    			public static final int L2NORMALIZE = 9;
    			public static final int LINFNORMALIZE = 10;
    			public static final int FLOYDWARSHALL = 11;
    			public static final int POWERITERATIONDEFLATE = 12;
    			public static final int LUDOLITTLEDECOMPOSITION = 13;
    			public static final int DETERMINANT = 14;
    			public static final int INVERSE = 15;
    			public static final int NOT = 16;
    			public static final int COMPLEMENT = 17;
    			public static final int UNARY_FIELD_COUNT = 18;
    		}
    		public class MatrixScalar {
    			public static final int SCALARADD = 0;
    			public static final int SCALARSUBTRACT = 1;
    			public static final int SCALARMULTIPLY = 2;
    			public static final int SCALARDIVIDE = 3;
    			public static final int HADAMARDPOWER = 4;		
    			public static final int FASTPROPAGATEDMULTIPRODUCT = 5;
    			public static final int FASTMULTIPRODUCT = 6;
    			public static final int ENTRYWISEMAPTORANGE = 7;
    			public static final int THRESHOLD = 8;
    
    		}
    
    		public class Mod {
    			public static final int UNARY = 0;
    			public static final int SCALAR = 1;
    			public static final int BINARY = 2;
    			public class MatrixBinary {
    				public static final int PAIRWISESUM = 0;
    				public static final int PAIRWISESUBTRACT = 1;
    				public static final int HADARMARDPRODUCT = 2;
    				public static final int PRODUCTPROPAGATED = 3;
    				public static final int PRODUCT = 4;
    				public static final int HADAMARDDIVISION = 5;
    				public static final int AND = 6;
    				public static final int OR = 7;
    				public static final int XOR = 8;
    				public static final int KOR = 9;
    
    			}
    			public class MatrixUnary {
    				public static final int FROBENIUSINNERPRODUCT = 0;
    				public static final int ENTRYWISEINVERSION = 1;
    				public static final int EXPONENTIALTRACE = 2;
    				public static final int SQUAREROOTINVERSESQUAREROOT = 3;
    				public static final int SOFTSQUAREROOT = 4;
    				public static final int ENTRYWISENATURALLOG = 5;
    				public static final int RANDOMFILL = 6;
    				public static final int L0NORMALIZE = 7;
    				public static final int L1NORMALIZE = 8;
    				public static final int L2NORMALIZE = 9;
    				public static final int LINFNORMALIZE = 10;
    				public static final int FLOYDWARSHALL = 11;
    				public static final int POWERITERATIONDEFLATE = 12;
    				public static final int LUDOLITTLEDECOMPOSITION = 13;
    				public static final int DETERMINANT = 14;
    				public static final int INVERSE = 15;
    				public static final int NOT = 16;
    				public static final int COMPLEMENT = 17;
    			}
    			public class MatrixScalar {
    				public static final int SCALARADD = 0;
    				public static final int SCALARSUBTRACT = 1;
    				public static final int SCALARMULTIPLY = 2;
    				public static final int SCALARDIVIDE = 3;
    				public static final int HADAMARDPOWER = 4;		
    				public static final int FASTPROPAGATEDMULTIPRODUCT = 5;
    				public static final int FASTMULTIPRODUCT = 6;
    				public static final int ENTRYWISEMAPTORANGE = 7;
    				public static final int THRESHOLD = 8;
    
    			}
    		}
    
    	}
    
    	public static void vectorScalarAdd( float[] v, float add ) {
    		int i = v.length;
    		while(--i >= 0)
    			v[i]+=add;
    	}
    
    	public static Matrix ApplyScalar( int opNum, Matrix m, float[] threeArgs) {
    		switch(opNum) {
    		case(MatrixOperation.MatrixScalar.SCALARADD):
    			return scalarAddResult(m, threeArgs[0]);
    		case(MatrixOperation.MatrixScalar.SCALARSUBTRACT):
    			return scalarSubtractResult(m, threeArgs[0]);
    		case(MatrixOperation.MatrixScalar.SCALARMULTIPLY):
    			return scalarMultiplyResult(m, threeArgs[0]);
    		case(MatrixOperation.MatrixScalar.SCALARDIVIDE):
    			return scalarDivideResult(m, threeArgs[0]);
    		case(MatrixOperation.MatrixScalar.HADAMARDPOWER):		
    			return hadamardPowerResult(m, (int)threeArgs[0]);
    		case(MatrixOperation.MatrixScalar.FASTPROPAGATEDMULTIPRODUCT):
    			fastPropagatedMultiproduct(m, (int)threeArgs[0]);
    		return m;
    		case(MatrixOperation.MatrixScalar.FASTMULTIPRODUCT):
    			return fastMultiproduct(m, (int)threeArgs[0]);
    		case(MatrixOperation.MatrixScalar.ENTRYWISEMAPTORANGE):
    			return scaleToRangeResult(m, threeArgs[0], threeArgs[1]);
    		case(MatrixOperation.MatrixScalar.THRESHOLD):
    			return thresholdResult(m, threeArgs[0], (int)threeArgs[1]);
    		default:
    			return new Matrix(m);
    		}
    	}
    
    	public static Matrix ApplyModScalar( int opNum, Matrix m, float[] threeArgs) {
    		switch(opNum) {
    		case(MatrixOperation.MatrixScalar.SCALARADD):
    			return ModscalarAddResult(m, threeArgs[0], threeArgs[2]);
    		case(MatrixOperation.MatrixScalar.SCALARSUBTRACT):
    			return ModscalarSubtractResult(m, threeArgs[0], threeArgs[2]);
    		case(MatrixOperation.MatrixScalar.SCALARMULTIPLY):
    			return ModscalarMultiplyResult(m, threeArgs[0], threeArgs[2]);
    		case(MatrixOperation.MatrixScalar.SCALARDIVIDE):
    			return ModscalarDivideResult(m, threeArgs[0], threeArgs[2]);
    		case(MatrixOperation.MatrixScalar.HADAMARDPOWER):		
    			return ModhadamardPowerResult(m, (int)threeArgs[0], threeArgs[2]);
    		case(MatrixOperation.MatrixScalar.FASTPROPAGATEDMULTIPRODUCT):
    			ModfastPropagatedMultiproduct(m, (int)threeArgs[0], threeArgs[2]);
    		return m;
    		case(MatrixOperation.MatrixScalar.FASTMULTIPRODUCT):
    			return ModfastMultiproduct(m, (int)threeArgs[0], threeArgs[2]);
    		case(MatrixOperation.MatrixScalar.ENTRYWISEMAPTORANGE):
    			return ModscaleToRangeResult(m, threeArgs[0], threeArgs[1], threeArgs[2]);
    		case(MatrixOperation.MatrixScalar.THRESHOLD):
    			return ModthresholdResult(m, threeArgs[0], (int)threeArgs[1], threeArgs[2]);
    		default:
    			return new Matrix(m);
    		}
    	}
    
    
    	public  static Matrix ApplyUnary( int opNum, Matrix m, float[] threeArgs, int[] zeroOne) {
    		switch(opNum) {
    		case(MatrixOperation.MatrixUnary.ENTRYWISEINVERSION):
    			return entrywiseInversionResult(m);
    		case(MatrixOperation.MatrixUnary.EXPONENTIALTRACE):
    			float result = exponentialTrace(m);
    		return scalarMultiplyResult(m,result);
    		case(MatrixOperation.MatrixUnary.SQUAREROOTINVERSESQUAREROOT):
    			return squareRootInverseSquareRootResult(m)[0];
    		case(MatrixOperation.MatrixUnary.SOFTSQUAREROOT):
    			return entrywiseSquareRootResult(m);
    		case(MatrixOperation.MatrixUnary.ENTRYWISENATURALLOG):
    			return entrywiseLogarithmResult(m);
    		case(MatrixOperation.MatrixUnary.RANDOMFILL):
    			fill_random(m);
    		return m;
    		case(MatrixOperation.MatrixUnary.L0NORMALIZE):
    			L0normalize(m);
    		return m;
    		case(MatrixOperation.MatrixUnary.L1NORMALIZE):
    			L1normalize(m);
    		return m;
    		case(MatrixOperation.MatrixUnary.L2NORMALIZE):
    			L2normalize(m);
    		return m;
    		case(MatrixOperation.MatrixUnary.LINFNORMALIZE):
    			Linfnormalize(m);
    		return m;
    		case(MatrixOperation.MatrixUnary.FLOYDWARSHALL):
    			return FloydWarshall(m, 0.00000001f, threeArgs[0], threeArgs[1], zeroOne[0], zeroOne[1]);
    		case(MatrixOperation.MatrixUnary.POWERITERATIONDEFLATE):
    			m.eigenvalue = new float[m.rows];
    		m.eigenvector = new float[m.rows][m.columns];
    		PowerIterationDeflate(m, m.shortest, (double)0.00000001f, 1); // 1 populates krylov subspace
    		return new Matrix(m.eigenvector);
    		case(MatrixOperation.MatrixUnary.LUDOLITTLEDECOMPOSITION):
    			return LU_Dolittle_DecompositionResult(m);
    		case(MatrixOperation.MatrixUnary.DETERMINANT):
    			result = Determinant(m);
    		return scalarMultiplyResult(m,result);
    		case(MatrixOperation.MatrixUnary.INVERSE):
    			return Inverse(m);
    		case(MatrixOperation.MatrixUnary.NOT):
    			return NOTResult(m);
    		case(MatrixOperation.MatrixUnary.COMPLEMENT):
    			return complement(m);
    		default:
    			return new Matrix(m);
    		}
    	}
    
    	public static Matrix ApplyModUnary( int opNum, Matrix m, float[] threeArgs, int[] zeroOne) {
    		switch(opNum) {
    		case(MatrixOperation.MatrixUnary.ENTRYWISEINVERSION):
    			return ModentrywiseInversionResult(m, threeArgs[2]);
    		case(MatrixOperation.MatrixUnary.EXPONENTIALTRACE):
    			float result = ModexponentialTrace(m, threeArgs[2]);
    		return ModscalarMultiplyResult(m, result, threeArgs[2]);
    		case(MatrixOperation.MatrixUnary.SQUAREROOTINVERSESQUAREROOT):
    			return ModsquareRootInverseSquareRootResult(m, threeArgs[2])[0];
    		case(MatrixOperation.MatrixUnary.SOFTSQUAREROOT):
    			return ModentrywiseSquareRootResult(m, threeArgs[2]);
    		case(MatrixOperation.MatrixUnary.ENTRYWISENATURALLOG):
    			return ModentrywiseLogarithmResult(m, threeArgs[2]);
    		case(MatrixOperation.MatrixUnary.RANDOMFILL):
    			Modfill_random(m, threeArgs[2]);
    		return m;
    		case(MatrixOperation.MatrixUnary.L0NORMALIZE):
    			ModL0normalize(m, threeArgs[2]);
    		return m;
    		case(MatrixOperation.MatrixUnary.L1NORMALIZE):
    			ModL1normalize(m, threeArgs[2]);
    		return m;
    		case(MatrixOperation.MatrixUnary.L2NORMALIZE):
    			ModL2normalize(m, threeArgs[2]);
    		return m;
    		case(MatrixOperation.MatrixUnary.LINFNORMALIZE):
    			ModLinfnormalize(m, threeArgs[2]);
    		return m;
    		case(MatrixOperation.MatrixUnary.FLOYDWARSHALL):
    			return ModFloydWarshall(m, 0.00000001f, threeArgs[0], threeArgs[1], zeroOne[0], zeroOne[1], threeArgs[2]);
    		case(MatrixOperation.MatrixUnary.POWERITERATIONDEFLATE):
    			ModPowerIterationDeflate(m, m.shortest, (double)0.00000001f, 1, threeArgs[2]); // 1 populates krylov subspace
    		return new Matrix(m.eigenvector);
    		case(MatrixOperation.MatrixUnary.LUDOLITTLEDECOMPOSITION):
    			return ModLU_Dolittle_DecompositionResult(m, threeArgs[2]);
    		case(MatrixOperation.MatrixUnary.DETERMINANT):
    			result = ModDeterminant(m, threeArgs[2]);
    		return ModscalarMultiplyResult(m,result, threeArgs[2]);
    		case(MatrixOperation.MatrixUnary.INVERSE):
    			return ModInverse(m, threeArgs[2]);
    		case(MatrixOperation.MatrixUnary.NOT):
    			return ModNOTResult(m, threeArgs[2]);
    		case(MatrixOperation.MatrixUnary.COMPLEMENT):
    			return complement(m);
    		default:
    			return new Matrix(m);
    		}
    	}
    
    
    	public  static Matrix ApplyBinary( int opNum, Matrix m, Matrix m2, float[] threeArgs) {
    		switch(opNum) {
    		case(MatrixOperation.MatrixBinary.FROBENIUSINNERPRODUCT):
    			float result = FrobeniusInnerProduct(m, m2);
    		return scalarMultiplyResult(m,result);
    		case(MatrixOperation.MatrixBinary.PAIRWISESUM):
    			return pairwiseSumResult(m, m2);
    		case(MatrixOperation.MatrixBinary.PAIRWISESUBTRACT):
    			return pairwiseSubtractResult(m, m2);
    		case(MatrixOperation.MatrixBinary.HADARMARDPRODUCT):
    			return hadamardProductResult(m, m2);
    		case(MatrixOperation.MatrixBinary.PRODUCTPROPAGATED):
    			productPropagated(m, m2);
    		return m;
    		case(MatrixOperation.MatrixBinary.PRODUCT):
    			return productResult(m, m2);
    		case(MatrixOperation.MatrixBinary.HADAMARDDIVISION):
    			return hadamardDivisionResult(m, m2);
    		case(MatrixOperation.MatrixBinary.AND):
    			return ANDResult(m, m2);
    		case(MatrixOperation.MatrixBinary.OR):
    			return ORResult(m, m2);
    		case(MatrixOperation.MatrixBinary.XOR):
    			return XORResult(m, m2);
    		case(MatrixOperation.MatrixBinary.KOR):
    			return KORResult(m, m2);
    		default:
    			return new Matrix(m);
    		}
    	}
    	//Addition
    
    
    	public  static Matrix ApplyModBinary( int opNum, Matrix m, Matrix m2, float[] threeArgs) {
    		switch(opNum) {
    		case(MatrixOperation.MatrixBinary.FROBENIUSINNERPRODUCT):
    			float result = ModFrobeniusInnerProduct(m, m2, threeArgs[2]);
    		return ModscalarMultiplyResult(m,result, threeArgs[2]);
    		case(MatrixOperation.MatrixBinary.PAIRWISESUM):
    			return ModpairwiseSumResult(m, m2, threeArgs[2]);
    		case(MatrixOperation.MatrixBinary.PAIRWISESUBTRACT):
    			return ModpairwiseSubtractResult(m, m2, threeArgs[2]);
    		case(MatrixOperation.MatrixBinary.HADARMARDPRODUCT):
    			return ModhadamardProductResult(m, m2, threeArgs[2]);
    		case(MatrixOperation.MatrixBinary.PRODUCTPROPAGATED):
    			ModproductPropagated(m, m2, threeArgs[2]);
    		return m;
    		case(MatrixOperation.MatrixBinary.PRODUCT):
    			return ModproductResult(m, m2, threeArgs[2]);
    		case(MatrixOperation.MatrixBinary.HADAMARDDIVISION):
    			return ModhadamardDivisionResult(m, m2, threeArgs[2]);
    		case(MatrixOperation.MatrixBinary.AND):
    			return ModANDResult(m, m2, threeArgs[2]);
    		case(MatrixOperation.MatrixBinary.OR):
    			return ModORResult(m, m2, threeArgs[2]);
    		case(MatrixOperation.MatrixBinary.XOR):
    			return ModXORResult(m, m2, threeArgs[2]);
    		case(MatrixOperation.MatrixBinary.KOR):
    			return ModKORResult(m, m2, threeArgs[2]);
    		default:
    			return new Matrix(m);
    		}
    	}
    
    	public static void scalarAdd(Matrix accumulator, float addend) {
    		if(addend == Matrix.ZEROF) {
    			accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestColumn = accumulator.columns;
    		int i = accumulator.rows;
    		int j = shortestColumn;
    		while(--i >= 0) {
    			while(--j >= 0)
    				accumulator.entry[i][j] += addend;
    		}
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static void scalarAdd(Matrix accumulator, float addend, int row) {
    		if(addend == Matrix.ZEROF) {
    			accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestColumn = accumulator.columns;
    		int i = row;
    		int j = shortestColumn;
    		while(--j >= 0)
    			accumulator.entry[i][j] += addend;
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix scalarAddResult(Matrix adder, float addend) {
    		Matrix result;
    		if(addend == Matrix.ZEROF) {
    			result = new Matrix(adder);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int shortestRow = adder.rows;
    		int shortestColumn = adder.columns;
    		result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				result.entry[i][j] = adder.entry[i][j] + addend;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static void pairwiseSum(Matrix accumulator, Matrix summand) {
    		int shortestRow = accumulator.rows < summand.rows ? accumulator.rows : summand.rows;
    		int shortestColumn = accumulator.columns < summand.columns ? accumulator.columns : summand.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				accumulator.entry[i][j] += summand.entry[i][j];
    			}  
    		}
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix pairwiseSumResult(Matrix adder, Matrix summand) {
    		int shortestRow = adder.rows < summand.rows ? adder.rows : summand.rows;
    		int shortestColumn = adder.columns < summand.columns ? adder.columns : summand.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				result.entry[i][j] = adder.entry[i][j] + summand.entry[i][j];
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	// Subtraction
    
    	public static void scalarSubtract(Matrix accumulator, float subtractand) {
    		if(subtractand == Matrix.ZEROF) {
    			accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestRow = accumulator.rows;
    		int shortestColumn = accumulator.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				accumulator.entry[i][j] -= subtractand;
    			}  
    		}
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static void scalarSubtract(Matrix accumulator, float subtractand, int row) {
    		if(subtractand == Matrix.ZEROF) {
    			accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestColumn = accumulator.columns;
    		int i = row;
    		int j = shortestColumn;
    		while(--j >= 0)
    			accumulator.entry[i][j] -= subtractand;
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix scalarSubtractResult(Matrix subtractor, float subtractand) {
    		Matrix result;
    		if(subtractand == Matrix.ZEROF) {
    			result = new Matrix(subtractor);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int shortestRow = subtractor.rows;
    		int shortestColumn = subtractor.columns;
    		result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				result.entry[i][j] = subtractor.entry[i][j] - subtractand;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static void pairwiseSubtract(Matrix accumulator, Matrix subtractand) {
    		int shortestRow = accumulator.rows < subtractand.rows ? accumulator.rows : subtractand.rows;
    		int shortestColumn = accumulator.columns < subtractand.columns ? accumulator.columns : subtractand.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				accumulator.entry[i][j] -= subtractand.entry[i][j];
    			}  
    		}
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix pairwiseSubtractResult(Matrix subtractor, Matrix subtractand) {
    		int shortestRow = subtractor.rows < subtractand.rows ? subtractor.rows : subtractand.rows;
    		int shortestColumn = subtractor.columns < subtractand.columns ? subtractor.columns : subtractand.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				result.entry[i][j] = subtractor.entry[i][j] - subtractand.entry[i][j];
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	// Multiplication
    
    	public static void scalarMultiply(Matrix accumulator, float multiplier) {
    		int shortestRow = accumulator.rows;
    		int shortestColumn = accumulator.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				accumulator.entry[i][j] *= multiplier;
    			}  
    		}
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static void scalarMultiply(Matrix accumulator, float multiplier, int row) {
    		int shortestColumn = accumulator.columns;
    		int i = row;
    		int j = shortestColumn;
    		while(--j >= 0)
    			accumulator.entry[i][j] *= multiplier;
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix scalarMultiplyResult(Matrix multiplicand, float multiplier) {
    		int shortestRow = multiplicand.rows;
    		int shortestColumn = multiplicand.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				result.entry[i][j] = multiplicand.entry[i][j] * multiplier;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static float FrobeniusInnerProduct( Matrix multiplicand, Matrix multiplier ) {
    		int shortestRow = multiplicand.rows < multiplier.rows ? multiplicand.rows : multiplier.rows;
    		int shortestColumn = multiplicand.columns < multiplier.columns ? multiplicand.columns : multiplier.columns;
    		int i = shortestRow;
    		float accumulator = 0.0f;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				accumulator += multiplicand.entry[i][j]*multiplier.entry[i][j];
    			}  
    		}
    		return accumulator;
    	}
    
    	public static void hadamardProduct(Matrix accumulator, Matrix multiplicand) {
    		int shortestRow = accumulator.rows < multiplicand.rows ? accumulator.rows : multiplicand.rows;
    		int shortestColumn = accumulator.columns < multiplicand.columns ? accumulator.columns : multiplicand.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				accumulator.entry[i][j] *= multiplicand.entry[i][j];
    			}  
    		}
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix hadamardProductResult(Matrix multiplier, Matrix multiplicand) {
    		int shortestRow = multiplier.rows < multiplicand.rows ? multiplier.rows : multiplicand.rows;
    		int shortestColumn = multiplier.columns < multiplicand.columns ? multiplier.columns : multiplicand.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				result.entry[i][j] = multiplier.entry[i][j] * multiplicand.entry[i][j];
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static void productPropagated(Matrix accumulator, Matrix multiplier) {
    		int shortestRow = accumulator.rows < multiplier.rows ? accumulator.rows : multiplier.rows;
    		int shortestColumn = accumulator.columns < multiplier.columns ? accumulator.columns : multiplier.columns;
    		int shortest = shortestRow < shortestColumn ? shortestRow : shortestColumn;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				int k = shortest;
    				float entrySum = 0.0f;
    				while(--k >= 0) {
    					entrySum += accumulator.entry[i][k]*multiplier.entry[k][j];
    				}
    				accumulator.entry[i][j] = entrySum;
    			}  
    		}
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix productResult(Matrix multiplicand, Matrix multiplier) { 
    		int shortest = multiplicand.columns < multiplier.rows ? multiplicand.columns : multiplier.rows;
    		int i = multiplicand.rows;
    		int j = multiplier.columns;
    		Matrix result = new Matrix(Matrix.NONE, i, j);
    		while(--i >= 0) {
    			j = multiplier.columns;
    			while(--j >= 0) {
    				int k = shortest;
    				float entrySum = 0.0f;
    				while(--k >= 0) {
    					entrySum += multiplicand.entry[i][k]*multiplier.entry[k][j];
    				}
    				result.entry[i][j] = entrySum;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	// Division
    
    	public static void entrywiseInversion( Matrix divisor ) {
    		int shortestRow = divisor.rows;
    		int shortestColumn = divisor.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float divisorij = divisor.entry[i][j];
    				if(divisorij != Matrix.ZEROF)
    					divisor.entry[i][j] = Matrix.IDENTITYF / divisorij;
    				else
    					divisor.entry[i][j] = Matrix.IDENTITYF;
    			}  
    		}
    	}
    
    	public static Matrix entrywiseInversionResult ( Matrix divisor ) {
    		int shortestRow = divisor.rows;
    		int shortestColumn = divisor.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float divisorij = divisor.entry[i][j];
    				if(divisorij != Matrix.ZEROF)
    					result.entry[i][j] = Matrix.IDENTITYF / divisorij;
    				else
    					result.entry[i][j] = Matrix.IDENTITYF;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static void scalarDivide(Matrix accumulator, float divisor) {
    		int shortestRow = accumulator.rows;
    		int shortestColumn = accumulator.columns;
    		if(divisor == Matrix.ZEROF) {
    			Arrays.fill(accumulator.entry, Matrix.IDENTITYF);
    			accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) 
    				accumulator.entry[i][j] /= divisor;
    		}
    	}
    
    	public static Matrix scalarDivideResult(Matrix dividend, float divisor) {
    		int shortestRow = dividend.rows;
    		int shortestColumn = dividend.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				if(divisor != Matrix.ZEROF)
    					result.entry[i][j] = dividend.entry[i][j] / divisor;
    				else
    					result.entry[i][j] = Matrix.IDENTITYF;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static void hadamardDivision(Matrix accumulator, Matrix divisor) {
    		int shortestRow = accumulator.rows < divisor.rows ? accumulator.rows : divisor.rows;
    		int shortestColumn = accumulator.columns < divisor.columns ? accumulator.columns : divisor.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				if(divisor.entry[i][j] != Matrix.ZEROF)
    					accumulator.entry[i][j] /= divisor.entry[i][j];
    				else
    					accumulator.entry[i][j] = Matrix.ZEROF;
    			}  
    		}
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix hadamardDivisionResult(Matrix dividend, Matrix divisor) {
    		int shortestRow = dividend.rows < divisor.rows ? dividend.rows : divisor.rows;
    		int shortestColumn = dividend.columns < divisor.columns ? dividend.columns : divisor.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				if(divisor.entry[i][j] != Matrix.ZEROF)
    					result.entry[i][j] = dividend.entry[i][j] / divisor.entry[i][j];
    				else
    					result.entry[i][j] = Matrix.IDENTITYF;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	// Powers
    
    	public static void hadamardPower(Matrix accumulator, int power) {
    		int shortestRow = accumulator.rows;
    		int shortestColumn = accumulator.columns;
    		if(power == 0) {
    			accumulator.make_ones();
    			return;  
    		}
    		if(power == 1)
    			return;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				int p = power;
    				while(--p > 0)
    					accumulator.entry[i][j] *= accumulator.entry[i][j];
    			}  
    		}
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix hadamardPowerResult(Matrix multiplier, int power) {
    
    		int shortestRow = multiplier.rows;
    		int shortestColumn = multiplier.columns;
    		if(power == 1)
    			return new Matrix(multiplier);
    		Matrix result = new Matrix(Matrix.ONES, shortestRow, shortestColumn);
    		if(power == 0)
    			return result;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				int p = power;
    				while(--p >= 0)
    					result.entry[i][j] *= multiplier.entry[i][j];
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static int[] radix(int num, int base) {
    		int b = 1; int b1 = base;
    		int rem = 0; int rem1 = num % b1;
    		int bit = 0;
    		int[] bits = new int[10];
    		while(b <= num) {
    			bits[bit] = (rem1 - rem)/b;
    			b=b1;b1*=base;
    			rem=rem1; rem1 = num % b1;
    			bit++;
    			if(bit >= bits.length) {
    				int[] temp = new int[bit<<1];
    				System.arraycopy(temp, 0, bits, 0, bit);
    				bits = temp;
    			}
    		}
    		return bits;
    	}
    
    	public static float exponentialTrace( Matrix m ) {
    		float result = 1.0f;
    		float trace = m.trace();
    		int itrace = (int)trace;
    		float diff = trace - itrace;
    		int[] bits = radix(itrace, 2);
    		int iteration = 0;
    		float lastPow = 2.71828183f;
    		int lastPowIndex = 0;
    		while(++iteration < bits.length) {
    			int bit = bits[iteration];
    			if(bit == 1) {
    				int squaresRequired = iteration - lastPowIndex;
    				while(--squaresRequired >= 0)
    					lastPow *= lastPow;
    				result *= lastPow;
    			}
    		}
    		float extra = -(float)Math.log(diff);
    		if(extra != 0.0f)
    			result *= extra;
    		return result;
    	}
    
    	public static void polysquarePropagated(Matrix base, int times) {
    		while(--times >= 0)
    			productPropagated(base, base);
    	}
    
    	public static void fastPropagatedMultiproduct(Matrix base, int exponent) { 
    		int[] operations = radix(exponent, 2);
    		int lastProductIndex = 0, jmax = operations.length;
    		Matrix partialPowers;
    		if(operations[0] == 0)
    			partialPowers = new Matrix(Matrix.IDENTITY, base.rows, base.columns);
    		else
    			partialPowers = new Matrix(base);
    		for(int j = 1; j < jmax;j++) {
    			int bit = operations[j];
    			if(bit == 1) {
    				polysquarePropagated(partialPowers, j-lastProductIndex);
    				lastProductIndex = j;
    				productPropagated(base, partialPowers);
    			}
    		}
    	}
    
    	public static Matrix polysquare(Matrix base, int times) {
    		while(--times >= 0)
    			base = productResult(base, base);
    		return base;
    	}
    
    	public static Matrix fastMultiproduct(Matrix base, int exponent) { 
    		int[] operations = radix(exponent, 2);
    		int lastProductIndex = 0, jmax = operations.length;
    		Matrix partialPowers;
    		if(operations[0] == 0)
    			partialPowers = new Matrix(Matrix.IDENTITY, base.rows, base.columns);
    		else
    			partialPowers = new Matrix(base);
    		for(int j = 1; j < jmax;j++) {
    			int bit = operations[j];
    			if(bit == 1) {
    				polysquare(partialPowers, j-lastProductIndex);
    				lastProductIndex = j;
    				base = productResult(base, partialPowers);
    			}
    		}
    		return base;
    	}
    
    	public static Matrix squareRootReturnInverseSquareRoot(Matrix y) {
    		Matrix z = new Matrix(Matrix.IDENTITY, y.rows, y.columns);
    		int j = (int)Math.sqrt(y.rows) + 1;
    		while(--j >= 0) {
    			scalarMultiply(pairwiseSumResult(y,Inverse(z)), 0.5f);
    			scalarMultiply(pairwiseSumResult(z,Inverse(y)), 0.5f);
    		}
    		y.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		z.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return z;
    	}
    
    	public static Matrix[] squareRootInverseSquareRootResult(Matrix x) {
    		Matrix y = new Matrix(x);
    		Matrix z = new Matrix(Matrix.IDENTITY, y.rows, y.columns);
    		int j = (int)Math.sqrt(y.rows) + 1;
    		while(--j >= 0) {
    			scalarMultiply(pairwiseSumResult(y,Inverse(z)), 0.5f);
    			scalarMultiply(pairwiseSumResult(z,Inverse(y)), 0.5f);
    		}
    		y.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		z.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return new Matrix[] { y, z };
    	}
    
    	public static void entrywiseSquareRoot(Matrix x) {
    		int shortestRow = x.rows;
    		int shortestColumn = x.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float xij = x.entry[i][j];
    				float sign;
    				if(xij != 0.0f)
    					sign = xij/Math.abs(xij);
    				else 
    					sign = 1.0f;
    				x.entry[i][j] = (float)( sign*Math.sqrt(Math.abs(xij)) );
    			}  
    		}
    		x.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix entrywiseSquareRootResult(Matrix x) {
    		int shortestRow = x.rows;
    		int shortestColumn = x.columns;
    		int i = shortestRow;
    		Matrix result = new Matrix(Matrix.NONE, x.rows, x.columns);
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float xij = x.entry[i][j];
    				float sign;
    				if(xij != 0.0f)
    					sign = xij/Math.abs(xij);
    				else 
    					sign = 1.0f;
    				result.entry[i][j] = (float)( sign*Math.sqrt(Math.abs(xij)) );
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}	
    
    	// Logarithm
    
    	public static void entrywiseLogarithm( Matrix m ) {
    		int shortestRow = m.rows;
    		int shortestColumn = m.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float eij = m.entry[i][j];
    				float sign;
    				if(eij != 0.0f)
    					sign = eij/Math.abs(eij);
    				else 
    					sign = 1.0f;
    				m.entry[i][j] = (float)(sign*Math.log(eij));
    			}  
    		}
    		m.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix entrywiseLogarithmResult( Matrix m ) {
    		int shortestRow = m.rows;
    		int shortestColumn = m.columns;
    		int i = shortestRow;
    		Matrix result = new Matrix(m);
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float xij = m.entry[i][j];
    				float sign;
    				if(xij != 0.0f)
    					sign = xij/Math.abs(xij);
    				else 
    					sign = 1.0f;
    				result.entry[i][j] = (float)(sign*Math.log(xij));
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	// Mapping
    
    	public static void scaleToRange(Matrix m, float low, float high) {
    		float[] minmax = m.minmax();
    		float newrange = high-low;
    		float oldrange = minmax[1]-minmax[0];
    		float range = oldrange == 0.0f ? 1.0f : newrange/oldrange;
    		scalarSubtract(m, minmax[0]);
    		scalarMultiply(m, range );
    		scalarAdd(m, low );
    	}
    
    	public static void scaleToRangeRows(Matrix m, float low, float high) {
    		int i = m.rows;
    		while(--i >= 0) {
    			float[] minmax = m.minmaxRow(i);
    			float newrange = high-low;
    			float oldrange = minmax[1]-minmax[0];
    			float range = oldrange == 0.0f ? 1.0f : newrange/oldrange;
    			scalarSubtract(m, minmax[0], i);
    			scalarMultiply(m, range, i );
    			scalarAdd(m, low, i );
    		}
    	}
    
    	public static void scaleToRangeRow(Matrix m, int row, float low, float high) {
    		int i = row;
    		float[] minmax = m.minmaxRow(i);
    		float newrange = high-low;
    		float oldrange = minmax[1]-minmax[0];
    		float range = oldrange == 0.0f ? 1.0f : newrange/oldrange;
    		scalarSubtract(m, minmax[0], i);
    		scalarMultiply(m, range, i );
    		scalarAdd(m, low, i );
    
    	}
    
    	public static Matrix scaleToRangeResult(Matrix m, float low, float high) {
    		float[] minmax = m.minmax();
    		float newrange = high-low;
    		float oldrange = minmax[1]-minmax[0];
    		float range = oldrange == 0.0f ? 1.0f : newrange/oldrange;
    		Matrix result = new Matrix(Matrix.NONE, m.rows, m.columns);
    		result = scalarSubtractResult(m, minmax[0]);
    		scalarMultiply(result, range );
    		scalarAdd(result, low );
    		return result;
    	}
    
    
    	// Random
    
    	public static void fill_random(Matrix m) {
    		int i = m.rows;
    		while(--i >= 0 ) {
    			int j = m.columns;
    			while(--j >= 0 )
    				m.entry[i][j] = (float)Math.random();
    		}
    	}
    
    	public static void fill_random( float[] v) {
    		int j = v.length;
    		while(--j >= 0 ) v[j] = (float)Math.random();
    	}
    
    
    	// Norms & normalization vectors and matrices : 0, 1, 2, inf
    
    	public static void Linfnormalize( Matrix m ) {
    		int i = m.rows;
    		int j = m.columns;
    		if( i == 0 || j == 0)
    			return;
    		float max = Math.abs(m.entry[0][0]);
    		while( --i >= 0 ) {
    			while( --j >= 0 ) {
    				float eij = Math.abs(m.entry[i][j]);
    				if(eij > max)
    					max = eij;
    			}
    			j = m.columns;
    		}
    		i = m.rows;
    		if(max != 0.0f) {
    			while( --i >= 0 ) {
    				j = m.columns;
    				while( --j >= 0 ) {
    					m.entry[i][j] /= max;
    				}
    			}
    		}
    	}
    
    	public static void Linfnormalize( float[] v ) {
    		int j = v.length;
    		if(j == 0)
    			return;
    		float max = Math.abs(v[0]);
    		while(--j > 0) {
    			float vj = Math.abs(v[j]);
    			if(vj > max)
    				max = vj;
    		}
    		j = v.length;
    		if(max == 0.0f)
    			return;
    		while(--j >= 0) v[j] /= max;
    	}
    
    	public static float Linfnorm( Matrix m ) {
    		int i = m.rows;
    		int j = m.columns;
    		if( i == 0 || j == 0)
    			return 0.0f;
    		float max = Math.abs(m.entry[0][0]);
    		while( --i >= 0 ) {
    			while( --j >= 0 ) {
    				float eij = Math.abs(m.entry[i][j]);
    				if(eij > max)
    					max = eij;
    			}
    			j = m.columns;
    		}
    		if(m.norms == null)
    			m.norms = new float[4];
    		m.norms[3] = max;
    		return max;
    	}
    
    	public static float Linfnorm( float[] v ) {
    		int j = v.length;
    		if(j == 0)
    			return 0.0f;
    		float max = Math.abs(v[0]);
    		while(--j > 0) {
    			float vj = Math.abs(v[j]);
    			if(vj > max)
    				max = vj;
    		}
    		return max;
    	}
    
    	public static void L2normalize( Matrix m ) {
    		int i = m.rows;
    		float sumSquares = 0.0f;
    		while( --i >= 0 ) {
    			int j = m.columns;
    			while( --j >= 0 ) {
    				sumSquares += m.entry[i][j]*m.entry[i][j];
    			}
    		}
    		sumSquares = (float)Math.sqrt(sumSquares);
    		i = m.rows;
    		if(sumSquares == 0.0f)
    			return;
    		while( --i >= 0 ) {
    			int j = m.columns;
    			while( --j >= 0 ) {
    				m.entry[i][j] /= sumSquares;
    			}
    		}
    	}
    
    	public static void L2normalize( float [] v ) {
    		int j = v.length;
    		float sumSquares = 0.0f;
    		while(--j >= 0) sumSquares += v[j]*v[j];
    		j = v.length;
    		sumSquares = (float)Math.sqrt(sumSquares);
    		if(sumSquares == 0.0f)
    			return;
    		while(--j >= 0) v[j] /= sumSquares;
    	}
    
    	public static float L2norm( Matrix m ) {
    		int i = m.rows;
    		float sumSquares = 0.0f;
    		while( --i >= 0 ) {
    			int j = m.columns;
    			while( --j >= 0 ) {
    				sumSquares += m.entry[i][j];
    			}
    		}
    		sumSquares = (float)Math.sqrt(sumSquares);
    		if(m.norms == null)
    			m.norms = new float[4];
    		m.norms[2] = sumSquares;
    		return sumSquares;
    	}
    
    	public static float L2norm( float [] v ) {
    		int j = v.length;
    		float sumSquares = 0.0f;
    		while(--j >= 0) sumSquares += v[j]*v[j];
    		return (float)Math.sqrt(sumSquares);
    	}
    
    	public static void L1normalize( Matrix m ) {
    		int i = m.rows;
    		float sum = 0.0f;
    		while( --i >= 0 ) {
    			int j = m.columns;
    			while( --j >= 0 ) {
    				sum += Math.abs(m.entry[i][j]);
    			}
    		}
    		i = m.rows;
    		if(sum == 0.0f)
    			return;
    		while( --i >= 0 ) {
    			int j = m.columns;
    			while( --j >= 0 ) {
    				m.entry[i][j] /= sum;
    			}
    		}
    	}
    
    	public static void L1normalize( float[] v ) {
    		int j = v.length;
    		float sum = 0.0f;
    		while(--j >= 0) sum += Math.abs(v[j]);
    		j = v.length;
    		if(sum == 0.0f)
    			return;
    		while(--j >= 0) v[j] /= sum;
    	}
    
    	public static float L1norm( Matrix m ) {
    		int i = m.rows;
    		float sum = 0.0f;
    		while( --i >= 0 ) {
    			int j = m.columns;
    			while( --j >= 0 ) {
    				sum += Math.abs(m.entry[i][j]);
    			}
    		}
    		if(m.norms == null)
    			m.norms = new float[4];
    		m.norms[1] = sum;
    		return sum;
    	}
    
    	public static float L1norm( float[] v ) {
    		int j = v.length;
    		float sum = 0.0f;
    		while(--j >= 0) sum += Math.abs(v[j]);
    		return sum;
    	}
    
    	public static void L0normalize( Matrix m ) {
    		int i = m.rows;
    		float sum = 0.0f;
    		while( --i >= 0 ) {
    			int j = m.columns;
    			while( --j >= 0 ) {
    				if(m.entry[i][j] != Matrix.ZEROF)
    					sum += 1.0f;
    			}
    		}
    		i = m.rows;
    		if(sum == 0.0f)
    			return;
    		while( --i >= 0 ) {
    			int j = m.columns;
    			while( --j >= 0 ) {
    				m.entry[i][j] /= sum;
    			}
    		}
    	}
    
    	public static void L0normalize( float[] v ) {
    		int j = v.length;
    		float sum = 0.0f;
    		while(--j >= 0) 
    			if(v[j] != 0.0f)
    				sum += 1.0f;
    		j = v.length;
    		if(sum == 0.0f)
    			return;
    		while(--j >= 0) v[j] /= sum;
    	}
    
    	public static float L0norm( Matrix m ) {
    		int i = m.rows;
    		float sum = 0.0f;
    		while( --i >= 0 ) {
    			int j = m.columns;
    			while( --j >= 0 ) {
    				if(m.entry[i][j] != Matrix.ZEROF)
    					sum += 1.0f;
    			}
    		}
    		if(m.norms == null)
    			m.norms = new float[4];
    		m.norms[0] = sum;
    		return sum;
    	}
    
    	public static float L0norm( float[] v ) {
    		int j = v.length;
    		float sum = 0.0f;
    		while(--j >= 0) 
    			if(v[j] != 0.0f)
    				sum += 1.0f;
    		return sum;
    	}
    
    	// Algorithms
    
    	public static Matrix FloydWarshall( Matrix connectivityMetric, float epsilon, float connected_bound, float disconnected_bound, int strictness, int minmax ) { 
    		epsilon = Math.abs(epsilon);
    		float connected = connected_bound;
    		float disconnected = disconnected_bound;
    		int i = connectivityMetric.rows;
    		int maxspan = connectivityMetric.shortest;
    		Matrix fw = new Matrix(Matrix.NONE, i, connectivityMetric.columns);
    		while(--i >= 0) {
    			int j = connectivityMetric.columns;
    			int max = (minmax == MIN) ? 0 : i;
    			while(--j >= max ) {
    				float eij = connectivityMetric.entry[i][j];
    				if( strictness == 0 && j < maxspan && i < maxspan ) {
    					eij += connectivityMetric.entry[j][i];
    				}
    				if( eij != Matrix.ZEROF && eij >= -epsilon && eij <= epsilon )
    					fw.entry[i][j] = connected;
    				else
    					fw.entry[i][j] = disconnected;
    			}
    		}
    		int k = maxspan;
    		while( --k >= 0 ) {      
    			i = connectivityMetric.rows;
    			while( --i >= 0 ) {
    				float current_distance_part = fw.entry[i][k];
    				int j = connectivityMetric.columns;
    				while( -- j >= 0 ) {
    					if(i==j)
    						fw.entry[i][j] = 0.0f;
    					else {
    						float current_distance = fw.entry[i][j];
    						float current_distance_whole;
    						switch(minmax) {
    						case(MIN):
    							current_distance_whole = current_distance_part + fw.entry[k][j];
    						fw.entry[i][j] = current_distance < current_distance_whole ? current_distance : current_distance_whole;
    						break;
    						case(MAX):
    							current_distance_whole = current_distance_part < fw.entry[k][j] ? current_distance_part : fw.entry[k][j];
    						fw.entry[i][j] = current_distance > current_distance_whole ? current_distance : current_distance_whole;
    						break;
    						}
    					}
    				}  
    			}
    		}
    		i = connectivityMetric.rows;
    		while( --i >= 0 ) {
    			int j = connectivityMetric.columns;
    			while( --j >= 0 ) 
    				fw.entry[i][j] *= fw.entry[i][j];
    		}
    		return fw;
    	}
    
    	public static void PowerIterationDeflate(Matrix m, int eigens_to_compute, double epsilons, int populateKrylovSubspace ) { 
    		int iteration = 0, i = -1;
    		int maxIteration = m.shortest;
    		m.krylovs = new float[populateKrylovSubspace][m.columns];
    		while(++i < eigens_to_compute ) {
    			Matrix next_eigen_approximation, current_eigen_approximation = new Matrix(Matrix.NONE, 1, m.columns );
    			double prev, current = epsilons; float eigenvalue_approximation;
    			fill_random( current_eigen_approximation );
    			L2normalize( current_eigen_approximation );
    			int iIteration = 0;
    			do {
    				prev = current;
    				next_eigen_approximation = new Matrix(current_eigen_approximation);
    				current_eigen_approximation = productResult(m, next_eigen_approximation.transpose()).transpose();
    				if(iteration<populateKrylovSubspace)
    					System.arraycopy(current_eigen_approximation.entry[0],0,m.krylovs[iteration++],0,m.columns);
    				eigenvalue_approximation = FrobeniusInnerProduct(next_eigen_approximation, current_eigen_approximation);
    				L2normalize(current_eigen_approximation);
    				current = FrobeniusInnerProduct(next_eigen_approximation,current_eigen_approximation);
    			} while( (current < (1-epsilons) && Math.abs( current/prev ) > (1 + epsilons)) && iIteration++ < maxIteration );
    			m.eigenvalue[i] = eigenvalue_approximation;
    	                Deflate(m, current_eigen_approximation, eigenvalue_approximation );
    			int shortest = current_eigen_approximation.entry[0].length < m.eigenvector[i].length ? current_eigen_approximation.entry[0].length :  m.eigenvector[i].length;
    			scalarMultiply(current_eigen_approximation, (float)Math.sqrt(Math.abs(eigenvalue_approximation)));
    			System.arraycopy( current_eigen_approximation.entry[0], 0, m.eigenvector[i], 0, shortest );
    		}
    	}
    
    	public static void show_v (float[] v) {
    		int i = v.length;
    		while(--i >= 0)
    			System.out.print(v[i] + " ");
    		System.out.println();
    	}
    
    	public static void Deflate( Matrix base, Matrix eigen_vector, float eigen_value ) {
    		Matrix r1 = scalarMultiplyResult(eigen_vector, eigen_value);
    		Matrix result = productResult(  eigen_vector.transpose(), r1 );
    		pairwiseSubtract( base, result );
    	}
    
    	public static Matrix DeflateResult( Matrix base, Matrix eigen_vector, float eigen_value ) {
    		Matrix result = productResult(  eigen_vector, scalarMultiplyResult(eigen_vector, eigen_value).transpose() );
    		result = pairwiseSubtractResult( base, result );
    		return result;
    	}
    
    	public static void LU_Dolittle_Decomposition( Matrix m ) { 
    		int rows = m.rows; int columns = m.columns;
    		for(int i = 0; i < rows;i++ ) {
    			for(int j = i; j < columns; j++ ) {
    				for(int k = 0; k < i-1; k++ )
    					m.entry[i][j] -= m.entry[i][k]*m.entry[k][j];
    			}
    			for(int j = i+1; j < rows; j++ ) {
    				for(int k = 0; k < i-1; k++ ) 
    					m.entry[j][i] -= m.entry[j][k]*m.entry[k][i];
    				if(m.entry[i][i] != 0.0f)
    					m.entry[j][i] /= m.entry[i][i];
    			}
    		}
    	}
    
    	public static Matrix LU_Dolittle_DecompositionResult( Matrix m ) { 
    		int rows = m.rows; int columns = m.columns;
    		Matrix lowerupper = new Matrix(Matrix.IDENTITY, rows, columns );
    		for(int i = 0; i < rows;i++ ) {
    			for(int j = i; j < columns; j++ ) {
    				lowerupper.entry[i][j] = m.entry[i][j];
    				for(int k = 0; k < i-1; k++ )
    					lowerupper.entry[i][j] -= lowerupper.entry[i][k]*lowerupper.entry[k][j];
    			}
    			for(int j = i+1; j < rows; j++ ) {
    				lowerupper.entry[j][i] = m.entry[j][i];
    				for(int k = 0; k < i-1; k++ ) 
    					lowerupper.entry[j][i] -= lowerupper.entry[j][k]*lowerupper.entry[j][i];
    				if(lowerupper.entry[i][i] != 0.0f)
    					lowerupper.entry[j][i] /= lowerupper.entry[i][i];
    			}
    		}
    		return lowerupper;
    	}
    
    	public static Matrix[] LU_Dolittle_DecompositionResultPair( Matrix m ) { 
    		int rows = m.rows; int columns = m.columns;
    		Matrix lower = new Matrix(Matrix.IDENTITY, rows, columns );
    		Matrix upper = new Matrix(Matrix.NONE, rows, columns );
    		for(int i = 0; i < rows;i++ ) {
    			for(int j = i; j < columns; j++ ) {
    				upper.entry[i][j] = m.entry[i][j];
    				for(int k = 0; k < i-1; k++ )
    					upper.entry[i][j] -= lower.entry[i][k]*upper.entry[k][j];
    			}
    			for(int j = i+1; j < rows; j++ ) {
    				lower.entry[j][i] = m.entry[j][i];
    				for(int k = 0; k < i-1; k++ ) 
    					lower.entry[j][i] -= lower.entry[j][k]*upper.entry[j][i];
    				if(lower.entry[i][i] != 0.0f)
    					lower.entry[j][i] /= upper.entry[i][i];
    			}
    		}
    		return new Matrix[] { lower, upper };
    	}
    
    	public static float diagonalDet( Matrix triangular ) {
    		float det = 1.0f;
    		int i = triangular.shortest;
    		while(--i >= 0 )
    			det *= triangular.entry[i][i];
    		triangular.det = det;
    		return det;
    	}
    
    	public static float Determinant( Matrix m ) { 
    		Matrix[] lowerupper = LU_Dolittle_DecompositionResultPair(m);
    		float detLower = diagonalDet(lowerupper[0]);
    		float detUpper = diagonalDet(lowerupper[1]);
    		m.det = detLower*detUpper;
    		return m.det;
    	}
    
    	public static Matrix Inverse( Matrix a ) {
    		Matrix m = new Matrix(a);
    		Matrix w = new Matrix( Matrix.NONE, m.rows, m.columns );
    		Matrix l = new Matrix( Matrix.NONE, m.rows, m.columns );
    		Matrix u = new Matrix( Matrix.NONE, m.rows, m.columns );
    		for(int k = 0; k < m.shortest; k++ ) {
    			l.entry[k][k] = Matrix.IDENTITY;
    			for(int i = k+1; i < m.shortest; i++ ) {
    				float coeff = Matrix.IDENTITYF; 
    				if(m.entry[k][k] != 0.0f)
    					coeff = m.entry[i][k]/m.entry[k][k];
    				l.entry[i][k] = coeff;
    				for(int j = k+1; j < m.shortest; j++ )
    					m.entry[i][j] -= coeff*m.entry[k][j];
    			}
    		}
    		for(int j = 0; j < m.shortest; j++ ) {
    			for(int i = 0; i < j; i++ ) {
    				u.entry[i][j] = m.entry[i][j];
    			}
    		}
    		float b[] = new float[m.shortest];
    		float d[] = new float[m.shortest];
    		float x[] = new float[m.shortest];
    		for(int k = 0; k < m.columns; k++ ) {
    
    			for(int i = 1; i < m.shortest; i++ ) {
    				b[k] = 1.0f;
    				d[1] = b[1];
    				for(int j = 1; j < i-1; j++ ) {
    					d[i] = b[i];
    					d[i] -= l.entry[i][j]*d[j];
    				}
    			}
    			if(u.entry[m.shortest-1][m.shortest-1] != 0.0f)
    				x[m.shortest-1] = d[m.shortest-1]/u.entry[m.shortest-1][m.shortest-1];
    			int i = m.shortest;
    			while(--i >= 0 ) {
    				x[i] = d[i];
    				int j = m.shortest;
    				while(--j > i ) {
    					x[i] = x[i] - u.entry[i][j]*x[j];
    				}
    				if(u.entry[i][i] != 0.0f) 
    					x[i] /= u.entry[i][i]; 
    			}
    			for(i = 0; i < m.shortest; i++ ) {
    				w.entry[i][k] = x[i];
    			}
    			b[k] = 0.0f;
    		}
    		return w;
    	}
    
    	// Thresholding
    
    	public static void threshold ( Matrix a, float threshold, int directed ) {
    		int shortestRow = a.rows;
    		int shortestColumn = a.columns ;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float aij = a.entry[i][j];
    				if(directed==0)
    					aij = Math.abs(a.entry[i][j]);
    				if(aij < threshold)
    					a.entry[i][j] = 0.0f;
    				else
    					a.entry[i][j] = 1.0f;
    			}  
    		}
    		a.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix thresholdResult ( Matrix a, float threshold, int directed ) {
    		int shortestRow = a.rows;
    		int shortestColumn = a.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float aij = a.entry[i][j];
    				if(directed==0)
    					aij = Math.abs(a.entry[i][j]);
    				if(aij < threshold)
    					result.entry[i][j] = 0.0f;
    				else
    					result.entry[i][j] = 1.0f;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	// Pair/Entry-Wise Fuzzy Binary arithmetic
    	// a AND 0 = 0
    	// a or 0 = a
    	// a XOR 0 = a
    	// a XOR a = 0
    	// a AND b = a*b
    	// a OR b = a+b
    	// a XOR b = (a/b + b/a)
    	// a KOR b = -ab + b/a 
    	// NOT a = 0
    	// a NAND B = a/b
    	// a NOR b = a + 1/b
    
    	public static void AND( Matrix a, Matrix b ) {
    		int shortestRow = a.rows < b.rows ? a.rows : b.rows;
    		int shortestColumn = a.columns < b.columns ? a.columns : b.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				a.entry[i][j] = a.entry[i][j]*b.entry[i][j];
    			}  
    		}
    		a.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix ANDResult ( Matrix a, Matrix b ) {
    		int shortestRow = a.rows < b.rows ? a.rows : b.rows;
    		int shortestColumn = a.columns < b.columns ? a.columns : b.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				result.entry[i][j] = a.entry[i][j]*b.entry[i][j];
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static void OR( Matrix a, Matrix b ) {
    		int shortestRow = a.rows < b.rows ? a.rows : b.rows;
    		int shortestColumn = a.columns < b.columns ? a.columns : b.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				a.entry[i][j] = a.entry[i][j]+b.entry[i][j];
    			}  
    		}
    		a.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix ORResult ( Matrix a, Matrix b ) {
    		int shortestRow = a.rows < b.rows ? a.rows : b.rows;
    		int shortestColumn = a.columns < b.columns ? a.columns : b.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				result.entry[i][j] = a.entry[i][j]+b.entry[i][j];
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static void XOR( Matrix a, Matrix b ) {
    		int shortestRow = a.rows < b.rows ? a.rows : b.rows;
    		int shortestColumn = a.columns < b.columns ? a.columns : b.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float aij = a.entry[i][j];
    				float bij = b.entry[i][j];
    				if(aij == 0) {
    					if(bij == 0 )
    						a.entry[i][j] = 0.0f;
    					else
    						a.entry[i][j] = bij;
    				}
    				else {
    					if(bij != 0 )
    						a.entry[i][j] = aij/bij + bij/aij;
    				}
    			}  
    		}
    		a.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix XORResult ( Matrix a, Matrix b ) {
    		int shortestRow = a.rows < b.rows ? a.rows : b.rows;
    		int shortestColumn = a.columns < b.columns ? a.columns : b.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float aij = a.entry[i][j];
    				float bij = b.entry[i][j];
    				if(aij == 0) {
    					if(bij == 0 )
    						result.entry[i][j] = 0.0f;
    					else
    						result.entry[i][j] = bij;
    				}
    				else {
    					if(bij != 0 )
    						result.entry[i][j] = aij/bij + bij/aij;
    				}
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static void KOR( Matrix a, Matrix b ) {
    		int shortestRow = a.rows < b.rows ? a.rows : b.rows;
    		int shortestColumn = a.columns < b.columns ? a.columns : b.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float aij = a.entry[i][j];
    				float bij = b.entry[i][j];
    				if(aij != 0)
    					a.entry[i][j] = -aij*bij + bij/aij;
    			}
    		}
    		a.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix KORResult ( Matrix a, Matrix b ) {
    		int shortestRow = a.rows < b.rows ? a.rows : b.rows;
    		int shortestColumn = a.columns < b.columns ? a.columns : b.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float aij = a.entry[i][j];
    				float bij = b.entry[i][j];
    				if(aij != 0)
    					result.entry[i][j] = -aij*bij + bij/aij;
    			}
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static void NOT ( Matrix a ) {
    		int shortestRow = a.rows;
    		int shortestColumn = a.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float aij = a.entry[i][j];
    				if(aij != 0)
    					a.entry[i][j] = 1/-aij;
    			}
    		}
    		a.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix NOTResult ( Matrix a ) {
    		int shortestRow = a.rows;
    		int shortestColumn = a.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float aij = a.entry[i][j];
    				if(aij != 0)
    					result.entry[i][j] = 1.0f/-aij;
    			}
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	// General
    
    	public static Matrix complement ( Matrix m ) {
    		float[] mm = m.minmax();
    		float min = mm[0];
    		float max = mm[1];
    		float avg = (min+max)/2.0f;
    		Matrix result = new Matrix(Matrix.NONE, m.rows, m.columns);
    		int shortestRow = m.rows;
    		int shortestColumn = m.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float mij = m.entry[i][j];
    				if(mij < avg)
    					result.entry[i][j] = max;
    				else
    					result.entry[i][j] = min;
    			}
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	// Modular arithmetic 
    
    	//Addition
    
    	public static void ModscalarAdd(Matrix accumulator, float addend, float modulus ) {
    		if(addend == Matrix.ZEROF || modulus == Matrix.ZEROF) {
    			accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestRow = accumulator.rows;
    		int shortestColumn = accumulator.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				accumulator.entry[i][j] += addend;
    				accumulator.entry[i][j] %= modulus;
    			}  
    		}
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix ModscalarAddResult(Matrix adder, float addend, float modulus ) {
    		Matrix result;
    		if(addend == Matrix.ZEROF || modulus == Matrix.ZEROF) {
    			result = new Matrix(adder);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int shortestRow = adder.rows;
    		int shortestColumn = adder.columns;
    		result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				result.entry[i][j] = adder.entry[i][j] + addend;
    				result.entry[i][j] %= modulus;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static void ModpairwiseSum(Matrix accumulator, Matrix summand, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestRow = accumulator.rows < summand.rows ? accumulator.rows : summand.rows;
    		int shortestColumn = accumulator.columns < summand.columns ? accumulator.columns : summand.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				accumulator.entry[i][j] += summand.entry[i][j];
    				accumulator.entry[i][j] %= modulus;
    			}  
    		}
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix ModpairwiseSumResult(Matrix adder, Matrix summand, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			adder.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return adder;
    		}int shortestRow = adder.rows < summand.rows ? adder.rows : summand.rows;
    		int shortestColumn = adder.columns < summand.columns ? adder.columns : summand.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				result.entry[i][j] = adder.entry[i][j] + summand.entry[i][j];
    				result.entry[i][j] %= modulus;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	// Subtraction
    
    	public static void ModscalarSubtract(Matrix accumulator, float subtractand, float modulus ) {
    		if(modulus == Matrix.ZEROF || subtractand == Matrix.ZEROF) {
    			accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestRow = accumulator.rows;
    		int shortestColumn = accumulator.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				accumulator.entry[i][j] -= subtractand;
    				accumulator.entry[i][j] %= modulus;
    			}  
    		}
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix ModscalarSubtractResult(Matrix subtractor, float subtractand, float modulus ) {
    		Matrix result;
    		if(modulus == Matrix.ZEROF || subtractand == Matrix.ZEROF) {
    			result = new Matrix(subtractor);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int shortestRow = subtractor.rows;
    		int shortestColumn = subtractor.columns;
    		result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				result.entry[i][j] = subtractor.entry[i][j] - subtractand;
    				result.entry[i][j] %= modulus;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static void ModpairwiseSubtract(Matrix accumulator, Matrix subtractand, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestRow = accumulator.rows < subtractand.rows ? accumulator.rows : subtractand.rows;
    		int shortestColumn = accumulator.columns < subtractand.columns ? accumulator.columns : subtractand.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				accumulator.entry[i][j] -= subtractand.entry[i][j];
    				accumulator.entry[i][j] %= modulus;
    			}  
    		}
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix ModpairwiseSubtractResult(Matrix subtractor, Matrix subtractand, float modulus ) {
    		Matrix result;
    		if(modulus == Matrix.ZEROF) {
    			result = new Matrix(subtractor);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int shortestRow = subtractor.rows < subtractand.rows ? subtractor.rows : subtractand.rows;
    		int shortestColumn = subtractor.columns < subtractand.columns ? subtractor.columns : subtractand.columns;
    		result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				result.entry[i][j] = subtractor.entry[i][j] - subtractand.entry[i][j];
    				result.entry[i][j] %= modulus;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	// Multiplication
    
    	public static void ModscalarMultiply(Matrix accumulator, float multiplier, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestRow = accumulator.rows;
    		int shortestColumn = accumulator.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				accumulator.entry[i][j] *= multiplier;
    				accumulator.entry[i][j] %= modulus;
    			}  
    		}
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix ModscalarMultiplyResult(Matrix multiplicand, float multiplier, float modulus ) {
    		Matrix result;
    		if(modulus == Matrix.ZEROF) {
    			result = new Matrix(multiplicand);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int shortestRow = multiplicand.rows;
    		int shortestColumn = multiplicand.columns;
    		result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				result.entry[i][j] = multiplicand.entry[i][j] * multiplier;
    				result.entry[i][j] %= modulus;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static float ModFrobeniusInnerProduct( Matrix multiplicand, Matrix multiplier, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			return modulus;
    		}
    		int shortestRow = multiplicand.rows < multiplier.rows ? multiplicand.rows : multiplier.rows;
    		int shortestColumn = multiplicand.columns < multiplier.columns ? multiplicand.columns : multiplier.columns;
    		int i = shortestRow;
    		float accumulator = 0.0f;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				accumulator += multiplicand.entry[i][j]*multiplier.entry[i][j];
    			}  
    		}
    		return accumulator % modulus;
    	}
    
    	public static void ModhadamardProduct(Matrix accumulator, Matrix multiplicand, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestRow = accumulator.rows < multiplicand.rows ? accumulator.rows : multiplicand.rows;
    		int shortestColumn = accumulator.columns < multiplicand.columns ? accumulator.columns : multiplicand.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				accumulator.entry[i][j] *= multiplicand.entry[i][j];
    				accumulator.entry[i][j] %= modulus;
    			}  
    		}
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix ModhadamardProductResult(Matrix multiplier, Matrix multiplicand, float modulus ) {
    		Matrix result;
    		if(modulus == Matrix.ZEROF) {
    			result = new Matrix(multiplicand);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int shortestRow = multiplier.rows < multiplicand.rows ? multiplier.rows : multiplicand.rows;
    		int shortestColumn = multiplier.columns < multiplicand.columns ? multiplier.columns : multiplicand.columns;
    		result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				result.entry[i][j] = multiplier.entry[i][j] * multiplicand.entry[i][j];
    				result.entry[i][j] %= modulus;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static void ModproductPropagated(Matrix accumulator, Matrix multiplier, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestRow = accumulator.rows < multiplier.rows ? accumulator.rows : multiplier.rows;
    		int shortestColumn = accumulator.columns < multiplier.columns ? accumulator.columns : multiplier.columns;
    		int shortest = shortestRow < shortestColumn ? shortestRow : shortestColumn;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				int k = shortest;
    				float entrySum = 0.0f;
    				while(--k >= 0) {
    					entrySum += accumulator.entry[i][k]*multiplier.entry[k][j];
    				}
    				accumulator.entry[i][j] = entrySum;
    				accumulator.entry[i][j] %= modulus;
    			}  
    		}
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix ModproductResult(Matrix multiplicand, Matrix multiplier, float modulus ) { 
    		Matrix result;
    		if(modulus == Matrix.ZEROF) {
    			result = new Matrix(multiplicand);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int shortest = multiplicand.columns < multiplier.rows ? multiplicand.columns : multiplier.rows;
    		int i = multiplicand.rows;
    		int j = multiplier.columns;
    		result = new Matrix(Matrix.NONE, i, j);
    		while(--i >= 0) {
    			j = multiplier.columns;
    			while(--j >= 0) {
    				int k = shortest;
    				float entrySum = 0.0f;
    				while(--k >= 0) {
    					entrySum += multiplicand.entry[i][k]*multiplier.entry[k][j];
    				}
    				result.entry[i][j] = entrySum;
    				result.entry[i][j] %= modulus;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	// Division
    
    	public static void ModentrywiseInversion( Matrix divisor, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			divisor.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestRow = divisor.rows;
    		int shortestColumn = divisor.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float divisorij = divisor.entry[i][j];
    				if(divisorij != Matrix.ZEROF)
    					divisor.entry[i][j] = Matrix.IDENTITYF / divisorij;
    				else
    					divisor.entry[i][j] = Matrix.IDENTITYF;
    				divisor.entry[i][j] %= modulus;
    			}  
    		}
    	}
    
    	public static Matrix ModentrywiseInversionResult ( Matrix divisor, float modulus ) {
    		int shortestRow = divisor.rows;
    		int shortestColumn = divisor.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float divisorij = divisor.entry[i][j];
    				if(divisorij != Matrix.ZEROF)
    					result.entry[i][j] = Matrix.IDENTITYF / divisorij;
    				else
    					result.entry[i][j] = Matrix.IDENTITYF;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static void ModscalarDivide(Matrix accumulator, float divisor, float modulus) {
    		if(modulus == Matrix.ZEROF) {
    			accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestRow = accumulator.rows;
    		int shortestColumn = accumulator.columns;
    		if(divisor == Matrix.ZEROF) {
    			Arrays.fill(accumulator.entry, Matrix.IDENTITYF);
    			accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) 
    				accumulator.entry[i][j] /= divisor;
    		}
    	}
    
    	public static Matrix ModscalarDivideResult(Matrix dividend, float divisor, float modulus) {
    		Matrix result;
    		if(modulus == Matrix.ZEROF) {
    			result = new Matrix(dividend);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int shortestRow = dividend.rows;
    		int shortestColumn = dividend.columns;
    		result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				if(divisor != Matrix.ZEROF)
    					result.entry[i][j] = dividend.entry[i][j] / divisor;
    				else
    					result.entry[i][j] = Matrix.IDENTITYF;
    				result.entry[i][j] %= modulus;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static void ModhadamardDivision(Matrix accumulator, Matrix divisor, float modulus) {
    		if(modulus == Matrix.ZEROF) {
    			accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestRow = accumulator.rows < divisor.rows ? accumulator.rows : divisor.rows;
    		int shortestColumn = accumulator.columns < divisor.columns ? accumulator.columns : divisor.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				if(divisor.entry[i][j] != Matrix.ZEROF)
    					accumulator.entry[i][j] /= divisor.entry[i][j];
    				else
    					accumulator.entry[i][j] = Matrix.ZEROF;
    				accumulator.entry[i][j] %= modulus;
    			}  
    		}
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix ModhadamardDivisionResult(Matrix dividend, Matrix divisor, float modulus) {
    		Matrix result;
    		if(modulus == Matrix.ZEROF) {
    			result = new Matrix(dividend);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int shortestRow = dividend.rows < divisor.rows ? dividend.rows : divisor.rows;
    		int shortestColumn = dividend.columns < divisor.columns ? dividend.columns : divisor.columns;
    		result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				if(divisor.entry[i][j] != Matrix.ZEROF)
    					result.entry[i][j] = dividend.entry[i][j] / divisor.entry[i][j];
    				else
    					result.entry[i][j] = Matrix.ZEROF;
    				result.entry[i][j] %= modulus;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	// Powers
    
    	public static void ModhadamardPower(Matrix accumulator, int power, float modulus) {
    		if(modulus == Matrix.ZEROF) {
    			accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestRow = accumulator.rows;
    		int shortestColumn = accumulator.columns;
    		if(power == 0) {
    			accumulator.make_ones();
    			return;  
    		}
    		if(power == 1)
    			return;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				int p = power;
    				while(--p > 0) {
    					accumulator.entry[i][j] *= accumulator.entry[i][j];
    					accumulator.entry[i][j] %= modulus;
    				}
    			}  
    		}
    		accumulator.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix ModhadamardPowerResult(Matrix multiplier, int power, float modulus) {
    		Matrix result;
    		if(modulus == Matrix.ZEROF) {
    			result = new Matrix(multiplier);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int shortestRow = multiplier.rows;
    		int shortestColumn = multiplier.columns;
    		if(power == 1)
    			return new Matrix(multiplier);
    		result = new Matrix(Matrix.ONES, shortestRow, shortestColumn);
    		if(power == 0)
    			return result;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				int p = power;
    				while(--p >= 0) {
    					result.entry[i][j] *= multiplier.entry[i][j];
    					result.entry[i][j] %= modulus;
    				}
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static int[] Modradix(int num, int base, float modulus) {
    		if(modulus == Matrix.ZEROF) {
    			return new int[10];
    		}
    		int b = 1; int b1 = base;
    		int rem = 0; int rem1 = num % b1;
    		int bit = 0;
    		int[] bits = new int[10];
    		while(b <= num) {
    			bits[bit] = ((rem1 - rem)/b) % (int)modulus;
    			b=b1;b1*=base;
    			rem=rem1; rem1 = num % b1;
    			bit++;
    			if(bit >= bits.length) {
    				int[] temp = new int[bit<<1];
    				System.arraycopy(bits, 0, temp, 0, bit);
    				bits = temp;
    			}
    		}
    		return bits;
    	}
    
    	public static float ModexponentialTrace( Matrix m, float modulus ) {
    		if(modulus == Matrix.ZEROF)
    			return modulus;
    		float result = 1.0f;
    		float trace = m.trace();
    		int itrace = (int)trace;
    		float diff = trace - itrace;
    		int[] bits = radix(itrace, 2);
    		int iteration = 0;
    		float lastPow = 2.71828183f;
    		int lastPowIndex = 0;
    		while(iteration++ < bits.length) {
    			int bit = bits[iteration];
    			if(bit == 1) {
    				int squaresRequired = iteration - lastPowIndex;
    				while(--squaresRequired >= 0)
    					lastPow = (lastPow * lastPow) % modulus;
    				result = (result * lastPow) % modulus;
    			}
    		}
    		float extra = -(float)Math.log(diff);
    		if(extra != 0.0f)
    			result *= extra;
    		return result % modulus;
    	}
    
    	public static void mod(Matrix base, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			base.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestRow = base.rows;
    		int shortestColumn = base.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				base.entry[i][j] %= modulus;
    			}  
    		}
    		base.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix modResult( Matrix base, float modulus ) {
    		Matrix result;
    		if(modulus == Matrix.ZEROF) {
    			result = new Matrix(base);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int shortestRow = base.rows;
    		int shortestColumn = base.columns;
    		result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0)
    				result.entry[i][j] %= modulus;
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static void ModpolysquarePropagated(Matrix base, int times, float modulus) {
    		if(modulus == Matrix.ZEROF) {
    			base.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		while(--times >= 0) {
    			productPropagated(base, base);
    			mod(base, modulus);
    		}
    	}
    
    	public static void ModfastPropagatedMultiproduct(Matrix base, int exponent, float modulus) { 
    		if(modulus == Matrix.ZEROF) {
    			base.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int[] operations = radix(exponent, 2);
    		int lastProductIndex = 0, jmax = operations.length;
    		Matrix partialPowers;
    		if(operations[0] == 0)
    			partialPowers = new Matrix(Matrix.IDENTITY, base.rows, base.columns);
    		else
    			partialPowers = new Matrix(base);
    		for(int j = 1; j < jmax;j++) {
    			int bit = operations[j];
    			if(bit == 1) {
    				ModpolysquarePropagated(partialPowers, j-lastProductIndex, modulus);
    				lastProductIndex = j;
    				ModproductPropagated(base, partialPowers, modulus);
    				mod(base,modulus);
    			}
    		}
    	}
    
    	public static Matrix Modpolysquare(Matrix base, int times, float modulus) {
    		if(modulus == Matrix.ZEROF) {
    			Matrix result = new Matrix(base);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		while(--times >= 0) {
    			base = productResult(base, base);
    			base = modResult(base, modulus);
    		}
    		base.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return base;
    	}
    
    	public static Matrix ModfastMultiproduct(Matrix base, int exponent, float modulus) { 
    		if(modulus == Matrix.ZEROF) {
    			Matrix result = new Matrix(base);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int[] operations = radix(exponent, 2);
    		int lastProductIndex = 0, jmax = operations.length;
    		Matrix partialPowers;
    		if(operations[0] == 0)
    			partialPowers = new Matrix(Matrix.IDENTITY, base.rows, base.columns);
    		else
    			partialPowers = new Matrix(base);
    		for(int j = 1; j < jmax;j++) {
    			int bit = operations[j];
    			if(bit == 1) {
    				Modpolysquare(partialPowers, j-lastProductIndex, modulus);
    				lastProductIndex = j;
    				base = ModproductResult(base, partialPowers, modulus);
    				base = modResult(base,modulus);
    			}
    		}
    		return base;
    	}
    
    	public static Matrix ModsquareRootReturnInverseSquareRoot(Matrix y, float modulus) {
    		if(modulus == Matrix.ZEROF) {
    			y.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return ModInverse(y, modulus);
    		}
    		Matrix z = new Matrix(Matrix.IDENTITY, y.rows, y.columns);
    		int j = (int)Math.sqrt(y.rows) + 1;
    		while(--j >= 0) {
    			scalarMultiply(pairwiseSumResult(y,Inverse(z)), 0.5f);
    			scalarMultiply(pairwiseSumResult(z,Inverse(y)), 0.5f);
    		}
    		y.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		z.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return z;
    	}
    
    	public static Matrix[] ModsquareRootInverseSquareRootResult(Matrix x, float modulus) {
    		if(modulus == Matrix.ZEROF) {
    			Matrix result = new Matrix(x);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return new Matrix[] {result, ModInverse(result, modulus)};
    		}
    		Matrix y = new Matrix(x);
    		Matrix z = new Matrix(Matrix.IDENTITY, y.rows, y.columns);
    		int j = (int)Math.sqrt(y.rows) + 1;
    		while(--j >= 0) {
    			scalarMultiply(pairwiseSumResult(y,Inverse(z)), 0.5f);
    			scalarMultiply(pairwiseSumResult(z,Inverse(y)), 0.5f);
    		}
    		y.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		z.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return new Matrix[] { y, z };
    	}
    
    	public static void ModentrywiseSquareRoot(Matrix x, float modulus) {
    		if(modulus == Matrix.ZEROF)
    			return;
    		int shortestRow = x.rows;
    		int shortestColumn = x.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float xij = x.entry[i][j] % modulus;
    				float sign = xij/Math.abs(xij);
    				x.entry[i][j] = (float)( sign*Math.sqrt(Math.abs(xij)) );
    			}  
    		}
    		x.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix ModentrywiseSquareRootResult(Matrix x, float modulus) {
    		if(modulus == Matrix.ZEROF)
    			return new Matrix(x);
    		int shortestRow = x.rows;
    		int shortestColumn = x.columns;
    		int i = shortestRow;
    		Matrix result = new Matrix(Matrix.NONE, x.rows, x.columns);
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float xij = x.entry[i][j] % modulus;
    				float sign = xij/Math.abs(xij);
    				result.entry[i][j] = (float)( sign*Math.sqrt(Math.abs(xij)) );
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	// Logarithm
    
    	public static void ModentrywiseLogarithm( Matrix m, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			return;
    		}
    		int shortestRow = m.rows;
    		int shortestColumn = m.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float eij = m.entry[i][j];
    				float sign = eij/Math.abs(eij);
    				m.entry[i][j] = (float)(sign*Math.log(eij));
    			}  
    		}
    		m.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix ModentrywiseLogarithmResult( Matrix m, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			m.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return m;
    		}
    		int shortestRow = m.rows;
    		int shortestColumn = m.columns;
    		int i = shortestRow;
    		Matrix result = new Matrix(m);
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float eij = m.entry[i][j];
    				float sign = eij/Math.abs(eij);
    				result.entry[i][j] = (float)(sign*Math.log(eij));
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    
    	// Mapping 
    
    	public static void ModscaleToRange(Matrix m, float low, float high, float modulus) {
    		if(modulus == Matrix.ZEROF) {
    			m.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		float[] minmax = m.minmax();
    		float newrange = high-low;
    		float oldrange = minmax[1]-minmax[0];
    		float range = oldrange == 0.0f ? 1.0f : newrange/oldrange;
    		mod(m,modulus);
    		scalarSubtract(m, minmax[0]);
    		scalarMultiply(m, range );
    		scalarAdd(m, low );
    
    	}
    
    	public static Matrix ModscaleToRangeResult(Matrix m, float low, float high, float modulus) {
    		if(modulus == Matrix.ZEROF) {
    			Matrix result = new Matrix(m);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		float[] minmax = m.minmax();
    		float newrange = high-low;
    		float oldrange = minmax[1]-minmax[0];
    		float range = oldrange == 0.0f ? 1.0f : newrange/oldrange;
    		Matrix result = new Matrix(Matrix.NONE, m.rows, m.columns);
    		result = ModscalarSubtractResult(m, minmax[0], modulus);
    		ModscalarMultiply(result, range, modulus );
    		ModscalarAdd(result, low, modulus );
    		return result;
    	}
    
    
    	// Random
    
    	public static void Modfill_random(Matrix m, float modulus) {
    		if(modulus == Matrix.ZEROF) {
    			m.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int i = m.rows;
    		while(--i >= 0 ) {
    			int j = m.columns;
    			while(--j >= 0 )
    				m.entry[i][j] = (float)Math.random() % modulus;
    		}
    	}
    
    	public static void Modfill_random( float[] v, float modulus) {
    		if(modulus == Matrix.ZEROF) {
    			return;
    		}
    		int j = v.length;
    		while(--j >= 0 ) v[j] = (float)Math.random() % modulus;
    	}
    
    
    	// Norms & normalization vectors and matrices : 0, 1, 2, inf
    
    	public static void ModLinfnormalize( Matrix m, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			m.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int i = m.rows;
    		int j = m.columns;
    		if( i == 0 || j == 0)
    			return;
    		float max = Math.abs(m.entry[0][0]);
    		while( --i >= 0 ) {
    			while( --j >= 0 ) {
    				float eij = Math.abs(m.entry[i][j]);
    				if(eij > max)
    					max = eij;
    			}
    			j = m.columns;
    		}
    		i = m.rows;
    		while( --i >= 0 ) {
    			j = m.columns;
    			while( --j >= 0 ) {
    				m.entry[i][j] /= max;
    			}
    		}
    	}
    
    	public static void ModLinfnormalize( float[] v, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			return;
    		}
    		int j = v.length;
    		if(j == 0)
    			return;
    		float max = Math.abs(v[0]);
    		while(--j > 0) {
    			float vj = Math.abs(v[j]);
    			if(vj > max)
    				max = vj;
    		}
    		j = v.length;
    		while(--j >= 0) v[j] /= max;
    	}
    
    	public static float ModLinfnorm( Matrix m, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			m.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return modulus;
    		}
    		int i = m.rows;
    		int j = m.columns;
    		if( i == 0 || j == 0)
    			return 0.0f;
    		float max = Math.abs(m.entry[0][0]);
    		while( --i >= 0 ) {
    			while( --j >= 0 ) {
    				float eij = Math.abs(m.entry[i][j]);
    				if(eij > max)
    					max = eij;
    			}
    			j = m.columns;
    		}
    		if(m.norms == null)
    			m.norms = new float[4];
    		m.norms[3] = max;
    		return max;
    	}
    
    	public static float ModLinfnorm( float[] v, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			return modulus;
    		}
    		int j = v.length;
    		if(j == 0)
    			return 0.0f;
    		float max = Math.abs(v[0]);
    		while(--j > 0) {
    			float vj = Math.abs(v[j]);
    			if(vj > max)
    				max = vj;
    		}
    		return max;
    	}
    
    	public static void ModL2normalize( Matrix m, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			m.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int i = m.rows;
    		float sumSquares = 0.0f;
    		while( --i >= 0 ) {
    			int j = m.columns;
    			while( --j >= 0 ) {
    				sumSquares += m.entry[i][j]*m.entry[i][j];
    			}
    		}
    		sumSquares = (float)Math.sqrt(sumSquares);
    		i = m.rows;
    		while( --i >= 0 ) {
    			int j = m.columns;
    			while( --j >= 0 ) {
    				m.entry[i][j] /= sumSquares;
    			}
    		}
    	}
    
    	public static void ModL2normalize( float [] v, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			return;
    		}
    		int j = v.length;
    		float sumSquares = 0.0f;
    		while(--j >= 0) sumSquares += v[j]*v[j];
    		j = v.length;
    		sumSquares = (float)Math.sqrt(sumSquares);
    		while(--j >= 0) v[j] /= sumSquares;
    	}
    
    	public static float ModL2norm( Matrix m, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			m.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return modulus;
    		}
    		int i = m.rows;
    		float sumSquares = 0.0f;
    		while( --i >= 0 ) {
    			int j = m.columns;
    			while( --j >= 0 ) {
    				sumSquares += (m.entry[i][j]*m.entry[i][j])%modulus;
    			}
    		}
    		sumSquares = (float)Math.sqrt(sumSquares);
    		if(m.norms == null)
    			m.norms = new float[4];
    		m.norms[2] = sumSquares;
    		return sumSquares;
    	}
    
    	public static float ModL2norm( float [] v, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			return modulus;
    		}
    		int j = v.length;
    		float sumSquares = 0.0f;
    		while(--j >= 0) sumSquares += (v[j]*v[j])%modulus;
    		return (float)Math.sqrt(sumSquares);
    	}
    
    	public static void ModL1normalize( Matrix m, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			m.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int i = m.rows;
    		float sum = 0.0f;
    		while( --i >= 0 ) {
    			int j = m.columns;
    			while( --j >= 0 ) {
    				sum += Math.abs(m.entry[i][j]);
    			}
    		}
    		i = m.rows;
    		while( --i >= 0 ) {
    			int j = m.columns;
    			while( --j >= 0 ) {
    				m.entry[i][j] /= sum;
    			}
    		}
    	}
    
    	public static void ModL1normalize( float[] v, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			return;
    		}
    		int j = v.length;
    		float sum = 0.0f;
    		while(--j >= 0) sum += Math.abs(v[j]);
    		j = v.length;
    		while(--j >= 0) v[j] /= sum;
    	}
    
    	public static float ModL1norm( Matrix m, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			m.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return modulus;
    		}
    		int i = m.rows;
    		float sum = 0.0f;
    		while( --i >= 0 ) {
    			int j = m.columns;
    			while( --j >= 0 ) {
    				sum += Math.abs(m.entry[i][j]);
    			}
    		}
    		if(m.norms == null)
    			m.norms = new float[4];
    		m.norms[1] = sum;
    		return sum;
    	}
    
    	public static float ModL1norm( float[] v, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			return modulus;
    		}
    		int j = v.length;
    		float sum = 0.0f;
    		while(--j >= 0) sum += Math.abs(v[j]);
    		return sum;
    	}
    
    	public static void ModL0normalize( Matrix m, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			m.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int i = m.rows;
    		float sum = 0.0f;
    		while( --i >= 0 ) {
    			int j = m.columns;
    			while( --j >= 0 ) {
    				if(m.entry[i][j] != Matrix.ZEROF)
    					sum += 1.0f;
    			}
    		}
    		i = m.rows;
    		while( --i >= 0 ) {
    			int j = m.columns;
    			while( --j >= 0 ) {
    				m.entry[i][j] /= sum;
    			}
    		}
    	}
    
    	public static void ModL0normalize( float[] v, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			return;
    		}
    		int j = v.length;
    		float sum = 0.0f;
    		while(--j >= 0) 
    			if(v[j] != 0.0f)
    				sum += 1.0f;
    		j = v.length;
    		while(--j >= 0) v[j] /= sum;
    	}
    
    	public static float ModL0norm( Matrix m, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			m.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return modulus;
    		}
    		int i = m.rows;
    		float sum = 0.0f;
    		while( --i >= 0 ) {
    			int j = m.columns;
    			while( --j >= 0 ) {
    				if(m.entry[i][j] != Matrix.ZEROF)
    					sum += 1.0f;
    			}
    		}
    		if(m.norms == null)
    			m.norms = new float[4];
    		m.norms[0] = sum;
    		return sum;
    	}
    
    	public static float ModL0norm( float[] v, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			return modulus;
    		}
    		int j = v.length;
    		float sum = 0.0f;
    		while(--j >= 0) 
    			if(v[j] != 0.0f)
    				sum += 1.0f;
    		return sum;
    	}
    
    	// Algorithms
    
    	public static Matrix ModFloydWarshall( Matrix base, float epsilon, float connected_bound, float disconnected_bound, int strictness, int minmax, float modulus ) { 
    		if(modulus == Matrix.ZEROF) {
    			Matrix result = new Matrix(base);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		epsilon = Math.abs(epsilon);
    		float connected = connected_bound;
    		float disconnected = disconnected_bound;
    		int i = base.rows;
    		int maxspan = base.shortest;
    		Matrix fw = new Matrix(Matrix.NONE, i, base.columns);
    		while(--i >= 0) {
    			int j = base.columns;
    			while(--j >= 0 ) {
    				float eij = base.entry[i][j];
    				if( strictness == 0 && j < maxspan && i < maxspan ) {
    					eij += base.entry[j][i];
    				}
    				if( eij > -epsilon && eij < epsilon )
    					fw.entry[i][j] = connected;
    				else
    					fw.entry[i][j] = disconnected;
    			}
    		}
    		int k = maxspan;
    		while( --k >= 0 ) {      
    			i = base.rows;
    			while( --i >= 0 ) {
    				float current_distance_part = fw.entry[i][k];
    				int j = base.columns;
    				while( -- j >= 0 ) {
    					if(i==j)
    						fw.entry[i][j] = 0.0f;
    					else {
    						float current_distance = fw.entry[i][j];
    						float current_distance_whole = current_distance_part + fw.entry[k][j];
    						switch(minmax) {
    						case(MIN):
    							fw.entry[i][j] = current_distance < current_distance_whole ? current_distance : current_distance_whole;
    						break;
    						case(MAX):
    							fw.entry[i][j] = current_distance > current_distance_whole ? current_distance : current_distance_whole;
    							break;
    						}
    						fw.entry[i][j] %= modulus;
    					}
    				}  
    			}
    		}
    		i = base.rows;
    		while( --i >= 0 ) {
    			int j = base.columns;
    			while( --j >= 0 ) 
    				fw.entry[i][j] *= fw.entry[i][j];
    		}
    		return fw;
    	}
    
    	public static void ModPowerIterationDeflate(Matrix m, int eigens_to_compute, double epsilons, int populateKrylovSubspace, float modulus ) { 
    		if(modulus == Matrix.ZEROF) {
    			m.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int iteration = 0;
    		m.krylovs = new float[populateKrylovSubspace][m.columns];
    		while(--eigens_to_compute >= 0) {
    			Matrix next_eigen_approximation, current_eigen_approximation = new Matrix(Matrix.NONE, 1, m.columns );
    			double prev, current = epsilons; float eigenvalue_approximation;
    			fill_random( current_eigen_approximation );
    			L2normalize( current_eigen_approximation );
    			do {
    				prev = current;
    				next_eigen_approximation = new Matrix(current_eigen_approximation);
    				current_eigen_approximation = ModproductResult(m, next_eigen_approximation, modulus);
    				if(iteration<populateKrylovSubspace)
    					System.arraycopy(current_eigen_approximation.entry[0],0,m.krylovs[iteration++],0,m.columns);
    				eigenvalue_approximation = ModFrobeniusInnerProduct(next_eigen_approximation, current_eigen_approximation, modulus);
    				ModL2normalize(current_eigen_approximation, modulus);
    				current = ModFrobeniusInnerProduct(next_eigen_approximation,current_eigen_approximation, modulus);
    			} while( (current < (1-epsilons) && Math.abs( current/prev ) > (1 + epsilons)) );
    			ModscalarMultiply(current_eigen_approximation, (float)Math.sqrt(Math.abs(eigenvalue_approximation)), modulus);
    			m.eigenvalue[eigens_to_compute] = eigenvalue_approximation;
    			System.arraycopy( current_eigen_approximation.entry[0], 0,  m.eigenvector[eigens_to_compute],0, m.columns );
    			if(eigens_to_compute > 0)
    				m = ModDeflateResult(m, current_eigen_approximation, eigenvalue_approximation, modulus );
    		}
    	}
    
    	public static Matrix ModDeflateResult( Matrix base, Matrix eigen_vector, float eigen_value, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			Matrix result = new Matrix(base);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		Matrix result = ModproductResult(  eigen_vector, scalarMultiplyResult(eigen_vector, eigen_value).transpose(), modulus );
    		result = ModpairwiseSubtractResult( base, result, modulus );
    		return result;
    	}
    
    	public static void ModLU_Dolittle_Decomposition( Matrix m, float modulus ) { 
    		if(modulus == Matrix.ZEROF) {
    			m.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int rows = m.rows; int columns = m.columns;
    		for(int i = 0; i < rows;i++ ) {
    			for(int j = i; j < columns; j++ ) {
    				for(int k = 0; k < i-1; k++ ) {
    					m.entry[i][j] -= m.entry[i][k]*m.entry[k][j];
    					m.entry[i][j] %= modulus;
    				}
    			}
    			for(int j = i+1; j < rows; j++ ) {
    				for(int k = 0; k < i-1; k++ ) 
    					m.entry[j][i] -= m.entry[j][k]*m.entry[k][i];
    				m.entry[j][i] /= m.entry[i][i];
    				m.entry[j][i] %= modulus;
    			}
    		}
    	}
    
    	public static Matrix ModLU_Dolittle_DecompositionResult( Matrix m, float modulus ) { 
    		if(modulus == Matrix.ZEROF) {
    			Matrix result = new Matrix(m);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int rows = m.rows; int columns = m.columns;
    		Matrix lowerupper = new Matrix(Matrix.IDENTITY, rows, columns );
    		for(int i = 0; i < rows;i++ ) {
    			for(int j = i; j < columns; j++ ) {
    				lowerupper.entry[i][j] = m.entry[i][j];
    				for(int k = 0; k < i-1; k++ ) {
    					lowerupper.entry[i][j] -= lowerupper.entry[i][k]*lowerupper.entry[k][j];
    					lowerupper.entry[i][j] %= modulus;
    				}
    			}
    			for(int j = i+1; j < rows; j++ ) {
    				lowerupper.entry[j][i] = m.entry[j][i];
    				for(int k = 0; k < i-1; k++ ) 
    					lowerupper.entry[j][i] -= lowerupper.entry[j][k]*lowerupper.entry[j][i];
    				lowerupper.entry[j][i] /= lowerupper.entry[i][i];
    				lowerupper.entry[j][i] %= modulus;
    			}
    		}
    		return lowerupper;
    	}
    
    	public static Matrix[] ModLU_Dolittle_DecompositionResultPair( Matrix m, float modulus ) { 
    		if(modulus == Matrix.ZEROF) {
    			Matrix result = new Matrix(m);
    			Matrix id = new Matrix(Matrix.IDENTITY, m.rows, m.columns );
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			id.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return new Matrix[] { result, id };
    		}
    		int rows = m.rows; int columns = m.columns;
    		Matrix lower = new Matrix(Matrix.IDENTITY, rows, columns );
    		Matrix upper = new Matrix(Matrix.NONE, rows, columns );
    		for(int i = 0; i < rows;i++ ) {
    			for(int j = i; j < columns; j++ ) {
    				upper.entry[i][j] = m.entry[i][j];
    				for(int k = 0; k < i-1; k++ ) {
    					upper.entry[i][j] -= lower.entry[i][k]*upper.entry[k][j];
    					upper.entry[i][j] %= modulus;
    				}
    			}
    			for(int j = i+1; j < rows; j++ ) {
    				lower.entry[j][i] = m.entry[j][i];
    				for(int k = 0; k < i-1; k++ ) 
    					lower.entry[j][i] -= lower.entry[j][k]*upper.entry[j][i];
    				lower.entry[j][i] /= upper.entry[i][i];
    				lower.entry[j][i] %= modulus;
    			}
    		}
    		return new Matrix[] { lower, upper };
    	}
    
    	public static float ModdiagonalDet( Matrix triangular, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			triangular.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return modulus;
    		}
    		float det = 1.0f;
    		int i = triangular.shortest;
    		while(--i >= 0 )
    			det = (det * triangular.entry[i][i]) % modulus;
    		triangular.det = det;
    		return det;
    	}
    
    	public static float ModDeterminant( Matrix m, float modulus ) { 
    		if(modulus == Matrix.ZEROF) {
    			m.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return modulus;
    		}
    		Matrix[] lowerupper = ModLU_Dolittle_DecompositionResultPair(m, modulus);
    		float detLower = ModdiagonalDet(lowerupper[0], modulus);
    		float detUpper = ModdiagonalDet(lowerupper[1], modulus);
    		m.det = (detLower*detUpper) % modulus;
    		return m.det;
    	}
    
    	public static Matrix ModInverse( Matrix a, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			Matrix result = new Matrix(a);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		Matrix m = new Matrix(a);
    		Matrix w = new Matrix( Matrix.NONE, m.rows, m.columns );
    		Matrix l = new Matrix( Matrix.NONE, m.rows, m.columns );
    		Matrix u = new Matrix( Matrix.NONE, m.rows, m.columns );
    		for(int k = 0; k < m.shortest; k++ ) {
    			l.entry[k][k] = Matrix.IDENTITY;
    			for(int i = k+1; i < m.shortest; i++ ) {
    				float coeff = m.entry[i][k]/m.entry[k][k];
    				l.entry[i][k] = coeff;
    				for(int j = k+1; j < m.shortest; j++ ) {
    					m.entry[i][j] -= coeff*m.entry[k][j];
    					m.entry[i][j] %= modulus;
    				}
    			}
    		}
    		for(int j = 0; j < m.shortest; j++ ) {
    			for(int i = 0; i < j; i++ ) {
    				u.entry[i][j] = m.entry[i][j] % modulus;
    			}
    		}
    		float b[] = new float[m.shortest];
    		float d[] = new float[m.shortest];
    		float x[] = new float[m.shortest];
    		for(int k = 0; k < m.columns; k++ ) {
    			d[1] = b[1];
    			b[k] = 1.0f;
    			for(int i = 1; i < m.shortest; i++ ) {
    				for(int j = 1; j < i-1; j++ ) {
    					d[i] = b[i];
    					d[i] -= l.entry[i][j]*d[j];
    					d[i] %= modulus;
    				}
    			}
    			x[m.shortest-1] = d[m.shortest-1]/u.entry[m.shortest-1][m.shortest-1];
    			for(int i = m.shortest; i >= 0; i-- ) {
    				x[i] = d[i];
    				for(int j = m.shortest; j > i; j-- ) {
    					x[i] = x[i] - u.entry[i][j]*x[j];
    					x[i] %= modulus;
    				}
    				x[i] /= u.entry[i][i]; 
    			}
    			for(int i = 0; i < m.shortest; i++ ) {
    				w.entry[i][k] = x[i];
    				w.entry[i][k] %= modulus;
    			}
    			b[k] = 0.0f;
    		}
    		return w;
    	}
    
    	// Thresholding
    
    	public static void Modthreshold ( Matrix a, float threshold, int directed, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			a.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestRow = a.rows;
    		int shortestColumn = a.columns ;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float aij = a.entry[i][j];
    				if(directed==0)
    					aij = Math.abs(a.entry[i][j]);
    				if((aij % modulus ) < threshold)
    					a.entry[i][j] = 0.0f;
    				else
    					a.entry[i][j] = 1.0f;
    			}  
    		}
    		a.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix ModthresholdResult ( Matrix a, float threshold, int directed, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			Matrix result = new Matrix(a);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int shortestRow = a.rows;
    		int shortestColumn = a.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float aij = a.entry[i][j];
    				if(directed==0)
    					aij = Math.abs(a.entry[i][j]);
    				if((aij % modulus) < threshold)
    					result.entry[i][j] = 0.0f;
    				else
    					result.entry[i][j] = 1.0f;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	// Pair/Entry-Wise Fuzzy Binary arithmetic
    	// a AND 0 = 0
    	// a or 0 = a
    	// a XOR 0 = a
    	// a XOR a = 0
    	// a AND b = a*b
    	// a OR b = a+b
    	// a XOR b = (a/b + b/a)
    	// a KOR b = -ab + b/a 
    	// NOT a = 0
    	// a NAND B = a/b
    	// a NOR b = a + 1/b
    
    	public static void ModAND( Matrix a, Matrix b, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			a.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestRow = a.rows < b.rows ? a.rows : b.rows;
    		int shortestColumn = a.columns < b.columns ? a.columns : b.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				a.entry[i][j] = a.entry[i][j]*b.entry[i][j];
    				a.entry[i][j] %= modulus;
    			}  
    		}
    		a.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix ModANDResult ( Matrix a, Matrix b, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			Matrix result = new Matrix(a);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int shortestRow = a.rows < b.rows ? a.rows : b.rows;
    		int shortestColumn = a.columns < b.columns ? a.columns : b.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				result.entry[i][j] = a.entry[i][j]*b.entry[i][j];
    				result.entry[i][j] %= modulus;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static void ModOR( Matrix a, Matrix b, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			a.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestRow = a.rows < b.rows ? a.rows : b.rows;
    		int shortestColumn = a.columns < b.columns ? a.columns : b.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				a.entry[i][j] = (a.entry[i][j]+b.entry[i][j]) % modulus;
    			}  
    		}
    		a.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix ModORResult ( Matrix a, Matrix b, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			Matrix result = new Matrix(a);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int shortestRow = a.rows < b.rows ? a.rows : b.rows;
    		int shortestColumn = a.columns < b.columns ? a.columns : b.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				result.entry[i][j] = a.entry[i][j]+b.entry[i][j];
    				result.entry[i][j] %= modulus;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static void ModXOR( Matrix a, Matrix b, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			a.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestRow = a.rows < b.rows ? a.rows : b.rows;
    		int shortestColumn = a.columns < b.columns ? a.columns : b.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float aij = a.entry[i][j];
    				float bij = b.entry[i][j];
    				if(aij == 0) {
    					if(bij == 0 )
    						a.entry[i][j] = 0.0f;
    					else
    						a.entry[i][j] = bij;
    				}
    				else {
    					if(bij != 0 )
    						a.entry[i][j] = aij/bij + bij/aij;
    				}
    				a.entry[i][j] %= modulus;
    			}  
    		}
    		a.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix ModXORResult ( Matrix a, Matrix b, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			Matrix result = new Matrix(a);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int shortestRow = a.rows < b.rows ? a.rows : b.rows;
    		int shortestColumn = a.columns < b.columns ? a.columns : b.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float aij = a.entry[i][j];
    				float bij = b.entry[i][j];
    				if(aij == 0) {
    					if(bij == 0 )
    						result.entry[i][j] = 0.0f;
    					else
    						result.entry[i][j] = bij;
    				}
    				else {
    					if(bij != 0 )
    						result.entry[i][j] = aij/bij + bij/aij;
    				}
    				result.entry[i][j] %= modulus;
    			}  
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static void ModKOR( Matrix a, Matrix b, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			a.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestRow = a.rows < b.rows ? a.rows : b.rows;
    		int shortestColumn = a.columns < b.columns ? a.columns : b.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float aij = a.entry[i][j];
    				float bij = b.entry[i][j];
    				if(aij != 0) {
    					a.entry[i][j] = -aij*bij + bij/aij;
    					a.entry[i][j] %= modulus;
    				}
    			}
    		}
    		a.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix ModKORResult ( Matrix a, Matrix b, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			Matrix result = new Matrix(a);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int shortestRow = a.rows < b.rows ? a.rows : b.rows;
    		int shortestColumn = a.columns < b.columns ? a.columns : b.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float aij = a.entry[i][j];
    				float bij = b.entry[i][j];
    				if(aij != 0) {
    					result.entry[i][j] = -aij*bij + bij/aij;
    					result.entry[i][j] %= modulus;
    				}
    			}
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    	public static void ModNOT ( Matrix a, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			a.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return;
    		}
    		int shortestRow = a.rows;
    		int shortestColumn = a.columns;
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float aij = a.entry[i][j];
    				if(aij != 0) {
    					a.entry[i][j] = 1/-aij;
    					a.entry[i][j] %= modulus;
    				}
    			}
    		}
    		a.updates &= (Matrix.all_changed^Matrix.entry_changed);
    	}
    
    	public static Matrix ModNOTResult ( Matrix a, float modulus ) {
    		if(modulus == Matrix.ZEROF) {
    			Matrix result = new Matrix(a);
    			result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    			return result;
    		}
    		int shortestRow = a.rows;
    		int shortestColumn = a.columns;
    		Matrix result = new Matrix(Matrix.NONE, shortestRow, shortestColumn);
    		int i = shortestRow;
    		while(--i >= 0) {
    			int j = shortestColumn;
    			while(--j >= 0) {
    				float aij = a.entry[i][j];
    				if(aij != 0) {
    					result.entry[i][j] = 1.0f/-aij;
    					result.entry[i][j] %= modulus;
    				}
    			}
    		}
    		result.updates &= (Matrix.all_changed^Matrix.entry_changed);
    		return result;
    	}
    
    }
    
    import processing.core.*; 
    
    import java.util.ArrayList; 
    
    public class AspektWorld extends PApplet {
    	public static final int BIG_STROKE = 3;
    	public static final int MIDDLE_STROKE = 1 ;
    	public static final int SMALL_STROKE = 1;
    	// private static final long serialVersionUID = 61803L;
    	public final static int FORWARD = 1;
    	public final static int BACKWARD = 2;
    	public final static int RIGHTWARD = 4;
    	public final static int LEFTWARD = 8;
    	public final static int UPWARD = 16;
    	public final static int DOWNWARD = 32;
    	static public void main(String args[]) {
    		PApplet.main(new String[] { "--bgcolor=#D4D0C8", "AspektWorld" });
    	}
    	public int direction = 0;
    	public int last_direction = 0;
    	public float lmx,lmy,dx,dy;
    	public final static float MAX_SPEED = 60.0f;
    	public final static float MIN_SPEED = 1.0f;
    	public float speed = 60.0f;
    	public float wd = 1600;
    	public float hh = 900;
    	public float dp = 1000;
    	public PVector forward_heading;
    	public PVector back_heading,left_heading,right_heading,up_heading,down_heading;
    	public PVector straight_up, straight_left, straight_down, straight_right, straight_forward, straight_back;
    	public int appletMode=1;
    	public int diameter = 100;
    	public float scalar;
    	public int longest;
    	public double ttheta;
    	// public Rotation r;
    	public int double_click;
    	public float sbxs,sbys;
    	public ArrayList<Line> lines;
    	public int edgeColor = 1;
    	public int mouseLookOn = 1;
    	public int verticesOn = 0;
            public int edgesOn = 1;
    	public float edgesOnC = 1;
    	public float rotations = 0.0f;
    	public int rotOn = 1;
    	public int textOn = 1;
    	public int fixedOn = 1;
            public int animateOn = 1;
            public int faster = 0;
    
    
    	public Graph.Vertex hoverNode;
    	public PMatrix3D currCameraMatrix;
    
    	public PGraphics3D g3;
    	public int in_a_contro2222l = 0;
    	public int basics_panel_active = 0;
    	public int matrix_panel_active = 0;
    	public int ev_panel_active = 0;
    	public int instructions_panel_active = 0;
    	public int ev1_sz, ev2_sz, ev3_sz, ev4_sz, ev5_sz;
    	public int ev_sz = 138, ev_sz_actv = 150;
    	public int mpa_sz, mpl_sz, mpd_sz;
    	public int m_sz = 100, m_sz_actv = 168;
    	public int mpa_sd, mpl_sd, mpd_sd;
    	public float m_actv_delta = (m_sz_actv-m_sz)/2.0f;
    	public int counter = 0;
    	public PFont face; 
    	public float th_constant;
    	public Visionary cs;
    	public int droplets;
    	public Rain[] drops;
    
    	PVector pos;
    
    
    	public Graph g1;
    	public int layoutOn = 1;
    
    	//public void attach_graph_to_local_coordinate_master() {
    	//	int i = g1.v.length;
    	//	while(--i>=0)
    	//		g1.v[i].posa = pos;
    	//	i = g1.e.length;
    	//}
    
    
    
    	@Override
    	public void draw() {
                    if(animateOn==1) {
                      if(faster==1)
                        edgesOnC += 0.3;
                      else
                        edgesOnC += 0.1;
                      if(edgesOnC >= 64.0f)
                        edgesOnC = 0.0f;
                      edgesOn = (int)edgesOnC;
                    }
    		//in_a_control = 0;
    		background(0);
    		pushMatrix();
    		translate(pos.x,pos.y,pos.z);
    		//draw_grid();
    		g1.draw();
    		//rotateY(rotations);
    		//if(rotOn==1)
    		//  rotations-=0.15f;
    		//int i=droplets;        
    		//while(--i>=0)
    		//  drops[i].draw();
    		//if(rotations <= -2*PI)
    		//  rotations = 0.0f;
    		popMatrix();
    		//currCameraMatrix = new PMatrix3D(g3.camera);
    		//camera();
    		//if(matrix_panel_active != 0)
    		//	draw_matrix_panel();
    		//draw_controls();
    		//g3.camera = currCameraMatrix;
    		update_heading();
    	}
    
    	public void draw_grid() {
    
    		int linum = lines.size();
    		for(int i = 0; i < linum;i++) {
    			Line lin = lines.get(i);
    			lin.draw();
    		}  
    	}
    
    
    	public void dvals() {
    		pos = new PVector(3600,300,1000);
    		lmx = 0.0f; lmy = 0.0f;
    		//int boxnum = boxes.size();
    		forward_heading = new PVector(1000,-300,500);
    		straight_up = new PVector(0,1,0);
    		straight_down = new PVector(0,-1,0);
    		straight_left = new PVector(-1,0,0);
    		straight_right = new PVector(1,0,0);
    		straight_forward = new PVector(0,0,1);
    		straight_back = new PVector(0,0,-1);
    		make_normals();
    		//cam.lookAt(forward_heading.x, forward_heading.y, forward_heading.z, 1.0f);
    
    		camera(0,0,0, forward_heading.x, forward_heading.y, forward_heading.z, 0.0f, 1.0f, 0.0f);
    	}
    
    
    	public void input() {
    		float mx = mouseX;
    		float my = mouseY;
    		//if(result < height*height/4 ) {
    		if(mouseLookOn==1)
    			cursor(CROSS);  
    		else
    			cursor(HAND);
    		mx = map(mx, 0, width, -1, 1);
    		my = map(my, 0, height, -1, 1); 
    		//}
    		//else {
    		// cursor(HAND);
    		// return; 
    		//}
    		float xang = mx * Math.abs(mx) / (23*PI);
    		float yang = my * Math.abs(my) / (12*PI);
    		if(mouseLookOn==1) {
    			right_heading.mult(speed*sin(xang));
    			forward_heading.mult(cos(xang));
    			forward_heading.add(right_heading);
    			straight_up.mult(speed*sin(yang));
    			forward_heading.mult(cos(yang));
    			forward_heading.add(straight_up);
    		}
    		//cam.lookAt(forward_heading.x, forward_heading.y, forward_heading.z, 1.0f);
    		camera(0,0,0, forward_heading.x, forward_heading.y, forward_heading.z, 0.0f, 1.0f, 0.0f);
    		forward_heading.normalize();
    		update_normals();
    		forward_heading.mult(speed);
    	}
    
    
    	@Override
    	public void keyPressed(){
    		if(key != CODED)
    			switch(key) {
    			case('w'):case('W'):direction |=FORWARD; last_direction = FORWARD; break;
    			case('d'):case('D'):direction |=RIGHTWARD; last_direction = RIGHTWARD; break;
    			case('s'):case('S'):direction |=BACKWARD; last_direction = BACKWARD; break;
    			case('a'):case('A'):direction |=LEFTWARD; last_direction = LEFTWARD; break;
    			case(' '):direction |=UPWARD; last_direction = UPWARD; break;
    			case('c'):case('C'):direction |=DOWNWARD; last_direction = DOWNWARD; break;
    
    			case('t'):case('T'):
    				textOn ^= 1;
    			break;
                            case('P'):
                                faster ^= 1;
                                break;
                           
                            case('p'):
                                animateOn ^=1;
                                edgesOnC = (float)edgesOn;
                                break;
                            case('['):
                                    edgesOn -= 1;
                                    if(edgesOn <= -1)
                                      edgesOn = 63;
                                    break;
    			
                            case(']'):
                                    edgesOn += 1;
                                    if(edgesOn >= 64)
                                      edgesOn = 0;
                                    break;
    			case('3'):
                                    //edgesOn = 1;
    				layoutOn ^= 1;
    			if(layoutOn == 0) 
    				cs.randomizeLayoutColorSize();
    			else
    				cs.squaresTrianglesCirclesLayout();
    			break;
    			case('`'):case('~'):
    				mouseLookOn ^= 1;
    			break;
    			case('v'):case('V'):
    				verticesOn ^= 1;
    			break;
    			case('r'):case('R'):
    				rotOn ^= 1;
    			}
    		else {
    			switch(keyCode) {
    			case(SHIFT):
    				if(speed > MIN_SPEED) {
    					speed = MIN_SPEED; 
    					break;
    				}
    			}
    		}
    	}
    
    	@Override
    	public void keyReleased(){  
    		if(key != CODED)
    			switch(key) {
    			case('w'):case('W'):direction ^=FORWARD; last_direction = FORWARD; break;
    			case('d'):case('D'):direction ^=RIGHTWARD; last_direction = RIGHTWARD; break;
    			case('s'):case('S'):direction ^=BACKWARD; last_direction = BACKWARD; break;
    			case('a'):case('A'):direction ^=LEFTWARD; last_direction = LEFTWARD; break;
    			case(' '):direction ^=UPWARD; last_direction = UPWARD; break;
    			case('c'):case('C'):direction ^=DOWNWARD; last_direction = DOWNWARD; break;
    
    			}  
    		else
    			switch(keyCode) {
    			case(SHIFT):
    				if(speed < MAX_SPEED) {
    					speed = MAX_SPEED; 
    					break;
    				}
    			}
    	}
    
    	public void make_grid() {
    		float spacing = 100;
    		lines = new ArrayList((int)(2*(wd+dp)/spacing + 1));
    		stroke(200,255,255,255);
    		for(float i = -wd*2; i <= wd*2; i+=spacing) {
    			Line nl = new Line(this, i,0,-2*wd,i,0,2*wd);
    			nl.posa = pos;
    			lines.add(nl);
    		}
    		for(float i = -wd*2; i <= wd*2; i+= spacing) {
    			Line nl = new Line(this, -2*wd,0,i,2*wd,0,i);
    			nl.posa = pos;
    			lines.add(nl);
    		}  
    		stroke(0,0,0,255);
    	}
    
    	public void make_normals() {
    		back_heading = new PVector(-forward_heading.x, -forward_heading.y, -forward_heading.z);
    		up_heading = new PVector(0,speed,0);
    		down_heading = new PVector(0,-speed,0);
    		right_heading = forward_heading.cross(up_heading);
    		left_heading = forward_heading.cross(down_heading);
    	}
    
    
    
    	@Override
    	public void mouseClicked() {
    		if(mouseEvent.getClickCount() == 1) { 
    			fixedOn ^= 1;
    			cs.randomGraph();
    			cs.randomizeLayoutColorSize();
    			g1 = cs.g1;
    			if(layoutOn==1)
    				cs.squaresTrianglesCirclesLayout();
    			if(fixedOn == 1) {
    				//attach_graph_to_local_coordinate_master();
    				make_normals();
    				make_grid();
    				update_heading();
    			}
    		}
    		else if(mouseEvent.getClickCount() == 3) {
    			dvals();
    			
    		}
    
    
    
    	}
    
    
    	@Override
    	public void setup() {
    		textSize(15);
    		th_constant = textAscent();
    		//textFont(face);
    		int xw = (screenWidth*15)/16;
    		int yh = (screenHeight*7)/8;
    		size(900,568,P3D);
    		sbxs = width/50;
    		sbys = -height/50;
    		rectMode(CENTER);
    		colorMode(HSB,360,255,255,255);
    		longest = width < height ? 1 : 0;
    		scalar = width < height ? width : height;
    		//tthea = tan(scalar);
    		g3 = (PGraphics3D)g;
    		background(0);
    		cs = new Visionary(this);
    		cs.randomGraph();
    		cs.randomizeLayoutColorSize();
    		g1 = cs.g1;
    		cs.squaresTrianglesCirclesLayout();
    		//drops = cs.makeRain();
    		//droplets = drops.length;
    		dvals();
    		make_normals();
    		make_grid();
    		update_heading();
    		//smooth();
    		// not for applet
    	}
    
    	public void setup_matrix_panel() {
    		mpa_sz = m_sz;
    		mpa_sd = 0;
    		mpl_sz = m_sz;
    		mpl_sd = 0;
    		mpd_sz = m_sz_actv;
    		mpd_sd = 1;
    	}
    
    	public void update_heading() {
    		input();
    		update_v();
    	}
    	public void update_normals() {
    		back_heading.set(-forward_heading.x, -forward_heading.y, -forward_heading.z); 
    		up_heading.set(0,speed,0);
    		down_heading.set(0,-speed,0);
    		straight_left.set(-1,0,0);
    		straight_right.set(1,0,0);
    		straight_forward.set(0,0,1);
    		straight_back.set(0,0,-1);
    		straight_up.set(0,1,0);
    		straight_down.set(0,-1,0);
    		right_heading = forward_heading.cross(straight_up);
    		left_heading = forward_heading.cross(straight_down);
    		back_heading.mult(speed);
    		right_heading.mult(speed);
    		left_heading.mult(speed);
    	}
    
    
    
    	public void update_selected() {
    		int ns = g1.v.length;
    		for(int i = 0; i < ns;i++) {
    			Graph.Vertex n = g1.v[i];
    			if(n == null)
    				continue;
    		}
    	}
    
    	public void update_v() {
    		switch(direction) {
    		case FORWARD:pos.sub(forward_heading); break;
    		case BACKWARD:pos.sub(back_heading); break;
    		case LEFTWARD:pos.sub(left_heading); break;
    		case RIGHTWARD:pos.sub(right_heading); break;
    		case UPWARD:pos.add(up_heading); break;
    		case DOWNWARD:pos.add(down_heading); break;
    		case FORWARD|LEFTWARD:pos.sub(forward_heading);pos.sub(left_heading); break;
    		case FORWARD|RIGHTWARD:pos.sub(forward_heading);pos.sub(right_heading);  break;
    		case BACKWARD|LEFTWARD:pos.sub(back_heading);pos.sub(left_heading);  break;
    		case BACKWARD|RIGHTWARD:pos.sub(back_heading);pos.sub(right_heading);  break;
    		case UPWARD|FORWARD:pos.sub(forward_heading);pos.add(up_heading);  break;
    		case UPWARD|BACKWARD:pos.sub(back_heading);pos.add(up_heading);  break;
    		case UPWARD|LEFTWARD:pos.add(up_heading);pos.sub(left_heading);  break;
    		case UPWARD|RIGHTWARD:pos.add(up_heading);pos.sub(right_heading);  break;
    		case DOWNWARD|FORWARD:pos.sub(forward_heading);pos.add(down_heading);  break;
    		case DOWNWARD|BACKWARD:pos.sub(back_heading);pos.add(down_heading);  break;
    		case DOWNWARD|LEFTWARD:pos.add(down_heading);pos.sub(left_heading);  break;
    		case DOWNWARD|RIGHTWARD:pos.add(down_heading);pos.sub(right_heading);  break;
    		case UPWARD|FORWARD|RIGHTWARD:pos.sub(forward_heading);pos.add(up_heading);pos.sub(right_heading);break;
    		case UPWARD|FORWARD|LEFTWARD:pos.sub(forward_heading);pos.add(up_heading);pos.sub(left_heading);  break;
    		case UPWARD|BACKWARD|RIGHTWARD:pos.sub(back_heading);pos.add(up_heading);pos.sub(right_heading);  break;
    		case UPWARD|BACKWARD|LEFTWARD:pos.sub(back_heading);pos.add(up_heading);pos.sub(left_heading);  break;
    		case DOWNWARD|FORWARD|LEFTWARD:pos.sub(forward_heading);pos.add(down_heading);pos.sub(left_heading);  break;
    		case DOWNWARD|FORWARD|RIGHTWARD:pos.sub(forward_heading);pos.add(down_heading);pos.sub(right_heading);  break;
    		case DOWNWARD|BACKWARD|LEFTWARD:pos.sub(back_heading);pos.add(down_heading);pos.sub(left_heading); break;
    		case DOWNWARD|BACKWARD|RIGHTWARD:pos.sub(back_heading);pos.add(down_heading);pos.sub(right_heading);  break;
    		case LEFTWARD|RIGHTWARD: 
    			if(last_direction==LEFTWARD)
    				pos.sub(left_heading);
    			else
    				pos.sub(right_heading);  
    			break;
    		case FORWARD|BACKWARD: 
    			if(last_direction==FORWARD)
    				pos.sub(forward_heading);
    			else
    				pos.sub(back_heading);
    			break;
    		case UPWARD|DOWNWARD:
    			if(last_direction==UPWARD)
    				pos.add(up_heading);
    			else
    				pos.add(down_heading);
    			break;
    		} 
    		if(pos.y < 300)
    			pos.y = 300;
    	}
    }
    
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.Set;
    
    import processing.core.PVector;
    
    class Rain extends Graph {
    	public int resetCount;
    	public PVector dpos;
    	public AspektWorld aw;
    	public Rain (AspektWorld awa) {
    		super(awa);
    		aw = awa;
    		reset();
    	}
    
    	public void reset() {
    		resetCount = 120+(int)aw.random(120);
    		int vn = 3 + (int)aw.random(4);
    		int i = 0;
    		Graph.Vertex vl = this.new Vertex();
    		vl.color = aw.color(200,200,200,200);
    		vl.radius = 2;
    		addVertex(vl);
    		ArrayList<Graph.Vertex> knownVertices = new ArrayList<Graph.Vertex>();
    		knownVertices.add(vl);
    		dpos = new PVector(aw.random(4*aw.width)-2*aw.width,18000+aw.random(4000),aw.random(4*aw.width)-2*aw.width);
    		while(i < vn) {
    			Graph.Vertex vr = this.new Vertex();
    			addVertex(vr);
    			vr.color = aw.color(200,200,200,200);
    			vr.radius = 2;
    			vr.pos = new PVector(aw.random(300)-150,aw.random(300)-150,aw.random(300)-150);
    			addEdge(new Edge(vl,vr));
    			int randomKV = (int)aw.random(i);
    			vl = (Graph.Vertex)knownVertices.get(randomKV);
    			knownVertices.add(vr);
    			i++;
    		}
    		crystallizeGraph();  
    	}
    
    	public void draw() {
    		aw.pushMatrix();
    		aw.translate(-dpos.x,-dpos.y,-dpos.z);
    		super.draw();
    		aw.popMatrix();
    		if(dpos.y > 111) 
    			dpos.y -= 10*v.length*v.length;
    		else
    			resetCount--;
    		if(resetCount <= 0)
    			reset();
    	}
    
    
    
    }
    
    // The local image of the global concept
    public class Graph { // implements Comparable<Graph> .... just joking
             
    	public class MatrixTypeIndex {
    		public static final int ADJACENCY = 0;
    		public static final int DEGREE = 1;
    		public static final int LAPLACIAN = 2;
    		public static final int COLLOCATION = 3;
    		public static final int MATRIX_FIELD_COUNT = 4;
    	}
    	public class EdgeBattle { 
    		public static final int ESCHER = -8;
    		public static final int ONEFROMTHREE = -5;
    		public static final int TOTALFAIL = -2;
    		public static final int DEPENDSWHICHWAYYOULOOKATIT = 1;
    		public static final int PARALLEL = 4;
    	}
    	public class Vertex {
    		public int id; public PVector pos, posa; public int color; public float radius; public int hover;
    		public Vertex() {
    			id = 0; 
    			hover = 0;
    			pos = new PVector(0,0,0);
    		}
    		public void draw() {
    			aspektWorld.pushMatrix();
    			aspektWorld.fill(color);
    			aspektWorld.stroke(color);
    			aspektWorld.strokeWeight(aspektWorld.SMALL_STROKE);
    			aspektWorld.translate(pos.x,pos.y,pos.z);
    			//aspektWorld.rotateY(aspektWorld.rotations);
    			aspektWorld.box(radius);
    			aspektWorld.popMatrix();
    		}
    	}
    	public class Edge {
    		public final int edgeColorB = aspektWorld.color(141,250,250,250); 
    		public Vertex a; public Vertex b; public int[] strength; 
    		public Edge( Vertex av, Vertex bv ) {
    			a = av; b = bv; strength = new int[6];
    		}
    		public void draw() {
    			if(a.hover==1) {
    				aspektWorld.strokeWeight(aspektWorld.BIG_STROKE);
    				aspektWorld.stroke(edgeColorB);
    			}
    			else {
    				aspektWorld.strokeWeight(aspektWorld.SMALL_STROKE);
    				aspektWorld.stroke(a.color^((int)aspektWorld.alpha(a.color)<<24)^(230<<24));
    			}
    			aspektWorld.line(a.pos.x,a.pos.y,a.pos.z,
    					b.pos.x,b.pos.y,b.pos.z);
    		}
    	}
    	public HashMap<Vertex, Set<Edge>> edgesByVertexA, edgesByVertexB;
    	public HashMap<Vertex,Integer> numbering;
    	public HashMap<Edge,Integer> edgeNumbering;
    	public Matrix[] matrix;
    	public Vertex[] v;
    	public Edge[] e;
    	public float volume;
    	private final AspektWorld aspektWorld;
            public final int red,yellow,green,blue,gray;
    
    	public Graph(AspektWorld aspektWorld) {
    		this.aspektWorld = aspektWorld;
    red = aspektWorld.color(0,200,200,200);
    yellow = aspektWorld.color(60,200,200,200);
    green = aspektWorld.color(119,255,250,200);
    blue = aspektWorld.color(200,200,200,200);
    gray = aspektWorld.color(0,0,200,100);
            
    		edgesByVertexA = new HashMap<Vertex, Set<Edge>>();
    		edgesByVertexB = new HashMap<Vertex, Set<Edge>>();
    		matrix = new Matrix[MatrixTypeIndex.MATRIX_FIELD_COUNT];
    	}
    
    	public HashMap<Graph.Vertex,Integer> numbering() {
    		if(numbering != null)
    			return numbering;
    		int vertices = edgesByVertexA.size();
    		Set<Graph.Vertex> verticeSet = edgesByVertexA.keySet();
    		Iterator<Graph.Vertex> vertexIterator = verticeSet.iterator();
    		numbering = new HashMap<Graph.Vertex,Integer> ();
    		int i = vertices;
    		while(--i >= 0)
    			numbering.put(vertexIterator.next(), new Integer(i));
    		return numbering;
    	}
    
    	public HashMap<Graph.Edge, Integer> edgeNumbering() {
    		if(edgeNumbering != null)
    			return edgeNumbering;
    		Set<Graph.Vertex> verticeSet = edgesByVertexA.keySet();
    		Iterator<Graph.Vertex> vertexIterator = verticeSet.iterator();
    		edgeNumbering = new HashMap<Edge,Integer> ();
    		int edges = 0;
    		while(vertexIterator.hasNext()) {
    			Graph.Vertex stupidFuckFace = vertexIterator.next();
    			Set<Graph.Edge> fuckingMoron = edgesByVertexA.get(stupidFuckFace);
    			Iterator<Graph.Edge> edgeIterator = fuckingMoron.iterator();
    			while(edgeIterator.hasNext()) {
    				Edge e = edgeIterator.next();
    				if(!edgeNumbering.containsKey(e))
    					edgeNumbering.put(e,edges++);
    			}
    		}
    		return edgeNumbering;
    	}
    
    	public void addVertex( Vertex  a ) {
    		if(edgesByVertexA.containsKey(a))
    			return;
    		edgesByVertexA.put( a, new HashSet<Edge>() );
    		edgesByVertexB.put( a, new HashSet<Edge>() );
    	}
    
    	public void cutVertex( Vertex a ) {
    		edgesByVertexA.remove( a );
    		edgesByVertexB.remove( a );
    	}
    
    	public void addEdge( Edge e ) {
    		edgesByVertexA.get(e.a).add(e);
    		edgesByVertexB.get(e.b).add(e);
    	}
    
    	public void cutEdge( Edge e ) {
    		edgesByVertexA.get(e.a).remove(e);
    		edgesByVertexB.get(e.b).remove(e);
    	}
    
    	public float degree ( Vertex v ) {
    		int index = numbering.get(v);
    		return matrix[Graph.MatrixTypeIndex.DEGREE].entry[index][index];  
    	}
    
    	public void crystallizeGraph() {
    		numbering = null;
    		edgeNumbering = null;
    		numbering();
    		edgeNumbering();
    		Set<Vertex> vertices = numbering.keySet();
    		v = new Vertex[vertices.size()];
    		vertices.toArray(v);
    		int j = v.length;
    		while(--j>=0) {
    			Graph.Vertex vj = v[j];
    			numbering.put(vj, new Integer(j));
    		}
    		Set<Edge> edges = edgeNumbering.keySet();
    		e = new Edge[edges.size()];
    		edges.toArray(e);
    		int i = Graph.MatrixTypeIndex.MATRIX_FIELD_COUNT;
    		j = 0;
    		while(j < i) {
    			Algebraicist.form(this, j++);  
    		}
    	}
    
    	public void draw() {
    		int i = e.length;
    		if(aspektWorld.layoutOn == 1) {
    			if(aspektWorld.edgesOn<32) {
    				while(--i >= 0) {
    				    if((aspektWorld.edgesOn&1)==1 && e[i].a.color == red) {
    				      e[i].draw();
    				    }
    				    else if((aspektWorld.edgesOn&2)==2 && e[i].a.color == yellow) {
    				      e[i].draw();
    				    }
    				    else if((aspektWorld.edgesOn&4)==4 && e[i].a.color == green) {
    				      e[i].draw();
    				    }
    				    else if((aspektWorld.edgesOn&8)==8 && e[i].a.color == blue) {
    				      e[i].draw();
    				    }
    				    else if((aspektWorld.edgesOn&16)==16 && e[i].a.color == gray) {
    				      e[i].draw();
    				    }
    				}
    			}
    			else {
    				while(--i >= 0) {
    				    if((aspektWorld.edgesOn&1)==1 && e[i].a.color == red && e[i].b.color == red) {
    				      e[i].draw();
    				    }
    				    else if((aspektWorld.edgesOn&2)==2 && e[i].a.color == yellow && e[i].b.color == yellow) {
    				      e[i].draw();
    				    }
    				    else if((aspektWorld.edgesOn&4)==4 && e[i].a.color == green && e[i].b.color == green) {
    				      e[i].draw();
    				    }
    				    else if((aspektWorld.edgesOn&8)==8 && e[i].a.color == blue && e[i].b.color == blue) {
    				      e[i].draw();
    				    }
    				    else if((aspektWorld.edgesOn&16)==16 && e[i].a.color == gray && e[i].b.color == gray) {
    				      e[i].draw();
    				    }
    				}
    			}
    		}
    		else {
                        while(--i >= 0)
    			e[i].draw();
    		}
    		i = v.length;
    		if(aspektWorld.verticesOn==1)
    			while(--i >= 0)
    				v[i].draw();
    	}
    
    }
    
    import processing.core.PVector;
    
    
    class Line {
    	/**
    	 * 
    	 */
    	private final AspektWorld aspektWorld;
    	public PVector another, posa;
    	public PVector yetanother;
    	public int lc;
    
    	public Line( AspektWorld aspektWorld, float ax, float ay, float az, float tx, float ty, float tz ) {
    		this.aspektWorld = aspektWorld;
    		another = new PVector(ax,ay,az);
    		yetanother = new PVector(tx,ty,tz);
    		lc = this.aspektWorld.color (180,200,200,200);
    	}  
    
    	public void draw() {
    		this.aspektWorld.stroke(lc);
    		this.aspektWorld.strokeWeight(aspektWorld.MIDDLE_STROKE);
    		this.aspektWorld.line(posa.x+another.x,posa.y+another.y,posa.z+another.z,posa.x+yetanother.x,posa.y+yetanother.y,posa.z+yetanother.z);  
    	}
    }
    
    import java.util.Arrays;
    import java.util.HashSet;
    
    public class Matrix {
    	public int rows, columns, shortest, symmetric;
    	public int i, j;
    	public static final int NONE = -1;
    	public static final int ZERO = 0;
    	public static final int IDENTITY = 1;
    	public static final int COUNTERIDENTITY = 2;
    	public static final int ONES = 3;
            public static final int COLLOCATION = 5;
    	public static final int entry_changed = 1;
    	public static final int det_changed = 2;
    	public static final int eigen_changed = 4;
    	public static final int norms_changed = 8;
    	public static final int lu_changed = 16;
    	public static final int inverse_changed = 32;
    	public static final int minmax_changed = 64;
    	public static final int all_changed = 127;
    	public static final float ZEROF = 0.0f;
    	public static final float IDENTITYF = 1.0f;
    	public float eij;
    	public float entry[][];
            public HashSet<Integer> hentry[][];
    	public float trace;
    	public float det;
    	public float[] minmax;
    	public float eigenvector[][];
    	public float eigenvalue[];
    	public float krylovs[][];
    	public float norms[];
    	public float lu_entry[][];
    	public float inverse_entry[][];
    	public int updates;
    	public int eigens_calculated;
    	public int norms_calculated;
    
    	public Matrix(int TYPE, int rows_num, int columns_num) {
    		rows = rows_num;
    		columns = columns_num;
    		symmetric = rows == columns ? 1 : 0;
    		shortest = rows < columns ? rows : columns;
    		updates = all_changed;
    		switch (TYPE) {
    		case (NONE):
    		case (ZERO):
    			make_zero();
    		break;
    		case (IDENTITY):
    			make_identity();
    		break;
    		case (COUNTERIDENTITY):
    			make_counterIdentity();
    		break;
    		case (ONES):
    			make_ones();
                    case ( COLLOCATION ):
                            make_collocation();
    		break;
    		}
    		eigenvector = new float[rows][columns];
    		eigenvalue = new float[rows];
    	}
    
    	public void show() {
    		int i = rows;
    		while(--i >= 0)
    			show_v(entry[i]);
    		System.out.println(rows + "," + columns);
    	}
    
    	public static void show_v (float[] v) {
    		int i = v.length;
    		while(--i >= 0)
    			System.out.print(v[i] + " ");
    		System.out.println();
    	}
    
    	public float[] minmax() {
    		if (minmax!=null && (updates & minmax_changed) == 0)
    			return minmax;
    		minmax = new float[2];
    		if (rows == 0 || columns == 0)
    			return minmax;
    		minmax[0] = minmax[1] = entry[0][0];
    		i = rows;
    		while (--i >= 0) {
    			j = columns;
    			while (--j >= 0) {
    				eij = entry[i][j];
    				if (eij > minmax[1])
    					minmax[1] = eij;
    				else if (eij < minmax[0])
    					minmax[0] = eij;
    			}
    		}
    		updates &= (all_changed ^ minmax_changed);
    		return minmax;
    	}
    
    	public float[] minmaxRow(int row) {
    		float[] minmaxRow = new float[2];
    		if (rows < row || columns == 0)
    			return minmaxRow;
    		minmaxRow[0] = minmaxRow[1] = entry[row][0];
    		j = columns;
    		while (--j >= 0) {
    			eij = entry[row][j];
    			if (eij > minmaxRow[1])
    				minmaxRow[1] = eij;
    			else if (eij < minmaxRow[0])
    				minmaxRow[0] = eij;
    		}
    		return minmaxRow;
    	}
    
    	public float trace() {
    		i = shortest;
    		trace = 0.0f;
    		while (--i >= 0)
    			trace += entry[i][i];
    		return trace;
    	}
    
            public float traces() {
            	i = shortest;
    		trace = 0.0f;
    		while (--i >= 0)
    			trace += entry[i][i]*entry[i][i];
    		return trace;
    	  
            }
    
    	public void make_zero() {
    		entry = new float[rows][columns];
    		updates &= (all_changed ^ entry_changed);
    	}
    
            public void make_collocation() {
    	        hentry = new HashSet[rows][columns];
    		updates &= (all_changed ^ entry_changed);
    	}
    
    	public void make_identity() {
    		entry = new float[rows][columns];
    		i = shortest;
    		while (--i >= 0)
    			entry[i][i] = IDENTITYF;
    		updates &= (all_changed ^ entry_changed);
    	}
    
    	public void make_counterIdentity() {
    		entry = new float[rows][columns];
    		i = shortest;
    		while (--i >= 0)
    			entry[i][shortest - i - 1] = IDENTITYF;
    		updates &= (all_changed ^ entry_changed);
    	}
    
    	public void make_ones() {
    		entry = new float[rows][columns];
    		i = rows;
    		while (--i >= 0) {
    			Arrays.fill(entry[i], IDENTITYF);
    		}
    	}
    
    	public static void copy(float[][] source, float[][] dest) {
    		int si = dest.length;
    		int sj = dest[0].length;
    		while (--si >= 0) {
    			System.arraycopy(source[si], 0, dest[si], 0, sj);
    		}
    	}
    
    	public Matrix(float[][] entries) {
    		rows = entries.length;
    		if (rows != 0)
    			columns = entries[0].length;
    		else
    			columns = 0;
    		symmetric = rows == columns ? 1 : 0;
    		shortest = rows < columns ? rows : columns;
    		entry = new float[rows][columns];
    		Matrix.copy(entries,entry);
    		eigenvector = new float[rows][columns];
    		eigenvalue = new float[rows];
    		updates = all_changed;
    	}
    
    	public Matrix(Matrix expired) {
    		rows = expired.rows;
    		columns = expired.columns;
    		entry = new float[rows][columns];
    		eigenvector = new float[rows][columns];
    		eigenvalue = new float[rows];
    		Matrix.copy(expired.entry, entry);
    		Matrix.copy(expired.eigenvector, eigenvector);
    		System.arraycopy(expired.eigenvalue, 0, eigenvalue, 0,
    				eigenvalue.length);
    		shortest = expired.shortest;
    	}
    
    	public Matrix transpose() {
    		int j = columns;
    		int i = rows;
    		Matrix transpose = new Matrix(Matrix.NONE, j, i);
    		while (--j >= 0) {
    			while (--i >= 0) {
    				transpose.entry[j][i] = entry[i][j];
    			}
    			i = rows;
    		}
    		return transpose;
    	}
    
    }
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Iterator;
    
    import processing.core.PApplet;
    import processing.core.PConstants;
    import processing.core.PVector;
    
    public class Visionary {
    	public final static int VERTICESONSCREEN = 333;
    	public final static int NOMOD = 0;
    	public final static int MOD = 1;
    	public int[] gridsz;
    	public int mc = 0;
    	public Matrix lrf;
    	public Matrix gridv;
    	public int etype = 0;
    	public int offset = 0;
    	public float conMetParam = 1.0f;
    	public float conMetStep = 0.5f;
    	public float[] conMetMinMax;
    
    	public final AspektWorld aspektWorld;
    	public Graph g1;
    
    	public Visionary(AspektWorld aw) {
    		aspektWorld = aw;
    		gridsz = new int[] { 70,140,210,280,350,420,490,560,630,700 };
    		lrf = new Matrix(Matrix.IDENTITY,VERTICESONSCREEN, VERTICESONSCREEN);
    	}
    
    	public Graph randomGraph() {
    		Graph g = new Graph(aspektWorld);
    		ArrayList<Graph.Vertex> knownVertices = new ArrayList<Graph.Vertex>();
    		int i = VERTICESONSCREEN;
    		while(--i >= 0) {
    			Graph.Vertex v = g.new Vertex();
    			g.addVertex(v);
    			knownVertices.add(v);
    			int k,j;
    			k = VERTICESONSCREEN-i;
    			j = (int)Math.log(aspektWorld.random(k));
    			while(--j >= 0) {
    				Graph.Vertex randomNeighbour = knownVertices.get((int)(aspektWorld.random(k)));
    
    				Graph.Edge newEdge = g.new Edge(v, randomNeighbour);
    				if(j == 3) {
    					Graph.Edge newEdge2 = g.new Edge(randomNeighbour,v);
    					g.addEdge(newEdge2);
    				}
    				g.addEdge(newEdge);
    
    			}
    		}
    		g.crystallizeGraph();
    		g1 = g;
    		return g;
    	}
    
    
    	public Graph randomizeLayoutColorSize( ) {
    		int i = g1.v.length;
    		while(--i >= 0) {
    			Graph.Vertex v = g1.v[i];
    			v.color = aspektWorld.color(aspektWorld.random(360),200,200,200);
    			v.radius = 53;
    			float x = aspektWorld.random(4*aspektWorld.width)-2*aspektWorld.width;
    			float z= aspektWorld.random(4*aspektWorld.width)-2*aspektWorld.width;
    			float y = aspektWorld.random(4*aspektWorld.width)-2*aspektWorld.width;
    			v.pos.set(x,-y-300,z);
    		}
    		i = g1.e.length;
    		while(--i >= 0) {
    			Graph.Edge e = g1.e[i];
    		}
    		return g1;
    	}
    
    	public void squaresTrianglesCirclesLayout() {
    		int i = g1.v.length;
    		while(--i >= 0) {
    			g1.v[i].pos.set(0.0f,0.0f,0.0f);
    		}
    		ArrayList tcs = findCycles(4);
    		ArrayList fcs = findCycles(3);
    		ArrayList wcs = findCycles(2);
    		ArrayList ocs = findCycles(1);
    		embedRegular(tcs, 4);
    		embedRegular(fcs, 3);
    		embedRegular(wcs, 2);
    		embedRegular(ocs, 1);
    		embedRest();
    	}
    
    	public void embedRest() {
    		int j = g1.v.length;
    		int xcount = 0;
    		int ycount = 0;
    		int zcount = 0;
    		while(--j >= 0) {
    			Graph.Vertex v = g1.v[j];
    			if(v.pos.y == 0.0f) {
    				v.pos.set(xcount,ycount,zcount);
    				xcount-=150;
    				v.color = aspektWorld.color(0,0,200,100);
    			}
    			if(xcount < -1000) {
    				zcount -= 150;
    				xcount =0;
    			}
    			if(zcount < -1000) {
    				ycount -= 150;
    				zcount = 0;
    
    			}
    
    
    		}
    
    	}
    
    	public ArrayList findCycles(int cnum) {
    		Matrix a = g1.matrix[Graph.MatrixTypeIndex.ADJACENCY];
    		Matrix h = g1.matrix[Graph.MatrixTypeIndex.COLLOCATION];
    		int rows = a.rows;
    		ArrayList cs = new ArrayList(a.rows*a.rows/2);
    		int columns = a.columns;
    		while(--rows >= 0) {
    			while(--columns >= 0) {
    				if(rows==columns && cnum != 1)
    					continue;
    				float aij = a.entry[rows][columns];
    				if(aij == 1.0f) {
    					switch(cnum) {
    					case(1):
    						cs.add(new int[] { rows} );
    					break;
    					case(2):
    						if(a.entry[columns][rows] == 1.0f) {
    							cs.add(new int[] { rows, columns } );
    						}
    					break;
    					case(3):
    						HashSet threes = h.hentry[rows][columns];
    					int tsz = threes.size();
    					Iterator it = threes.iterator();
    					while(--tsz >= 0) {
    						int third = (Integer)it.next();
    						if(third != rows && third != columns) {
    							int[] triangle = new int[] { rows, columns, third };
    							cs.add(triangle);  
    						}
    					}
    					break;
    					case(4):
    						int j = a.columns;
    					while(--j >= 0) {
    						if(j == columns || j == rows)
    							continue;
    						aij = a.entry[columns][j];
    						if(aij == 1.0f) {
    							HashSet fours = h.hentry[rows][j];
    							int fsz = fours.size();
    							it = fours.iterator();
    							while(--fsz >= 0) {
    								int fourth = (Integer)it.next();
    								if(fourth != rows && fourth != columns && fourth != j) {
    									int[] square = new int[] { rows, columns, j, fourth };
    									cs.add(square);  
    								}
    							}
    						}  
    					}
    					break;  
    					}
    				}       
    			}
    			columns = a.columns;
    		}
    		return cs;
    	}
    
    	public void embedRegular(ArrayList cycled, int size) {
    		int j = cycled.size();
    		int sz = 1;
    		while(--j >= 0)
    			sz = embedRegular((int[])cycled.get(j), size, sz);
    	}
    
    	public int embedRegular(int[] cycle, int size, int count) {
    		int j = size;
    		float ang = 2*PConstants.PI/size;
    		float twist = PConstants.PI/size;
    		float radius = size*200;
    		int vw = 200;
    		int vh = 168;
    		PVector centroid = new PVector(vw*(10),-count*vh,vw*(10*size)-vw*20);
    		int vc = g1.v[cycle[0]].color;
    		while(--j >= 0) {
    			Graph.Vertex v = g1.v[cycle[j]];
    			if(v.pos.y != 0.0f)
    				return count;
    		}
    		j = size;
    		while(--j >= 0) {
    			Graph.Vertex v = g1.v[cycle[j]];
    			switch(size) {
    			case(1):
    				v.color = aspektWorld.color(0,200,200,200);
    			break;
    			case(2):
    				v.color = aspektWorld.color(60,200,200,200);
    			break;
    			case(3):
    				v.color = aspektWorld.color(119,255,250,200);
    			break;
    			case(4):
    				v.color = aspektWorld.color(200,200,200,200);
    			break;
    			
    			}
    			v.pos.set(centroid.x+(radius*PApplet.sin(twist+j*ang)),centroid.y, centroid.z+(radius*PApplet.cos(twist+j*ang)));
    			//v.pos.set(centroid);
    		}
    		return count+1;
    	}
    
    }
    

    code

    tweaks (0)

    about this sketch

    This sketch is running as Java applet, exported from Processing.

    license

    advertisement

    Cris Stringfellow

    AspektWorld LightShow *NEW VERSION 2/2/12*

    Add to Faves Me Likey@!
    You must login/register to add this sketch to your favorites.

    -=Summary=-
    Deconstructs a graph into its connected cycles.

    -=Control Summary=-
    Click the app to warm it up.
    Press 3 to toggle between random and connected layouts.
    Press p to toggle animation on and off.
    Press v to toggle vertices on or off.
    Press ~ to toggle mousefreelook.~
    Controls:
    -----------
    Animation
    ========
    P toggles faster mode.
    p toggles play/pause.
    [ step one frame back.
    ] step one frame forward.

    Layout
    ======
    3 - toggles between 'random' and 'designed' layouts.

    Player movement
    =============
    W,A,S,D steps forward, leftward, backward etc...

    You need to login/register to comment.