// Calling sequence: ./subgp C1 C2 OUTFILE
//
// C1 will be the forced value for Cycle[1].  If no forcing is desired
// use the value -1.
//
// OUTFILE is for the output (can be /dev/null, of course).  There is
// also some output to standard out, to show how things are going.

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <complex.h>
#include <string.h>

#define TRUE 1
#define FALSE 0

#define MAX(a,b) ( (a)>=(b) ? (a) : (b) )
#define MIN(a,b) ( (a)<=(b) ? (a) : (b) )

#define NN 24

// WPerm2  means the the deduction should be applied to Perm2;
// WPerm3 means it should be applied to Perm3.
enum Where_t {WPerm2=66, WPerm3=77};

// Deduction Type
typedef struct {
  int Fr; // The deduction in question is that Perm[Fr]=To
  int To; // and Perm3[Fr]=To+NN/12
  enum Where_t Where;
} Ded_t;

// Deduction Stack Type
#define StackSiz (2)
typedef struct {
  Ded_t Deds[StackSiz];
  int StackIx;
} DedStack_t;

// Node Type
typedef struct {
  int Cycle[NN]; // Cycle representation of partial permutation Perm2
  int Used[NN]; // Which indices have appeared in the cycle
		// representation
  int Perm2[NN];  // Partial permutation
  int Perm3[NN];   // Perm3[Ix]=Perm2[Ix]+NN/12
  int Perm3Inv[NN]; // Inverse of Perm3
  int Where;      // Daughter nodes to be obtained by varying
		  // Cycle[Where]
  int DaughterVal; // Actual value of Cycle[Where]
  DedStack_t DedStack; // Facts/deductions to use when completing this
		       // node
} Node_t;


void DisplayNode(Node_t *Node_p);
void DisplayDedStack(DedStack_t *DStack_p);
int CompleteNode(Node_t *Node_p);
int ApplyDeds(Node_t *Node_p);
inline int ApplyDedForPerm3(Node_t *Node_p);
inline void AddDedToPerm3(Node_t *Node_p,int Ff3,int To3);
inline int ApplyDedForPerm2(Node_t *Node_p);
inline void AddDedToPerm2(Node_t *Node_p,int Fr2,int To2);
int CheckCompletedNode(Node_t *Node_p);
int Check2Completed(int Perm[]);
int Check3Completed(int Perm[]);
int RootNode(Node_t *Root_p);
int FindDaughter(Node_t *Mother_p,Node_t *Daughter_p);
void DoTerminalNode(Node_t *Term_p);
void DisplayPerm(int Perm[]);
int Check2Perm(int Perm[]);
int Check3Perm(int Perm[]);

FILE *PermFile; // Output file for ``good'' permutations
int CycleForce[NN]; // Forced values for Cycle[1], Cycle[2]

long int NodeCnt=0, TermCnt=0, Cnt4=0;

int main(int argc,char *(argv[])) {
  int NodeIx,NewNodeFg;
  Node_t Nodes[NN];

  assert(NN % 2 == 0);
  assert(NN % 3 == 0);

  memset(CycleForce,-1,sizeof(CycleForce));
  
  assert(argc==3);
  assert(sscanf(argv[1],"%i",&CycleForce[1]) == 1);
  assert(CycleForce[1]>0 && CycleForce[1]<NN || CycleForce[1]==(-1));
  PermFile=fopen(argv[2],"w");
  assert(PermFile != NULL);

  assert(RootNode(&Nodes[0])); // Set up root node

  NodeIx=0;
  NewNodeFg=TRUE;

  while(NewNodeFg) {
    NewNodeFg=FALSE;
    // Try to construct the first daughter of the actual node
    if(FindDaughter(&Nodes[NodeIx],&Nodes[NodeIx+1])) {
      NewNodeFg=TRUE;
      NodeIx++;
    }
    // If that fails, try to construct first a sister, then a sister
    // of the mother, then a sister of the grandmother, etc.
    else
      while(NodeIx>0) {
	Nodes[NodeIx-1].DaughterVal++;
	if(FindDaughter(&Nodes[NodeIx-1],&Nodes[NodeIx])) {
	  NewNodeFg=TRUE;
	  break;
	}
	else
	  NodeIx--;
      }
  }
  printf("\nTermCnt=%li, NodeCnt=%li, Cnt4=%li\n",TermCnt,NodeCnt,Cnt4);
}

