package Current.plot.Dyadic; import Current.popups.Unfold.*; import Current.basic.*; import Current.*; import java.applet.Applet; import java.awt.event.*; import java.awt.*; import java.awt.geom.*; public class DyadicPlotter { int mode; int detail; // detail of the plot to do int type_of_plot; int filter; Color C; public Complex Z; //defining functions int[][][] denominator=new int[3][3][1000]; int[][] numerator=new int[4][1000]; CombinatorialTriangle[] CT; int[] top; int[] bot; int palindrome; int spine; String W; int sign; VertexPair V; int[][] record=new int[2][2000]; //lists of dyadic squares DyadicSquare INIT; DyadicSquare[] D=new DyadicSquare[10000]; DyadicSquare[] DEF=new DyadicSquare[10000]; DyadicSquare[] IN=new DyadicSquare[10000]; int D_N,IN_N,DEF_N; //memory VertexPair[] VP=new VertexPair[5000]; Complex[][] CORNER=new Complex[3][3]; int corner[]=new int[3]; Complex[][] data=new Complex[3][11]; int SMALL; //billiard like input Complex[] BL; Complex BL_CENTER; int right,obtuse; DyadicPlotterInit DPI; //for the zone plotter VertexPair LEADER; Interrupter I; public DyadicPlotter(int mode, int type_of_plot, int detail,int filter, String word, Color C, Interrupter I) { this.mode=mode; this.type_of_plot=type_of_plot; this.detail=detail; this.filter=filter; this.C=C; this.I=I; doReset(word); } public static DyadicTile zonePlot(int type_of_plot,String word,int detail,Color C,Complex Z, Interrupter I) { double time1=System.currentTimeMillis(); DyadicTile T=null; DyadicPlotter PRE=new DyadicPlotter(2,0,1,1,word,C, I); PRE.doReset(word); GeneralPath gp=new GeneralPath(); while(PRE.D_N>0) PRE.processSquare(); int[][] y=VertexPairOrganizer.pairSurvivalList(PRE.INIT,PRE.IN,PRE.IN_N,PRE.DEF,PRE.DEF_N); int[] TOP=PRE.INIT.top; int[] BOT=PRE.INIT.bot; int[] top=PRE.top; int[] bot=PRE.bot; if(type_of_plot<2) { for (int i=1; i<=TOP[0]; i++) { for (int j=1; j<=BOT[0]; j++) { if(y[i][j]==1) { DyadicPlotter DP=new DyadicPlotter(4,type_of_plot,detail,1,word, C, I); DP.doReset(word); DP.LEADER=new VertexPair(1,top[TOP[i]],2,bot[BOT[j]]); T=DP.continuePlot(PRE); if (T!=null) gp.append(new GeneralPath(T.P),false); } } } } if(type_of_plot==2) { DyadicPlotter DP=new DyadicPlotter(4,type_of_plot,detail,1,word, C, I); DP.Z=Z; DP.doReset(word); DP.setLeader(); T=DP.continuePlot(PRE); if (T!=null) gp.append(new GeneralPath(T.P),false); } double time2=System.currentTimeMillis(); double time=time2-time1; System.out.println("time: "+time); return(new DyadicTile(word,gp,C)); } public DyadicTile basicPlot() { double time1=System.currentTimeMillis(); if (BL==null) return null; // b-like tile is empty while ((D_N>0)&&(!I.isInterrupted())) // added to check to see if the plot has been interrupted processSquare(); if (I.isInterrupted()) return null; // if interrupted then return null DyadicTile DT=plot(); if(type_of_plot==2) { DT.record=record; DT.record_active=1; DT.Z=Z; if(IN_N>0) DT.Z=IN[0].getCenter(); if(DEF_N>0) DT.dyadic_size=DEF[0].k; if(IN_N>0) DT.dyadic_size=IN[0].k; } double time2=System.currentTimeMillis(); double time=time2-time1; System.out.println("time: "+time); return DT; } // call only if type of plot is 4 (solid or boxes or find) public DyadicTile continuePlot(DyadicPlotter PRE) { //here the the copy part for(int i=0;i0) processSquare(); DyadicTile DT=plot(); return DT; } public DyadicTile plot() { if(mode<=2) { if(type_of_plot==0) return DyadicPlotHandler.plotSolid(W,IN,IN_N,DEF,DEF_N,CORNER,corner,C); else return DyadicPlotHandler.plotBoxes(W,IN,IN_N,DEF,DEF_N,CORNER,corner,C); } if(mode==3) { if(type_of_plot==0) return DyadicPlotHandler.coverPlotSolid(W,IN,IN_N,DEF,DEF_N,CORNER,corner,C); else return DyadicPlotHandler.coverPlotBoxes(W,IN,IN_N,DEF,DEF_N,CORNER,corner,C); } if(mode==4) { if(type_of_plot!=1) return DyadicPlotHandler.medianPlotSolid(W,LEADER,INIT,IN,IN_N,DEF,DEF_N,CORNER,corner,C); else return DyadicPlotHandler.medianPlotBoxes(W,LEADER,INIT,IN,IN_N,DEF,DEF_N,CORNER,corner,C); } return null; } //All the stuff above is just wrapping. Here is the real start of the // plotting algorithm. public void doReset(String word) { DPI=new DyadicPlotterInit(word,filter); BL=DPI.BL; BL_CENTER=DPI.BL_CENTER; CORNER=DPI.CORNER; corner=DPI.corner; INIT=DPI.INIT; D[0]=DPI.D; record=DPI.record; CT=DPI.CT; palindrome=DPI.palindrome; right=DPI.right; obtuse=DPI.obtuse; V=new VertexPair(); VP[0]=new VertexPair(0,0,0,0); VP[0].cert=0; SMALL=4; W=word; top=Spine.completeList(1,CT); bot=Spine.completeList(2,CT); D_N=1; IN_N=0; DEF_N=0; denominator[0]=Function.computeDenominator(0,CT); denominator[1]=Function.computeDenominator(1,CT); denominator[2]=Function.computeDenominator(2,CT); } /**FUNCTION CREATION AND EVALUATION*/ //in the non-palindrome case, this routine just sets the sign and spine number public int[][] getSignedNumerator() { int[][]f=new int[0][0]; if(palindrome==0) { spine=Converter.spineNumber(V,CT); sign=Spine.getSign(V,CT,denominator[spine]); } if(palindrome==1) { spine=Converter.spineNumber(V,CT); f=PalindromeFunction.getFunction(denominator[spine],V,CT); } return(f); } //the basic evaluation routine public double evaluate(Complex Z) { if(palindrome==0) { double val=Spine.evaluate(sign,V,CT,denominator[spine],Z); return(val); } if(palindrome==1) return(PalindromeFunction.evaluate(numerator,Z)); return(0); } //this routine uses the function certificates computed below. public int signEvaluate(int cert) { DyadicSquare A=D[D_N-1]; if(palindrome==1) return(PalindromeFunction.signEvaluate(numerator,A,cert)); if(palindrome==0) { int test=0; int gm=getMatchNumber(); if(gm>SMALL) test=Spine.signEvaluate(sign,V,CT,data[spine],A,cert); if(gm<=SMALL) test=Spine.signEvaluate(sign,V,CT,denominator[spine],A,cert); return(test); } return(0); } public int crudePositiveTest() { DyadicSquare A=D[D_N-1]; if(palindrome==1) return(PalindromeFunction.crudePositiveTest(numerator,A)); if(palindrome==0) { int[] a=lookup3(); if(a[0]+a[1]+a[2]==0) { a=Spine.absSecond(V,CT,denominator[spine]); ++VP[0].cert; VP[VP[0].cert]=new VertexPair(V.o1,V.e1,V.o2,V.e2,a[0],a[1],a[2]); } int test=0; int gm=getMatchNumber(); if(gm>SMALL) test=Spine.crudePositiveTest(sign,V,CT,data[spine],A,a); if(gm<=SMALL) test=Spine.crudePositiveTest(sign,V,CT,denominator[spine],A,a); return(test); } return(0); } /**FUNCTION CERTIFICATES: These routines are designed to certify that * a given defining function is quadrantic in a given square. A function * is quadrantic in a region if its gradient lies in a quadrant throughout * that region. The first routine does the computations. This routine * is somewhat costly to compute, and so we store any certificates * we do compute, for later use. The second and third routines manage * this storing and looking up of certificates.*/ public int certify() { DyadicSquare A=D[D_N-1]; if(palindrome==1) { return(PalindromeFunction.certify(numerator,A)); } if(palindrome==0) { int[] a=lookup3(); if(a[0]+a[1]+a[2]==0) { a=Spine.absSecond(V,CT,denominator[spine]); ++VP[0].cert; VP[VP[0].cert]=new VertexPair(V.o1,V.e1,V.o2,V.e2,a[0],a[1],a[2]); } int test=0; int test2=0; int gm=getMatchNumber(); if(gm>SMALL) test=Certify.certify(sign,V,CT,data[spine],A,a); if(gm<=SMALL) test=Certify.certify(sign,V,CT,denominator[spine],A,a); return(test); } return(0); } public int[] lookupCertify(int q) { DyadicSquare A=D[D_N-1]; int[] cert=new int[2]; cert[0]=0; cert[1]=0; if(q==1) cert[1]=lookup1(); if(q==2) cert[1]=lookup2(); if(cert[1]>0) cert[0]=cert[1]; if(cert[1]==0) cert[0]=certify(); return(cert); } public void recordCertify(int q,int[] cert) { DyadicSquare A=D[D_N-1]; if(q==1) { if((cert[1]==0)&&(cert[0]>0)) { //record certificate for later use ++A.V1[0].cert; int L=A.V1[0].cert; A.V1[L]=new VertexPair(V.o1,V.e1,V.o2,V.e2); A.V1[L].cert=cert[0]; }} if(q==2) { if((cert[1]==0)&&(cert[0]>0)) { //record certificate for later use ++A.V2[0].cert; int L=A.V2[0].cert; A.V2[L]=new VertexPair(V.o1,V.e1,V.o2,V.e2); A.V2[L].cert=cert[0]; }} } /**LOOKING UP STORED INFORMATION*/ public int compare(VertexPair VV1,VertexPair VV2) { if(VV1.o1!=VV2.o1) return(0); if(VV1.e1!=VV2.e1) return(0); if(VV1.o2!=VV2.o2) return(0); if(VV1.e2!=VV2.e2) return(0); return(VV2.cert); } public int lookup1() { int N=D[D_N-1].V1[0].cert; int cert=0; for(int i=N;i>=1;--i) { cert=compare(V,D[D_N-1].V1[i]); if(cert!=0) return(cert); } return(0); } public int lookup2() { int N=D[D_N-1].V2[0].cert; int cert=0; for(int i=N;i>=1;--i) { cert=compare(V,D[D_N-1].V2[i]); if(cert!=0) return(cert); } return(0); } public int[] compare3(VertexPair VV1,VertexPair VV2) { int[] a=new int[3]; a[0]=0; a[1]=0; a[2]=0; int test=1; if(VV1.o1!=VV2.o1) test=0; if(VV1.e1!=VV2.e1) test=0; if(VV1.o2!=VV2.o2) test=0; if(VV1.e2!=VV2.e2) test=0; if(test==1) { a[0]=VV2.a20; a[1]=VV2.a11; a[2]=VV2.a02; } return(a); } public int[] lookup3() { int N=VP[0].cert; int[] a=new int[3]; a[0]=0; a[1]=0; a[2]=0; for(int i=N;i>=1;--i) { a=compare3(V,VP[i]); if(a[0]!=0) return(a); } return(a); } public int getMatchNumber() { return(D[D_N-1].top[0]*D[D_N-1].bot[0]); } /**HERE IS THE ALGORITHM*/ public void processSquare() { int action=determineAction(); if(action==-1) --D_N; if(action==0) refineList(); if(action==1) addToInsiders(); if(action==2) addToDefiners(); } public void refineList() { DyadicSquare A=D[D_N-1]; D[D_N-1]=DyadicSquare.subdivideAndRemember(0,0,A); D[D_N+0]=DyadicSquare.subdivideAndRemember(0,1,A); D[D_N+1]=DyadicSquare.subdivideAndRemember(1,1,A); D[D_N+2]=DyadicSquare.subdivideAndRemember(1,0,A); D_N=D_N+3; } public void addToInsiders() { DyadicSquare A=D[D_N-1]; IN[IN_N]=new DyadicSquare(A.x,A.y,A.k); IN[IN_N].top=new int[300]; IN[IN_N].bot=new int[300]; IN[IN_N].top[0]=A.top[0]; IN[IN_N].bot[0]=A.bot[0]; for(int i=1;i<=A.top[0];++i) { IN[IN_N].top[i]=A.top[i]; } for(int i=1;i<=A.bot[0];++i) { IN[IN_N].bot[i]=A.bot[i]; } if((mode<4)&&(type_of_plot>=2)) { Z=A.getCenter(); // set Z D_N=0; } ++IN_N; --D_N; } public void addToDefiners() { if(mode>1) { DyadicSquare A=D[D_N-1]; DEF[DEF_N]=new DyadicSquare(A.x,A.y,A.k); DEF[DEF_N].top=new int[300]; DEF[DEF_N].bot=new int[300]; DEF[DEF_N].top[0]=A.top[0]; DEF[DEF_N].bot[0]=A.bot[0]; for(int i=1;i<=A.top[0];++i) { DEF[DEF_N].top[i]=A.top[i]; } for(int i=1;i<=A.bot[0];++i) { DEF[DEF_N].bot[i]=A.bot[i]; } ++DEF_N; } --D_N; } public int determineAction() { DyadicSquare A=D[D_N-1]; //in box mode, check if box contains point if((mode<4)&&(type_of_plot==2)) { int touch=ConvexIntersector.checkTouch(Z,A.toPolygon()); if(touch==0) return(-1); } //in general, check if box intersects billiard-like tile int test=ConvexIntersector.checkDisjoint(A,BL); if(test==3) return(-1); //does not intersect tile if(test==2) return(0); //contains tile //for tiles which might intersect corner of parameter space for(int ii=0;ii<3;++ii) { if(corner[ii]!=0) { int test0=ConvexIntersector.checkNearCorner(A,CORNER[ii]); if(test0==1) return(-1); } } //if there are many matches to be played we precompute the denominators int gm=getMatchNumber(); if(gm>SMALL) { data[0]=Function.assignData(denominator[0],A); data[1]=Function.assignData(denominator[1],A); data[2]=Function.assignData(denominator[2],A); } //in the zone modes, we see if the vertex pair of interest //is amongst the list associated to the box if(mode>=4) { int a=CT[LEADER.e1].c[1]; int b=CT[LEADER.e2].c[2]; if(VertexPairOrganizer.checkAppears(a,b,A)==0) return(-1); } //now for the real action tournament(); int p=0; p=playoffs(); if(p==-1) return(-1); //box is outside tile;all modes if((mode<=3)&&(p==1)) return(1); //box is inside tile;ordinary modes if((mode>=4)&&(p==1)) { //box is inside tile;zone mode ++D[D_N-1].age[1]; if(2*D[D_N-1].age[1]>detail) return(1); if(gm==1) return(1); //single leader if(checkDominant(A)==1) return(1); //last resort for eliminating box } //at this point p=0, meaning that the playoffs are inconclusive. p=checkCertified(); if(p==2) ++D[D_N-1].age[0]; if(D[D_N-1].age[0]>detail) return(2); return(0); } public void tournament() { int STOP=1; while(STOP!=0) STOP=round(1); STOP=1; while(STOP!=0) STOP=round(2); } public int round(int q) { int match=0; int count=0; int previous=0; int elim=0; int BEFORE=0; DyadicSquare A=D[D_N-1]; if(q==1) BEFORE=A.top[0]; if(q==2) BEFORE=A.bot[0]; for(int i=1;i0) return(2); } return(0); } public int ordinaryMatch() { numerator=getSignedNumerator(); int match=0; int[] cert=lookupCertify(1); recordCertify(1,cert); //special case for tiles abutting right angle line if((cert[0]>0)&&(palindrome==1)&&(right==1)&&(obtuse==1)) { match=rightMatch(); if(V.o1*V.o2==1) match=3-match; if(match==2) return(2); if(match==1) return(1); } //regular case: do the match match=signEvaluate(cert[0]); if(V.o1*V.o2==1) match=3-match; if(match==1) return(1); if(match==2) return(2); return(0); } /**this routine is the same as the previous one, except that * we're more conservative about storing certificates. We * don't want the list of certificates to blow up.*/ public int playoffMatch() { int quick=0; quick=lookup2(); if(quick>10) return(2); numerator=getSignedNumerator(); quick=crudePositiveTest(); if(quick==1) return(2); int[] cert=new int[2]; cert=lookupCertify(2); int match=0; match=signEvaluate(cert[0]); //do actual match if(match==2) cert[0]=10+cert[0]; if(getMatchNumber()<25) recordCertify(2,cert); return(match); } //FOR THE ZONE PLOTTER public double[] getValues(SmallPolygon P) { double[] x=new double[P.N]; numerator=getSignedNumerator(); for(int i=0;i.000000000001) return(0); } return(1); } public int checkDominant(DyadicSquare Q) { Complex[] ZZ=Q.toPolygon(); SmallPolygon P=new SmallPolygon(ZZ,4); int test=1; for(int i=1;i<=Q.top[0];++i) { V=new VertexPair(1,LEADER.e1,1,top[Q.top[i]]); if(V.e1>V.e2) test=checkPositive(P); if(V.e1V.e2) test=checkNegative(P); if(test==0) return(0); } return(1); } //for the zone plotter public void setLeader() { Corridor COR=new Corridor(); LEADER=COR.getLeader(W,Z); if(palindrome==0) { int v1=CT[LEADER.e1].c[1]; if(v1>W.length()/2) LEADER.e1=1; int v2=CT[LEADER.e2].c[2]; if(v2>W.length()/2) LEADER.e2=1; } if(palindrome==1) { int n=W.length(); int a=CT[LEADER.e1].c[1]; int b=CT[LEADER.e2].c[2]; if(a>INIT.top.length) a=n/2+2-a; if(b>INIT.top.length) b=n/2+2-b; LEADER.e1=top[a]; LEADER.e2=bot[b]; } } }