package ddddbb.comb; public class DOp { public static int length(int[] a) { int res = 0; for (int i=0;i<a.length;i++) { res += Math.abs(a[i]); } return res; } public static int dist(int[] a,int[] b) { int res = 0; assert a.length == b.length; for (int i=0;i<a.length;i++) { res += Math.abs(b[i]-a[i]); } assert res == length(minus(b,a)); return res; } private static void copyAdjunctL(int l0, int dim, int[][] adjunct, int[][] matrix) { for (int l=0;l<dim;l++) { matrix[l][0] = 0; } for (int k=1;k<dim;k++) { for (int l=0;l<l0;l++) { matrix[l][k] = adjunct[l][k-1]; } for (int l=l0+1;l<dim;l++) { matrix[l][k] = adjunct[l-1][k-1]; } } } /** * computes all matrices M with det M = -1 * the indices are [number][line][column] */ public static int[][][] mirrorRotations(int dim) { int[][][] nr; //negative rotations, result if (dim==1) { nr = new int[1][1][1]; nr[0][0][0]=1; } else { int[][][] snr = mirrorRotations(dim-1); // sub negative rotations int[][][] spr = rotations(dim-1); // sub positive rotations int N = 2*dim*snr.length; //number of negative/positive rotations nr = new int[N][dim][dim]; int n=0; //positive subdeterminants for (int i=0;i<dim;i++) { for (int ispr=0;ispr<spr.length;ispr++) { copyAdjunctL(i,dim,spr[ispr],nr[n]); nr[n][i][0] = (i % 2) * 2 - 1; // -1 at [0][0], alternating //for the determinant being -1, the subdeterminant must be 1 n++; } } //negative subdeterminants for (int i=0;i<dim;i++) { for (int isnr=0;isnr<snr.length;isnr++) { copyAdjunctL(i,dim,snr[isnr],nr[n]); nr[n][i][0] = 1 - (i % 2) * 2; // 1 at [0][0], alternating //for the determinant being -1, the subdeterminant must be -1 n++; } } } return nr; } /** * computes all matrices M with det M = 1 * the indices are [number][line][column] */ public static int[][][] rotations(int dim) { int[][][] pr; //positive rotations, result if (dim==1) { pr = new int[1][1][1]; pr[0][0][0]=1; } else { int[][][] snr = mirrorRotations(dim-1); // sub negative rotations int[][][] spr = rotations(dim-1); // sub positive rotations int N = 2*dim*snr.length; //number of negative/positive rotations pr = new int[N][dim][dim]; int n=0; //positive subdeterminants for (int i=0;i<dim;i++) { for (int ispr=0;ispr<spr.length;ispr++) { copyAdjunctL(i,dim,spr[ispr],pr[n]); pr[n][i][0] = 1 - (i % 2) * 2; // 1 at [0][0], alternating //for the determinant being 1, the subdeterminant must be 1 n++; } } //negative subdeterminants for (int i=0;i<dim;i++) { for (int isnr=0;isnr<snr.length;isnr++) { copyAdjunctL(i,dim,snr[isnr],pr[n]); pr[n][i][0] = (i % 2) * 2 - 1; //-1 at [0][0], alternating //for the determinant being 1, the subdeterminant must be -1 n++; } } } return pr; } /** * computes the vector of smalles coordinates of compound a * for dimension information a must not be empty */ public static int[] extentMin(int[][] a) { int dim = a[0].length; int[] v = new int[dim]; for (int ix=0;ix<dim;ix++) { v[ix]=Integer.MAX_VALUE; } for (int i=0;i<a.length;i++) { int[] p = a[i]; for (int ix=0;ix<dim;ix++) { if (p[ix]<v[ix]) {v[ix]=p[ix];} } } return v; } /** * computes the vector of largest coordinates of compound a * for dimension information a must not be empty */ public static int[] extentMax(int[][] a) { int dim = a[0].length; int[] v = new int[dim]; for (int ix=0;ix<dim;ix++) { v[ix] = Integer.MIN_VALUE; } for (int i=0;i<a.length;i++) { int[] p = a[i]; for (int ix=0;ix<dim;ix++) { if (p[ix]>v[ix]) {v[ix]=p[ix];} } } return v; } public static boolean vecEqual(int[] a,int[] b) { if (a.length!=b.length) { return false; } for (int i=0; i<a.length; i++) { if (a[i]!=b[i]) { return false; } } return true; } /** * verifies if compound a as a set of coordinates is contained in b. * @return true if a is contained in b */ public static boolean setContained(int[][] a, int[][] b) { if (a.length>b.length) { return false; } //heuristic optimization for (int i=0;i<a.length;i++) { boolean contained = false; for (int j=0;j<b.length;j++) { if (vecEqual(a[i],b[j])) { contained = true; break; } } if (!contained) { return false; } } return true; } /** * verifies if compound a takes the same space points as compound b * @return true if equal */ public static boolean setEqual(int[][] a,int[][] b) { if (a.length != b.length) { return false; } return setContained(a,b); //this suffice because there are no two equal cubes in a compound } public static boolean setContained(int[] a, int[] b) { if (a.length > b.length) { return false; } //heuristic optimization for (int i=0;i<a.length;i++) { boolean contained = false; for (int j=0;j<b.length;j++) { if (a[i]==b[j]) { contained = true; break; } } if (!contained) { return false; } } return true; } /** * precondition: a must have no 2 equal elements and b too */ public static boolean setEqual(int[] a,int[] b) { if (a.length!=b.length) { return false; } return setContained(a,b); } public static int[] minus(int[] a,int[] b) { int[] r = new int[a.length]; for (int i=0;i<a.length;i++) { r[i] = a[i]-b[i]; } return r; } public static int[] minus(int[] a) { // int[] r = new int[a.length]; // for (int i=0;i<a.length;i++) { // r[i] = -a[i]; // } int[] r = clone(a); negate(r); return r; } public static void negate(int[] a) { for (int i=0;i<a.length;i++) { a[i]=-a[i]; } } public static int[] plus(int[] a,int[] b) { // int[] r = new int[a.length]; // for (int i=0;i<a.length;i++) { // r[i] = a[i]+b[i]; // } int[] r = clone(a); translate(r,b); return r; } public static void translate(int[] a,int[] d) { for (int i=0;i<a.length;i++) { a[i]+=d[i]; } } public static int[][] trans(int[][] a,int[] d) { // int[][] r = new int[a.length][]; // for (int i=0;i<a.length;i++) { // r[i] = plus(a[i],d); // } int[][] r = clone(a); for (int i=0;i<a.length;i++) { translate(r[i],d); } return r; } public static void translate(int[][] a,int[] d) { for (int i=0;i<a.length;i++) { translate(a[i],d); } } public static int[] map(int[] a,int[][] matrix) { int[] r = new int[a.length]; for (int ix=0;ix<matrix.length;ix++) { r[ix]=0; for (int iv=0;iv<matrix.length;iv++) { r[ix]+=a[iv]*matrix[iv][ix]; } } return r; } public static int[][] map(int[][] a,int[][] matrix) { int[][] r = new int[a.length][]; for (int i=0;i<a.length;i++) { r[i] = map(a[i],matrix); } return r; } /** * verifies whether compound a can be shifted to be b * @return true if equal */ public static boolean transEqual(int[][] a,int b[][]) { int[][] b2 = trans(b,minus(extentMin(a),extentMin(b))); return setEqual(a,b2); } /** * verifies whether compound a can be shifted to be contained in b * @return true if a is contained in b */ public static boolean transContained(int[][] a, int[][] b) { int[] diff = minus(minus(extentMax(b),extentMin(b)),minus(extentMax(a),extentMin(a))); int prod = 1; for (int i=0;i<diff.length;i++) { prod *= diff[i]+1; } int[][] a2 = trans(a,minus(extentMin(b),extentMin(a))); for (int i=0;i<prod;i++) { int n = i; int[] d = new int[diff.length]; for (int j=0;j<diff.length;j++) { int base = diff[j] + 1; d[j] = n % base; n /= base; } int[][] a3 = trans(a2,d); if (setContained(a3,b)) { return true; } } return false; } /** * verifies whether a can be rotated and shifted to be b * dimension is retrieved from first element of a, so a must not be empty * @return true if equal */ public static boolean motionEqual(int[][] a,int[][] b) { //try all rotations of b and shiftCompare int[][][] rot = DOp.rotations(a[0].length); for (int i=0;i<rot.length;i++) { if (transEqual(a,map(b,rot[i]))) { return true; } } return false; } /** * verifies whether a can be rotated and shifted * to be contained or equal to be b * @return true if a is contained in b */ public static boolean motionContained(int[][] a, int[][] b) { int[][][] rot = DOp.rotations(a[0].length); for (int i=0;i<rot.length;i++) { if (transContained(a,map(b,rot[i]))) { return true; } } return false; } /** returns the number of different rotations of <b>a</b> that * are transEqual to the original <b>a</b>. Minimum is 1 because * of the identity rotation. * @param a the compound * @return number of rotations */ public static int rotationSymmetry(int[][] a) { int[][][] rot = DOp.rotations(a[0].length); int symmetry = 0; for (int i=0;i<rot.length;i++) { if (transEqual(a,map(a,rot[i]))) { symmetry++; } } return symmetry; } // /** // * // * verifies whether there is a motion to embed a into b // */ // public static boolean motionContained(int[][] a, int[][] b) { // //TODO // return true; // } /** returns the n-th 4d unit vector * i.e. 1 -> (1,0,0,0), 2-> (0,1,0,0) * for negative n returns the corresponding negated unit vector */ public static int[] unitVector(int n) { int[] r = { 0, 0, 0, 0}; if (n>0) { r[n-1] = 1; return r; } if (n<0) { r[-n-1] = -1; return r; } return r; } /** returns the n-th d-dimensional unit vector * * @see unitVector */ public static int[] unitVector(int n,int d) { int[] r = new int[d]; for (int i=0;i<d;i++) { r[i]=0; } if (n>0) { r[n-1] = 1; return r; } if (n<0) { r[n-1] = -1; return r; } return r; } /** * Compound created by going from o first into direction d[0] * then d[1], d[2], etc. Each d[i] can be the index of a unit vector * i.e. 1,2,3 or 4. Or it can be one of -1,-2,-3,-4 denoting the * inverse respective unit vector. */ public static int[][] compoundTail(int[] o,int[] d) { int[][] r = new int[1+d.length][]; r[0]=o; for (int i=0;i<d.length;i++) { r[i+1]=plus(r[i],unitVector(d[i])); } return r; } public static int[][] create4dTail(DSignedAxis[] d) { int[][] res = new int[d.length+1][]; res[0] = new int[] { 0, 0, 0, 0 }; for (int i=0;i<d.length;i++) { res[i+1] = plus(res[i],d[i].unitVector(4)); } return res; } public static int[][] create4dStar() { return new int[][] { new int[] { 0,0,0,0 }, new int[] { 1,0,0,0 }, new int[] { 0,1,0,0 }, new int[] { 0,0,1,0 }, new int[] { 0,0,0,1 }, new int[] { -1,0,0,0 }, new int[] { 0,-1,0,0 }, new int[] { 0,0,-1,0 }, new int[] { 0,0,0,-1 } }; } public static int[][] create4dCube(int d) { int[][] res = new int[d*d*d*d][]; for (int i0=0;i0<d;i0++) { for (int i1=0;i1<d;i1++) { for (int i2=0;i2<d;i2++) { for (int i3=0;i3<d;i3++) { res[d*d*d*i0+d*d*i1+d*i2+i3]=new int[] { i0,i1,i2,i3 }; } } } } return res; } public static void rotate(int[] a,int v,int w) { assert v!=w; // int sign = v.pmSign() * w.pmSign(); // int h = a[w.axis]; // a[w.axis]=sign*a[v.axis]; // a[v.axis]=-sign*h; int h = a[w]; a[w]=a[v]; a[v]=-h; } public static void rotate(int[][] a,int v,int w) { assert v!=w; for (int i=0;i<a.length;i++) { rotate(a[i],v,w); } } public static int[] rot(int[] a,int v,int w) { assert v!=w; int[] r = clone(a); // int sign, sign1=1, sign2=1; // if (v<0) { sign1=-1; } // if (w<0) { sign2=-1; } // sign = sign1 * sign2; // r[w-1]=sign*a[v-1]; // r[v-1]=-sign*a[w-1]; rotate(r,v,w); return r; } // public static int[] rot(int[] a,int[] o,int v, int w) { // return plus(rot(minus(a,o),v,w),o); // } public static void rotate(int[] a,int[] o,int v,int w) { assert v!=w; translate(a,minus(o)); rotate(a,v,w); translate(a,o); } public static void rotate(int[] a,DCenter o,int v, int w) { assert v!=w; for (int i=0;i<a.length;i++) { a[i] *= 2; } rotate(a,o.twice(),v,w); for (int i=0;i<a.length;i++) { a[i] /= 2; } } public static void rotateAsCenters(int[] a,DCenter o,int v, int w) { assert v!=w; for (int i=0;i<a.length;i++) { a[i] = a[i]*2 + 1; } rotate(a,o.twice(),v,w); for (int i=0;i<a.length;i++) { a[i] = (a[i]-1)/2; } } public static void rotate(int[][] a,DCenter o,int v, int w) { assert v!=w; for (int i=0;i<a.length;i++) { rotate(a[i],o,v,w); } } public static int[][] rot(int[][] a,int v,int w) { assert v!=w; int[][] b = clone(a); rotate(b,v,w); return b; } public static int[][] rot(int[][] a,DCenter o,int v, int w) { assert v!=w; int[][] b = clone(a); rotate(b,o,v,w); return b; } // public static void rotate(int[][] a,SignedAxis v, SignedAxis w) { // rotate(a,a[0],v,w); // } public static int[] trans(int[] a,int v) { return plus(a,unitVector(v)); } public static void translate(int[] a,DSignedAxis v) { a[v.axis] += v.pmSign(); } public static void translate(int[][] a,DSignedAxis v) { for (int i=0;i<a.length;i++) { translate(a[i],v); } } public static boolean intersecting(int[][][] compounds) { for (int i1=0;i1<compounds.length;i1++) { int[][] c1 = compounds[i1]; for (int i2=i1+1;i2<compounds.length;i2++) { int[][] c2 = compounds[i2]; for (int j1=0;j1<c1.length;j1++) { int[] t1 = c1[j1]; for (int j2=0;j2<c2.length;j2++) { int[] t2 = c2[j2]; if (vecEqual(t1,t2)) { return true; } } } } } return false; } public static int[] clone(int[] a) { int[] r = new int[a.length]; for (int i=0;i<a.length;i++) { r[i]=a[i]; } return r; } public static int[][] clone(int[][] a) { int[][] r = new int[a.length][]; for (int i=0;i<a.length;i++) { r[i] = clone(a[i]); } return r; } public static boolean d3adjacent(int[] a, int[] b) { int diff = 0; for (int ix=0;ix<a.length;ix++) { diff+=Math.abs(a[ix]-b[ix]); } return diff == 1; } public static boolean d3adjacent(int[][] a,int[][] b) { for (int i=0;i<a.length;i++) { for (int j=0;j<b.length;j++) { if (d3adjacent(a[i],b[j])) { return true; } } } return false; } public static String toString(int[] v) { String res = "["; for (int i=0;i<v.length;i++) { res += v[i]; if (i<v.length-1) { res += ","; } } res += "]"; return res; } public static void main(String[] args) { // int[][][] m = rotations(3); // for (int i=0;i<m.length;i++) { // for (int ix=0;ix<m[i].length;ix++) { // for (int iv=0;iv<m[i].length;iv++) { // System.out.print(m[i][iv][ix]+"\t"); // } // System.out.println(); // } // System.out.println(); // } int[][] c1 = { new int[] { 0, 0, 0, 0 } }; System.out.println(rotationSymmetry(c1)); System.out.println(rotationSymmetry(create4dTail(new DSignedAxis[] { new DSignedAxis(1), new DSignedAxis(2), new DSignedAxis(3), new DSignedAxis(4) }))); // System.out.println(rotationSymmetry(Objectives.LEVEL0.goal)); // System.out.println(rotationSymmetry(Objectives.LEVEL1.goal)); // System.out.println(rotationSymmetry(Objectives.LEVEL2.goal)); // System.out.println(rotationSymmetry(Objectives.LEVEL4.goal)); } }