// Display a node
void DisplayNode(Node_t *Node_p) {
  int Ix;
  printf("Cycle: ");
  for(Ix=0;Ix<NN;Ix++)printf("%3i",Node_p->Cycle[Ix]);
  printf("\n");

  printf("Used:   ");
  for(Ix=0;Ix<NN;Ix++)printf("%3i",Ix);    
  printf("\n  ->    ");
  for(Ix=0;Ix<NN;Ix++)printf("%3i",Node_p->Used[Ix]);
  printf("\n");

  printf("Perm2:   ");
  for(Ix=0;Ix<NN;Ix++)printf("%3i",Ix);    
  printf("\n  ->     ");
  for(Ix=0;Ix<NN;Ix++)printf("%3i",Node_p->Perm2[Ix]);
  printf("\n");

  printf("Perm3:     ");
  for(Ix=0;Ix<NN;Ix++)printf("%3i",Ix);    
  printf("\n  ->       ");
  for(Ix=0;Ix<NN;Ix++)printf("%3i",Node_p->Perm3[Ix]);
  printf("\n");

  printf("Perm3Inv:   ");
  for(Ix=0;Ix<NN;Ix++)printf("%3i",Ix);    
  printf("\n  ->        ");
  for(Ix=0;Ix<NN;Ix++)printf("%3i",Node_p->Perm3Inv[Ix]);
  printf("\n");

  printf("Where=%3i, DaughterVal=%3i\n",
	 Node_p->Where,Node_p->DaughterVal);
  
  DisplayDedStack(&Node_p->DedStack);
  printf("\n");
}  

void DisplayDedStack(DedStack_t *DStack_p) {
  int Ix;

  assert(DStack_p->StackIx<StackSiz);
  printf("Deds: ");
  for(Ix=0;Ix<=DStack_p->StackIx;Ix++) 
    printf("%3i -> %3i (%2i);  ",
	   DStack_p->Deds[Ix].Fr,DStack_p->Deds[Ix].To,DStack_p->Deds[Ix].Where);
    printf("\n");
}

// Construct the root node
int RootNode(Node_t *Root_p) {
  memset(Root_p,-1,sizeof(Node_t));
  Root_p->Where=0;
  Root_p->DaughterVal=0;
  Root_p->DedStack.StackIx=(-1);
  return CompleteNode(Root_p);
}

// Construct a daughter node
int FindDaughter(Node_t *Mother_p,Node_t *Daughter_p) {
  int Ix0,Force;
  DedStack_t *DStack_p;

  Ix0=Mother_p->Where;
  if(Ix0>=NN)return FALSE;
  assert(Ix0 % 2 != 0);

  for(;Mother_p->DaughterVal < NN;Mother_p->DaughterVal++) {

    Force=CycleForce[Ix0];
    if(Force != -1 && Mother_p->DaughterVal != Force)continue;

    if(Mother_p->Used[Mother_p->DaughterVal] != -1)continue;
    memcpy(Daughter_p,Mother_p,sizeof(Node_t));
    Daughter_p->Cycle[Ix0]=Mother_p->DaughterVal;
    Daughter_p->Used[Mother_p->DaughterVal]=Ix0;
    Daughter_p->Where++; // The daughter node will construct _her_
			 // daughters by varying Cycle[Where] with
			 // Where advanced (at least) one from the
			 // value used by the mother node
    Daughter_p->DaughterVal=0;

    DStack_p=&Daughter_p->DedStack;
    DStack_p->StackIx=0;
    DStack_p->Deds[DStack_p->StackIx].Fr=Daughter_p->Cycle[Ix0-1];
    DStack_p->Deds[DStack_p->StackIx].To=Daughter_p->Cycle[Ix0];
    DStack_p->Deds[DStack_p->StackIx].Where=WPerm2;

    DStack_p->StackIx++;
    assert(DStack_p->StackIx<StackSiz);
    DStack_p->Deds[DStack_p->StackIx].Fr=Daughter_p->Cycle[Ix0-1];
    DStack_p->Deds[DStack_p->StackIx].To=Daughter_p->Cycle[Ix0];
    DStack_p->Deds[DStack_p->StackIx].Where=WPerm3;

    if(CompleteNode(Daughter_p))return TRUE; // If all goes well,
					     // we're done
  }
  return FALSE; // No new daughter is possible for this mother
}

// Complete a node, filling in obligatory data

// (1) First, applies the deductions in DedStack and fills in as much
// of Perm2 and Perm3 as possible.  Returns FALSE if this leads to a
// contradiction.

// (2) Otherwise fills in as many successive values in Cycle as are now
// available and returns TRUE.
int CompleteNode(Node_t *Node_p) {
  int Ix,ChoiceIx,DoneFg,F,T;

  //printf("CompleteNode A: (node to complete):\n");
  //DisplayNode(Node_p);

  // Get Perm2 and Perm3 set up as fully as possible
  if(!ApplyDeds(Node_p))return FALSE;

  // See how many entries in Cycle are determined
  DoneFg=FALSE;
  while(Node_p->Where<NN && !DoneFg) {

    //printf("CompleteNode B:\n");
    //DisplayNode(Node_p);

    DoneFg=TRUE;
    // When Node_p->Where % 2 == 0, the current element in Cycle must
    // take the next unused value
    if(Node_p->Where % 2 == 0) {
      for(Ix=0;Ix<NN;Ix++)
	if(Node_p->Used[Ix] == -1)break;
      assert(Ix<NN);
      Node_p->Cycle[Node_p->Where]=Ix;
      Node_p->Used[Ix]=Node_p->Where;
      Node_p->Where++;
      DoneFg=FALSE;
    }
    else {
      // Do we already know the value of Perm as applied to the
      // previous element of Cycle?
      if(Node_p->Perm2[Node_p->Cycle[Node_p->Where-1]] != -1) {
	Node_p->Cycle[Node_p->Where]=
	  Node_p->Perm2[Node_p->Cycle[Node_p->Where-1]];
	Node_p->Used[Node_p->Cycle[Node_p->Where]]=Node_p->Where;

	// Since Perm should be completed at this point, and since we
	// have Cycle[Where-1]->Cycle[Where], we should also have
	// Cycle[Where]->Cycle[Where-1]

	assert(Node_p->Perm2[Node_p->Cycle[Node_p->Where]] == 
	       Node_p->Cycle[Node_p->Where-1]);
	
	Node_p->Where++;

	DoneFg=FALSE;
      }
    }
  }
  // Here we have completed a new node
  CheckCompletedNode(Node_p);
  NodeCnt++;

  //printf("CompleteNode C: (completed node): NodeCnt=%li\n",NodeCnt);
  //DisplayNode(Node_p);

  // If there's nothing left to vary, we have a terminal node
  if(Node_p->Where >= NN)DoTerminalNode(Node_p);
  return TRUE;
}

// Apply deductions to a node, filling in as much of Perm and Perm3 as
// possible.

// (1) Initially Node_p->DedStack contains certain deductions or facts
// to be applied to Perm and Perm3.  Each such deduction is of the
// form Perm2[To]=Fr, and concommitantly Perm3[To]=Fr+NN/12.

// (2) Taking advantage of the fact that Perm is supposed to be all
// 2-cycles, and Perm3 is supposed to be all 3-cycles (1-cycles NOT
// allowed), we may be able to make further deductions.  And based on
// those we may be able to make yet further deductions.

// (3) Returns TRUE if all goes well, FALSE if the above process leads
// to a contradiction.
int ApplyDeds(Node_t *Node_p) {
  DedStack_t *DStack_p;

  DStack_p=&Node_p->DedStack;
  assert(DStack_p->StackIx >= (-1) && DStack_p->StackIx<StackSiz);

  while(DStack_p->StackIx >= 0) {
    switch(DStack_p->Deds[DStack_p->StackIx].Where) {
    case WPerm3: // Deduction comes from Perm, must be applied to Perm3
      if(!ApplyDedForPerm3(Node_p))return FALSE;
      break;
    case WPerm2: // Deduction comes from Perm3, must be applied to Perm
      if(!ApplyDedForPerm2(Node_p))return FALSE;
      break;
    default: assert(FALSE);
    }
  }
  return TRUE;
}


// (1) Applies a deduction to Perm3 and Perm3Inv;
// (2) checks whether it is valid to apply the deduction to Perm3;
// (3) removes the applied deduction from the stack;
// (4) if possible, deduces and fills in further values of Perm3;
// (5) and adds those deductions to the stack, marked to be applied
// to Perm

inline int ApplyDedForPerm3(Node_t *Node_p) {
  int FrLoc,ToLoc,To3,C0,C1,C2,C0Prime,C1Prime;
  DedStack_t *DStack_p;

  DStack_p=&Node_p->DedStack;
  FrLoc=DStack_p->Deds[DStack_p->StackIx].Fr;
  ToLoc=DStack_p->Deds[DStack_p->StackIx].To;

  DStack_p->StackIx--; // Take this deduction off the stack

  C0=FrLoc;
  C1=(ToLoc+NN/12) % NN;
  if(Node_p->Perm3[C0] != -1 && Node_p->Perm3[C0] != C1)
    return FALSE;
  if(Node_p->Perm3Inv[C1] != -1 && Node_p->Perm3Inv[C1] != C0)
    return FALSE;
  if(C0 == C1)return FALSE;

  Node_p->Perm3[C0]=C1; // Apply the given deduction to Perm3
  Node_p->Perm3Inv[C1]=C0;

  C2=Node_p->Perm3[C1];
  if(C2 != -1) {
    if(C2 == C0)
      return FALSE;
    else {
      C0Prime=Node_p->Perm3[C2];
      if(C0Prime != C0) {
	if(C0Prime != -1)
	  return FALSE;
	else  // We have deduced that Perm3[C2]=C0
	  AddDedToPerm3(Node_p,C2,C0);
      }
    }
  }
  else { // C2 == -1, working forward from C1
    C2=Node_p->Perm3Inv[C0];
    if(C2 != -1) {
      if(C2 == C1)return FALSE;
      C1Prime=Node_p->Perm3Inv[C2];
      if(C1Prime != C1)
	if(C1Prime != -1)
	  return FALSE;
	else // We have deduced that Perm3[C1]=C2
	  AddDedToPerm3(Node_p,C1,C2);
    }
  }
  return TRUE;
}

// Adds a deduction to Perm3; adds an entry to the deduction stack to 
// apply this deduction to Perm
inline void AddDedToPerm3(Node_t *Node_p,int Fr3,int To3) {
  DedStack_t *DStack_p;

  DStack_p=&Node_p->DedStack;

  // Modify Perm3 and Perm3Inv to take account of the deduction
  Node_p->Perm3[Fr3]=To3;
  Node_p->Perm3Inv[To3]=Fr3;
  // Add the entry on the stack so the same deduction will be applied
  // also to Perm
  DStack_p->StackIx++;
  assert(DStack_p->StackIx<StackSiz);
  DStack_p->Deds[DStack_p->StackIx].Fr=Fr3;
  DStack_p->Deds[DStack_p->StackIx].To=(To3-2+NN) % NN;
  DStack_p->Deds[DStack_p->StackIx].Where=WPerm2;
  return;
}

  // (1) Applies a deduction to Perm2;
  // (2) checks whether it is valid to apply the deduction to Perm2;
  // (3) removes the applied deduction from the stack;
  // (4) if possible, deduces and fills in further values of Perm2;
  // (5) and adds those deductions to the stack, marked to be applied
  // to Perm3
  inline int ApplyDedForPerm2(Node_t *Node_p) {
    int FrLoc,ToLoc,C0,C1;
    DedStack_t *DStack_p;

    DStack_p=&Node_p->DedStack;
    FrLoc=DStack_p->Deds[DStack_p->StackIx].Fr;
    ToLoc=DStack_p->Deds[DStack_p->StackIx].To;

    DStack_p->StackIx--; // Take this deduction off the stack

    C0=FrLoc;
    C1=ToLoc;
    if(Node_p->Perm2[C0] != -1 && Node_p->Perm2[C0] != C1)
      return FALSE;
    if(C0 == C1)return FALSE;

    Node_p->Perm2[C0]=C1; // Apply the given deduction to Perm2

    // If Perm2[C1]=C0, also Perm2[C0]=C1
    AddDedToPerm2(Node_p,C1,C0);
    return TRUE;
 }

  // Adds a deduction to Perm2; adds an entry to the deduction stack
  // to apply this deduction to Perm3.
  inline void AddDedToPerm2(Node_t *Node_p,int Fr2,int To2) {
    DedStack_t *DStack_p;

    DStack_p=&Node_p->DedStack;

    //printf("AddDedToPerm: Fr0=%i, To0=%i\n",Fr2,To2);

    // Modify Perm2 to take account of the deduction
    Node_p->Perm2[Fr2]=To2;

    // Add the entry on the stack so the same deduction will be applied
    // also to Perm2
    DStack_p->StackIx++;
    assert(DStack_p->StackIx<StackSiz);
    DStack_p->Deds[DStack_p->StackIx].Fr=Fr2;
    DStack_p->Deds[DStack_p->StackIx].To=To2;
    DStack_p->Deds[DStack_p->StackIx].Where=WPerm3;
    return;
  }

// Checks the permutations in a _completed_ node:

// (1) Perm2, Perm3, and Perm3Inv (all partial permutations)
// should correspond.  For Perm3, this means Perm3[Ix]=Perm2[Ix]+NN/12;

// (2) Perm2 should not have anything which would prevent it from being
// finished so as to be a permutation of cycle-type 12(2);

// (3) and moreover any values of Perm deducible from the fact that
// the finished permutation will be finished to have cycle-type 12(3)
// should already be included;

// (4) Perm3 should not have anything which would prevent it from being
// finished so as to be a permutation of cycle-type 8(3)

// (5) and moreover any values of Perm3 deducible from the fact that
// the permutation will finished to have cycle-type 8(3) should
// already be included.

int CheckCompletedNode(Node_t *Node_p) {
  int Ix,CntPerm2,CntPerm3,CntPerm3Inv,FrLoc,ToLoc;

  // See how many values are filled in
  CntPerm2=CntPerm3=CntPerm3Inv=0;
  for(Ix=0;Ix<NN;Ix++) {
    if(Node_p->Perm2[Ix] != -1)CntPerm2++;
    if(Node_p->Perm3[Ix] != -1)CntPerm3++;
    if(Node_p->Perm3Inv[Ix] != -1)CntPerm3Inv++;
  }
  // Values should be the same
  assert(CntPerm2 == CntPerm3);
  assert(CntPerm3 == CntPerm3Inv);

  for(Ix=0;Ix<NN;Ix++) {
    FrLoc=Ix;
    ToLoc=Node_p->Perm2[FrLoc];
    if(ToLoc == -1)continue;
    // One filled in value is Perm2[FrLoc]=ToLoc:
    // check whether the corresponding values are filled in
    // in the other permuation vectors
    assert(Node_p->Perm3[FrLoc] == (ToLoc+NN/12) % NN);
    assert(Node_p->Perm3Inv[(ToLoc+NN/12) % NN] == FrLoc);
  }

  assert(Check2Completed(Node_p->Perm2));
  assert(Check3Completed(Node_p->Perm3));

  return TRUE;
}

// Checks whether a _partial_ permutation Perm might be finished so as
// to become a permutation with only 2-cycles (1-cycles not allowed).

// Moreover, checks whether any entries of Perm deducible from the
// fact that it is to be finished so as to have only 2-cycles have
// already been included.

int Check2Completed(int Perm[]) {
  int PermX[NN+1],Iterates[5][NN],Ix,IterIx;

  for(Ix=0;Ix<NN;Ix++)
    if(Perm[Ix] == -1)
	PermX[Ix]=NN; // Use NN for the missing value
    else if (Perm[Ix]>=0 && Perm[Ix]<NN)
	PermX[Ix]=Perm[Ix];
    else
	assert(FALSE);
  PermX[NN]=NN;

  for(Ix=0;Ix<NN;Ix++)
    Iterates[0][Ix]=Ix;

  for(IterIx=1;IterIx<3;IterIx++)
    for(Ix=0;Ix<=NN;Ix++)
	Iterates[IterIx][Ix]=PermX[Iterates[IterIx-1][Ix]];

  // For a chain C0 -> C1 -> C2
  for(Ix=0;Ix<NN;Ix++) {
    assert(Iterates[0][Ix] != Iterates[1][Ix]); // C0 != C1
    if(Iterates[2][Ix] != NN)
	// Here C1 is filled in
	assert(Iterates[2][Ix] == Iterates[0][Ix]); // C2 == C0
  }
  return TRUE;
}

// Checks whether a _partial_ permutation Perm might be finished so as
// to become a permutation made up of all 3-cyces (no 1-cycles
// allowed);

// Moreover, checks whether any entries of Perm deducible from the
// fact that it is to be finished so as to have only 3-cycles have
// already been included.

int Check3Completed(int Perm[]) {
  int PermX[NN+1],Iterates[4][NN],Ix,IterIx;

  for(Ix=0;Ix<NN;Ix++)
    if(Perm[Ix] == -1)
      PermX[Ix]=NN;
    else if (Perm[Ix]>=0 && Perm[Ix]<NN)
      PermX[Ix]=Perm[Ix];
    else
      assert(FALSE);
  PermX[NN]=NN;

  for(Ix=0;Ix<NN;Ix++)
    Iterates[0][Ix]=Ix;

  for(IterIx=1;IterIx<4;IterIx++)
    for(Ix=0;Ix<=NN;Ix++)
      Iterates[IterIx][Ix]=PermX[Iterates[IterIx-1][Ix]];

  // For a chain C0 -> C1 -> C2 -> C3
  for(Ix=0;Ix<NN;Ix++) {
    assert(Iterates[0][Ix] != Iterates[1][Ix]); // C0 != C1
    assert(Iterates[0][Ix] != Iterates[2][Ix]); // C0 != C2
    if(Iterates[2][Ix] != NN)
      // Here C1 and C2 are filled in
      assert(Iterates[0][Ix] == Iterates[3][Ix]); // C0 == C3
  }
  return TRUE;
}

/* This routine treats a terminal node */
void DoTerminalNode(Node_t *Term_p) {
  int Ix;

  TermCnt++;
  assert(Check2Perm(Term_p->Perm2));
  if(Check3Perm(Term_p->Perm3)) {
    Cnt4++;
    for(Ix=0;Ix<NN;Ix++)fprintf(PermFile,"%3i",Term_p->Perm2[Ix]);
    fprintf(PermFile,"\n");
    if(Cnt4 % 10000 == 0) {
	printf("C%10i ",Cnt4);
	DisplayPerm(Term_p->Perm2);
	fflush(stdout);
	fflush(PermFile);
	if(Cnt4 % 100000 == 0) {
	  printf("XX Cnt4= %i TermCnt= %li NodeCnt= %li, NodeCnt/Cnt4= %.1f\n",
		 Cnt4,TermCnt,NodeCnt,(double) NodeCnt/(double) Cnt4);
	}
    }
  }
  return;

}

void DisplayPerm(int Perm[]) {
  int StartIx,Ix,Displayed[NN];

  memset(Displayed,0,sizeof(Displayed));

  StartIx=0;
  while(StartIx<NN) {
    printf("(");
    Ix=StartIx;
    while(TRUE) {
	printf("%3i",Ix);
	Displayed[Ix]=TRUE;
	Ix=Perm[Ix];
	if(Ix == StartIx)break;
    }
    printf(") ");
    for(StartIx++;StartIx<NN && Displayed[StartIx];StartIx++);
  }
  printf("\n");

  return;
}
    
// Check whether a permutations is all 2-cycles (1-cycles NOT allowed)
int Check2Perm(int Perm[]) {
  int Ix,C0,C1,Checked[NN];

  memset(Checked,FALSE,sizeof(Checked));

  for(Ix=0;Ix<NN;Ix++) {
    if(Checked[Ix])continue;
    C0=Ix;
    C1=Perm[C0];
    if(C0 == C1)return FALSE;
    if(C0 != Perm[C1])return FALSE;
    Checked[C0]=Checked[C1]=TRUE;
  }

  return TRUE;
}

// Check whether a permutations is all 3-cycles (1-cycles NOT allowed)
int Check3Perm(int Perm[]) {
  int Ix,C0,C1,C2,Checked[NN];

  memset(Checked,FALSE,sizeof(Checked));

  for(Ix=0;Ix<NN;Ix++)assert(Perm[Ix]>=0 && Perm[Ix]<NN);

  for(Ix=0;Ix<NN;Ix++) {
    if(Checked[Ix])continue;
    C0=Ix;
    C1=Perm[C0];
    if(C0 == C1)return FALSE;
    C2=Perm[C1];
    if(C0 != Perm[C2])return FALSE;
    Checked[C0]=Checked[C1]=Checked[C2]=TRUE;
  }

  return TRUE;
}
