diff options
Diffstat (limited to 'nauty/traces.c')
| -rw-r--r-- | nauty/traces.c | 10490 |
1 files changed, 10490 insertions, 0 deletions
diff --git a/nauty/traces.c b/nauty/traces.c new file mode 100644 index 0000000..78b397d --- /dev/null +++ b/nauty/traces.c @@ -0,0 +1,10490 @@ +/****************************************************************************** + * * + * This is the main file for traces() version 2.2, which is included into * + * nauty() version 2.8.6. * + * * + * nauty is Copyright (1984-2018) Brendan McKay. All rights reserved. * + * Traces is Copyright Adolfo Piperno, 2008-2018. All rights reserved. * + * See the file COPYRIGHT for the details of the software license. * + * * + * CHANGE HISTORY * + * 28-Dec-12 : final changes for version 2.0 * + * 20-Jan-13 : add code for ^C catching in Traces * + * 29-Mar-13 : bug correction in automorphism mode * + * 02-Apr-13 : add preprocessing * + * 21-May-13 : bug correction (coloured lists) * + * 29-Jun-13 : bug correction (coloured lists and cycles) * + * 07-Dec-13 : bug correction in automorphism mode (wrong group size * + * due to randomness in Schreier-Sims orbit computation) * + * bug correction (discrete initial partition) * + * 15-Feb-14 : CPUDEFS removed (already declared in gtools.h) * + * 01-Sep-15 : add weighted edges (not active) * + * 28-Jan-16 : version ready for nauty and Traces v.2.6 distribution * + * 12-Jul-16 : bug correction (reaching degree 2 vertices) * + * 07-Jun-18 : bug correction (finalnumcells, thanks R.Kralovic) * + * 07-Jun-18 : bug correction (index computation when findperm) * + * 10-Nov-22 : bug correction (cycles in degree 2 subgraphs) * + *****************************************************************************/ + +#include "traces.h" + +#ifdef NAUTY_IN_MAGMA +#include "cleanup.e" +#endif + +#define SORT_OF_SORT 2 +#define SORT_NAME sort2ints +#define SORT_TYPE1 int +#define SORT_TYPE2 int +#include "sorttemplates.c" + +typedef struct weightwhere { + int weight; + int *ref; +} weightwhere; + +#define SORT_OF_SORT 2 +#define SORT_NAME sortweights +#undef SORT_TYPE2 +#define SORT_TYPE1 int +#define SORT_TYPE2 weightwhere +#include "sorttemplates.c" + +#define NAUTY_ABORTED (-11) +#define NAUTY_KILLED (-12) + +typedef struct Candidate { + boolean sortedlab; + int *invlab; + int *lab; + int code; + int do_it; + int indnum; + int name; + int vertex; + struct Candidate *next; + struct searchtrie *stnode; + unsigned int firstsingcode; + unsigned int pathsingcode; + unsigned int singcode; +} Candidate; + +typedef struct Partition { + int *cls; + int *inv; + int active; + int cells; + int code; +} Partition; + +typedef struct trielist { + struct searchtrie *triearray; + struct trielist *prev; + struct trielist *next; +} trielist; + +typedef struct TracesVars { + char digstring[25]; + double autchk; + double expaths; + double schreier1; + double schreier2; + double schreier3; + int augmented_cells; + int build_autom; + int *currorbit; + int *orbits; + int answ; + int brkstpcount; + int compstage; + int cand_level; + int canlist; + int digits; + int expathlength; + int firstpathlength; + int fromlevel; + int group_level; + int indivend; + int indivstart; + int indiv_vtx; + int lastcell; + int lastlev; + int lev_of_lastauto; + int levelfromCS0; + int linelgth; + int mark; + int treemark; + int autmark; + int markcell1; + int markcell2; + int maxdeg; + int maxtreelevel; + int maxspineorblevel; + int mindeg; + int name; + struct searchtrie *gotonode; + struct searchtrie *newgotonode; + struct searchtrie *newst_stage1; + int newindex; + int nextlevel; + int nfix; + int finalnumcells; + int permInd; + int preprocessed; + int samepref; + int specialgens; + int stackmark; + int steps; + int strategy; + trielist *strielist; + int strienext; + int tcell_sz; + int tcell; + int tcellevel; + int tcellexpath_sz; + int tcellexpath; + int tolevel_tl; + int tolevel; + int treedepth; + int trienext; + int triepos; + TracesOptions *options; + TracesStats *stats; + unsigned int singlongcode; + sparsegraph *graph; + sparsegraph *cangraph; + sparsegraph *input_graph; + int conta0; + int conta1; + int conta2; + int conta3; + int conta4; + int conta5; + int conta6; + int conta7; + int contatc; +} TracesVars; + +typedef struct TracesInfo { + boolean autofound; + boolean deg_one; + boolean first_matching; + boolean regular; + boolean exitfromref; + boolean identitygroup; + boolean minimalinorbits; + boolean thegraphisparse; + boolean thegrouphaschanged; + boolean thereisnextlevel; + boolean useTempOrbits1; + boolean useTempOrbits2; +} TracesInfo; + +typedef struct TracesSpine { + boolean thetracexists; + Candidate *listend; + Candidate *liststart; + int ccend; + int ccstart; + int listcounter; + int stpend; + int stpstart; + int tgtcell; + int tgtend; + int tgtfrom; + int tgtpos; + int tgtsize; + int trcend; + int trcstart; + int singend; + int singstart; + int updates; + unsigned long keptcounter; + unsigned long levelcounter; + Partition *part; + unsigned int singcode; +} TracesSpine; + +typedef struct trie { + int value; + struct trie *first_child; + struct trie *next_sibling; +} trie; + +typedef struct searchtrie { + int index; + int name; + int vtx; + int level; + struct searchtrie *father; + struct searchtrie *first_child; + struct searchtrie *last_child; + struct searchtrie *next_sibling; + struct searchtrie *goes_to; +} searchtrie; + +typedef struct pair { + int arg; + int val; +} pair; + +typedef struct grph_strct { + int *e; + int *w; + int d; + boolean one; +} grph_strct; + +typedef struct ExpPathInfo { + int code; + int cell; + int info; +} ExpPathInfo; + +static boolean traces_degree_refine(sparsegraph*, Candidate*, int, Partition*, + struct TracesVars*, struct TracesInfo*, int, int*); +static int traces_vertexclass_refine (int, int*, int*, Candidate*, Partition*, int*); +static int traces_refine(Candidate*, int, Partition*, + struct TracesVars*, struct TracesInfo*, int, boolean); +static void traces_refine_notrace(Candidate*, int, Partition*, + struct TracesVars*, struct TracesInfo*); +static void traces_refine_maketrie(Candidate*, int, Partition*, + struct TracesVars*, struct TracesInfo*); +static int traces_refine_comptrie(Candidate*, int, Partition*, + struct TracesVars*, struct TracesInfo*); +static int traces_refine_sametrace(Candidate*, int, Partition*, + struct TracesVars*, struct TracesInfo*); +static int traces_refine_refine(sparsegraph*, Candidate*, int, Partition*, + struct TracesVars*, struct TracesInfo*); +static void refine_tr_refine(Candidate*, int, Partition*, + struct TracesVars*, struct TracesInfo*); +static int given_gens(sparsegraph*, permnode*, int*, boolean); +static void quickSort(int*, int); +static struct Partition* NewPartition(int); +static struct Candidate* NewCandidate(int, Candidate**, int); +static void NewPartSpine(int, int); +static int FreeList(Candidate*, int); +static int FixBase(int*, struct TracesVars*, Candidate*, int, int); +static boolean FixedBase(int*, struct TracesVars*, Candidate*, int, int); +static void factorial(double*, int*, int); +static void factorial2(double*, int*, int); +static int CheckForAutomorphisms(Candidate*, Candidate*, struct TracesVars*, struct TracesInfo*, int, int, Partition*); +static int CheckForSingAutomorphisms(Candidate*, Partition*, Candidate*, struct TracesVars*, struct TracesInfo*, int, int); +static int CheckForMatching(Candidate*, Candidate*, Partition*, struct TracesVars*, struct TracesInfo*, int, int); +static void Individualize(Partition*, Candidate*, int, int, int, int); +static boolean TreeFyTwo(int, Candidate*, Candidate*, Partition*, int, struct TracesVars*, struct TracesInfo*); +static void ExperimentalStep(Partition*, Candidate*, struct TracesVars*, struct TracesInfo*, int, int); +static boolean TargetCell(Candidate*, Partition*, int, struct TracesVars*, int); +static boolean TargetCellFirstPath(Candidate*, Partition*, struct TracesVars*); +static int TargetCellExpPath(Candidate*, Partition*, struct TracesVars*); +static boolean TargetCellSmall(Candidate*, Partition*, int, struct TracesVars*, int); +static boolean TargetCellFirstPathSmall(Candidate*, Partition*, struct TracesVars*); +static int TargetCellExpPathSmall(Candidate*, Partition*, struct TracesVars*); +static boolean SelectNextLevel(int, struct TracesVars*, struct TracesInfo*); +static void CopyCand(Candidate*, Candidate*, int, int*, int*); +static struct trie* trie_new(int, struct TracesVars*); +static struct trie* trie_make(trie*, int, int, struct TracesVars*); +static struct trie* trie_comp(trie*, int); +static void trie_dump(trie*); +static void trie_class(trie*, int*); +static void RemoveFromLevel(int, int, int, boolean); +static int CompStage0(Partition*, Partition*, Candidate*, Candidate*, int, int, struct TracesVars*, struct TracesInfo*); +static int CompStage1(Partition*, Partition*, Candidate*, Candidate*, int, int, struct TracesVars*, struct TracesInfo*); +static int CompStage2(Partition*, Partition*, Candidate*, Candidate*, int, int, struct TracesVars*, struct TracesInfo*); +static void grouporderplus(sparsegraph*, Candidate*, Partition*, permnode**, double*, int*, int, struct TracesVars*, struct TracesInfo*); +static boolean Prefix(Candidate*, Candidate*, int); +static boolean findperm(permnode*, int*, int); +static int spinelementorbsize(int*, int*, int, int); +static trielist* searchtrie_new(int, struct TracesVars*); +static searchtrie* searchtrie_make(Candidate*, Candidate*, int, struct TracesVars*); +static boolean lookup(searchtrie*); +static int* findcurrorbits(schreier*, int); +static int Preprocess(sparsegraph*, permnode**, Candidate*, int, Partition*, struct TracesVars*); +static void MakeTree(int, int, sparsegraph*, int, struct TracesVars*, boolean); +static void MakeCanTree(int, sparsegraph*, int, Candidate*, Partition*, struct TracesVars*); +static int maxint(int, int); +static int minint(int, int); +static void orbjoin_sp_perm(int*, int*, int*, int, int*); +static void orbjoin_sp_pair(int*, int*, int, int, int, int*); +static boolean isautom_sg_pair(graph*, int*, boolean, int, int, struct TracesVars*); +static void SetAutom(int, int, struct TracesVars*); +static void ResetAutom(int, int, struct TracesVars*); +static void PrintVect(int*, int, int, int); +static void putgraphplus_sg(FILE*, sparsegraph*, int); +static boolean VerifyId(int *p, int n); +static void PrintPartition(int*, int*, int, int, int); +static void Place(int, Candidate*, Partition*); +static int NonSingDeg(int, Candidate*, Partition*); +static int NonSingDegPlus1(Candidate*, Partition*, int, TracesVars*); +static void NonSingDegPlus2(Candidate*, Partition*, int, TracesVars*); +static void Edge_Delete(int, int, Candidate*, TracesVars*); +static boolean VerifyPart(Partition*, int, int); +static int VerifyPerm(int*, int,int); +static boolean VerifyCand(Candidate*, int, int); +static int FirstNeighbour(int, Candidate*, Partition*, int*, int, int*, int); +static int NextNeighbour(int, Candidate*, Partition*, int*, int, int*, int); +static sparsegraph* copy_sg_structure(sparsegraph*, sparsegraph*); +static void WeightCodes (int); +static void PrintWeightedGraph1(sparsegraph*, int, char[30]); +static void PrintWeightedGraph2(int n, char msg[30]); +static void MakeDiscrete(Partition*, int); +static void Complete(sparsegraph*, Candidate*, Partition*, int, TracesVars*, double*, int*,permnode**, int); +static void Allocate_Traces_Structures(int); +static void Allocate_refine_Structures(int); +static void Initialize_Traces_Variables(TracesVars*, TracesOptions*, TracesStats*, int*, sparsegraph*, sparsegraph*, int); +static void Initialize_Traces_Statistics (TracesStats*, int); +static void Initialize_Traces_Time_Variables (TracesVars*); +static int trie_classify(int, TracesVars*); +static int Check_degree_one(sparsegraph*, Candidate*, Partition*, int); +static void sort_Split_Array(int*, int); +static const unsigned int fuzz1[] = {037541, 061532, 005257, 026416}; +static const unsigned int fuzz2[] = {006532, 070236, 035523, 062437}; +static int Select_from_CStack(int*, int); +static void PrintBlissGraph(int); +static void CodeClassify(int, int, int); +static void Adjust_Cycles(Candidate*, Partition*, int, TracesVars*); + +#define FUZZ1(x) ((x) ^ fuzz1[(x)&3]) +#define FUZZ2(x) ((x) ^ fuzz2[(x)&3]) + +#define MASHCOMM(l, i) ((l) + FUZZ1(i)) +#define MASHNONCOMM(l, i) (FUZZ2(l) + (i)) +#define MASH(l, i) ((((l) ^ 065435) + (i)) & 077777) +#define MASH1(l, i) ((l + (i*i)) & 077777) +#define CLEANUP(l) ((int)((l) % 0x7FFF)) +#define SS(n, sing, plur) (n), ((n) == 1?(sing):(plur)) + +#define SETMARK(Arr, Mrk) if (Mrk > (NAUTY_INFINITY-2)) { memset(Arr, 0, n*sizeof(int)); Mrk = 0; } Mrk++; + +#define COPYNODE(W, V) { \ +memcpy(W->lab, V->lab, n*sizeof(int)); \ +memcpy(W->invlab, V->invlab, n*sizeof(int)); \ +W->code = V->code; \ +W->singcode = V->singcode; \ +W->do_it = V->do_it; } + +#define NEXTLINE fprintf(outfile, "\n"); + +#define PRINTCHAR(c) fprintf(outfile, "%s", c); + +#define PRINTCAND(V, Lev) PRINTCHAR(" ") for (tmp=1; tmp<=Lev; tmp++) {fprintf(outfile, tv->digstring, V->lab[Spine[tmp].tgtpos]+labelorg);} + +#define PRINTCANDF(V, Lev) { NEXTLINE for (tmp=1; tmp<=Lev; tmp++) {fprintf(outfile, "F%di", V->lab[Spine[tmp].tgtpos]+labelorg);} NEXTLINE } + +#define PRINTCANDBIG(V, Lev) { PRINTCHAR(" ") \ +for (tmp=1; tmp<=5; tmp++) {fprintf(outfile, tv->digstring, V->lab[Spine[tmp].tgtpos]+labelorg);} \ +fprintf(outfile, "... "); \ +for (tmp=Lev-4; tmp<=Lev; tmp++) {fprintf(outfile, tv->digstring, V->lab[Spine[tmp].tgtpos]+labelorg);} } + +#define LINE(K, c) { PRINTCHAR(c) for (tmp=1; tmp<=K; tmp++) {fprintf(outfile, c);} } + +#define TRACE_CHECK(Tr, Ind, Arg, End) { TracePos = Tr+Ind; \ +if (newtrace) { \ +*TracePos = Arg; \ +} \ +else { \ +if (Ind < *End) { \ +if (*TracePos != Arg) { \ +if (*TracePos > Arg) { \ +return FALSE; \ +} \ +else { \ +*TracePos = Arg; \ +newtrace = TRUE; \ +} \ +} \ +} \ +else { \ +*TracePos = Arg; \ +newtrace = TRUE; \ +} \ +} \ +Ind++; } + +#define SAMETRACE_CHECK(Tr, Ind, Arg, End) { TracePos = Tr+Ind; \ +if (Ind < *End) { \ +if (*TracePos != Arg) { \ +return FALSE; \ +} \ +} \ +else { \ +return FALSE; \ +} \ +Ind++; } + +#define NEWPARTSPINE(Lev) { if (Lev > 3) { \ +Spine[Lev].part = malloc(sizeof(*(Spine[Lev].part))); \ +if (Spine[Lev].part == NULL) { \ +fprintf(ERRFILE, "\nError, memory not allocated.\n"); \ +exit(1); \ +} \ +Spine[Lev].part->cls = Spine[Lev-3].part->cls; \ +Spine[Lev].part->inv = Spine[Lev-3].part->inv; \ +Spine[Lev-3].part->cls = Spine[Lev-3].part->inv = NULL; \ +Spine[Lev].part->code = -1; \ +Spine[Lev].part->cells = 0; \ +} \ +else { \ +Spine[Lev].part = NewPartition(n); \ +} } + +#define FIND_SPLIT_CELLS SplInd = 0; \ +for (j = 0; j < HitClsInd; j++) { \ +ind1 = HitCls[j]; \ +ElmHitCll[ind1] -= ind1; \ +if ((ElmHitCll[ind1] > 0) && (ElmHitCll[ind1] < cls[ind1])) { \ +SplCls[SplInd++] = ind1; \ +} \ +} + +#define FREEPART(Part) { if (Part) { \ +if (Part->cls) free(Part->cls); \ +if (Part->inv) free(Part->inv); \ +free(Part); } \ +} + +#define FREECAND(Cand) { if (Cand) { \ +if (Cand->lab) free(Cand->lab); \ +if (Cand->invlab) free(Cand->invlab); \ +free(Cand); \ +} } + +#define COPYPART(P, Q) { memcpy(P->cls, Q->cls, n*sizeof(int)); \ +memcpy(P->inv, Q->inv, n*sizeof(int)); \ +P->cells = Q->cells; \ +P->code = Q->code; } \ + +#define ADDTONEXTLEVEL { if (SpineTL->listend) { \ +(SpineTL->listend)->next = NewCandidate(n, &GarbList, TRUE); \ +if ((tv->compstage < 2) && (SpineTL->listcounter <= (NAUTY_INFINITY-2))) SpineTL->listcounter++; \ +SpineTL->listend = (SpineTL->listend)->next; \ +CopyCand(SpineTL->listend, NextCand, n, NULL, NULL); \ +} \ +else { \ +SpineTL->liststart = NewCandidate(n, &GarbList, TRUE); \ +if (tv->compstage < 2) SpineTL->listcounter = 1; \ +SpineTL->listend = SpineTL->liststart; \ +CopyCand(SpineTL->liststart, NextCand, n, NULL, NULL); \ +} } + +#define ORBITSIZES { memset(OrbSize, 0, n*sizeof(int)); \ +for (i=0; i<n; i++) { \ +OrbSize[tv->orbits[i]]++; \ +} } + +#define CURRORBITSIZES { memset(CurrOrbSize, 0, n*sizeof(int)); \ +for (i=SpineTL->tgtcell; i<SpineTL->tgtend; i++) { \ +CurrOrbSize[tv->currorbit[CurrCand->lab[i]]]++; \ +} } + +#define EXITFROMSTAGE0REFINE { PRINT_LINE_PLUS(tv->tolevel) \ +if (tv->options->verbosity >= 2) fprintf(outfile, "-=="); \ +CurrCand->indnum--; \ +RemoveFromLevel(tv->tolevel, tv->treedepth, tv->strategy, FALSE); \ +tv->compstage = 1; \ +TempOrbits = NULL; \ +trieroot = trie_new(n, tv); \ +trieref = trieroot; \ +tv->nextlevel = tv->maxtreelevel = tv->fromlevel; \ +ti->thereisnextlevel = TRUE; \ +ti->exitfromref = TRUE; \ +return 0; } + +#define EXITFROMSTAGE0EXPATH2 { PRINT_LINE_PLUS(tv->tolevel) \ +if (tv->options->verbosity >= 2) fprintf(outfile, "=-="); \ +tv->compstage = 1; \ +TempOrbits = NULL; \ +trieroot = trie_new(n, tv); \ +trieref = trieroot; \ +tv->nextlevel = tv->maxtreelevel = tv->tolevel; \ +ti->thereisnextlevel = TRUE; \ +ti->exitfromref = FALSE; \ +return 0; } + +#define EXITFROMSTAGE0EXPATH1 { PRINT_RETURN PRINT_LINE_PLUS(tv->tolevel) \ +if (tv->options->verbosity >= 2) fprintf(outfile, "==-"); \ +if (SpineTL->liststart) { \ +AuxCand = SpineTL->liststart; \ +SpineTL->liststart = NewCandidate(n, &GarbList, TRUE); \ +CopyCand(SpineTL->liststart, NextCand, n, NULL, NULL); \ +SpineTL->liststart->next = AuxCand; \ +} \ +else { \ +SpineTL->liststart = NewCandidate(n, &GarbList, TRUE); \ +SpineTL->listend = SpineTL->liststart; \ +SpineTL->liststart->next = NULL; \ +CopyCand(SpineTL->liststart, NextCand, n, NULL, NULL); \ +} \ +tv->compstage = 1; \ +TempOrbits = NULL; \ +trieroot = trie_new(n, tv); \ +trieref = trieroot; \ +tv->nextlevel = tv->maxtreelevel = tv->tolevel; \ +ti->thereisnextlevel = TRUE; \ +ti->exitfromref = FALSE; \ +return 0; } + +#define UPDATE_LINELGTH { if (tv->options->verbosity >= 2) { \ +if (tv->tolevel < 12) { \ +tv->linelgth = (tv->digits+1)*tv->tolevel+16; \ +} \ +else { \ +tv->linelgth = (tv->digits+1)*10+20; \ +} \ +} } + +#define PRINT_LINE { if ((tv->options->verbosity >= 1) && (tv->strategy == 0)) { \ +if (tv->options->verbosity >= 2) { LINE(tv->linelgth, "-"); \ +NEXTLINE} \ +} \ +} + +#define PRINT_LINE_PLUS(Lev) { if ((tv->options->verbosity >= 1) && (tv->strategy == 0)) { \ +if (tv->options->verbosity >= 2) { LINE(16+tv->digits+1, "-");} \ +fprintf(outfile, " Level %d: %d cell%s; %d singleton%s; target cell: %d; %d orbit%s; %lu node%s (%lu kept); %d update%s;", \ +Lev, SS(Spine[Lev].part->cells, "", "s"), SS((Spine[Lev].part->cells == n) ? n : Spine[Lev].singend, "", "s"), Spine[Lev].tgtsize, SS(tv->stats->numorbits, "", "s"), \ +SS(Spine[Lev].levelcounter, "", "s"), Spine[Lev].keptcounter, SS(Spine[Lev].updates, "", "s")); \ +if (Lev <= tv->group_level) fprintf(outfile, " group_level: %d", tv->group_level); \ +NEXTLINE \ +} \ +} + +#define PRINT_CANDIDATE(Cand, Lev) { \ +for (tmp = Cand->name, cu = 0; tmp > 0; tmp /= 10, ++cu) {} \ +for (tmp = Lev, cu1 = 0; tmp > 0; tmp /= 10, ++cu1) {} \ +cu = 14-cu-cu1; \ +LINE(cu, "-") \ +fprintf(outfile, " %d, %d) ", Lev % 10000, Cand->name % 10000000); \ +if (Lev < 12) { \ +PRINTCAND(Cand, Lev) \ +} \ +else { \ +PRINTCANDBIG(Cand, Lev) \ +} \ +PRINTCHAR("| ") \ +fprintf(outfile, "{%x, %x} ", Cand->code, Cand->singcode); \ +} + +#define PRINT_CANDIDATEPLUS(PrevCand, Cand, Lev) { \ +for (tmp = Cand->name, cu = 0; tmp > 0; tmp /= 10, ++cu) {} \ +for (tmp = Lev, cu1 = 0; tmp > 0; tmp /= 10, ++cu1) {} \ +cu = 14-cu-cu1; \ +LINE(cu, "-") \ +fprintf(outfile, " %d, %d, %d) ", Lev % 10000, Cand->name % 10000000, PrevCand->name); \ +if (Lev < 12) { \ +PRINTCAND(Cand, Lev) \ +} \ +else { \ +PRINTCANDBIG(Cand, Lev) \ +} \ +PRINTCHAR("| ") \ +fprintf(outfile, "{%x, %x} ", Cand->code, Cand->singcode); \ +} + +#define PRINT_EXPPATHSTEP(Cand, Boo) { \ +if (tv->options->verbosity >= 2) { \ +if ((tv->tolevel_tl-tv->tolevel < 6) || !has_nexttcell) { \ +fprintf(outfile, "%d ", tv->indiv_vtx+labelorg); \ +if (Boo) { \ +if (tv->options->verbosity >= 2) fprintf(outfile, "{%d:%x} ", tv->tcellexpath, Cand->code); \ +} \ +else fprintf(outfile, "{interr.(%d)} ", NextPart->cells); \ +if ((!has_nexttcell) && (tv->compstage == 0)) { \ +fprintf(outfile, "(%d) ", tv->tolevel_tl); \ +} \ +} \ +else { \ +if (tv->tolevel_tl-tv->tolevel == 6) { \ +fprintf(outfile, "... "); \ +} \ +} \ +} \ +} + +#define PRINT_RETURN { if (tv->options->verbosity >= 2) { \ +fprintf(outfile, "\n"); \ +} } + +#define PRINT_FROM_VERB(Verb,Lev) { if (tv->options->verbosity >= Verb) { \ +fprintf(outfile, "FROM: "); \ +if (Lev < 12) { \ +PRINTCAND(CurrCand, tv->fromlevel) \ +} \ +else { \ +PRINTCANDBIG(CurrCand, tv->fromlevel) \ +} \ +fprintf(outfile, " do_it: %d, indnum: %d, stnode->index: %d tcell @ %d: %d", CurrCand->do_it, CurrCand->indnum, CurrCand->stnode->index,tv->tcellevel,Spine[tv->tcellevel].tgtcell); \ +PRINT_RETURN \ +} } + +#define PRINT_NOTMIN_VERB(Verb) { if (tv->options->verbosity >= Verb) { \ +fprintf(outfile, " is NOT minimal in orbits (1, %d) [%d]; ", gom_level, CurrCand->lab[Spine[gom_level+1].tgtpos]+labelorg); \ +fprintf(outfile, "at lev %d, orb[%d] = %d.\n", gom_level+1, CurrCand->lab[Spine[gom_level+1].tgtpos]+labelorg, tv->currorbit[CurrCand->lab[Spine[gom_level+1].tgtpos]]+labelorg); } } + +#define PRINT_SKIPPED_VERB(Verb) { if (tv->options->verbosity >= Verb) \ +fprintf(outfile, " skipped (0) (orbit[%d] = %d)\n", \ +NextCand->vertex+labelorg, tv->currorbit[NextCand->vertex]+labelorg); } + +#define PRINT_REFINE_VERB(Verb,where) { if (tv->options->verbosity >= Verb) \ +fprintf(outfile, " REFINE(%c) (orbit[%d] = %d)\n",where, NextCand->vertex+labelorg, tv->currorbit[NextCand->vertex]+labelorg); } + +#define PRINT_INDIV_VERB(Verb,Lev) { if (tv->options->verbosity >= Verb) { \ +if (Lev < 12) { \ +PRINTCAND(CurrCand, tv->fromlevel) \ +} \ +else { \ +PRINTCANDBIG(CurrCand, tv->fromlevel) \ +} \ +fprintf(outfile, "| "); \ +fprintf(outfile, tv->digstring, NextCand->vertex+labelorg); \ +} } + +#define PRINT_INDEX(V,Verb,where) if (tv->options->verbosity >= Verb) \ +fprintf(outfile,"Set index @ %d: Name %d, index %d\n",where,V->name,V->index); + +#define SPECIALGENERATORS { if (tv->options->generators) addpermutation(ring, AUTPERM, n); \ +tv->stats->numgenerators++; \ +tv->specialgens++; \ +if (tv->options->writeautoms) { \ +fprintf(outfile, "Gen #%d: ", tv->stats->numgenerators); \ +writeperm(outfile, AUTPERM, tv->options->cartesian, tv->options->linelength, n); \ +} \ +if (tv->options->userautomproc) { \ +(*tv->options->userautomproc)(tv->stats->numgenerators, AUTPERM, n); \ +} } + +#define UPDATEMIN(A, B) if (B < A) A = B; + +#define PAIRORBJOIN(A, V) { if (A != V) { \ +PrmPairs[tv->permInd].arg = A; \ +PrmPairs[tv->permInd].val = V; \ +tv->permInd++; \ +orbjoin_sp_pair(tv->orbits, OrbList, n, A, V, &tv->stats->numorbits); \ +MakeTree(A, V, sg, n, tv, FALSE); \ +} } + +#define SETPAIRS(A, V) { if (A != V) { \ +PrmPairs[tv->permInd].arg = A; \ +PrmPairs[tv->permInd].val = V; \ +tv->permInd++; \ +} } + +#define SETPAIRSAUT(A, V) { if ((A != V) && (AUTPERM[A] != V)) { \ +AUTPERM[A] = V; \ +PrmPairs[tv->permInd].arg = A; \ +PrmPairs[tv->permInd].val = V; \ +tv->permInd++; \ +} } + +#define SETPAIRSAUTANDTREE(arg, val) { if (tv->build_autom) { SETPAIRSAUT(arg, val) } \ +if (arg != val) orbjoin_sp_pair(tv->orbits, OrbList, n, arg, val, &tv->stats->numorbits); \ +MakeTree(arg, val, sg_orig, n, tv, FALSE); } + +#define PRINTF2(A, B) if (tv->options->verbosity > 3) printf(A, B) +#define PRINTF2_2(A, B, C) if (tv->options->verbosity > 3) printf(A, B, C) +#define PRINTF2_3(A, B, C, D) if (tv->options->verbosity > 3) printf(A, B, C, D) +#define PRINTF2_4(A, B, C, D, E) if (tv->options->verbosity > 3) printf(A, B, C, D, E) + +#define VERB_PRINT(V,Verb,R) if (tv->options->verbosity >= Verb) { \ +fprintf(outfile,"\033[0;32m%s\033[0m ",V); \ +if (R) fprintf(outfile,"\n"); } + +/* data decls. for CPUTIME */ +#ifdef CPUDEFS +CPUDEFS +#endif + +#if !MAXN +DYNALLSTAT(int, AUTPERM, AUTPERM_sz); +DYNALLSTAT(int, BreakSteps, BreakSteps_sz); +DYNALLSTAT(int, CStack, CStack_sz); +DYNALLSTAT(int, CurrOrbSize, CurrOrbSize_sz); +DYNALLSTAT(int, CurrRefCells, CurrRefCells_sz); +DYNALLSTAT(boolean, Diff, Diff_sz); +DYNALLSTAT(boolean, Factorials, Factorials_sz); +DYNALLSTAT(int, fix, fix_sz); +DYNALLSTAT(int, IDENTITY_PERM, IDENTITY_PERM_sz); +DYNALLSTAT(int, Markers, Markers_sz); +DYNALLSTAT(int, TreeMarkers, TreeMarkers_sz); +DYNALLSTAT(int, AutMarkers, AutMarkers_sz); +DYNALLSTAT(int, MarkHitVtx, MarkHitVtx_sz); +DYNALLSTAT(int, MultRefCells, MultRefCells_sz); +DYNALLSTAT(int, NghCounts, NghCounts_sz); +DYNALLSTAT(int, OrbSize, OrbSize_sz); +DYNALLSTAT(int, OrbList, OrbList_sz); +DYNALLSTAT(pair, PrmPairs, PrmPairs_sz); +DYNALLSTAT(int, TempOrbList, TempOrbList_sz); +DYNALLSTAT(int, RefCells, RefCells_sz); +DYNALLSTAT(searchtrie*, RefPath, RefPath_sz); +DYNALLSTAT(int, Singletons, Singletons_sz); +DYNALLSTAT(int, SplCls, SplCls_sz); +DYNALLSTAT(int, SplCnt, SplCnt_sz); +DYNALLSTAT(int, SplPos, SplPos_sz); +DYNALLSTAT(int, StackMarkers, StackMarkers_sz); +DYNALLSTAT(int, TheTrace, TheTrace_sz); +DYNALLSTAT(int, TheTraceCC, TheTraceCC_sz); +DYNALLSTAT(int, TheTraceSplNum, TheTraceSplNum_sz); +DYNALLSTAT(int, TheTraceSteps, TheTraceSteps_sz); +DYNALLSTAT(int, TEMPLAB, TEMPLAB_sz); +DYNALLSTAT(int, TEMPINVLAB, TEMPINVLAB_sz); +DYNALLSTAT(int, WeightsSeq, WeightsSeq_sz); +DYNALLSTAT(int, WorkArray, WorkArray_sz); +DYNALLSTAT(int, WorkArray0, WorkArray0_sz); +DYNALLSTAT(int, WorkArray1, WorkArray1_sz); +DYNALLSTAT(int, WorkArray2, WorkArray2_sz); +DYNALLSTAT(int, WorkArray3, WorkArray3_sz); +DYNALLSTAT(int, WorkArray4, WorkArray4_sz); +DYNALLSTAT(int, WorkArray5, WorkArray5_sz); +DYNALLSTAT(int, WorkArray6, WorkArray6_sz); +DYNALLSTAT(int, WorkArray7, WorkArray7_sz); +DYNALLSTAT(int, Neighbs1, Neighbs1_sz); +DYNALLSTAT(int, Neighbs2, Neighbs2_sz); +DYNALLSTAT(int, TreeStack, TreeStack_sz); +DYNALLSTAT(TracesSpine, Spine, Spine_sz); +DYNALLSTAT(trie*, TrieArray, TrieArray_sz); +DYNALLSTAT(grph_strct, TheGraph, TheGraph_sz); +DYNALLSTAT(ExpPathInfo, EPCodes, EPCodes_sz); +DYNALLSTAT(int, CyclesPart, CyclesPart_sz); +DYNALLSTAT(int, CyclesLength, CyclesLength_sz); +#else +static TLS_ATTR int CStack[MAXN]; +static TLS_ATTR int AUTPERM[MAXN]; +static TLS_ATTR int BreakSteps[MAXN]; +static TLS_ATTR int CurrOrbSize[MAXN]; +static TLS_ATTR int CurrRefCells[MAXN]; +static TLS_ATTR boolean Diff[MAXN]; +static TLS_ATTR boolean Factorials[MAXN]; +static TLS_ATTR int fix[MAXN]; +static TLS_ATTR int IDENTITY_PERM[MAXN]; +static TLS_ATTR int Markers[MAXN]; +static TLS_ATTR int TreeMarkers[MAXN]; +static TLS_ATTR int AutMarkers[MAXN]; +static TLS_ATTR int MarkHitVtx[MAXN]; +static TLS_ATTR int MultRefCells[MAXN]; +static TLS_ATTR int NghCounts[MAXN]; +static TLS_ATTR int OrbSize[MAXN]; +static TLS_ATTR int OrbList[MAXN]; +static TLS_ATTR pair PrmPairs[MAXN]; +static TLS_ATTR int TempOrbList[MAXN]; +static TLS_ATTR int RefCells[MAXN]; +static TLS_ATTR searchtrie* RefPath[MAXN]; +static TLS_ATTR int Singletons[MAXN]; +static TLS_ATTR int SplCls[MAXN]; +static TLS_ATTR int SplCnt[MAXN]; +static TLS_ATTR int SplPos[MAXN]; +static TLS_ATTR int StackMarkers[MAXN]; +static TLS_ATTR int TheTrace[MAXN]; +static TLS_ATTR int TheTraceCC[MAXN]; +static TLS_ATTR int TheTraceSplNum[MAXN]; +static TLS_ATTR int TheTraceSteps[MAXN]; +static TLS_ATTR int TEMPLAB[MAXN]; +static TLS_ATTR int TEMPINVLAB[MAXN]; +static TLS_ATTR int WeightsSeq[MAXN]; +static TLS_ATTR int WorkArray[MAXN]; +static TLS_ATTR int WorkArray0[MAXN]; +static TLS_ATTR int WorkArray1[MAXN]; +static TLS_ATTR int WorkArray2[MAXN]; +static TLS_ATTR int WorkArray3[MAXN]; +static TLS_ATTR int WorkArray4[MAXN]; +static TLS_ATTR int WorkArray5[MAXN]; +static TLS_ATTR int WorkArray6[MAXN]; +static TLS_ATTR int WorkArray7[MAXN]; +static TLS_ATTR int TreeStack[MAXN]; +static TLS_ATTR TracesSpine Spine[MAXN]; +static TLS_ATTR trie* TrieArray[MAXN]; +static TLS_ATTR grph_strct TheGraph[MAXN]; +static TLS_ATTR int Neighbs1[MAXN]; +static TLS_ATTR int Neighbs2[MAXN]; +static TLS_ATTR ExpPathInfo EPCodes[MAXN]; +static TLS_ATTR int CyclesPart[MAXN]; +static TLS_ATTR int CyclesLength[MAXN]; +#endif + +#define PERMSTACK WorkArray1 +#define CYCLES WorkArray1 +#define HitCls WorkArray2 +#define CYCOLR WorkArray2 +#define HitVtx WorkArray3 +#define CYLGTH WorkArray3 +#define CYMULT WorkArray4 +#define HitCount WorkArray5 +#define ElmHitCll WorkArray5 +#define CYCPOS WorkArray5 +#define CYCHIT TempOrbList +#define LGHATTR RefCells +#define CYCREP MultRefCells +#define TempOrbSize TEMPLAB +#define AutomCount TEMPINVLAB +#define CanonIndices MarkHitVtx +#define NSFCells NghCounts +#define TreeNodes AutMarkers +#define CellMarkers1 WorkArray6 +#define CellMarkers2 WorkArray7 +#define SingNonSing Singletons + +static TLS_ATTR FILE *outfile; + +/* Brendan's SCHREIER */ +static TLS_ATTR schreier *gpB; /* This will point to the Schreier structure */ +static TLS_ATTR permnode *gensB; /* This will point to the stored generators */ + +static TLS_ATTR Candidate *GarbList, *SpOrd, *SpCyc, *SpSwp; +static TLS_ATTR Partition *SpPart1, *SpPart2; +static TLS_ATTR TracesSpine *SpineTL, *SpineFL, *SpineTL_tl; +static TLS_ATTR trie *trieroot, *trieref; +static TLS_ATTR int *TempOrbits = NULL; +static TLS_ATTR sparsegraph redgraph; + + +void +Traces(sparsegraph *g_arg, int *lab, int *ptn, + int *orbits_arg, TracesOptions *options_arg, TracesStats *stats_arg, + sparsegraph *canong_arg) { + int i, j; + int tmp; + int deg, vtx1, vtx2, *ngh1, *ngh2, *wgh1, *wgh2, ord; + size_t j1; + + trielist *STStart, *STAux; + searchtrie *TrieNode; + int retval; + Partition *CurrPart, *NextPart; + Candidate *CurrCand, *NextCand, *BestCand, *AuxCand; + + const int n = g_arg->nv; + const int m = SETWORDSNEEDED(n); + + if (g_arg->nv > (NAUTY_INFINITY-2)) + { + fprintf(ERRFILE, "Traces: need n <= %d, but n=%d\n\n", + NAUTY_INFINITY-2, g_arg->nv); + return; + } + + Allocate_Traces_Structures(n); + + struct TracesVars *tv = malloc(sizeof(struct TracesVars)); + if (tv == NULL) { + fprintf(ERRFILE, "\nError, memory not allocated.\n"); + exit(1); + } + struct TracesInfo *ti = malloc(sizeof(struct TracesInfo)); + if (ti == NULL) { + fprintf(ERRFILE, "\nError, memory not allocated.\n"); + exit(1); + } + + trieroot = NULL; + NextCand = GarbList = NULL; + DYNFREE(g_arg->w,g_arg->wlen); /* to be removed in presence of weightd edges */ + + Initialize_Traces_Variables(tv, options_arg, stats_arg, orbits_arg, g_arg, canong_arg, n); + + outfile = (tv->options->outfile == NULL ? stdout : tv->options->outfile); + + SpOrd = SpCyc = SpSwp = NULL; + SpPart1 = SpPart2 = NULL; + + if (tv->options->verbosity >= 2) { + for (i = n, tv->digits = 0; i > 0; i /= 10, ++tv->digits) {} + snprintf(tv->digstring, 25, "%s%dd ", "%", tv->digits); + } + + /* Initialize group and statistics */ + Initialize_Traces_Statistics(stats_arg,n); + + if (tv->options->verbosity >= 2) { + Initialize_Traces_Time_Variables(tv); + } + + /* Initialize lab and ptn when in the unit partition case */ + if (tv->options->defaultptn) { + for (i = 0; i < n; i++) { + IDENTITY_PERM[i] = i; + ptn[i] = NAUTY_INFINITY; + } + ptn[n-1] = 0; + memcpy(lab, IDENTITY_PERM, n*sizeof(int)); + } else { + for (i = 0; i < n; i++) { + IDENTITY_PERM[i] = i; + } + } + + memcpy(orbits_arg, IDENTITY_PERM, n*sizeof(int)); + + if (tv->options->generators) { + tv->stats->numorbits = given_gens(g_arg, *tv->options->generators, + orbits_arg, tv->options->digraph); + newgroup(&gpB, NULL, n); + gensB = *tv->options->generators; + expandschreier(gpB, &gensB, n); + ti->thegrouphaschanged = TRUE; + ti->identitygroup = FALSE; + memcpy(OrbList, gpB->orbits, n*sizeof(int)); + } + else { + newgroup(&gpB, &gensB, n); + memcpy(OrbList, IDENTITY_PERM, n*sizeof(int)); + tv->stats->numorbits = n; + ti->thegrouphaschanged = FALSE; + ti->identitygroup = TRUE; + } + + copy_sg_structure(&redgraph, g_arg); + + tv->graph = &redgraph; + if (g_arg->w) memcpy(tv->graph->w, g_arg->w, tv->graph->wlen*sizeof(int)); + if (g_arg->e) memcpy(tv->graph->e, g_arg->e, tv->graph->elen*sizeof(int)); + + for (i=0; i<n; i++) { + EPCodes[i].info = 0; + TheGraph[i].d = g_arg->d[i]; + if (TheGraph[i].d > tv->maxdeg) { + tv->maxdeg = TheGraph[i].d; + } + if (TheGraph[i].d < tv->mindeg) { + tv->mindeg = TheGraph[i].d; + } + if (g_arg->e) { + TheGraph[i].e = tv->graph->e + g_arg->v[i]; + } + else { + TheGraph[i].e = NULL; + } + if (g_arg->w) { + TheGraph[i].w = tv->graph->w + g_arg->v[i]; + } + else { + TheGraph[i].w = NULL; + } + TheGraph[i].one = FALSE; + } + + ord = 0; + + /*----------- WEIGHTS --------------*/ + if (tv->options->weighted) { + WeightCodes(n); + ord = trie_classify(n,tv); + } + /*----------------------------------*/ + + if ((tv->maxdeg == tv->mindeg) && (ord == 0)) ti->regular = TRUE; else ti->regular = FALSE; + + tv->currorbit = gpB->orbits; + + memcpy(AUTPERM, IDENTITY_PERM, n*sizeof(int)); + tv->permInd = 0; + + memset(fix, 0, n*sizeof(int)); + memset(TheTraceCC, 0, n*sizeof(int)); + memset(Factorials, 0, n*sizeof(int)); + /* ran_init(1234); any long int as an argument */ + + /* The graph is sparse? */ + if (g_arg->nde < n || g_arg->nde / n < n / (g_arg->nde / n)) { + ti->thegraphisparse = TRUE; + } + else { + ti->thegraphisparse = FALSE; + } + + tv->preprocessed = 0; + ti->deg_one = FALSE; + ti->first_matching = FALSE; + retval = 0; + + /* Initialize candidate, partition, cells, orbits */ + Spine[0].part = NewPartition(n); + CurrPart = Spine[0].part; + memset(CurrPart->inv, 0, n*sizeof(int)); + + NextPart = NewPartition(n); + CurrCand = NewCandidate(n, &GarbList, TRUE); + + CurrCand->singcode = 0; + TempOrbits = NULL; + STStart = NULL; + + if (ti->regular) { + if (tv->options->defaultptn) { + memcpy(CurrCand->lab, IDENTITY_PERM, n*sizeof(int)); + memcpy(CurrCand->invlab, IDENTITY_PERM, n*sizeof(int)); + CurrPart->cells = 1; + CurrPart->cls[0] = n; + TheTrace[0] = 0; + } + else { + memcpy(CurrCand->lab, lab, n*sizeof(int)); + CurrPart->cells = 0; + j = 0; + for (i = 0; i < n; i++) { + if (j) CurrPart->inv[i] = j; + CurrCand->invlab[CurrCand->lab[i]] = i; + if (!ptn[i]) { + CurrPart->cls[j] = i-j+1; + if (CurrPart->cls[j] == 1) { + CurrCand->singcode = MASHCOMM(CurrCand->singcode, CurrCand->lab[j]); + } + TheTrace[CurrPart->cells++] = j; + j = i+1; + } + } + } + } else { + if (tv->options->weighted) { + CurrPart->cells = traces_vertexclass_refine(n, lab, ptn, + CurrCand, CurrPart, WeightsSeq); + } + else { + CurrPart->cells = traces_vertexclass_refine (n, lab, ptn, + CurrCand, CurrPart, g_arg->d); + } + } + + memset(NghCounts,0,n*sizeof(int)); + if (tv->options->verbosity == 7) PrintPartition(CurrCand->lab,CurrPart->cls,n,labelorg,1323); + + /* Check for deg 1 vertices */ + ti->deg_one = Check_degree_one(g_arg, CurrCand, CurrPart, n); + +#if !MAXN + DYNALLOC1(int, Neighbs1, Neighbs1_sz, tv->maxdeg, "Traces"); + DYNALLOC1(int, Neighbs2, Neighbs2_sz, tv->maxdeg, "Traces"); +#endif + + if (ti->deg_one) { + tv->preprocessed = Preprocess(g_arg, &gensB, CurrCand, n, CurrPart, tv); + } + + if (tv->preprocessed) { + memset(Diff,0,n*sizeof(boolean)); + for (i=0; i<n; i++) { + if ((TheGraph[i].d > 1) && (tv->input_graph->d[i] != TheGraph[i].d)) + Diff[i] = TRUE; + } + } + + /* Initialization of Spine structure */ + SpineFL = Spine; + SpineFL->tgtcell = SpineFL->tgtpos = 0; + SpineFL->tgtend = n; + SpineFL->tgtfrom = -1; + SpineFL->trcstart = 0; + SpineFL->trcend = CurrPart->active = CurrPart->cells; + SpineFL->ccstart = SpineFL->ccend = 0; + SpineFL->stpstart = SpineFL->stpend = 0; + SpineFL->singstart = SpineFL->singend = 0; + SpineFL->thetracexists = FALSE; + SpineFL->liststart = SpineFL->listend = CurrCand; + SpineFL->levelcounter = 1; + SpineFL->keptcounter = 1; + SpineFL->updates = 1; + + /* Further initializations */ + tv->maxtreelevel = 0; + tv->tolevel = 0; + tv->tcell = 0; + UPDATE_LINELGTH + + /* First refinement */ + if (tv->preprocessed < 2) + traces_refine(CurrCand, n, CurrPart, tv, ti, 0, FALSE); + + CurrCand->name = 0; + + if (CurrPart->cells == n) { + tv->stats->canupdates++; + + /* CANONICAL FORM ? */ + if (tv->options->getcanon) { + memcpy(lab, CurrCand->lab, n*sizeof(int)); + if (canong_arg) memcpy(CurrPart->inv, CurrCand->invlab, n*sizeof(int)); + if (tv->options->usercanonproc != NULL) + { + (*tv->options->usercanonproc)((graph*)g_arg, lab, (graph*)canong_arg, tv->stats->canupdates, CurrCand->code, m, n); + } + } + } + else { + STStart = searchtrie_new(n, tv); + CurrCand->stnode = tv->strielist->triearray; + NextCand = NewCandidate(n, &GarbList, TRUE); + SpineFL->listcounter = 1; + tv->tcellevel = 0; + ti->exitfromref = FALSE; + Spine[1].levelcounter = 0; + Spine[1].updates = 0; + Spine[1].tgtfrom = 0; + + memset(WorkArray, 0, n*sizeof(int)); + + do { + tv->fromlevel = tv->tolevel; + SpineFL = Spine+tv->fromlevel; + + if (CurrCand) { + switch (tv->compstage) { + case 0: retval = CompStage0(CurrPart, NextPart, CurrCand, NextCand, m, n, tv, ti); + break; + case 1: + if (!TempOrbits) { + memcpy(WorkArray1, tv->currorbit, n*sizeof(int)); + TempOrbits = WorkArray1; + } + memset(TempOrbSize, 0, n*sizeof(int)); + for (i=SpineTL->tgtcell; i<SpineTL->tgtend; i++) { + TempOrbSize[TempOrbits[CurrCand->lab[i]]]++; + } + retval = CompStage1(CurrPart, NextPart, CurrCand, NextCand, m, n, tv, ti); + break; + case 2: + retval = CompStage2(CurrPart, NextPart, CurrCand, NextCand, m, n, tv, ti); + break; + default: + break; + } + if (retval == NAUTY_ABORTED) + tv->stats->errstatus = NAUABORTED; + else if (retval == NAUTY_KILLED) { + tv->stats->errstatus = NAUKILLED; + return; + } + } + /* NEXT CANDIDATE */ + if (ti->thereisnextlevel) { + if (tv->nextlevel != tv->fromlevel) { + UPDATE_LINELGTH + } + tv->tolevel = tv->nextlevel; + CurrCand = Spine[tv->nextlevel].liststart; + CurrPart = Spine[tv->nextlevel].part; + } + } + while (ti->thereisnextlevel); + + if (!retval) { + if (tv->compstage) { + memset(CurrOrbSize, 0, n*sizeof(int)); + for (i=0; i<n; i++) { + CurrOrbSize[TempOrbits[i]]++; + } + } + + if (!tv->options->getcanon) { + if (tv->compstage) { + tv->maxtreelevel++; + TrieNode = Spine[tv->maxtreelevel].liststart->stnode; + if (TrieNode->father) { + TrieNode = TrieNode->father; + } + if (!ti->exitfromref) { + TrieNode->index = 0; + for (i=1; i<AutomCount[0]; i++) { + TrieNode->index += CurrOrbSize[AutomCount[i]]; + PRINT_INDEX(TrieNode,4,30) + } + } + } + } + + if (tv->maxtreelevel) PRINT_LINE_PLUS(tv->maxtreelevel); + + AuxCand = Spine[tv->maxtreelevel].liststart; + while (!AuxCand->do_it) { + AuxCand = AuxCand->next; + } + + /* CANONICAL FORM ? */ + if (tv->options->getcanon) { + BestCand = AuxCand; + AuxCand = AuxCand->next; + while (AuxCand) { + if (AuxCand->do_it) { + if (comparelab_tr(g_arg, BestCand->lab, BestCand->invlab, AuxCand->lab, AuxCand->invlab, Spine[tv->maxtreelevel].part->cls, Spine[tv->maxtreelevel].part->inv) == 1) { + BestCand = AuxCand; + tv->stats->canupdates++; + if (tv->options->usercanonproc != NULL) + { + (*tv->options->usercanonproc)((graph*)g_arg, lab, (graph*)canong_arg, tv->stats->canupdates, CurrCand->code, m, n); + } + } + } + AuxCand = AuxCand->next; + } + + grouporderplus(g_arg, BestCand, Spine[tv->maxtreelevel].part, &gensB, &(tv->stats->grpsize1), &(tv->stats->grpsize2), n, tv, ti); + + if (tv->options->verbosity >= 2) { + LINE(32, "-") + NEXTLINE + fprintf(outfile, "Canonical:"); + PRINTCAND(BestCand, tv->maxtreelevel) + PRINT_RETURN + } + memcpy(lab, BestCand->lab, n*sizeof(int)); + if (canong_arg) memcpy(CurrPart->inv, BestCand->invlab, n*sizeof(int)); + } + else { + grouporderplus(g_arg, AuxCand, Spine[tv->maxtreelevel].part, &gensB, &(tv->stats->grpsize1), &(tv->stats->grpsize2), n, tv, ti); + } + + if (tv->options->verbosity >= 2) { + if (tv->linelgth < 40) { + tv->linelgth = 40; + } + LINE(32, "-") + NEXTLINE + } + + } + } + tv->stats->treedepth = tv->treedepth; + if (Spine[tv->treedepth].part->code == -1) { + tv->stats->treedepth--; + } + + if (tv->options->verbosity >= 2) { + fprintf(outfile, "group time: %.2f, %.2f, %.2f; total: %.2f; exp_paths time: %.2f; aut_check time: %.2f\n%lu refinement%s interrupted by trace comparison (%s); special cells: %d\n------", tv->schreier1, tv->schreier2, tv->schreier3, tv->schreier1+tv->schreier2+tv->schreier3, + tv->expaths, tv->autchk, SS(tv->stats->interrupted, "", "s"), (tv->options->strategy == 0 ? "breadth-first" : "depth-first"), tv->specialgens); + PRINT_RETURN + } + if (tv->options->verbosity >= 3) fprintf(outfile, "CPYCAND(0): %d, ID<-TMPORB(1): %d, LAB(2): %d, PART(3): %d, TEMP(4)->: %d, TEMP(5)<-: %d, CHKFORAUT(6): %d, ISAUT(7): %d, ContaTC: %d\n", tv->conta0, tv->conta1, tv->conta2, tv->conta3, tv->conta4, tv->conta5, tv->conta6, tv->conta7, tv->contatc); + + if (tv->options->getcanon && canong_arg) { + canong_arg->nv = g_arg->nv; + canong_arg->nde = g_arg->nde; + SG_ALLOC(*canong_arg, g_arg->nv, g_arg->nde, "traces canong"); + updatecan_tr(g_arg, canong_arg, lab, CurrPart->inv, 0); + } + + if (tv->options->generators) { + deleteunmarked(&gensB); + *tv->options->generators = gensB; + freeschreier(&gpB, NULL); + } + else { + freeschreier(&gpB, &gensB); + schreier_freedyn(); + } + + while (STStart) { + STAux = STStart; + free(STAux->triearray); + STStart = STStart->next; + free(STAux); + } + + tv->canlist = 0; + for (i=0; i<=tv->treedepth; i++) { + if (Spine[i].liststart) { + tv->canlist += FreeList(Spine[i].liststart, TRUE); + Spine[i].liststart = Spine[i].listend = NULL; + } + } + + if (GarbList) { + tv->stats->peaknodes = FreeList(GarbList, FALSE); + } + + FREECAND(NextCand) + FREECAND(SpOrd) + FREECAND(SpCyc) + FREECAND(SpSwp) + FREEPART(NextPart) + FREEPART(SpPart1) + FREEPART(SpPart2) + + if (!tv->options->getcanon && trieroot) { + for (i=0; i<=tv->triepos; i++) { + free(TrieArray[i]); + } + } + + for (i=0; i <= tv->treedepth; i++) { + FREEPART(Spine[i].part) + } + + CurrCand = GarbList = NULL; + tv->stats->peaknodes += tv->canlist; + + if (tv->graph != g_arg) { + SG_FREE(redgraph); + } + free(tv); + free(ti); + traces_freedyn(); + + return; +} + +int traces_vertexclass_refine (int n, int *lab, int *ptn, Candidate *Cand, Partition *Part, int *RefArray) { + + int i, j, k, aux, cells, end; + + memcpy(Cand->lab, lab, n*sizeof(int)); + + cells = 0; + j = 0; + + for (i = 0; i < n; i++) { + WorkArray1[i] = RefArray[Cand->lab[i]]; + if (!ptn[i]) { + TheTrace[cells++] = j; + + sort2ints(WorkArray1+j,Cand->lab+j,i-j+1); + + aux = WorkArray1[j]; + Part->cls[j] = 1; + Part->inv[j] = j; + Cand->invlab[Cand->lab[j]] = j; + + if (i == j) { + Cand->singcode = MASHCOMM(Cand->singcode, Cand->lab[j]); + j++; + } else { + end = i+1; + for (k=j+1; k<end; k++) { + if (WorkArray1[k] == aux) { + (Part->cls[j])++; + Part->inv[k] = j; + Cand->invlab[Cand->lab[k]] = k; + } else { + if (Part->cls[j] == 1) { + Cand->singcode = MASHCOMM(Cand->singcode, Cand->lab[j]); + } + + TheTrace[cells++] = k; + j = k; + aux = WorkArray1[j]; + Part->cls[j] = 1; + Part->inv[j] = j; + Cand->invlab[Cand->lab[j]] = j; + } + } + j = end; + } + } + } + return cells; +} + +int traces_refine(Candidate *Cand, + int n, + Partition *Part, + struct TracesVars* tv, + struct TracesInfo *ti, + int num_indv, + boolean make_code) { + + int i, j, k, jk, sc, ind0, ind1, ind2, ind3, ind4, tlp1, labi; + int value, iend, newcell; + int HitClsInd, SplInd, SplCntInd, CStackInd, TraceInd, TraceCCInd, TraceStepsInd, SingInd; + int j1int, iend1int; + unsigned int longcode; + int newtrace = FALSE; + int Sparse = TRUE; + int *lab, *cls, *InvLab, *TracePos, *SplitCell, *LabCell, *TraceEnd, Traceccend, *Tracestpend; + int BigCell, BigCellPos, BigCellSize; + boolean TraceCell = FALSE; + int *nghb; + int conta; + const int variation = 0; + int currentweight, weightstart, weightend, currentcell, currentsize; + + VERB_PRINT("RFLT",3,FALSE) + + HitClsInd = 0; + if (tv->stackmark > (NAUTY_INFINITY-2)) { + memset(StackMarkers, 0, n*sizeof(int)); + tv->stackmark = 0; + } + tv->stackmark++; + tv->augmented_cells = Part->cells; + + SpineTL = Spine+tv->tolevel; + TraceEnd = &(SpineTL->trcend); + Traceccend = SpineTL->ccend; + Tracestpend = &(SpineTL->stpend); + TraceCCInd = SpineTL->ccstart; + TraceStepsInd = SpineTL->stpstart; + + SingInd = SpineTL->singstart + num_indv; + + lab = Cand->lab; + InvLab = Cand->invlab; + cls = Part->cls; + + UPDATEMIN(Part->active, n-1); + memcpy(CStack+1, TheTrace+SpineTL->trcstart, (Part->active)*sizeof(int)); + CStackInd = Part->active; + for (i = 1; i <= CStackInd; i++) { + StackMarkers[CStack[i]] = tv->stackmark; + } + + longcode = Part->cells; + TraceInd = SpineTL->trcstart+Part->active; + if (!SpineTL->thetracexists) { + newtrace = TRUE; + } + conta=0; + + while (CStackInd > 0) { + + weightend = 0; + + if (tv->mark > (NAUTY_INFINITY-2)) { + memset(Markers, 0, n*sizeof(int)); + memset(MarkHitVtx, 0, n*sizeof(int)); + tv->mark = 0; + } + tv->mark++; + + if (Part->cells == n) break; + + k = Select_from_CStack(cls, CStackInd); + + currentcell = CStack[k]; + currentsize = currentcell+cls[currentcell]; + CStack[k] = CStack[CStackInd--]; + StackMarkers[currentcell] = 0; + + labi = lab[currentcell]; + iend1int = TheGraph[labi].d; + nghb = TheGraph[labi].e; + + do { + ind0 = currentcell; + ind2 = currentsize; + weightstart = weightend; + + if (tv->options->weighted) { + currentweight = (TheGraph[labi].w)[weightstart]; + while ((iend1int > weightend) && ((TheGraph[labi].w)[weightend] == currentweight)) { + weightend++; + } + } else { + weightend = TheGraph[labi].d; + } + + if (!newtrace) { + TraceCell = ((ind0 == TheTraceCC[TraceCCInd]) && (TraceCCInd < Traceccend)); + } + + /* Analysis of occurrences of neighbors of the current cell */ + /* The list of cells with neighbors in the current cell is built */ + if (cls[ind0] == 1) { /* SINGLETON CURRENT CELL CASE */ + + /* NEIGHCOUNT_SING_MULT */ + HitClsInd = 0; + for (j1int = weightstart; j1int < weightend; ++j1int) { + k = nghb[j1int]; + value = Part->inv[InvLab[k]]; + if (cls[value] > 1) { + if (Markers[value] != tv->mark) { + HitCls[HitClsInd++] = value; + Markers[value] = tv->mark; + ElmHitCll[value] = value; + } + HitVtx[ElmHitCll[value]++] = k; + } else { + switch (variation) { + case 1: + longcode = MASHCOMM(longcode, value); + break; + default: + break; + } + } + } + /* end NEIGHCOUNT_SING_MULT */ + + tv->mark++; + FIND_SPLIT_CELLS; + + /* SINGLETON CC CASE */ + if (SplInd) { + if (newtrace) { + TheTraceCC[TraceCCInd] = ind0; + } + if (!TraceCell) { + TheTraceCC[TraceCCInd] = ind0; + newtrace = TRUE; + } + + TRACE_CHECK(TheTraceSplNum, TraceCCInd, SplInd, &Traceccend) + + /* Sorting the cells to be split */ + sort_Split_Array(SplCls, SplInd); + + for (j = 0; j < SplInd; j++) { + ind1 = SplCls[j]; + i = ind1+cls[ind1]-ElmHitCll[ind1]; + TRACE_CHECK(TheTrace, TraceInd, i, TraceEnd) + } + + for (j = 0; j < SplInd; j++) { + /* REARRANGE_CELLS */ + ind1 = SplCls[j]; + cls[ind1] = cls[ind1]-ElmHitCll[ind1]; + newcell = ind1+cls[ind1]; + cls[newcell] = ElmHitCll[ind1]; + Part->cells++; + if (StackMarkers[ind1] != tv->stackmark) { + if (cls[newcell] < cls[ind1]) { + CStack[++CStackInd] = newcell; + StackMarkers[newcell] = tv->stackmark; + } + else { + CStack[++CStackInd] = ind1; + StackMarkers[ind1] = tv->stackmark; + } + } + else { + CStack[++CStackInd] = newcell; + StackMarkers[newcell] = tv->stackmark; + } + SplitCell = HitVtx+ind1; + ind3 = cls[newcell]; + LabCell = lab+newcell; + for (jk = 0; jk < ind3; jk++) { + k = SplitCell[jk]; + i = LabCell[jk]; + Part->inv[newcell+jk] = newcell; + lab[InvLab[k]] = i; + InvLab[i] = InvLab[k]; + LabCell[jk] = k; + InvLab[k] = newcell+jk; + } + /* END REARRANGE_CELLS */ + + if (cls[ind1] == 1) { + Cand->singcode = MASHCOMM(Cand->singcode, Cand->lab[ind1]); + if (newtrace) Singletons[SingInd] = ind1; + SingInd++; + } + if (cls[newcell] == 1) { + Cand->singcode = MASHCOMM(Cand->singcode, Cand->lab[newcell]); + if (newtrace) Singletons[SingInd] = newcell; + SingInd++; + } + } + } + else { + if ((!newtrace) && TraceCell) { + if (!tv->options->weighted) return 0; + } + } + } + else { + if (ti->thegraphisparse) { + + /* NEIGHCOUNT_SPARSE_MULT */ + HitClsInd = 0; + if (cls[ind0] != n) { + for (i = ind0; i < ind2; i++) { + labi = lab[i]; + nghb = TheGraph[labi].e; + for (j = weightstart; j < weightend; j++) { + k = nghb[j]; + if (MarkHitVtx[k] == tv->mark) { + NghCounts[k]++; + } + else { + value = Part->inv[InvLab[k]]; + if (cls[value] > 1) { + MarkHitVtx[k] = tv->mark; + NghCounts[k] = 1; + if (Markers[value] != tv->mark) { + HitCls[HitClsInd++] = value; + Markers[value] = tv->mark; + HitVtx[value] = k; + ElmHitCll[value] = 1; + } + else { + HitVtx[value+ElmHitCll[value]++] = k; + } + } + else { + switch (variation) { + case 1: + longcode = MASHCOMM(longcode, value); + break; + default: + break; + } + } + } + } + } + } + /* End NEIGHCOUNT_SPARSE_MULT */ + + tv->mark++; + + SplInd = 0; + SplCls[0] = n; + for (j = 0; j < HitClsInd; j++) { + ind1 = HitCls[j]; + if ((ElmHitCll[ind1] > 0) && (ElmHitCll[ind1] < cls[ind1])) { + SplCls[SplInd++] = ind1; + } + else { + ind2 = ind1+cls[ind1]; + value = NghCounts[lab[ind1++]]; + for (i = ind1; i < ind2; i++) + { + if (NghCounts[lab[i]] != value) + { + SplCls[SplInd++] = HitCls[j]; + break; + } + } + } + } + + /* SPARSE CASE */ + if (SplInd) { + if (newtrace) { + TheTraceCC[TraceCCInd] = ind0; + } + if (!TraceCell) { + TheTraceCC[TraceCCInd] = ind0; + newtrace = TRUE; + } + TRACE_CHECK(TheTraceSplNum, TraceCCInd, SplInd+n, &Traceccend) + + /* Sorting the cells to be split */ + sort_Split_Array(SplCls, SplInd); + + for (sc = 0; sc < SplInd; sc++) { /* For each cell C to be split */ + ind0 = SplCls[sc]; + ind1 = ind0 + cls[ind0]; + SplCntInd = 0; + if (ElmHitCll[ind0] < cls[ind0]) { + SplCnt[SplCntInd++] = 0; + SplPos[0] = cls[ind0] - ElmHitCll[ind0]; + } + + /* According to the numbers of neighbors of C into the current cell */ + /* compute how many vertices in C will be placed into the same new cell */ + iend = ind0 + ElmHitCll[ind0]; + for (i = ind0; i < iend; i++) { + value = NghCounts[HitVtx[i]]; + if (Markers[value] != tv->mark) { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = 1; + } + else { + SplPos[value]++; + } + } + tv->mark++; + + if (SplCntInd) { + TRACE_CHECK(TheTraceSteps, TraceStepsInd, SplCntInd+n, Tracestpend) + } + + /* Sort the values deriving from the previous step */ + sort_Split_Array(SplCnt,SplCntInd); + Part->cells += SplCntInd-1; + + /* Split the cell C and update the information for sizes of new cells */ + /* Put the new cells into the stack */ + i = ind0; + if (StackMarkers[i] != tv->stackmark) { + BigCellSize = 0; + } + for (k = 0; k < SplCntInd; k++) { + value = SplPos[SplCnt[k]]; + cls[i] = value; + if ((StackMarkers[ind0] != tv->stackmark) && (value > BigCellSize)) { + BigCell = i; + BigCellPos = CStackInd; + BigCellSize = cls[i]; + } + SplPos[SplCnt[k]] = i; + i += value; + if (i < ind1) { + CStack[++CStackInd] = i; + StackMarkers[i] = tv->stackmark; + TRACE_CHECK(TheTrace, TraceInd, i, TraceEnd) + } + } + + if ((StackMarkers[ind0] != tv->stackmark) && (BigCell != ind0)) { + CStack[BigCellPos] = ind0; + StackMarkers[BigCell] = 0; + StackMarkers[ind0] = tv->stackmark; + } + /* Permute elements of the cell C */ + iend = ind0 + ElmHitCll[ind0]; + for (i = ind0; i < iend; i++) { + value = HitVtx[i]; + j = SplPos[NghCounts[value]]++; /* where HitVtx[i] goes */ + k = InvLab[value]; /* where HitVtx[i] is in lab */ + lab[k] = lab[j]; + lab[j] = value; + InvLab[value] = j; + InvLab[lab[k]] = k; + NghCounts[value] = 0; + } + + /* Reconstruct the cell C and update the inverse partition */ + newcell = ind1 - ElmHitCll[ind0]; + i = newcell; + ind2 = newcell+cls[newcell]-1; + do { + Part->inv[i] = newcell; + if (i == ind2) { + newcell = i+1; + if (newcell < n) ind2 = newcell+cls[newcell]-1; + } + } + while (++i < ind1); + + for (i = ind0, k = 0; k < SplCntInd; i+=cls[i], k++) { + if (cls[i] == 1) { + Cand->singcode = MASHCOMM(Cand->singcode, Cand->lab[i]); + if (newtrace) Singletons[SingInd] = i; + SingInd++; + } + } + + } + } + else { + if ((!newtrace) && TraceCell) { + return 0; + } + } + + } + else { + if (TheGraph[lab[ind0]].d > n/cls[ind0]) { + Sparse = FALSE; + } + else { + Sparse = TRUE; + } + Sparse = TRUE; + if (Sparse) { + /* Counting occurrences of neighbors of the current cell */ + /* The list of cells with neighbors in the current cell is also built */ + if (cls[ind0] == n) { + for (i = 0; i < n; i++) { + NghCounts[i] = TheGraph[i].d; + } + HitCls[0] = 0; + HitClsInd = 1; + } + else { + memset(NghCounts, 0, n*sizeof(int)); + + /* NEIGHCOUNT_DENSE_SPARSE_MULT */ + HitClsInd = 0; + for (i = ind0; i < ind2; i++) { + labi = lab[i]; + nghb = TheGraph[labi].e; + for (j1int = weightstart; j1int < weightend; ++j1int) { + k = nghb[j1int]; + (NghCounts[k])++; + value = Part->inv[InvLab[k]]; + if (Markers[value] != tv->mark) { + if (cls[value] > 1) HitCls[HitClsInd++] = value; + Markers[value] = tv->mark; + } + } + } + /* End NEIGHCOUNT_DENSE_SPARSE_MULT */ + + } + + tv->mark++; + + + SplInd = 0; + for (j = 0; j < HitClsInd; j++) { + ind1 = HitCls[j]; + ind2 = ind1+cls[ind1]; + value = NghCounts[lab[ind1++]]; + for (i = ind1; i < ind2; i++) + { + if (NghCounts[lab[i]] != value) + { + SplCls[SplInd++] = HitCls[j]; + break; + } + } + } + + /* DENSE-SPARSE CASE */ + if (SplInd) { + if (newtrace) { + TheTraceCC[TraceCCInd] = ind0; + } + if (!TraceCell) { + TheTraceCC[TraceCCInd] = ind0; + newtrace = TRUE; + } + TRACE_CHECK(TheTraceSplNum, TraceCCInd, SplInd+2*n, &Traceccend) + + /* Sorting the cells to be split */ + sort_Split_Array(SplCls, SplInd); + + for (j = 0; j < SplInd; j++) { /* For each cell C to be split */ + ind0 = SplCls[j]; + ind1 = ind0+cls[ind0]; + SplCntInd = 0; + + /* According to the numbers of neighbors of C into the current cell */ + /* compute how many vertices in C will be placed into the same new cell */ + for (i = ind0; i < ind1; i++) { + value = NghCounts[lab[i]]; + if (Markers[value] != tv->mark) { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = 1; + } + else { + SplPos[value]++; + } + } + tv->mark++; + + if (SplCntInd) { + TRACE_CHECK(TheTraceSteps, TraceStepsInd, SplCntInd+2*n, Tracestpend) + } + + /* Sort the values deriving from the previous step */ + sort_Split_Array(SplCnt, SplCntInd); + + Part->cells += SplCntInd-1; + + /* Split the cell C and update the information for sizes of new cells */ + /* Put the new cells into the stack */ + i = ind0; + if (StackMarkers[i] != tv->stackmark) { + BigCellSize = 0; + } + for (k = 0; k < SplCntInd; k++) { + value = SplPos[SplCnt[k]]; + cls[i] = value; + + if ((StackMarkers[ind0] != tv->stackmark) && (value > BigCellSize)) { + BigCell = i; + BigCellPos = CStackInd; + BigCellSize = cls[i]; + } + SplPos[SplCnt[k]] = i; + i += value; + if (i < ind1) { + CStack[++CStackInd] = i; + StackMarkers[i] = tv->stackmark; + TRACE_CHECK(TheTrace, TraceInd, i, TraceEnd) + } + } + + if ((StackMarkers[ind0] != tv->stackmark) && (BigCell != ind0)) { + CStack[BigCellPos] = ind0; + StackMarkers[BigCell] = 0; + StackMarkers[ind0] = tv->stackmark; + } + + /* Permute elements of the cell C */ + i = ind0; + do { + SplCnt[SplPos[NghCounts[lab[i]]]++] = lab[i]; + } + while(++i < ind1); + + /* Reconstruct the cell C and update the inverse partition */ + newcell = ind0; + i = ind0; + ind2 = newcell+cls[newcell]-1; + do { + lab[i] = SplCnt[i]; + InvLab[lab[i]] = i; + + Part->inv[i] = newcell; + if (i == ind2) { + newcell = i+1; + if (newcell < n) ind2 = newcell+cls[newcell]-1; + } + } + while (++i < ind1); + + for (i = ind0, k = 0; k < SplCntInd; i+=cls[i], k++) { + if (cls[i] == 1) { + Cand->singcode = MASHCOMM(Cand->singcode, Cand->lab[i]); + if (newtrace) Singletons[SingInd] = i; + SingInd++; + } + } + + } + } + else { + if ((!newtrace) && TraceCell) { + return 0; + } + } + + } + else { + if (cls[ind0] == n) { + for (i = 0; i < n; i++) { + NghCounts[i] = TheGraph[i].d; + } + } + else { + memset(NghCounts, 0, n*sizeof(int)); + + /* NEIGHCOUNT_DENSE_DENSE_MULT */ + for (i = ind0; i < ind2; i++) { + labi = lab[i]; + nghb = TheGraph[labi].e; + for (j1int = weightstart; j1int < weightend; ++j1int) { + k = nghb[j1int]; + (NghCounts[k])++; + } + } + /* End NEIGHCOUNT_DENSE_DENSE_MULT */ + + } + SplInd = 0; + ind4 = 0; + while (ind4 < n) { /* For each cell C with size(C) > 1 */ + ind1 = ind4+cls[ind4]; + if (cls[ind4] > 1) { + + + /* Determine whether C must be split */ + SplCntInd = 0; + value = NghCounts[lab[ind4]]; + for (i = ind4+1; i < ind1; i++) { + if (NghCounts[lab[i]] != value) + { + SplInd++; + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = i-ind4; + do { + value = NghCounts[lab[i++]]; + if (Markers[value] != tv->mark) { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = 1; + } + else { + SplPos[value]++; + } + } + while(i != ind1); + break; + } + } + tv->mark++; + + if (SplInd && !TraceCell) newtrace = TRUE; + + if (SplCntInd) { + TRACE_CHECK(TheTraceSteps, TraceStepsInd, SplCntInd+3*n, Tracestpend) + + /* Sort the values deriving from the previous step */ + sort_Split_Array(SplCnt, SplCntInd); + + Part->cells += SplCntInd-1; + + /* Split the cell C and update the information for sizes of new cells */ + /* Put the new cells into the stack */ + i = ind4; + if (StackMarkers[i] != tv->stackmark) { + BigCellSize = 0; + } + for (k = 0; k < SplCntInd; k++) { + value = SplPos[SplCnt[k]]; + cls[i] = value; + + if ((StackMarkers[ind4] != tv->stackmark) && (value > BigCellSize)) { + BigCell = i; + BigCellPos = CStackInd; + BigCellSize = cls[i]; + } + SplPos[SplCnt[k]] = i; + i += value; + if (i < ind1) { + CStack[++CStackInd] = i; + StackMarkers[i] = tv->stackmark; + TRACE_CHECK(TheTrace, TraceInd, i, TraceEnd) + } + } + if ((StackMarkers[ind4] != tv->stackmark) && (BigCell != ind4)) { + CStack[BigCellPos] = ind4; + StackMarkers[BigCell] = 0; + StackMarkers[ind4] = tv->stackmark; + } + + /* Permute elements of the cell C */ + i = ind4; + do { + SplCnt[SplPos[NghCounts[lab[i]]]++] = lab[i]; + } + while(++i < ind1); + + /* Reconstruct the cell C and update the inverse partition */ + newcell = ind4; + i = ind4; + ind2 = newcell+cls[newcell]-1; + do { + lab[i] = SplCnt[i]; + InvLab[lab[i]] = i; + Part->inv[i] = newcell; + if (i == ind2) { + newcell = i+1; + if (newcell < n) ind2 = newcell+cls[newcell]-1; + } + } + while (++i < ind1); + + for (i = ind4; i < ind1; i+=cls[i]) { + if (cls[i] == 1) { + Cand->singcode = MASHCOMM(Cand->singcode, Cand->lab[i]); + if (newtrace) Singletons[SingInd] = i; + SingInd++; + } + } + } + } + ind4 = ind1; + } + + /* DENSE-DENSE CASE */ + if (SplInd) { + if (!TraceCell) { + newtrace = TRUE; + } + TRACE_CHECK(TheTraceSplNum, TraceCCInd, SplInd+3*n, &Traceccend) + if (newtrace) { + TheTraceCC[TraceCCInd-1] = ind0; + } + } + else { + if ((!newtrace) && TraceCell) { + return 0; + } + } + + } + } + } + } + while (weightend < iend1int); + } /* end while (CStackInd > 0) */ + + tv->augmented_cells = Part->cells - tv->augmented_cells; + + if (make_code) { + for (i=SpineTL->trcstart; i < TraceInd; i++) { + ind0 = TheTrace[i]; + longcode = MASHNONCOMM(longcode, Part->inv[ind0]); + labi = lab[ind0]; + iend1int = TheGraph[labi].d; + nghb = TheGraph[labi].e; + for (j1int = 0; j1int < iend1int; ++j1int) { + k = nghb[j1int]; + value = Part->inv[InvLab[k]]; + longcode = MASHCOMM(longcode, value); + } + } + } + Part->code = Cand->code = CLEANUP(longcode); + tlp1 = tv->tolevel+1; + if (newtrace) { + if ((tlp1 < n) && (tlp1 > tv->treedepth)) { + tv->treedepth = tlp1; + if (tv->strategy) { + Spine[tlp1].part = NewPartition(n); + } + else { + NewPartSpine(tlp1,n); + } + Spine[tlp1].liststart = Spine[tlp1].listend = NULL; + Spine[tlp1].listcounter = 0; + } + *TraceEnd = TraceInd; + SpineTL->ccend = TraceCCInd; + SpineTL->singend = SingInd; + *Tracestpend = TraceStepsInd; + + SpineTL->thetracexists = TRUE; + if (tlp1 < n) { + Spine[tlp1].ccstart = TraceCCInd; + Spine[tlp1].singstart = Spine[tlp1].singend = SingInd; + Spine[tlp1].stpstart = TraceStepsInd; + Spine[tlp1].thetracexists = FALSE; + Spine[tlp1].part->code = -1; + } + return 2; + } + else { + if (TraceInd < *TraceEnd) { + return 0; + } + if (Cand->code > SpineTL->part->code) { + return 2; + } + else { + if (Cand->code < SpineTL->part->code) { + return 0; + } + } + return 1; + } +} + +void traces_refine_notrace(Candidate *Cand, + int n, + Partition *Part, + struct TracesVars* tv, + struct TracesInfo *ti) { + int i, j, k, jk, sc, ind0, ind1, ind2, ind3, labi, auxcells; + int value, iend, newcell; + int HitClsInd, SplInd, SplCntInd, CStackInd; + int iend1int, j1int; + unsigned int longcode; + int Split = 0; + int Sparse = TRUE; + int *lab, *cls, *InvLab, *SplitCell, *LabCell; + int BigCell, BigCellPos, BigCellSize; + int *nghb; + const int variation = 1; + int currentweight, weightstart, weightend, currentcell, currentsize; + + if (tv->stackmark > (NAUTY_INFINITY-2)) { + memset(StackMarkers, 0, n*sizeof(int)); + tv->stackmark = 0; + } + tv->stackmark++; + + tv->augmented_cells = Part->cells; + + lab = Cand->lab; + InvLab = Cand->invlab; + cls = Part->cls; + + CStackInd = 1; + CStack[1] = tv->tcellexpath+cls[tv->tcellexpath]; + + for (i = 1; i <= CStackInd; i++) { + StackMarkers[CStack[i]] = tv->stackmark; + } + + longcode = Part->cells; + + while (CStackInd > 0) { + + weightend = 0; + + if (tv->mark > (NAUTY_INFINITY-2)) { + memset(Markers, 0, n*sizeof(int)); + memset(MarkHitVtx, 0, n*sizeof(int)); + tv->mark = 0; + } + tv->mark++; + + k = Select_from_CStack(cls, CStackInd); + + currentcell = CStack[k]; + currentsize = currentcell+cls[currentcell]; + CStack[k] = CStack[CStackInd--]; /* Current Cell */ + longcode = MASHNONCOMM(longcode, currentcell); + StackMarkers[currentcell] = 0; + + labi = lab[currentcell]; + iend1int = TheGraph[labi].d; + nghb = TheGraph[labi].e; + + do { + ind0 = currentcell; + ind2 = currentsize; + weightstart = weightend; + + if (tv->options->weighted) { + currentweight = (TheGraph[labi].w)[weightstart]; + while ((iend1int > weightend) && ((TheGraph[labi].w)[weightend] == currentweight)) { + weightend++; + } + } else { + weightend = TheGraph[labi].d; + } + + /* Analysis of occurrences of neighbors of the current cell */ + /* The list of cells with neighbors in the current cell is built */ + + if (cls[ind0] == 1) { /* SINGLETON CURRENT CELL CASE */ + + /* NEIGHCOUNT_SING_MULT */ + HitClsInd = 0; + for (j1int = weightstart; j1int < weightend; ++j1int) { + k = nghb[j1int]; + value = Part->inv[InvLab[k]]; + if (cls[value] > 1) { + if (Markers[value] != tv->mark) { + HitCls[HitClsInd++] = value; + Markers[value] = tv->mark; + ElmHitCll[value] = value; + } + HitVtx[ElmHitCll[value]++] = k; + } else { + switch (variation) { + case 1: + longcode = MASHCOMM(longcode, value); + break; + default: + break; + } + } + } + /* end NEIGHCOUNT_SING_MULT */ + + tv->mark++; + FIND_SPLIT_CELLS; + + /* Sorting the cells to be split */ + sort_Split_Array(SplCls, SplInd); + + /* REARRANGE THE CELLS */ + for (j = 0; j < SplInd; j++) { + /* REARRANGE_CELLS */ + ind1 = SplCls[j]; + cls[ind1] = cls[ind1]-ElmHitCll[ind1]; + newcell = ind1+cls[ind1]; + cls[newcell] = ElmHitCll[ind1]; + Part->cells++; + if (StackMarkers[ind1] != tv->stackmark) { + if (cls[newcell] < cls[ind1]) { + CStack[++CStackInd] = newcell; + StackMarkers[newcell] = tv->stackmark; + } + else { + CStack[++CStackInd] = ind1; + StackMarkers[ind1] = tv->stackmark; + } + } + else { + CStack[++CStackInd] = newcell; + StackMarkers[newcell] = tv->stackmark; + } + SplitCell = HitVtx+ind1; + ind3 = cls[newcell]; + LabCell = lab+newcell; + for (jk = 0; jk < ind3; jk++) { + k = SplitCell[jk]; + i = LabCell[jk]; + Part->inv[newcell+jk] = newcell; + lab[InvLab[k]] = i; + InvLab[i] = InvLab[k]; + LabCell[jk] = k; + InvLab[k] = newcell+jk; + } + /* END REARRANGE_CELLS */ + + if (cls[ind1] == 1) { + Cand->pathsingcode = MASHCOMM(Cand->pathsingcode, lab[ind1]); + } + if (cls[newcell] == 1) { + Cand->pathsingcode = MASHCOMM(Cand->pathsingcode, lab[newcell]); + } + } + } + else { + if (ti->thegraphisparse) { + + /* NEIGHCOUNT_SPARSE_MULT */ + HitClsInd = 0; + if (cls[ind0] != n) { + for (i = ind0; i < ind2; i++) { + labi = lab[i]; + nghb = TheGraph[labi].e; + for (j = weightstart; j < weightend; j++) { + k = nghb[j]; + if (MarkHitVtx[k] == tv->mark) { + NghCounts[k]++; + } + else { + value = Part->inv[InvLab[k]]; + if (cls[value] > 1) { + MarkHitVtx[k] = tv->mark; + NghCounts[k] = 1; + if (Markers[value] != tv->mark) { + HitCls[HitClsInd++] = value; + Markers[value] = tv->mark; + HitVtx[value] = k; + ElmHitCll[value] = 1; + } + else { + HitVtx[value+ElmHitCll[value]++] = k; + } + } + else { + switch (variation) { + case 1: + longcode = MASHCOMM(longcode, value); + break; + default: + break; + } + } + } + } + } + } + /* End NEIGHCOUNT_SPARSE_MULT */ + + tv->mark++; + + SplInd = 0; + SplCls[0] = n; + for (j = 0; j < HitClsInd; j++) { + ind1 = HitCls[j]; + if ((ElmHitCll[ind1] > 0) && (ElmHitCll[ind1] < cls[ind1])) { + SplCls[SplInd++] = ind1; + } + else { + ind2 = ind1+cls[ind1]; + Split = FALSE; + value = NghCounts[lab[ind1++]]; + for (i = ind1; i < ind2; i++) + { + if (NghCounts[lab[i]] != value) + { + SplCls[SplInd++] = HitCls[j]; + Split = TRUE; + break; + } + } + if (!Split) { + longcode = MASHCOMM(longcode, ind1); + } + } + } + + /* Sorting the cells to be split */ + sort_Split_Array(SplCls, SplInd); + + for (sc = 0; sc < SplInd; sc++) { /* For each cell C to be split */ + ind0 = SplCls[sc]; + ind1 = ind0 + cls[ind0]; + SplCntInd = 0; + if (ElmHitCll[ind0] < cls[ind0]) { + SplCnt[SplCntInd++] = 0; + SplPos[0] = cls[ind0] - ElmHitCll[ind0]; + } + + /* According to the numbers of neighbors of C into the current cell */ + /* compute how many vertices in C will be placed into the same new cell */ + iend = ind0 + ElmHitCll[ind0]; + for (i = ind0; i < iend; i++) { + value = NghCounts[HitVtx[i]]; + if (Markers[value] != tv->mark) { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = 1; + } + else { + SplPos[value]++; + } + } + tv->mark++; + + /* Sort the values deriving from the previous step */ + sort_Split_Array(SplCnt, SplCntInd); + Part->cells += SplCntInd-1; + + /* Split the cell C and update the information for sizes of new cells */ + /* Put the new cells into the stack */ + i = ind0; + if (StackMarkers[i] != tv->stackmark) { + BigCellSize = 0; + } + for (k = 0; k < SplCntInd; k++) { + value = SplPos[SplCnt[k]]; + cls[i] = value; + if ((StackMarkers[ind0] != tv->stackmark) && (value > BigCellSize)) { + BigCell = i; + BigCellPos = CStackInd; + BigCellSize = cls[i]; + } + SplPos[SplCnt[k]] = i; + i += value; + if (i < ind1) { + CStack[++CStackInd] = i; + StackMarkers[i] = tv->stackmark; + } + } + + if ((StackMarkers[ind0] != tv->stackmark) && (BigCell != ind0)) { + CStack[BigCellPos] = ind0; + StackMarkers[BigCell] = 0; + StackMarkers[ind0] = tv->stackmark; + } + + /* Permute elements of the cell C */ + iend = ind0 + ElmHitCll[ind0]; + for (i = ind0; i < iend; i++) { + value = HitVtx[i]; + j = SplPos[NghCounts[value]]++; /* where HitVtx[i] goes */ + k = InvLab[value]; /* where HitVtx[i] is in lab */ + lab[k] = lab[j]; + lab[j] = value; + InvLab[value] = j; + InvLab[lab[k]] = k; + NghCounts[value] = 0; + } + + /* Reconstruct the cell C and update the inverse partition */ + newcell = ind1 - ElmHitCll[ind0]; + i = newcell; + ind2 = newcell+cls[newcell]-1; + do { + Part->inv[i] = newcell; + if (i == ind2) { + newcell = i+1; + if (newcell < n) ind2 = newcell+cls[newcell]-1; + } + } + while (++i < ind1); + + for (i = ind0, k = 0; k < SplCntInd; i+=cls[i], k++) { + if (cls[i] == 1) { + Cand->pathsingcode = MASHCOMM(Cand->pathsingcode, lab[i]); + } + } + + } + } + else { + if (TheGraph[lab[ind0]].d > n/cls[ind0]) { + Sparse = FALSE; + } + else { + Sparse = TRUE; + } + Sparse = TRUE; + if (Sparse) { + /* Counting occurrences of neighbors of the current cell */ + /* The list of cells with neighbors in the current cell is also built */ + if (cls[ind0] == n) { + for (i = 0; i < n; i++) { + NghCounts[i] = TheGraph[i].d; + } + HitCls[0] = 0; + HitClsInd = 1; + } + else { + memset(NghCounts, 0, n*sizeof(int)); + + /* NEIGHCOUNT_DENSE_SPARSE_MULT */ + HitClsInd = 0; + for (i = ind0; i < ind2; i++) { + labi = lab[i]; + nghb = TheGraph[labi].e; + for (j1int = weightstart; j1int < weightend; ++j1int) { + k = nghb[j1int]; + (NghCounts[k])++; + value = Part->inv[InvLab[k]]; + if (Markers[value] != tv->mark) { + if (cls[value] > 1) HitCls[HitClsInd++] = value; + Markers[value] = tv->mark; + } + } + } + /* End NEIGHCOUNT_DENSE_SPARSE_MULT */ + + } + + tv->mark++; + + SplInd = 0; + for (j = 0; j < HitClsInd; j++) { + ind1 = HitCls[j]; + ind2 = ind1+cls[ind1]; + value = NghCounts[lab[ind1++]]; + for (i = ind1; i < ind2; i++) + { + if (NghCounts[lab[i]] != value) + { + SplCls[SplInd++] = HitCls[j]; + break; + } + } + } + + /* Sorting the cells to be split */ + sort_Split_Array(SplCls, SplInd); + + for (j = 0; j < SplInd; j++) { /* For each cell C to be split */ + ind0 = SplCls[j]; + ind1 = ind0+cls[ind0]; + SplCntInd = 0; + + /* According to the numbers of neighbors of C into the current cell */ + /* compute how many vertices in C will be placed into the same new cell */ + for (i = ind0; i < ind1; i++) { + value = NghCounts[lab[i]]; + if (Markers[value] != tv->mark) { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = 1; + } + else { + SplPos[value]++; + } + } + + tv->mark++; + + /* Sort the values deriving from the previous step */ + sort_Split_Array(SplCnt, SplCntInd); + + Part->cells += SplCntInd-1; + + /* Split the cell C and update the information for sizes of new cells */ + /* Put the new cells into the stack */ + i = ind0; + if (StackMarkers[i] != tv->stackmark) { + BigCellSize = 0; + } + for (k = 0; k < SplCntInd; k++) { + value = SplPos[SplCnt[k]]; + cls[i] = value; + if ((StackMarkers[ind0] != tv->stackmark) && (value > BigCellSize)) { + BigCell = i; + BigCellPos = CStackInd; + BigCellSize = cls[i]; + } + SplPos[SplCnt[k]] = i; + i += value; + if (i < ind1) { + CStack[++CStackInd] = i; + StackMarkers[i] = tv->stackmark; + } + } + if ((StackMarkers[ind0] != tv->stackmark) && (BigCell != ind0)) { + CStack[BigCellPos] = ind0; + StackMarkers[BigCell] = 0; + StackMarkers[ind0] = tv->stackmark; + } + + /* Permute elements of the cell C */ + i = ind0; + do { + SplCnt[SplPos[NghCounts[lab[i]]]++] = lab[i]; + } + while(++i < ind1); + + /* Reconstruct the cell C and update the inverse partition */ + newcell = ind0; + i = ind0; + ind2 = newcell+cls[newcell]-1; + do { + lab[i] = SplCnt[i]; + InvLab[lab[i]] = i; + Part->inv[i] = newcell; + + if (i == ind2) { + newcell = i+1; + if (newcell < n) ind2 = newcell+cls[newcell]-1; + } + } + while (++i < ind1); + + for (i = ind0, k = 0; k < SplCntInd; i+=cls[i], k++) { + if (cls[i] == 1) { + Cand->pathsingcode = MASHCOMM(Cand->pathsingcode, lab[i]); + } + } + + } + } + else { + if (cls[ind0] == n) { + for (i = 0; i < n; i++) { + NghCounts[i] = TheGraph[i].d; + } + } + else { + memset(NghCounts, 0, n*sizeof(int)); + + /* NEIGHCOUNT_DENSE_DENSE_MULT */ + for (i = ind0; i < ind2; i++) { + labi = lab[i]; + nghb = TheGraph[labi].e; + for (j1int = weightstart; j1int < weightend; ++j1int) { + k = nghb[j1int]; + (NghCounts[k])++; + } + } + /* End NEIGHCOUNT_DENSE_DENSE_MULT */ + + } + + ind0 = 0; + while (ind0 < n) { /* For each cell C with size(C) > 1 */ + ind1 = ind0+cls[ind0]; + if (cls[ind0] > 1) { + + /* Determine whether C must be split */ + SplCntInd = 0; + value = NghCounts[lab[ind0]]; + for (i = ind0+1; i < ind1; i++) + { + if (NghCounts[lab[i]] != value) + { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = i-ind0; + do { + value = NghCounts[lab[i++]]; + if (Markers[value] != tv->mark) { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = 1; + } + else { + SplPos[value]++; + } + } + while(i != ind1); + break; + } + } + + if (SplCntInd) { + tv->mark++; + + /* Sort the values deriving from the previous step */ + sort_Split_Array(SplCnt, SplCntInd); + Part->cells += SplCntInd-1; + + /* Split the cell C and update the information for sizes of new cells */ + /* Put the new cells into the stack */ + i = ind0; + if (StackMarkers[i] != tv->stackmark) { + BigCellSize = 0; + } + for (k = 0; k < SplCntInd; k++) { + value = SplPos[SplCnt[k]]; + cls[i] = value; + if ((StackMarkers[ind0] != tv->stackmark) && (value > BigCellSize)) { + BigCell = i; + BigCellPos = CStackInd; + BigCellSize = cls[i]; + } + SplPos[SplCnt[k]] = i; + i += value; + if (i < ind1) { + CStack[++CStackInd] = i; + StackMarkers[i] = tv->stackmark; + } + } + if ((StackMarkers[ind0] != tv->stackmark) && (BigCell != ind0)) { + CStack[BigCellPos] = ind0; + StackMarkers[BigCell] = 0; + StackMarkers[ind0] = tv->stackmark; + } + + /* Permute elements of the cell C */ + i = ind0; + do { + SplCnt[SplPos[NghCounts[lab[i]]]++] = lab[i]; + } + while(++i < ind1); + + /* Reconstruct the cell C and update the inverse partition */ + newcell = ind0; + i = ind0; + ind2 = newcell+cls[newcell]-1; + do { + lab[i] = SplCnt[i]; + InvLab[lab[i]] = i; + Part->inv[i] = newcell; + if (i == ind2) { + newcell = i+1; + if (newcell < n) ind2 = newcell+cls[newcell]-1; + } + } + while (++i < ind1); + + for (i = ind0; i < ind1; i+=cls[i]) { + if (cls[i] == 1) { + Cand->pathsingcode = MASHCOMM(Cand->pathsingcode, lab[i]); + } + } + + } + } + ind0 = ind1; + } + } + } + } + } + while (weightend < iend1int); + } /* end while (CStackInd > 0) */ + + tv->augmented_cells = Part->cells - tv->augmented_cells; + Cand->code = CLEANUP(longcode); + return; +} + +void traces_refine_maketrie(Candidate *Cand, + int n, + Partition *Part, + struct TracesVars* tv, + struct TracesInfo *ti) { + int i, j, k, jk, sc, ind0, ind1, ind2, ind3, labi; + int value, iend, newcell; + int HitClsInd, SplInd, SplCntInd, CStackInd; + int j1int, iend1int; + unsigned int longcode; + int Split = 0; + int Sparse = TRUE; + int *lab, *cls, *InvLab, *SplitCell, *LabCell; + int BigCell, BigCellPos, BigCellSize; + int *nghb; + const int variation = 1; + int currentweight, weightstart, weightend, currentcell, currentsize; + + if (tv->stackmark > (NAUTY_INFINITY-2)) { + memset(StackMarkers, 0, n*sizeof(int)); + tv->stackmark = 0; + } + tv->stackmark++; + + tv->augmented_cells = Part->cells; + + lab = Cand->lab; + InvLab = Cand->invlab; + cls = Part->cls; + + CStack[1] = Spine[tv->tolevel_tl].tgtpos; + CStackInd = 1; + for (i = 1; i <= CStackInd; i++) { + StackMarkers[CStack[i]] = tv->stackmark; + } + + longcode = Part->cells; + + while (CStackInd > 0) + { + weightend = 0; + + if (tv->mark > (NAUTY_INFINITY-2)) { + memset(Markers, 0, n*sizeof(int)); + memset(MarkHitVtx, 0, n*sizeof(int)); + tv->mark = 0; + } + tv->mark++; + + if (Part->cells == n) break; + + k = Select_from_CStack(cls, CStackInd); + + currentcell = CStack[k]; + currentsize = currentcell+cls[currentcell]; + CStack[k] = CStack[CStackInd--]; + longcode = MASHNONCOMM(longcode, currentcell); + StackMarkers[currentcell] = 0; + + labi = lab[currentcell]; + iend1int = TheGraph[labi].d; + nghb = TheGraph[labi].e; + + do { + ind0 = currentcell; + ind2 = currentsize; + weightstart = weightend; + + if (tv->options->weighted) { + currentweight = (TheGraph[labi].w)[weightstart]; + while ((iend1int > weightend) && ((TheGraph[labi].w)[weightend] == currentweight)) { + weightend++; + } + } else { + weightend = TheGraph[labi].d; + } + + /* Analysis of occurrences of neighbors of the current cell */ + /* The list of cells with neighbors in the current cell is built */ + if (cls[ind0] == 1) { /* SINGLETON CURRENT CELL CASE */ + + /* NEIGHCOUNT_SING_MULT */ + HitClsInd = 0; + for (j1int = weightstart; j1int < weightend; ++j1int) { + k = nghb[j1int]; + value = Part->inv[InvLab[k]]; + if (cls[value] > 1) { + if (Markers[value] != tv->mark) { + HitCls[HitClsInd++] = value; + Markers[value] = tv->mark; + ElmHitCll[value] = value; + } + HitVtx[ElmHitCll[value]++] = k; + } else { + switch (variation) { + case 1: + longcode = MASHCOMM(longcode, value); + break; + default: + break; + } + } + } + /* end NEIGHCOUNT_SING_MULT */ + + tv->mark++; + FIND_SPLIT_CELLS; + + /* Sorting the cells to be split */ + sort_Split_Array(SplCls, SplInd); + + for (j = 0; j < SplInd; j++) { + ind1 = SplCls[j]; + i = ind1+cls[ind1]-ElmHitCll[ind1]; + trieref = trie_make(trieref, i, n, tv); + } + + /* REARRANGE THE CELLS */ + for (j = 0; j < SplInd; j++) { + /* REARRANGE_CELLS */ + ind1 = SplCls[j]; + cls[ind1] = cls[ind1]-ElmHitCll[ind1]; + newcell = ind1+cls[ind1]; + cls[newcell] = ElmHitCll[ind1]; + Part->cells++; + if (StackMarkers[ind1] != tv->stackmark) { + if (cls[newcell] < cls[ind1]) { + CStack[++CStackInd] = newcell; + StackMarkers[newcell] = tv->stackmark; + } + else { + CStack[++CStackInd] = ind1; + StackMarkers[ind1] = tv->stackmark; + } + } + else { + CStack[++CStackInd] = newcell; + StackMarkers[newcell] = tv->stackmark; + } + SplitCell = HitVtx+ind1; + ind3 = cls[newcell]; + LabCell = lab+newcell; + for (jk = 0; jk < ind3; jk++) { + k = SplitCell[jk]; + i = LabCell[jk]; + Part->inv[newcell+jk] = newcell; + lab[InvLab[k]] = i; + InvLab[i] = InvLab[k]; + LabCell[jk] = k; + InvLab[k] = newcell+jk; + } + /* END REARRANGE_CELLS */ + } + } + else { + if (ti->thegraphisparse) { + + /* NEIGHCOUNT_SPARSE_MULT */ + HitClsInd = 0; + if (cls[ind0] != n) { + for (i = ind0; i < ind2; i++) { + labi = lab[i]; + nghb = TheGraph[labi].e; + for (j = weightstart; j < weightend; j++) { + k = nghb[j]; + if (MarkHitVtx[k] == tv->mark) { + NghCounts[k]++; + } + else { + value = Part->inv[InvLab[k]]; + if (cls[value] > 1) { + MarkHitVtx[k] = tv->mark; + NghCounts[k] = 1; + if (Markers[value] != tv->mark) { + HitCls[HitClsInd++] = value; + Markers[value] = tv->mark; + HitVtx[value] = k; + ElmHitCll[value] = 1; + } + else { + HitVtx[value+ElmHitCll[value]++] = k; + } + } + else { + switch (variation) { + case 1: + longcode = MASHCOMM(longcode, value); + break; + default: + break; + } + } + } + } + } + } + /* End NEIGHCOUNT_SPARSE_MULT */ + + tv->mark++; + + SplInd = 0; + SplCls[0] = n; + for (j = 0; j < HitClsInd; j++) { + ind1 = HitCls[j]; + if ((ElmHitCll[ind1] > 0) && (ElmHitCll[ind1] < cls[ind1])) { + SplCls[SplInd++] = ind1; + } + else { + ind2 = ind1+cls[ind1]; + Split = FALSE; + value = NghCounts[lab[ind1++]]; + for (i = ind1; i < ind2; i++) + { + if (NghCounts[lab[i]] != value) + { + SplCls[SplInd++] = HitCls[j]; + Split = TRUE; + break; + } + } + if (!Split) { + longcode = MASHCOMM(longcode, ind1); + } + } + } + + /* Sorting the cells to be split */ + sort_Split_Array(SplCls, SplInd); + + for (sc = 0; sc < SplInd; sc++) { /* For each cell C to be split */ + ind0 = SplCls[sc]; + ind1 = ind0 + cls[ind0]; + SplCntInd = 0; + if (ElmHitCll[ind0] < cls[ind0]) { + SplCnt[SplCntInd++] = 0; + SplPos[0] = cls[ind0] - ElmHitCll[ind0]; + } + + /* According to the numbers of neighbors of C into the current cell */ + /* compute how many vertices in C will be placed into the same new cell */ + iend = ind0 + ElmHitCll[ind0]; + for (i = ind0; i < iend; i++) { + value = NghCounts[HitVtx[i]]; + if (Markers[value] != tv->mark) { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = 1; + } + else { + SplPos[value]++; + } + } + + tv->mark++; + + /* Sort the values deriving from the previous step */ + sort_Split_Array(SplCnt, SplCntInd); + Part->cells += SplCntInd-1; + + /* Split the cell C and update the information for sizes of new cells */ + /* Put the new cells into the stack */ + i = ind0; + if (StackMarkers[i] != tv->stackmark) { + BigCellSize = 0; + } + for (k = 0; k < SplCntInd; k++) { + value = SplPos[SplCnt[k]]; + cls[i] = value; + if ((StackMarkers[ind0] != tv->stackmark) && (value > BigCellSize)) { + BigCell = i; + BigCellPos = CStackInd; + BigCellSize = cls[i]; + } + SplPos[SplCnt[k]] = i; + i += value; + if (i < ind1) { + CStack[++CStackInd] = i; + StackMarkers[i] = tv->stackmark; + trieref = trie_make(trieref, i, n, tv); + } + } + + if ((StackMarkers[ind0] != tv->stackmark) && (BigCell != ind0)) { + CStack[BigCellPos] = ind0; + StackMarkers[BigCell] = 0; + StackMarkers[ind0] = tv->stackmark; + } + /* Permute elements of the cell C */ + iend = ind0 + ElmHitCll[ind0]; + for (i = ind0; i < iend; i++) { + value = HitVtx[i]; + j = SplPos[NghCounts[value]]++; /* where HitVtx[i] goes */ + k = InvLab[value]; /* where HitVtx[i] is in lab */ + lab[k] = lab[j]; + lab[j] = value; + InvLab[value] = j; + InvLab[lab[k]] = k; + NghCounts[value] = 0; + } + + /* Reconstruct the cell C and update the inverse partition */ + newcell = ind1 - ElmHitCll[ind0]; + i = newcell; + ind2 = newcell+cls[newcell]-1; + do { + Part->inv[i] = newcell; + if (i == ind2) { + newcell = i+1; + if (newcell < n) ind2 = newcell+cls[newcell]-1; + } + } + while (++i < ind1); + } + } + else { + if (TheGraph[lab[ind0]].d > n/cls[ind0]) { + Sparse = FALSE; + } + else { + Sparse = TRUE; + } + Sparse = TRUE; + if (Sparse) { + /* Counting occurrences of neighbors of the current cell */ + /* The list of cells with neighbors in the current cell is also built */ + if (cls[ind0] == n) { + for (i = 0; i < n; i++) { + NghCounts[i] = TheGraph[i].d; + } + HitCls[0] = 0; + HitClsInd = 1; + } + else { + memset(NghCounts, 0, n*sizeof(int)); + + /* NEIGHCOUNT_DENSE_SPARSE_MULT */ + HitClsInd = 0; + for (i = ind0; i < ind2; i++) { + labi = lab[i]; + nghb = TheGraph[labi].e; + for (j1int = weightstart; j1int < weightend; ++j1int) { + k = nghb[j1int]; + (NghCounts[k])++; + value = Part->inv[InvLab[k]]; + if (Markers[value] != tv->mark) { + if (cls[value] > 1) HitCls[HitClsInd++] = value; + Markers[value] = tv->mark; + } + } + } + /* End NEIGHCOUNT_DENSE_SPARSE_MULT */ + + } + + tv->mark++; + + SplInd = 0; + for (j = 0; j < HitClsInd; j++) { + ind1 = HitCls[j]; + ind2 = ind1+cls[ind1]; + value = NghCounts[lab[ind1++]]; + for (i = ind1; i < ind2; i++) + { + if (NghCounts[lab[i]] != value) + { + SplCls[SplInd++] = HitCls[j]; + break; + } + } + } + + /* Sorting the cells to be split */ + sort_Split_Array(SplCls, SplInd); + + for (j = 0; j < SplInd; j++) { /* For each cell C to be split */ + ind0 = SplCls[j]; + ind1 = ind0+cls[ind0]; + SplCntInd = 0; + + /* According to the numbers of neighbors of C into the current cell */ + /* compute how many vertices in C will be placed into the same new cell */ + for (i = ind0; i < ind1; i++) { + value = NghCounts[lab[i]]; + if (Markers[value] != tv->mark) { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = 1; + } + else { + SplPos[value]++; + } + } + + tv->mark++; + + /* Sort the values deriving from the previous step */ + sort_Split_Array(SplCnt, SplCntInd); + Part->cells += SplCntInd-1; + + /* Split the cell C and update the information for sizes of new cells */ + /* Put the new cells into the stack */ + i = ind0; + if (StackMarkers[i] != tv->stackmark) { + BigCellSize = 0; + } + for (k = 0; k < SplCntInd; k++) { + value = SplPos[SplCnt[k]]; + cls[i] = value; + if ((StackMarkers[ind0] != tv->stackmark) && (value > BigCellSize)) { + BigCell = i; + BigCellPos = CStackInd; + BigCellSize = cls[i]; + } + SplPos[SplCnt[k]] = i; + i += value; + if (i < ind1) { + CStack[++CStackInd] = i; + StackMarkers[i] = tv->stackmark; + trieref = trie_make(trieref, i, n, tv); + } + } + if ((StackMarkers[ind0] != tv->stackmark) && (BigCell != ind0)) { + CStack[BigCellPos] = ind0; + StackMarkers[BigCell] = 0; + StackMarkers[ind0] = tv->stackmark; + } + + /* Permute elements of the cell C */ + i = ind0; + do { + SplCnt[SplPos[NghCounts[lab[i]]]++] = lab[i]; + } + while(++i < ind1); + + /* Reconstruct the cell C and update the inverse partition */ + newcell = ind0; + i = ind0; + ind2 = newcell+cls[newcell]-1; + do { + lab[i] = SplCnt[i]; + InvLab[lab[i]] = i; + Part->inv[i] = newcell; + if (i == ind2) { + newcell = i+1; + if (newcell < n) ind2 = newcell+cls[newcell]-1; + } + } + while (++i < ind1); + } + } + else { + if (cls[ind0] == n) { + for (i = 0; i < n; i++) { + NghCounts[i] = TheGraph[i].d; + } + } + else { + memset(NghCounts, 0, n*sizeof(int)); + + /* NEIGHCOUNT_DENSE_DENSE_MULT */ + for (i = ind0; i < ind2; i++) { + labi = lab[i]; + nghb = TheGraph[labi].e; + for (j1int = weightstart; j1int < weightend; ++j1int) { + k = nghb[j1int]; + (NghCounts[k])++; + } + } + /* End NEIGHCOUNT_DENSE_DENSE_MULT */ + + } + + ind0 = 0; + while (ind0 < n) { /* For each cell C with size(C) > 1 */ + ind1 = ind0+cls[ind0]; + if (cls[ind0] > 1) { + + /* Determine whether C must be split */ + SplCntInd = 0; + value = NghCounts[lab[ind0]]; + for (i = ind0+1; i < ind1; i++) + { + if (NghCounts[lab[i]] != value) + { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = i-ind0; + do { + value = NghCounts[lab[i++]]; + if (Markers[value] != tv->mark) { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = 1; + } + else { + SplPos[value]++; + } + } + while(i != ind1); + break; + } + } + + if (SplCntInd) { + tv->mark++; + + /* Sort the values deriving from the previous step */ + sort_Split_Array(SplCnt, SplCntInd); + + Part->cells += SplCntInd-1; + + /* Split the cell C and update the information for sizes of new cells */ + /* Put the new cells into the stack */ + i = ind0; + if (StackMarkers[i] != tv->stackmark) { + BigCellSize = 0; + } + for (k = 0; k < SplCntInd; k++) { + value = SplPos[SplCnt[k]]; + cls[i] = value; + if ((StackMarkers[ind0] != tv->stackmark) && (value > BigCellSize)) { + BigCell = i; + BigCellPos = CStackInd; + BigCellSize = cls[i]; + } + SplPos[SplCnt[k]] = i; + i += value; + if (i < ind1) { + CStack[++CStackInd] = i; + StackMarkers[i] = tv->stackmark; + } + } + if ((StackMarkers[ind0] != tv->stackmark) && (BigCell != ind0)) { + CStack[BigCellPos] = ind0; + StackMarkers[BigCell] = 0; + StackMarkers[ind0] = tv->stackmark; + trieref = trie_make(trieref, i, n, tv); + } + + /* Permute elements of the cell C */ + i = ind0; + do { + SplCnt[SplPos[NghCounts[lab[i]]]++] = lab[i]; + } + while(++i < ind1); + + /* Reconstruct the cell C and update the inverse partition */ + newcell = ind0; + i = ind0; + ind2 = newcell+cls[newcell]-1; + do { + lab[i] = SplCnt[i]; + InvLab[lab[i]] = i; + Part->inv[i] = newcell; + if (i == ind2) { + newcell = i+1; + if (newcell < n) ind2 = newcell+cls[newcell]-1; + } + } + while (++i < ind1); + } + } + ind0 = ind1; + } + } + } + } + } + while (weightend < iend1int); + } /* end while (CStackInd > 0) */ + + tv->augmented_cells = Part->cells - tv->augmented_cells; + + Cand->code = CLEANUP(longcode); + return; +} + +int traces_refine_comptrie(Candidate *Cand, + int n, + Partition *Part, + struct TracesVars* tv, + struct TracesInfo *ti) { + int i, j, k, jk, sc, ind0, ind1, ind2, ind3, labi; + int value, iend, newcell; + int HitClsInd, SplInd, SplCntInd, CStackInd; + int j1int, iend1int; + unsigned int longcode; + int Split = 0; + int Sparse = TRUE; + int *lab, *cls, *InvLab, *SplitCell, *LabCell; + int BigCell, BigCellPos, BigCellSize; + int *nghb; + const int variation = 1; + int currentweight, weightstart, weightend, currentcell, currentsize; + + if (tv->stackmark > (NAUTY_INFINITY-2)) { + memset(StackMarkers, 0, n*sizeof(int)); + tv->stackmark = 0; + } + tv->stackmark++; + + tv->augmented_cells = Part->cells; + + lab = Cand->lab; + InvLab = Cand->invlab; + cls = Part->cls; + + CStack[1] = Spine[tv->tolevel_tl].tgtpos; + CStackInd = 1; + for (i = 1; i <= CStackInd; i++) { + StackMarkers[CStack[i]] = tv->stackmark; + } + + longcode = Part->cells; + while (CStackInd > 0) + { + + weightend = 0; + + if (tv->mark > (NAUTY_INFINITY-2)) { + memset(Markers, 0, n*sizeof(int)); + memset(MarkHitVtx, 0, n*sizeof(int)); + tv->mark = 0; + } + tv->mark++; + + if (Part->cells == n) break; + + k = Select_from_CStack(cls, CStackInd); + + currentcell = CStack[k]; + currentsize = currentcell+cls[currentcell]; + CStack[k] = CStack[CStackInd--]; /* Current Cell */ + longcode = MASHNONCOMM(longcode, currentcell); + StackMarkers[currentcell] = 0; + + labi = lab[currentcell]; + iend1int = TheGraph[labi].d; + nghb = TheGraph[labi].e; + + do { + ind0 = currentcell; + ind2 = currentsize; + weightstart = weightend; + + if (tv->options->weighted) { + currentweight = (TheGraph[labi].w)[weightstart]; + while ((iend1int > weightend) && ((TheGraph[labi].w)[weightend] == currentweight)) { + weightend++; + } + } else { + weightend = TheGraph[labi].d; + } + + /* Analysis of occurrences of neighbors of the current cell */ + /* The list of cells with neighbors in the current cell is built */ + if (cls[ind0] == 1) { /* SINGLETON CURRENT CELL CASE */ + + /* NEIGHCOUNT_SING_MULT */ + HitClsInd = 0; + for (j1int = weightstart; j1int < weightend; ++j1int) { + k = nghb[j1int]; + value = Part->inv[InvLab[k]]; + if (cls[value] > 1) { + if (Markers[value] != tv->mark) { + HitCls[HitClsInd++] = value; + Markers[value] = tv->mark; + ElmHitCll[value] = value; + } + HitVtx[ElmHitCll[value]++] = k; + } else { + switch (variation) { + case 1: + longcode = MASHCOMM(longcode, value); + break; + default: + break; + } + } + } + /* end NEIGHCOUNT_SING_MULT */ + + tv->mark++; + FIND_SPLIT_CELLS; + + /* Sorting the cells to be split */ + sort_Split_Array(SplCls, SplInd); + + for (j = 0; j < SplInd; j++) { + ind1 = SplCls[j]; + i = ind1+cls[ind1]-ElmHitCll[ind1]; + trieref = trie_comp(trieref, i); + if (trieref == NULL) return 0; + } + + /* REARRANGE THE CELLS */ + for (j = 0; j < SplInd; j++) { + /* REARRANGE_CELLS */ + ind1 = SplCls[j]; + cls[ind1] = cls[ind1]-ElmHitCll[ind1]; + newcell = ind1+cls[ind1]; + cls[newcell] = ElmHitCll[ind1]; + Part->cells++; + if (StackMarkers[ind1] != tv->stackmark) { + if (cls[newcell] < cls[ind1]) { + CStack[++CStackInd] = newcell; + StackMarkers[newcell] = tv->stackmark; + } + else { + CStack[++CStackInd] = ind1; + StackMarkers[ind1] = tv->stackmark; + } + } + else { + CStack[++CStackInd] = newcell; + StackMarkers[newcell] = tv->stackmark; + } + SplitCell = HitVtx+ind1; + ind3 = cls[newcell]; + LabCell = lab+newcell; + for (jk = 0; jk < ind3; jk++) { + k = SplitCell[jk]; + i = LabCell[jk]; + Part->inv[newcell+jk] = newcell; + lab[InvLab[k]] = i; + InvLab[i] = InvLab[k]; + LabCell[jk] = k; + InvLab[k] = newcell+jk; + } + /* END REARRANGE_CELLS */ + } + } + else { + if (ti->thegraphisparse) { + + /* NEIGHCOUNT_SPARSE_MULT */ + HitClsInd = 0; + if (cls[ind0] != n) { + for (i = ind0; i < ind2; i++) { + labi = lab[i]; + nghb = TheGraph[labi].e; + for (j = weightstart; j < weightend; j++) { + k = nghb[j]; + if (MarkHitVtx[k] == tv->mark) { + NghCounts[k]++; + } + else { + value = Part->inv[InvLab[k]]; + if (cls[value] > 1) { + MarkHitVtx[k] = tv->mark; + NghCounts[k] = 1; + if (Markers[value] != tv->mark) { + HitCls[HitClsInd++] = value; + Markers[value] = tv->mark; + HitVtx[value] = k; + ElmHitCll[value] = 1; + } + else { + HitVtx[value+ElmHitCll[value]++] = k; + } + } + else { + switch (variation) { + case 1: + longcode = MASHCOMM(longcode, value); + break; + default: + break; + } + } + } + } + } + } + /* End NEIGHCOUNT_SPARSE_MULT */ + + tv->mark++; + + SplInd = 0; + SplCls[0] = n; + for (j = 0; j < HitClsInd; j++) { + ind1 = HitCls[j]; + if ((ElmHitCll[ind1] > 0) && (ElmHitCll[ind1] < cls[ind1])) { + SplCls[SplInd++] = ind1; + } + else { + ind2 = ind1+cls[ind1]; + Split = FALSE; + value = NghCounts[lab[ind1++]]; + for (i = ind1; i < ind2; i++) + { + if (NghCounts[lab[i]] != value) + { + SplCls[SplInd++] = HitCls[j]; + Split = TRUE; + break; + } + } + if (!Split) { + longcode = MASHCOMM(longcode, ind1); + } + } + } + + /* Sorting the cells to be split */ + sort_Split_Array(SplCls, SplInd); + + for (sc = 0; sc < SplInd; sc++) { /* For each cell C to be split */ + ind0 = SplCls[sc]; + ind1 = ind0 + cls[ind0]; + SplCntInd = 0; + if (ElmHitCll[ind0] < cls[ind0]) { + SplCnt[SplCntInd++] = 0; + SplPos[0] = cls[ind0] - ElmHitCll[ind0]; + } + + /* According to the numbers of neighbors of C into the current cell */ + /* compute how many vertices in C will be placed into the same new cell */ + iend = ind0 + ElmHitCll[ind0]; + for (i = ind0; i < iend; i++) { + value = NghCounts[HitVtx[i]]; + if (Markers[value] != tv->mark) { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = 1; + } + else { + SplPos[value]++; + } + } + + tv->mark++; + + /* Sort the values deriving from the previous step */ + sort_Split_Array(SplCnt, SplCntInd); + Part->cells += SplCntInd-1; + + /* Split the cell C and update the information for sizes of new cells */ + /* Put the new cells into the stack */ + i = ind0; + if (StackMarkers[i] != tv->stackmark) { + BigCellSize = 0; + } + for (k = 0; k < SplCntInd; k++) { + value = SplPos[SplCnt[k]]; + cls[i] = value; + if ((StackMarkers[ind0] != tv->stackmark) && (value > BigCellSize)) { + BigCell = i; + BigCellPos = CStackInd; + BigCellSize = cls[i]; + } + SplPos[SplCnt[k]] = i; + i += value; + if (i < ind1) { + CStack[++CStackInd] = i; + StackMarkers[i] = tv->stackmark; + trieref = trie_comp(trieref, i); + if (trieref == NULL) return 0; + } + } + + if ((StackMarkers[ind0] != tv->stackmark) && (BigCell != ind0)) { + CStack[BigCellPos] = ind0; + StackMarkers[BigCell] = 0; + StackMarkers[ind0] = tv->stackmark; + } + /* Permute elements of the cell C */ + iend = ind0 + ElmHitCll[ind0]; + for (i = ind0; i < iend; i++) { + value = HitVtx[i]; + j = SplPos[NghCounts[value]]++; /* where HitVtx[i] goes */ + k = InvLab[value]; /* where HitVtx[i] is in lab */ + lab[k] = lab[j]; + lab[j] = value; + InvLab[value] = j; + InvLab[lab[k]] = k; + NghCounts[value] = 0; + } + + /* Reconstruct the cell C and update the inverse partition */ + newcell = ind1 - ElmHitCll[ind0]; + i = newcell; + ind2 = newcell+cls[newcell]-1; + do { + Part->inv[i] = newcell; + if (i == ind2) { + newcell = i+1; + if (newcell < n) ind2 = newcell+cls[newcell]-1; + } + } + while (++i < ind1); + } + } + else { + if (TheGraph[lab[ind0]].d > n/cls[ind0]) { + Sparse = FALSE; + } + else { + Sparse = TRUE; + } + Sparse = TRUE; + if (Sparse) { + /* Counting occurrences of neighbors of the current cell */ + /* The list of cells with neighbors in the current cell is also built */ + if (cls[ind0] == n) { + for (i = 0; i < n; i++) { + NghCounts[i] = TheGraph[i].d; + } + HitCls[0] = 0; + HitClsInd = 1; + } + else { + memset(NghCounts, 0, n*sizeof(int)); + + /* NEIGHCOUNT_DENSE_SPARSE_MULT */ + HitClsInd = 0; + for (i = ind0; i < ind2; i++) { + labi = lab[i]; + nghb = TheGraph[labi].e; + for (j1int = weightstart; j1int < weightend; ++j1int) { + k = nghb[j1int]; + (NghCounts[k])++; + value = Part->inv[InvLab[k]]; + if (Markers[value] != tv->mark) { + if (cls[value] > 1) HitCls[HitClsInd++] = value; + Markers[value] = tv->mark; + } + } + } + /* End NEIGHCOUNT_DENSE_SPARSE_MULT */ + ; + } + + tv->mark++; + + SplInd = 0; + for (j = 0; j < HitClsInd; j++) { + ind1 = HitCls[j]; + ind2 = ind1+cls[ind1]; + value = NghCounts[lab[ind1++]]; + for (i = ind1; i < ind2; i++) + { + if (NghCounts[lab[i]] != value) + { + SplCls[SplInd++] = HitCls[j]; + break; + } + } + } + + /* Sorting the cells to be split */ + sort_Split_Array(SplCls, SplInd); + + for (j = 0; j < SplInd; j++) { /* For each cell C to be split */ + ind0 = SplCls[j]; + ind1 = ind0+cls[ind0]; + SplCntInd = 0; + + /* According to the numbers of neighbors of C into the current cell */ + /* compute how many vertices in C will be placed into the same new cell */ + for (i = ind0; i < ind1; i++) { + value = NghCounts[lab[i]]; + if (Markers[value] != tv->mark) { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = 1; + } + else { + SplPos[value]++; + } + } + + tv->mark++; + + /* Sort the values deriving from the previous step */ + sort_Split_Array(SplCnt, SplCntInd); + + Part->cells += SplCntInd-1; + + /* Split the cell C and update the information for sizes of new cells */ + /* Put the new cells into the stack */ + i = ind0; + if (StackMarkers[i] != tv->stackmark) { + BigCellSize = 0; + } + for (k = 0; k < SplCntInd; k++) { + value = SplPos[SplCnt[k]]; + cls[i] = value; + if ((StackMarkers[ind0] != tv->stackmark) && (value > BigCellSize)) { + BigCell = i; + BigCellPos = CStackInd; + BigCellSize = cls[i]; + } + SplPos[SplCnt[k]] = i; + i += value; + if (i < ind1) { + CStack[++CStackInd] = i; + StackMarkers[i] = tv->stackmark; + trieref = trie_comp(trieref, i); + if (trieref == NULL) return 0; + } + } + if ((StackMarkers[ind0] != tv->stackmark) && (BigCell != ind0)) { + CStack[BigCellPos] = ind0; + StackMarkers[BigCell] = 0; + StackMarkers[ind0] = tv->stackmark; + } + + /* Permute elements of the cell C */ + i = ind0; + do { + SplCnt[SplPos[NghCounts[lab[i]]]++] = lab[i]; + } + while(++i < ind1); + + /* Reconstruct the cell C and update the inverse partition */ + newcell = ind0; + i = ind0; + ind2 = newcell+cls[newcell]-1; + do { + lab[i] = SplCnt[i]; + InvLab[lab[i]] = i; + Part->inv[i] = newcell; + + if (i == ind2) { + newcell = i+1; + if (newcell < n) ind2 = newcell+cls[newcell]-1; + } + } + while (++i < ind1); + } + } + else { + if (cls[ind0] == n) { + for (i = 0; i < n; i++) { + NghCounts[i] = TheGraph[i].d; + } + } + else { + memset(NghCounts, 0, n*sizeof(int)); + + /* NEIGHCOUNT_DENSE_DENSE_MULT */ + for (i = ind0; i < ind2; i++) { + labi = lab[i]; + nghb = TheGraph[labi].e; + for (j1int = weightstart; j1int < weightend; ++j1int) { + k = nghb[j1int]; + (NghCounts[k])++; + } + } + /* End NEIGHCOUNT_DENSE_DENSE_MULT */ + + } + + ind0 = 0; + while (ind0 < n) { /* For each cell C with size(C) > 1 */ + ind1 = ind0+cls[ind0]; + if (cls[ind0] > 1) { + + /* Determine whether C must be split */ + SplCntInd = 0; + value = NghCounts[lab[ind0]]; + for (i = ind0+1; i < ind1; i++) + { + if (NghCounts[lab[i]] != value) + { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = i-ind0; + do { + value = NghCounts[lab[i++]]; + if (Markers[value] != tv->mark) { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = 1; + } + else { + SplPos[value]++; + } + } + while(i != ind1); + break; + } + } + + if (SplCntInd) { + tv->mark++; + + /* Sort the values deriving from the previous step */ + sort_Split_Array(SplCnt, SplCntInd); + + Part->cells += SplCntInd-1; + + /* Split the cell C and update the information for sizes of new cells */ + /* Put the new cells into the stack */ + i = ind0; + if (StackMarkers[i] != tv->stackmark) { + BigCellSize = 0; + } + for (k = 0; k < SplCntInd; k++) { + value = SplPos[SplCnt[k]]; + cls[i] = value; + if ((StackMarkers[ind0] != tv->stackmark) && (value > BigCellSize)) { + BigCell = i; + BigCellPos = CStackInd; + BigCellSize = cls[i]; + } + SplPos[SplCnt[k]] = i; + i += value; + if (i < ind1) { + CStack[++CStackInd] = i; + StackMarkers[i] = tv->stackmark; + } + } + if ((StackMarkers[ind0] != tv->stackmark) && (BigCell != ind0)) { + CStack[BigCellPos] = ind0; + StackMarkers[BigCell] = 0; + StackMarkers[ind0] = tv->stackmark; + trieref = trie_comp(trieref, i); + if (trieref == NULL) return 0; + } + + /* Permute elements of the cell C */ + i = ind0; + do { + SplCnt[SplPos[NghCounts[lab[i]]]++] = lab[i]; + } + while(++i < ind1); + + /* Reconstruct the cell C and update the inverse partition */ + newcell = ind0; + i = ind0; + ind2 = newcell+cls[newcell]-1; + do { + lab[i] = SplCnt[i]; + InvLab[lab[i]] = i; + Part->inv[i] = newcell; + if (i == ind2) { + newcell = i+1; + if (newcell < n) ind2 = newcell+cls[newcell]-1; + } + } + while (++i < ind1); + } + } + ind0 = ind1; + } + } + } + } + } + while (weightend < iend1int); + } /* end while (CStackInd > 0) */ + + tv->augmented_cells = Part->cells - tv->augmented_cells; + + Cand->code = CLEANUP(longcode); + return 1; +} + +int traces_refine_sametrace(Candidate *Cand, + int n, + Partition *Part, + struct TracesVars* tv, + struct TracesInfo *ti) { + int i, j, k, jk, sc, ind0, ind1, ind2, ind3, ind4, labi; + int value, iend, newcell; + int HitClsInd, SplInd, SplCntInd, CStackInd, TraceInd, TraceCCInd, TraceStepsInd; + int j1int, iend1int; + unsigned int longcode; + int Sparse = TRUE; + int *lab, *cls, *InvLab, *TracePos, *SplitCell, *LabCell, *TraceEnd, Traceccend, *Tracestpend; + int BigCell, BigCellPos, BigCellSize; + boolean TraceCell = FALSE; + int *nghb; + const int variation = 0; + int currentweight, weightstart, weightend, currentcell, currentsize; + + if (tv->stackmark > (NAUTY_INFINITY-2)) { + memset(StackMarkers, 0, n*sizeof(int)); + tv->stackmark = 0; + } + tv->stackmark++; + + tv->augmented_cells = Part->cells; + + SpineTL = Spine+tv->tolevel; + TraceEnd = &(SpineTL->trcend); + Traceccend = SpineTL->ccend; + Tracestpend = &(SpineTL->stpend); + TraceCCInd = SpineTL->ccstart; + TraceStepsInd = SpineTL->stpstart; + + lab = Cand->lab; + InvLab = Cand->invlab; + cls = Part->cls; + + UPDATEMIN(Part->active, n-1); + memcpy(CStack+1, TheTrace+SpineTL->trcstart, (Part->active)*sizeof(int)); + CStackInd = Part->active; + for (i = 1; i <= CStackInd; i++) { + StackMarkers[CStack[i]] = tv->stackmark; + } + + longcode = Part->cells; + TraceInd = SpineTL->trcstart+Part->active; + + while (CStackInd > 0) + { + + weightend = 0; + + if (tv->mark > (NAUTY_INFINITY-2)) { + memset(Markers, 0, n*sizeof(int)); + memset(MarkHitVtx, 0, n*sizeof(int)); + tv->mark = 0; + } + tv->mark++; + + if (Part->cells == n) break; + + k = Select_from_CStack(cls, CStackInd); + + currentcell = CStack[k]; + currentsize = currentcell+cls[currentcell]; + CStack[k] = CStack[CStackInd--]; /* Current Cell */ + StackMarkers[currentcell] = 0; + + labi = lab[currentcell]; + iend1int = TheGraph[labi].d; + nghb = TheGraph[labi].e; + + do { + ind0 = currentcell; + ind2 = currentsize; + weightstart = weightend; + + if (tv->options->weighted) { + currentweight = (TheGraph[labi].w)[weightstart]; + while ((iend1int > weightend) && ((TheGraph[labi].w)[weightend] == currentweight)) { + weightend++; + } + } else { + weightend = TheGraph[labi].d; + } + + TraceCell = ((ind0 == TheTraceCC[TraceCCInd]) && (TraceCCInd < Traceccend)); + + /* Analysis of occurrences of neighbors of the current cell */ + /* The list of cells with neighbors in the current cell is built */ + if (cls[ind0] == 1) { /* SINGLETON CURRENT CELL CASE */ + + /* NEIGHCOUNT_SING_MULT */ + HitClsInd = 0; + for (j1int = weightstart; j1int < weightend; ++j1int) { + k = nghb[j1int]; + value = Part->inv[InvLab[k]]; + if (cls[value] > 1) { + if (Markers[value] != tv->mark) { + HitCls[HitClsInd++] = value; + Markers[value] = tv->mark; + ElmHitCll[value] = value; + } + HitVtx[ElmHitCll[value]++] = k; + } else { + switch (variation) { + case 1: + longcode = MASHCOMM(longcode, value); + break; + default: + break; + } + } + } + /* end NEIGHCOUNT_SING_MULT */ + + tv->mark++; + FIND_SPLIT_CELLS; + + /* SINGLETON CC CASE */ + if (SplInd) { + SAMETRACE_CHECK(TheTraceSplNum, TraceCCInd, SplInd, &Traceccend) + + /* Sorting the cells to be split */ + sort_Split_Array(SplCls, SplInd); + + for (j = 0; j < SplInd; j++) { + ind1 = SplCls[j]; + i = ind1+cls[ind1]-ElmHitCll[ind1]; + SAMETRACE_CHECK(TheTrace, TraceInd, i, TraceEnd) + } + + /* REARRANGE THE CELLS */ + for (j = 0; j < SplInd; j++) { + /* REARRANGE_CELLS */ + ind1 = SplCls[j]; + cls[ind1] = cls[ind1]-ElmHitCll[ind1]; + newcell = ind1+cls[ind1]; + cls[newcell] = ElmHitCll[ind1]; + Part->cells++; + if (StackMarkers[ind1] != tv->stackmark) { + if (cls[newcell] < cls[ind1]) { + CStack[++CStackInd] = newcell; + StackMarkers[newcell] = tv->stackmark; + } + else { + CStack[++CStackInd] = ind1; + StackMarkers[ind1] = tv->stackmark; + } + } + else { + CStack[++CStackInd] = newcell; + StackMarkers[newcell] = tv->stackmark; + } + SplitCell = HitVtx+ind1; + ind3 = cls[newcell]; + LabCell = lab+newcell; + for (jk = 0; jk < ind3; jk++) { + k = SplitCell[jk]; + i = LabCell[jk]; + Part->inv[newcell+jk] = newcell; + lab[InvLab[k]] = i; + InvLab[i] = InvLab[k]; + LabCell[jk] = k; + InvLab[k] = newcell+jk; + } + /* END REARRANGE_CELLS */ + + if (cls[ind1] == 1) { + Cand->singcode = MASHCOMM(Cand->singcode, Cand->lab[ind1]); + } + if (cls[newcell] == 1) { + Cand->singcode = MASHCOMM(Cand->singcode, Cand->lab[newcell]); + } + } + } + else { + if (TraceCell) { + return 0; + } + } + + } + else { + if (ti->thegraphisparse) { + + /* NEIGHCOUNT_SPARSE_MULT */ + HitClsInd = 0; + if (cls[ind0] != n) { + for (i = ind0; i < ind2; i++) { + labi = lab[i]; + nghb = TheGraph[labi].e; + for (j = weightstart; j < weightend; j++) { + k = nghb[j]; + if (MarkHitVtx[k] == tv->mark) { + NghCounts[k]++; + } + else { + value = Part->inv[InvLab[k]]; + if (cls[value] > 1) { + MarkHitVtx[k] = tv->mark; + NghCounts[k] = 1; + if (Markers[value] != tv->mark) { + HitCls[HitClsInd++] = value; + Markers[value] = tv->mark; + HitVtx[value] = k; + ElmHitCll[value] = 1; + } + else { + HitVtx[value+ElmHitCll[value]++] = k; + } + } + else { + switch (variation) { + case 1: + longcode = MASHCOMM(longcode, value); + break; + default: + break; + } + } + } + } + } + } + /* End NEIGHCOUNT_SPARSE_MULT */ + + tv->mark++; + + SplInd = 0; + SplCls[0] = n; + for (j = 0; j < HitClsInd; j++) { + ind1 = HitCls[j]; + if ((ElmHitCll[ind1] > 0) && (ElmHitCll[ind1] < cls[ind1])) { + SplCls[SplInd++] = ind1; + } + else { + ind2 = ind1+cls[ind1]; + value = NghCounts[lab[ind1++]]; + for (i = ind1; i < ind2; i++) + { + if (NghCounts[lab[i]] != value) + { + SplCls[SplInd++] = HitCls[j]; + break; + } + } + } + } + + /* SPARSE CASE */ + if (SplInd) { + SAMETRACE_CHECK(TheTraceSplNum, TraceCCInd, SplInd+n, &Traceccend) + + /* Sorting the cells to be split */ + sort_Split_Array(SplCls, SplInd); + + for (sc = 0; sc < SplInd; sc++) { /* For each cell C to be split */ + ind0 = SplCls[sc]; + ind1 = ind0 + cls[ind0]; + SplCntInd = 0; + if (ElmHitCll[ind0] < cls[ind0]) { + SplCnt[SplCntInd++] = 0; + SplPos[0] = cls[ind0] - ElmHitCll[ind0]; + } + + /* According to the numbers of neighbors of C into the current cell */ + /* compute how many vertices in C will be placed into the same new cell */ + iend = ind0 + ElmHitCll[ind0]; + for (i = ind0; i < iend; i++) { + value = NghCounts[HitVtx[i]]; + if (Markers[value] != tv->mark) { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = 1; + } + else { + SplPos[value]++; + } + } + tv->mark++; + + if (SplCntInd) { + SAMETRACE_CHECK(TheTraceSteps, TraceStepsInd, SplCntInd+n, Tracestpend) + } + + /* Sort the values deriving from the previous step */ + sort_Split_Array(SplCnt, SplCntInd); + + Part->cells += SplCntInd-1; + + /* Split the cell C and update the information for sizes of new cells */ + /* Put the new cells into the stack */ + i = ind0; + if (StackMarkers[i] != tv->stackmark) { + BigCellSize = 0; + } + for (k = 0; k < SplCntInd; k++) { + value = SplPos[SplCnt[k]]; + cls[i] = value; + if ((StackMarkers[ind0] != tv->stackmark) && (value > BigCellSize)) { + BigCell = i; + BigCellPos = CStackInd; + BigCellSize = cls[i]; + } + SplPos[SplCnt[k]] = i; + i += value; + if (i < ind1) { + CStack[++CStackInd] = i; + StackMarkers[i] = tv->stackmark; + SAMETRACE_CHECK(TheTrace, TraceInd, i, TraceEnd) + } + } + + if ((StackMarkers[ind0] != tv->stackmark) && (BigCell != ind0)) { + CStack[BigCellPos] = ind0; + StackMarkers[BigCell] = 0; + StackMarkers[ind0] = tv->stackmark; + } + /* Permute elements of the cell C */ + iend = ind0 + ElmHitCll[ind0]; + for (i = ind0; i < iend; i++) { + value = HitVtx[i]; + j = SplPos[NghCounts[value]]++; /* where HitVtx[i] goes */ + k = InvLab[value]; /* where HitVtx[i] is in lab */ + lab[k] = lab[j]; + lab[j] = value; + InvLab[value] = j; + InvLab[lab[k]] = k; + NghCounts[value] = 0; + } + + /* Reconstruct the cell C and update the inverse partition */ + newcell = ind1 - ElmHitCll[ind0]; + i = newcell; + ind2 = newcell+cls[newcell]-1; + do { + Part->inv[i] = newcell; + if (i == ind2) { + newcell = i+1; + if (newcell < n) ind2 = newcell+cls[newcell]-1; + } + } + while (++i < ind1); + + for (i = ind0, k = 0; k < SplCntInd; i+=cls[i], k++) { + if (cls[i] == 1) { + Cand->singcode = MASHCOMM(Cand->singcode, Cand->lab[i]); + } + } + + } + } + else { + if (TraceCell) { + return 0; + } + } + + } + else { + if (TheGraph[lab[ind0]].d > n/cls[ind0]) { + Sparse = FALSE; + } + else { + Sparse = TRUE; + } + Sparse = TRUE; + if (Sparse) { + /* Counting occurrences of neighbors of the current cell */ + /* The list of cells with neighbors in the current cell is also built */ + if (cls[ind0] == n) { + for (i = 0; i < n; i++) { + NghCounts[i] = TheGraph[i].d; + } + HitCls[0] = 0; + HitClsInd = 1; + } + else { + memset(NghCounts, 0, n*sizeof(int)); + + /* NEIGHCOUNT_DENSE_SPARSE_MULT */ + HitClsInd = 0; + for (i = ind0; i < ind2; i++) { + labi = lab[i]; + nghb = TheGraph[labi].e; + for (j1int = weightstart; j1int < weightend; ++j1int) { + k = nghb[j1int]; + (NghCounts[k])++; + value = Part->inv[InvLab[k]]; + if (Markers[value] != tv->mark) { + if (cls[value] > 1) HitCls[HitClsInd++] = value; + Markers[value] = tv->mark; + } + } + } + /* End NEIGHCOUNT_DENSE_SPARSE_MULT */ + + } + + tv->mark++; + + SplInd = 0; + for (j = 0; j < HitClsInd; j++) { + ind1 = HitCls[j]; + ind2 = ind1+cls[ind1]; + value = NghCounts[lab[ind1++]]; + for (i = ind1; i < ind2; i++) + { + if (NghCounts[lab[i]] != value) + { + SplCls[SplInd++] = HitCls[j]; + break; + } + } + } + + /* DENSE-SPARSE CASE */ + if (SplInd) { + SAMETRACE_CHECK(TheTraceSplNum, TraceCCInd, SplInd+2*n, &Traceccend) + + /* Sorting the cells to be split */ + sort_Split_Array(SplCls, SplInd); + + for (j = 0; j < SplInd; j++) { /* For each cell C to be split */ + ind0 = SplCls[j]; + ind1 = ind0+cls[ind0]; + SplCntInd = 0; + + /* According to the numbers of neighbors of C into the current cell */ + /* compute how many vertices in C will be placed into the same new cell */ + for (i = ind0; i < ind1; i++) { + value = NghCounts[lab[i]]; + if (Markers[value] != tv->mark) { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = 1; + } + else { + SplPos[value]++; + } + } + tv->mark++; + + if (SplCntInd) { + SAMETRACE_CHECK(TheTraceSteps, TraceStepsInd, SplCntInd+2*n, Tracestpend) + } + + /* Sort the values deriving from the previous step */ + sort_Split_Array(SplCnt, SplCntInd); + Part->cells += SplCntInd-1; + + /* Split the cell C and update the information for sizes of new cells */ + /* Put the new cells into the stack */ + i = ind0; + if (StackMarkers[i] != tv->stackmark) { + BigCellSize = 0; + } + for (k = 0; k < SplCntInd; k++) { + value = SplPos[SplCnt[k]]; + cls[i] = value; + if ((StackMarkers[ind0] != tv->stackmark) && (value > BigCellSize)) { + BigCell = i; + BigCellPos = CStackInd; + BigCellSize = cls[i]; + } + SplPos[SplCnt[k]] = i; + i += value; + if (i < ind1) { + CStack[++CStackInd] = i; + StackMarkers[i] = tv->stackmark; + SAMETRACE_CHECK(TheTrace, TraceInd, i, TraceEnd) + } + } + + if ((StackMarkers[ind0] != tv->stackmark) && (BigCell != ind0)) { + CStack[BigCellPos] = ind0; + StackMarkers[BigCell] = 0; + StackMarkers[ind0] = tv->stackmark; + } + + /* Permute elements of the cell C */ + i = ind0; + do { + SplCnt[SplPos[NghCounts[lab[i]]]++] = lab[i]; + } + while(++i < ind1); + + /* Reconstruct the cell C and update the inverse partition */ + newcell = ind0; + i = ind0; + ind2 = newcell+cls[newcell]-1; + do { + lab[i] = SplCnt[i]; + InvLab[lab[i]] = i; + Part->inv[i] = newcell; + if (i == ind2) { + newcell = i+1; + if (newcell < n) ind2 = newcell+cls[newcell]-1; + } + } + while (++i < ind1); + + for (i = ind0, k = 0; k < SplCntInd; i+=cls[i], k++) { + if (cls[i] == 1) { + Cand->singcode = MASHCOMM(Cand->singcode, Cand->lab[i]); + } + } + + } + } + else { + if (TraceCell) { + return 0; + } + } + + } + else { + if (cls[ind0] == n) { + for (i = 0; i < n; i++) { + NghCounts[i] = TheGraph[i].d; + } + } + else { + memset(NghCounts, 0, n*sizeof(int)); + + /* NEIGHCOUNT_DENSE_DENSE_MULT */ + for (i = ind0; i < ind2; i++) { + labi = lab[i]; + nghb = TheGraph[labi].e; + for (j1int = weightstart; j1int < weightend; ++j1int) { + k = nghb[j1int]; + (NghCounts[k])++; + } + } + /* End NEIGHCOUNT_DENSE_DENSE_MULT */ + + } + SplInd = 0; + ind4 = 0; + while (ind4 < n) { /* For each cell C with size(C) > 1 */ + ind1 = ind4+cls[ind4]; + if (cls[ind4] > 1) { + + /* Determine whether C must be split */ + SplCntInd = 0; + value = NghCounts[lab[ind4]]; + for (i = ind4+1; i < ind1; i++) { + if (NghCounts[lab[i]] != value) + { + SplInd++; + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = i-ind4; + do { + value = NghCounts[lab[i++]]; + if (Markers[value] != tv->mark) { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = 1; + } + else { + SplPos[value]++; + } + } + while(i != ind1); + break; + } + } + tv->mark++; + + if (SplCntInd) { + SAMETRACE_CHECK(TheTraceSteps, TraceStepsInd, SplCntInd+3*n, Tracestpend) + + /* Sort the values deriving from the previous step */ + sort_Split_Array(SplCnt, SplCntInd); + + Part->cells += SplCntInd-1; + + /* Split the cell C and update the information for sizes of new cells */ + /* Put the new cells into the stack */ + i = ind4; + if (StackMarkers[i] != tv->stackmark) { + BigCellSize = 0; + } + for (k = 0; k < SplCntInd; k++) { + value = SplPos[SplCnt[k]]; + cls[i] = value; + if ((StackMarkers[ind4] != tv->stackmark) && (value > BigCellSize)) { + BigCell = i; + BigCellPos = CStackInd; + BigCellSize = cls[i]; + } + SplPos[SplCnt[k]] = i; + i += value; + if (i < ind1) { + CStack[++CStackInd] = i; + StackMarkers[i] = tv->stackmark; + SAMETRACE_CHECK(TheTrace, TraceInd, i, TraceEnd) + } + } + if ((StackMarkers[ind4] != tv->stackmark) && (BigCell != ind4)) { + CStack[BigCellPos] = ind4; + StackMarkers[BigCell] = 0; + StackMarkers[ind4] = tv->stackmark; + } + + /* Permute elements of the cell C */ + i = ind4; + do { + SplCnt[SplPos[NghCounts[lab[i]]]++] = lab[i]; + } + while(++i < ind1); + + /* Reconstruct the cell C and update the inverse partition */ + newcell = ind4; + i = ind4; + ind2 = newcell+cls[newcell]-1; + do { + lab[i] = SplCnt[i]; + InvLab[lab[i]] = i; + Part->inv[i] = newcell; + if (i == ind2) { + newcell = i+1; + if (newcell < n) ind2 = newcell+cls[newcell]-1; + } + } + while (++i < ind1); + + for (i = ind4, k = 0; k < SplCntInd; i+=cls[i], k++) { + if (cls[i] == 1) { + Cand->singcode = MASHCOMM(Cand->singcode, Cand->lab[i]); + } + } + + } + } + ind4 = ind1; + } + + /* DENSE-DENSE CASE */ + if (SplInd) { + SAMETRACE_CHECK(TheTraceSplNum, TraceCCInd, SplInd+3*n, &Traceccend) + } + else { + if (TraceCell) { + return 0; + } + } + + } + } + } + } + while (weightend < iend1int); + } /* end while (CStackInd > 0) */ + + for (i=SpineTL->trcstart; i < TraceInd; i++) { + ind0 = TheTrace[i]; + longcode = MASHNONCOMM(longcode, Part->inv[ind0]); + labi = lab[ind0]; + iend1int = TheGraph[labi].d; + nghb = TheGraph[labi].e; + for (j1int = 0; j1int < iend1int; ++j1int) { + k = nghb[j1int]; + value = Part->inv[InvLab[k]]; + longcode = MASHCOMM(longcode, value); + } + } + + tv->augmented_cells = Part->cells - tv->augmented_cells; + + Part->code = Cand->code = CLEANUP(longcode); + if ((Cand->code != SpineTL->part->code) || (TraceInd != *TraceEnd)) return FALSE; + return TRUE; +} + +void refine_tr(sparsegraph *sg, int *lab, int *ptn, int *numcells, int *code, TracesOptions *options_arg) { + + const int n = sg->nv; + const int m = SETWORDSNEEDED(n); + + int i, j, ord; + Partition *CurrPart; + Candidate *CurrCand; + struct TracesVars tvar, *tv; + struct TracesInfo tinf, *ti; + + if (n > (NAUTY_INFINITY-2)) + { + fprintf(ERRFILE, "Traces: need n <= %d, but n=%d\n\n", + NAUTY_INFINITY-2, n); + return; + } + + Allocate_refine_Structures(n); + + tv = &tvar; + ti = &tinf; + + tv->options = options_arg; + tv->mark = tv->stackmark = NAUTY_INFINITY-1; + tv->maxdeg = 0; + tv->mindeg = n; + + outfile = (tv->options->outfile == NULL ? stdout : tv->options->outfile); + + for (i = 0; i < n; i++) { + IDENTITY_PERM[i] = i; + } + + copy_sg_structure(&redgraph, sg); + + tv->graph = &redgraph; + if (tv->options->weighted) { + tv->graph->w = malloc(tv->graph->wlen*sizeof(int)); + if (tv->graph->w == NULL) { + fprintf(ERRFILE, "\nError, memory not allocated.\n"); + exit(1); + } + memcpy(tv->graph->w, sg->w, tv->graph->wlen*sizeof(int)); + } + memcpy(tv->graph->e, sg->e, tv->graph->elen*sizeof(int)); + + for (i=0; i<n; i++) { + TheGraph[i].d = sg->d[i]; + if (TheGraph[i].d > tv->maxdeg) { + tv->maxdeg = TheGraph[i].d; + } + if (TheGraph[i].d < tv->mindeg) { + tv->mindeg = TheGraph[i].d; + } + TheGraph[i].e = tv->graph->e + sg->v[i]; + if (sg->w) + TheGraph[i].w = tv->graph->w + sg->v[i]; + else + TheGraph[i].w = NULL; + TheGraph[i].one = FALSE; + } + + ord = 0; + + /*----------- WEIGHTS --------------*/ + if (tv->options->weighted) { + WeightCodes(n); + ord = trie_classify(n,tv); + } + /*----------------------------------*/ + + if ((tv->maxdeg == tv->mindeg) && (ord == 0)) ti->regular = TRUE; else ti->regular = FALSE; + + /* The graph is sparse? */ + if (sg->nde < n || sg->nde / n < n / (sg->nde / n)) { + ti->thegraphisparse = TRUE; + } + else { + ti->thegraphisparse = FALSE; + } + + /* Initialize candidate, partition, cells, orbits */ + CurrCand = NewCandidate(n, &GarbList, TRUE); + CurrPart = NewPartition(n); + memset(CurrPart->inv, 0, n*sizeof(int)); + + CurrCand->singcode = 0; + + if (ti->regular) { + memcpy(CurrCand->lab, lab, n*sizeof(int)); + CurrPart->cells = 0; + j = 0; + for (i = 0; i < n; i++) { + if (j) CurrPart->inv[i] = j; + CurrCand->invlab[CurrCand->lab[i]] = i; + if (!ptn[i]) { + CurrPart->cls[j] = i-j+1; + if (CurrPart->cls[j] == 1) { + CurrCand->singcode = MASHCOMM(CurrCand->singcode, CurrCand->lab[j]); + } + TheTrace[CurrPart->cells++] = j; + j = i+1; + } + } + } else { + if (tv->options->weighted) { + CurrPart->cells = traces_vertexclass_refine (n, lab, ptn, CurrCand, CurrPart, WeightsSeq); + } + else { + CurrPart->cells = traces_vertexclass_refine (n, lab, ptn, CurrCand, CurrPart, sg->d); + } + } + + /* First refinement */ + refine_tr_refine(CurrCand, n, CurrPart, tv, ti); + + for (i = CurrPart->cls[0]; i < n; i+=CurrPart->cls[i]) { + ptn[i-1] = 0; + } + ptn[n-1] = 0; + + memcpy(lab, CurrCand->lab, n*sizeof(int)); + *code = CurrCand->code; + *numcells = CurrPart->cells; + + FREECAND(CurrCand) + FREEPART(CurrPart) + + if (tv->graph != sg) { + SG_FREE(redgraph); + } + +#if !MAXN + DYNFREE(CStack, CStack_sz); + DYNFREE(IDENTITY_PERM, IDENTITY_PERM_sz); + DYNFREE(Markers, Markers_sz); + DYNFREE(MarkHitVtx, MarkHitVtx_sz); + DYNFREE(TreeMarkers, TreeMarkers_sz); + DYNFREE(NghCounts, NghCounts_sz); + DYNFREE(Singletons, Singletons_sz); + DYNFREE(SplPos, SplPos_sz); + DYNFREE(SplCls, SplCls_sz); + DYNFREE(SplCnt, SplCnt_sz); + DYNFREE(StackMarkers, StackMarkers_sz); + DYNFREE(TheTrace, TheTrace_sz); + DYNFREE(TheTraceSteps, TheTraceSteps_sz); + DYNFREE(TheTraceCC, TheTraceCC_sz); + DYNFREE(TheTraceSplNum, TheTraceSplNum_sz); + DYNFREE(WeightsSeq, WeightsSeq_sz); + DYNFREE(WorkArray1, WorkArray1_sz); + DYNFREE(WorkArray2, WorkArray2_sz); + DYNFREE(WorkArray3, WorkArray3_sz); + DYNFREE(WorkArray4, WorkArray4_sz); + DYNFREE(WorkArray5, WorkArray5_sz); + DYNFREE(TreeStack, TreeStack_sz); + DYNFREE(Spine, Spine_sz); + DYNFREE(TrieArray, TrieArray_sz); + DYNFREE(TheGraph, TheGraph_sz); +#endif +} + +void refine_tr_refine(Candidate *Cand, + int n, + Partition *Part, + struct TracesVars* tv, + struct TracesInfo *ti) { + + int i, j, k, jk, sc, ind0, ind1, ind2, ind3, ind4, labi; + int value, iend, newcell; + int HitClsInd, SplInd, SplCntInd, CStackInd, TraceInd, TraceCCInd, TraceStepsInd; + int j1int, iend1int; + unsigned int longcode; + int newtrace = FALSE; + int Sparse = TRUE; + int *lab, *cls, *InvLab, *TracePos, *SplitCell, *LabCell, TraceEnd, Traceccend, Tracestpend; + int BigCell, BigCellPos, BigCellSize; + boolean TraceCell = FALSE; + int *nghb; + const int variation = 0; + int currentweight, weightstart, weightend, currentcell, currentsize; + + HitClsInd = 0; + if (tv->stackmark > (NAUTY_INFINITY-2)) { + memset(StackMarkers, 0, n*sizeof(int)); + tv->stackmark = 0; + } + tv->stackmark++; + + lab = Cand->lab; + InvLab = Cand->invlab; + cls = Part->cls; + + UPDATEMIN(Part->active, n-1); + memcpy(CStack+1, TheTrace, (Part->cells)*sizeof(int)); + CStackInd = Part->cells; + + for (i = 1; i <= CStackInd; i++) { + StackMarkers[CStack[i]] = tv->stackmark; + } + + longcode = Part->cells; + newtrace = TRUE; + while (CStackInd > 0) { + + weightend = 0; + + if (tv->mark > (NAUTY_INFINITY-2)) { + memset(Markers, 0, n*sizeof(int)); + memset(MarkHitVtx, 0, n*sizeof(int)); + tv->mark = 0; + } + tv->mark++; + + if (Part->cells == n) break; + + k = Select_from_CStack(cls, CStackInd); + + currentcell = CStack[k]; + currentsize = currentcell+cls[currentcell]; + CStack[k] = CStack[CStackInd--]; + StackMarkers[currentcell] = 0; + + labi = lab[currentcell]; + iend1int = TheGraph[labi].d; + nghb = TheGraph[labi].e; + + do { + + ind0 = currentcell; + ind2 = currentsize; + weightstart = weightend; + + if (tv->options->weighted) { + currentweight = (TheGraph[labi].w)[weightstart]; + while ((iend1int > weightend) && ((TheGraph[labi].w)[weightend] == currentweight)) { + weightend++; + } + } else { + weightend = TheGraph[labi].d; + } + + /* Analysis of occurrences of neighbors of the current cell */ + /* The list of cells with neighbors in the current cell is built */ + if (cls[ind0] == 1) { /* SINGLETON CURRENT CELL CASE */ + + /* NEIGHCOUNT_SING_MULT */ + HitClsInd = 0; + for (j1int = weightstart; j1int < weightend; ++j1int) { + k = nghb[j1int]; + value = Part->inv[InvLab[k]]; + if (cls[value] > 1) { + if (Markers[value] != tv->mark) { + HitCls[HitClsInd++] = value; + Markers[value] = tv->mark; + ElmHitCll[value] = value; + } + HitVtx[ElmHitCll[value]++] = k; + } else { + switch (variation) { + case 1: + longcode = MASHCOMM(longcode, value); + break; + default: + break; + } + } + } + /* end NEIGHCOUNT_SING_MULT */ + + tv->mark++; + FIND_SPLIT_CELLS; + + /* SINGLETON CC CASE */ + if (SplInd) { + + /* Sorting the cells to be split */ + sort_Split_Array(SplCls, SplInd); + + for (j = 0; j < SplInd; j++) { + ind1 = SplCls[j]; + i = ind1+cls[ind1]-ElmHitCll[ind1]; + } + + /* REARRANGE THE CELLS */ + for (j = 0; j < SplInd; j++) { + /* REARRANGE_CELLS */ + ind1 = SplCls[j]; + cls[ind1] = cls[ind1]-ElmHitCll[ind1]; + newcell = ind1+cls[ind1]; + cls[newcell] = ElmHitCll[ind1]; + Part->cells++; + if (StackMarkers[ind1] != tv->stackmark) { + if (cls[newcell] < cls[ind1]) { + CStack[++CStackInd] = newcell; + StackMarkers[newcell] = tv->stackmark; + } + else { + CStack[++CStackInd] = ind1; + StackMarkers[ind1] = tv->stackmark; + } + } + else { + CStack[++CStackInd] = newcell; + StackMarkers[newcell] = tv->stackmark; + } + SplitCell = HitVtx+ind1; + ind3 = cls[newcell]; + LabCell = lab+newcell; + for (jk = 0; jk < ind3; jk++) { + k = SplitCell[jk]; + i = LabCell[jk]; + Part->inv[newcell+jk] = newcell; + lab[InvLab[k]] = i; + InvLab[i] = InvLab[k]; + LabCell[jk] = k; + InvLab[k] = newcell+jk; + } + /* END REARRANGE_CELLS */ + + } + } + else { + } + } + else { + if (ti->thegraphisparse) { + + /* NEIGHCOUNT_SPARSE_MULT */ + HitClsInd = 0; + if (cls[ind0] != n) { + for (i = ind0; i < ind2; i++) { + labi = lab[i]; + nghb = TheGraph[labi].e; + for (j = weightstart; j < weightend; j++) { + k = nghb[j]; + if (MarkHitVtx[k] == tv->mark) { + NghCounts[k]++; + } + else { + value = Part->inv[InvLab[k]]; + if (cls[value] > 1) { + MarkHitVtx[k] = tv->mark; + NghCounts[k] = 1; + if (Markers[value] != tv->mark) { + HitCls[HitClsInd++] = value; + Markers[value] = tv->mark; + HitVtx[value] = k; + ElmHitCll[value] = 1; + } + else { + HitVtx[value+ElmHitCll[value]++] = k; + } + } + else { + switch (variation) { + case 1: + longcode = MASHCOMM(longcode, value); + break; + default: + break; + } + } + } + } + } + } + /* End NEIGHCOUNT_SPARSE_MULT */ + + tv->mark++; + + SplInd = 0; + SplCls[0] = n; + for (j = 0; j < HitClsInd; j++) { + ind1 = HitCls[j]; + if ((ElmHitCll[ind1] > 0) && (ElmHitCll[ind1] < cls[ind1])) { + SplCls[SplInd++] = ind1; + } + else { + ind2 = ind1+cls[ind1]; + value = NghCounts[lab[ind1++]]; + for (i = ind1; i < ind2; i++) + { + if (NghCounts[lab[i]] != value) + { + SplCls[SplInd++] = HitCls[j]; + break; + } + } + } + } + + /* SPARSE CASE */ + if (SplInd) { + + /* Sorting the cells to be split */ + sort_Split_Array(SplCls, SplInd); + + for (sc = 0; sc < SplInd; sc++) { /* For each cell C to be split */ + ind0 = SplCls[sc]; + ind1 = ind0 + cls[ind0]; + SplCntInd = 0; + if (ElmHitCll[ind0] < cls[ind0]) { + SplCnt[SplCntInd++] = 0; + SplPos[0] = cls[ind0] - ElmHitCll[ind0]; + } + + /* According to the numbers of neighbors of C into the current cell */ + /* compute how many vertices in C will be placed into the same new cell */ + iend = ind0 + ElmHitCll[ind0]; + for (i = ind0; i < iend; i++) { + value = NghCounts[HitVtx[i]]; + if (Markers[value] != tv->mark) { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = 1; + } + else { + SplPos[value]++; + } + } + tv->mark++; + + sort_Split_Array(SplCnt,SplCntInd); + Part->cells += SplCntInd-1; + + /* Split the cell C and update the information for sizes of new cells */ + /* Put the new cells into the stack */ + i = ind0; + if (StackMarkers[i] != tv->stackmark) { + BigCellSize = 0; + } + for (k = 0; k < SplCntInd; k++) { + value = SplPos[SplCnt[k]]; + cls[i] = value; + if ((StackMarkers[ind0] != tv->stackmark) && (value > BigCellSize)) { + BigCell = i; + BigCellPos = CStackInd; + BigCellSize = cls[i]; + } + SplPos[SplCnt[k]] = i; + i += value; + if (i < ind1) { + CStack[++CStackInd] = i; + StackMarkers[i] = tv->stackmark; + } + } + + if ((StackMarkers[ind0] != tv->stackmark) && (BigCell != ind0)) { + CStack[BigCellPos] = ind0; + StackMarkers[BigCell] = 0; + StackMarkers[ind0] = tv->stackmark; + } + /* Permute elements of the cell C */ + iend = ind0 + ElmHitCll[ind0]; + for (i = ind0; i < iend; i++) { + value = HitVtx[i]; + j = SplPos[NghCounts[value]]++; /* where HitVtx[i] goes */ + k = InvLab[value]; /* where HitVtx[i] is in lab */ + lab[k] = lab[j]; + lab[j] = value; + InvLab[value] = j; + InvLab[lab[k]] = k; + NghCounts[value] = 0; + } + + /* Reconstruct the cell C and update the inverse partition */ + newcell = ind1 - ElmHitCll[ind0]; + i = newcell; + ind2 = newcell+cls[newcell]-1; + do { + Part->inv[i] = newcell; + if (i == ind2) { + newcell = i+1; + if (newcell < n) ind2 = newcell+cls[newcell]-1; + } + } + while (++i < ind1); + } + } + } + else { + if (TheGraph[lab[ind0]].d > n/cls[ind0]) { + Sparse = FALSE; + } + else { + Sparse = TRUE; + } + Sparse = TRUE; + if (Sparse) { + /* Counting occurrences of neighbors of the current cell */ + /* The list of cells with neighbors in the current cell is also built */ + if (cls[ind0] == n) { + for (i = 0; i < n; i++) { + NghCounts[i] = TheGraph[i].d; + } + HitCls[0] = 0; + HitClsInd = 1; + } + else { + memset(NghCounts, 0, n*sizeof(int)); + + /* NEIGHCOUNT_DENSE_SPARSE_MULT */ + HitClsInd = 0; + for (i = ind0; i < ind2; i++) { + labi = lab[i]; + nghb = TheGraph[labi].e; + for (j1int = weightstart; j1int < weightend; ++j1int) { + k = nghb[j1int]; + (NghCounts[k])++; + value = Part->inv[InvLab[k]]; + if (Markers[value] != tv->mark) { + if (cls[value] > 1) HitCls[HitClsInd++] = value; + Markers[value] = tv->mark; + } + } + } + /* End NEIGHCOUNT_DENSE_SPARSE_MULT */ + + } + + tv->mark++; + + + SplInd = 0; + for (j = 0; j < HitClsInd; j++) { + ind1 = HitCls[j]; + ind2 = ind1+cls[ind1]; + value = NghCounts[lab[ind1++]]; + for (i = ind1; i < ind2; i++) + { + if (NghCounts[lab[i]] != value) + { + SplCls[SplInd++] = HitCls[j]; + break; + } + } + } + + /* DENSE-SPARSE CASE */ + if (SplInd) { + + /* Sorting the cells to be split */ + sort_Split_Array(SplCls, SplInd); + + for (j = 0; j < SplInd; j++) { /* For each cell C to be split */ + ind0 = SplCls[j]; + ind1 = ind0+cls[ind0]; + SplCntInd = 0; + + /* According to the numbers of neighbors of C into the current cell */ + /* compute how many vertices in C will be placed into the same new cell */ + for (i = ind0; i < ind1; i++) { + value = NghCounts[lab[i]]; + if (Markers[value] != tv->mark) { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = 1; + } + else { + SplPos[value]++; + } + } + tv->mark++; + + /* Sort the values deriving from the previous step */ + sort_Split_Array(SplCnt, SplCntInd); + Part->cells += SplCntInd-1; + + /* Split the cell C and update the information for sizes of new cells */ + /* Put the new cells into the stack */ + i = ind0; + if (StackMarkers[i] != tv->stackmark) { + BigCellSize = 0; + } + for (k = 0; k < SplCntInd; k++) { + value = SplPos[SplCnt[k]]; + cls[i] = value; + + if ((StackMarkers[ind0] != tv->stackmark) && (value > BigCellSize)) { + BigCell = i; + BigCellPos = CStackInd; + BigCellSize = cls[i]; + } + SplPos[SplCnt[k]] = i; + i += value; + if (i < ind1) { + CStack[++CStackInd] = i; + StackMarkers[i] = tv->stackmark; + } + } + + if ((StackMarkers[ind0] != tv->stackmark) && (BigCell != ind0)) { + CStack[BigCellPos] = ind0; + StackMarkers[BigCell] = 0; + StackMarkers[ind0] = tv->stackmark; + } + + /* Permute elements of the cell C */ + i = ind0; + do { + SplCnt[SplPos[NghCounts[lab[i]]]++] = lab[i]; + } + while(++i < ind1); + + /* Reconstruct the cell C and update the inverse partition */ + newcell = ind0; + i = ind0; + ind2 = newcell+cls[newcell]-1; + do { + lab[i] = SplCnt[i]; + InvLab[lab[i]] = i; + + Part->inv[i] = newcell; + if (i == ind2) { + newcell = i+1; + if (newcell < n) ind2 = newcell+cls[newcell]-1; + } + } + while (++i < ind1); + } + } + } + else { + if (cls[ind0] == n) { + for (i = 0; i < n; i++) { + NghCounts[i] = TheGraph[i].d; + } + } + else { + memset(NghCounts, 0, n*sizeof(int)); + + /* NEIGHCOUNT_DENSE_DENSE_MULT */ + for (i = ind0; i < ind2; i++) { + labi = lab[i]; + nghb = TheGraph[labi].e; + for (j1int = weightstart; j1int < weightend; ++j1int) { + k = nghb[j1int]; + (NghCounts[k])++; + } + } + /* End NEIGHCOUNT_DENSE_DENSE_MULT */ + + } + SplInd = 0; + ind4 = 0; + while (ind4 < n) { /* For each cell C with size(C) > 1 */ + ind1 = ind4+cls[ind4]; + if (cls[ind4] > 1) { + + + /* Determine whether C must be split */ + SplCntInd = 0; + value = NghCounts[lab[ind4]]; + for (i = ind4+1; i < ind1; i++) { + if (NghCounts[lab[i]] != value) + { + SplInd++; + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = i-ind4; + do { + value = NghCounts[lab[i++]]; + if (Markers[value] != tv->mark) { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = 1; + } + else { + SplPos[value]++; + } + } + while(i != ind1); + break; + } + } + tv->mark++; + + if (SplCntInd) { + + /* Sort the values deriving from the previous step */ + sort_Split_Array(SplCnt, SplCntInd); + Part->cells += SplCntInd-1; + + /* Split the cell C and update the information for sizes of new cells */ + /* Put the new cells into the stack */ + i = ind4; + if (StackMarkers[i] != tv->stackmark) { + BigCellSize = 0; + } + for (k = 0; k < SplCntInd; k++) { + value = SplPos[SplCnt[k]]; + cls[i] = value; + + if ((StackMarkers[ind4] != tv->stackmark) && (value > BigCellSize)) { + BigCell = i; + BigCellPos = CStackInd; + BigCellSize = cls[i]; + } + SplPos[SplCnt[k]] = i; + i += value; + if (i < ind1) { + CStack[++CStackInd] = i; + StackMarkers[i] = tv->stackmark; + } + } + if ((StackMarkers[ind4] != tv->stackmark) && (BigCell != ind4)) { + CStack[BigCellPos] = ind4; + StackMarkers[BigCell] = 0; + StackMarkers[ind4] = tv->stackmark; + } + + /* Permute elements of the cell C */ + i = ind4; + do { + SplCnt[SplPos[NghCounts[lab[i]]]++] = lab[i]; + } + while(++i < ind1); + + /* Reconstruct the cell C and update the inverse partition */ + newcell = ind4; + i = ind4; + ind2 = newcell+cls[newcell]-1; + do { + lab[i] = SplCnt[i]; + InvLab[lab[i]] = i; + Part->inv[i] = newcell; + if (i == ind2) { + newcell = i+1; + if (newcell < n) ind2 = newcell+cls[newcell]-1; + } + } + while (++i < ind1); + } + } + ind4 = ind1; + } + + /* DENSE-DENSE CASE */ + } + } + } + } + while (weightend < iend1int); + } /* end while (CStackInd > 0) */ + + Cand->code = CLEANUP(longcode); + for (ind0=Part->cls[0]; ind0 < n; ind0+=Part->cls[ind0]) { + longcode = MASHNONCOMM(longcode, Part->inv[ind0]); + labi = lab[ind0]; + iend1int = TheGraph[labi].d; + nghb = TheGraph[labi].e; + for (j1int = 0; j1int < iend1int; ++j1int) { + k = nghb[j1int]; + value = Part->inv[InvLab[k]]; + longcode = MASHCOMM(longcode, value); + } + } + Part->code = Cand->code = CLEANUP(longcode); + return; +} + +void Adjust_Cycles(Candidate *Cand, Partition *Part, int n, struct TracesVars *tv) { + int i, j, i1, j1, k; + int tmp, arg, cyclength; + + if (Part->cells < n) { + memset(CyclesLength,0,n*sizeof(int)); + SETMARK(CellMarkers1, tv->markcell1) + SETMARK(CellMarkers2, tv->markcell2) + i1 = j1 = 0; + for (i=0; i<n; i+=Part->cls[i]) { + if (Part->cls[i] > 1) { + for (j=i; j<i+Part->cls[i]; j++) { + arg = Cand->lab[j]; + if (CellMarkers1[arg] != tv->markcell1) { + CellMarkers1[arg] = tv->markcell1; + cyclength = 1; + CyclesPart[i1++] = Cand->invlab[arg]; + do { + tmp = NextNeighbour(arg, Cand, Part, CellMarkers1, tv->markcell1, &arg, n); + if (tmp) { + CellMarkers1[arg] = tv->markcell1; + cyclength++; + CyclesPart[i1++] = Cand->invlab[arg]; + } + } while (tmp); + for (k=j1; k<i1; k++) { + CyclesLength[CyclesPart[k]] = cyclength; + } + j1 = i1; + } + } + } + } + } + for (i=0; i<n; i+=Part->cls[i]) { + if (Part->cls[i] > 1) { + sort2ints(CyclesLength+i, Cand->lab+i, Part->cls[i]); + } + for (j=i; j<i+Part->cls[i]; j++) { + Cand->invlab[Cand->lab[j]] = j; + } + } +} + +void Allocate_Traces_Structures(int n) { +#if !MAXN + DYNALLOC1(int, AUTPERM, AUTPERM_sz, n, "Traces"); + DYNALLOC1(int, BreakSteps, BreakSteps_sz, n, "Traces"); + DYNALLOC1(int, CurrOrbSize, CurrOrbSize_sz, n, "Traces"); + DYNALLOC1(int, CurrRefCells, CurrRefCells_sz, n, "Traces"); + DYNALLOC1(boolean, Diff, Diff_sz, n, "Traces"); + DYNALLOC1(int, CStack, CStack_sz, n, "Traces"); + DYNALLOC1(boolean, Factorials, Factorials_sz, n, "Traces"); + DYNALLOC1(int, fix, fix_sz, n, "Traces"); + DYNALLOC1(int, IDENTITY_PERM, IDENTITY_PERM_sz, n, "Traces"); + DYNALLOC1(int, Markers, Markers_sz, n, "Traces"); + DYNALLOC1(int, TreeMarkers, TreeMarkers_sz, n, "Traces"); + DYNALLOC1(int, AutMarkers, AutMarkers_sz, n, "Traces"); + DYNALLOC1(int, MarkHitVtx, MarkHitVtx_sz, n, "Traces"); + DYNALLOC1(int, MultRefCells, MultRefCells_sz, n, "Traces"); + DYNALLOC1(int, NghCounts, NghCounts_sz, n, "Traces"); + DYNALLOC1(int, OrbSize, OrbSize_sz, n, "Traces"); + DYNALLOC1(int, OrbList, OrbList_sz, n, "Traces"); + DYNALLOC1(pair, PrmPairs, PrmPairs_sz, n, "Traces"); + DYNALLOC1(int, TempOrbList, TempOrbList_sz, n, "Traces"); + DYNALLOC1(int, RefCells, RefCells_sz, n, "Traces"); + DYNALLOC1(int, Singletons, Singletons_sz, n, "Traces"); + DYNALLOC1(int, SplCls, SplCls_sz, n, "Traces"); + DYNALLOC1(int, SplCnt, SplCnt_sz, n, "Traces"); + DYNALLOC1(int, SplPos, SplPos_sz, n, "Traces"); + DYNALLOC1(int, StackMarkers, StackMarkers_sz, n, "Traces"); + DYNALLOC1(int, TheTrace, TheTrace_sz, n+10, "Traces"); + DYNALLOC1(int, TheTraceCC, TheTraceCC_sz, n, "Traces"); + DYNALLOC1(int, TheTraceSplNum, TheTraceSplNum_sz, n, "Traces"); + DYNALLOC1(int, TheTraceSteps, TheTraceSteps_sz, n+10, "Traces"); + DYNALLOC1(int, TEMPLAB, TEMPLAB_sz, n, "Traces"); + DYNALLOC1(int, TEMPINVLAB, TEMPINVLAB_sz, n, "Traces"); + DYNALLOC1(int, WeightsSeq, WeightsSeq_sz, n, "Traces"); + DYNALLOC1(int, WorkArray, WorkArray_sz, n, "Traces"); + DYNALLOC1(int, WorkArray0, WorkArray0_sz, n, "Traces"); + DYNALLOC1(int, WorkArray1, WorkArray1_sz, n, "Traces"); + DYNALLOC1(int, WorkArray2, WorkArray2_sz, n, "Traces"); + DYNALLOC1(int, WorkArray3, WorkArray3_sz, n, "Traces"); + DYNALLOC1(int, WorkArray4, WorkArray4_sz, n, "Traces"); + DYNALLOC1(int, WorkArray5, WorkArray5_sz, n, "Traces"); + DYNALLOC1(int, WorkArray6, WorkArray6_sz, n, "Traces"); + DYNALLOC1(int, WorkArray7, WorkArray7_sz, n, "Traces"); + DYNALLOC1(int, TreeStack, TreeStack_sz, n, "Traces"); + DYNALLOC1(TracesSpine, Spine, Spine_sz, n, "Traces"); + DYNALLOC1(trie*, TrieArray, TrieArray_sz, n, "Traces"); + DYNALLOC1(grph_strct, TheGraph, TheGraph_sz, n, "Traces"); + DYNALLOC1(ExpPathInfo, EPCodes, EPCodes_sz, n, "Traces"); + DYNALLOC1(int, CyclesPart, CyclesPart_sz, n, "Traces"); + DYNALLOC1(int, CyclesLength, CyclesLength_sz, n, "Traces"); +#endif + return; +} + +void Allocate_refine_Structures(int n) { +#if !MAXN + DYNALLOC1(int, CStack, CStack_sz, n, "refine_tr"); + DYNALLOC1(int, IDENTITY_PERM, IDENTITY_PERM_sz, n, "refine_tr"); + DYNALLOC1(int, Markers, Markers_sz, n, "refine_tr"); + DYNALLOC1(int, MarkHitVtx, MarkHitVtx_sz, n, "refine_tr"); + DYNALLOC1(int, TreeMarkers, TreeMarkers_sz, n, "refine_tr"); + DYNALLOC1(int, NghCounts, NghCounts_sz, n, "refine_tr"); + DYNALLOC1(int, Singletons, Singletons_sz, n, "refine_tr"); + DYNALLOC1(int, SplPos, SplPos_sz, n, "refine_tr"); + DYNALLOC1(int, SplCls, SplCls_sz, n, "refine_tr"); + DYNALLOC1(int, SplCnt, SplCnt_sz, n, "refine_tr"); + DYNALLOC1(int, StackMarkers, StackMarkers_sz, n, "refine_tr"); + DYNALLOC1(int, TheTrace, TheTrace_sz, n+10, "refine_tr"); + DYNALLOC1(int, TheTraceSteps, TheTraceSteps_sz, n+10, "refine_tr"); + DYNALLOC1(int, TheTraceCC, TheTraceCC_sz, n, "refine_tr"); + DYNALLOC1(int, TheTraceSplNum, TheTraceSplNum_sz, n, "refine_tr"); + DYNALLOC1(int, WeightsSeq, WeightsSeq_sz, n, "refine_tr"); + DYNALLOC1(int, WorkArray1, WorkArray1_sz, n, "refine_tr"); + DYNALLOC1(int, WorkArray2, WorkArray2_sz, n, "refine_tr"); + DYNALLOC1(int, WorkArray3, WorkArray3_sz, n, "refine_tr"); + DYNALLOC1(int, WorkArray4, WorkArray4_sz, n, "refine_tr"); + DYNALLOC1(int, WorkArray5, WorkArray5_sz, n, "refine_tr"); + DYNALLOC1(int, TreeStack, TreeStack_sz, n, "refine_tr"); + DYNALLOC1(TracesSpine, Spine, Spine_sz, n, "refine_tr"); + DYNALLOC1(trie*, TrieArray, TrieArray_sz, n, "refine_tr"); + DYNALLOC1(grph_strct, TheGraph, TheGraph_sz, n, "refine_tr"); +#endif + +#define HitCls WorkArray2 +#define HitVtx WorkArray3 +#define ElmHitCll WorkArray5 + return; +} + +struct Candidate *NewCandidate(int n, Candidate **GarbList, int Mrk) { + struct Candidate *Cand; + + if (*GarbList) { + Cand = *GarbList; + *GarbList = (*GarbList)->next; + } + else { + Cand = malloc(sizeof(*Cand)); + if (Cand == NULL) { + fprintf(ERRFILE, "\nError, memory not allocated.\n"); + exit(1); + } + Cand->lab = malloc(n*sizeof(*Cand->lab)); + if (Cand->lab == NULL) { + fprintf(ERRFILE, "\nError, memory not allocated.\n"); + exit(1); + } + Cand->invlab = malloc(n*sizeof(*Cand->invlab)); + if (Cand->invlab == NULL) { + fprintf(ERRFILE, "\nError, memory not allocated.\n"); + exit(1); + } + } + Cand->do_it = Mrk; + Cand->indnum = 0; + Cand->code = 0; + Cand->next = NULL; + Cand->stnode = NULL; + Cand->sortedlab = FALSE; + return Cand; +} + +int Check_degree_one(sparsegraph *sg, Candidate *Cand, Partition *Part, int n) { + + int i; + + for (i=0; i<n; i += Part->cls[i]) { + if (sg->d[Cand->lab[i]] == 1) { + return TRUE; + } + } + return FALSE; +} + +int CheckForAutomorphisms(Candidate *CurrCand, Candidate *NextCand, + struct TracesVars* tv, struct TracesInfo* ti, + int m, int n, Partition* Part) { + Candidate *CheckAutList; + int i, j, k, tgt_level, numtemporbits; + int CheckLevel, CheckLevelEnd; + int temp, tmp, tmp1, arg, arg1, val, val1; + searchtrie *TrieCandFrom, *TrieCheckFrom; + + VERB_PRINT("CFA",3,FALSE) + + CheckLevel = 0; + CheckLevelEnd = 0; + temp = 0; + tv->gotonode = NULL; + tv->conta6++; + + switch (tv->compstage) { + case 0: + if (tv->strategy) { + CheckLevel = CheckLevelEnd = tv->maxtreelevel; + } + else { + if ((Spine[tv->tolevel].part)->cells == tv->finalnumcells) { + CheckLevel = CheckLevelEnd = tv->maxtreelevel; + } + else { + CheckLevel = 1; + if ((Spine[tv->maxtreelevel].part)->cells == tv->finalnumcells) { + CheckLevelEnd = tv->maxtreelevel - 1; + } + else { + CheckLevelEnd = tv->maxtreelevel; + } + } + } + break; + case 1: + CheckLevel = CheckLevelEnd = tv->tolevel; + break; + case 2: + if (m || (tv->tolevel == tv->maxtreelevel+1)) { + CheckLevel = CheckLevelEnd = tv->maxtreelevel+1; + } + else { + CheckLevel = 1; + if ((Spine[tv->maxtreelevel].part)->cells == tv->finalnumcells) { + CheckLevelEnd = tv->maxtreelevel - 1; + } + else { + CheckLevelEnd = tv->maxtreelevel; + } + } + break; + default: + break; + } + + + Adjust_Cycles(NextCand, Part, n, tv); + + while (CheckLevel <= CheckLevelEnd) { + CheckAutList = Spine[CheckLevel].liststart; + while (CheckAutList) { + if (CheckAutList->do_it && lookup(CheckAutList->stnode) && (CheckAutList != NextCand) && (CheckAutList != CurrCand)) { + if (CheckAutList->code == NextCand->code) { + SETMARK(Markers, tv->mark) + if (Part->cells == n) { + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (i = 0; i < n; i++) { + arg = NextCand->lab[i]; + val = CheckAutList->lab[i]; + SETPAIRSAUT(arg, val) + } + } + else { + Adjust_Cycles(CheckAutList, Part, n, tv); + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + SETMARK(CellMarkers1, tv->markcell1) + SETMARK(CellMarkers2, tv->markcell2) + for (i=0; i<n; i+=Part->cls[i]) { + if (Part->cls[i] == 1) { + arg = NextCand->lab[i]; + val = CheckAutList->lab[i]; + SETPAIRSAUT(arg, val) + if (tv->preprocessed && Diff[arg]) + MakeTree(arg, val, tv->input_graph, n, tv, TRUE); + } + else { + k = i; + for (j=i; j<i+Part->cls[i]; j++) { + arg = arg1 = NextCand->lab[j]; + if (CellMarkers1[arg] != tv->markcell1) { + CellMarkers1[arg] = tv->markcell1; + while ((CellMarkers2[CheckAutList->lab[k]] == tv->markcell2) && (k < i+Part->cls[i])) { + k++; + } + if (k < i+Part->cls[i]) { + val = val1 = CheckAutList->lab[k]; + CellMarkers2[val] = tv->markcell2; + SETPAIRSAUT(arg, val) + if (tv->preprocessed && Diff[arg]) + MakeTree(arg, val, tv->input_graph, n, tv, TRUE); + tmp = FirstNeighbour(arg, NextCand, Part, CellMarkers1, tv->markcell1, &arg, n); + if (tmp) { + CellMarkers1[arg] = tv->markcell1; + tmp = FirstNeighbour(val, CheckAutList, Part, CellMarkers2, tv->markcell2, &val, n); + CellMarkers2[val] = tv->markcell2; + SETPAIRSAUT(arg, val) + if (tv->preprocessed && Diff[arg]) + MakeTree(arg, val, tv->input_graph, n, tv, TRUE); + while (tmp) { + tmp = NextNeighbour(arg, NextCand, Part, CellMarkers1, tv->markcell1, &arg, n); + if (tmp) { + CellMarkers1[arg] = tv->markcell1; + tmp = NextNeighbour(val, CheckAutList, Part, CellMarkers2, tv->markcell2, &val, n); + if (tmp) { + CellMarkers2[val] = tv->markcell2; + SETPAIRSAUT(arg, val) + if (tv->preprocessed && Diff[arg]) + MakeTree(arg, val, tv->input_graph, n, tv, TRUE); + } + } + } + arg = arg1; + val = val1; + do { + tmp = NextNeighbour(arg, NextCand, Part, CellMarkers1, tv->markcell1, &arg, n); + if (tmp) { + CellMarkers1[arg] = tv->markcell1; + tmp = NextNeighbour(val, CheckAutList, Part, CellMarkers2, tv->markcell2, &val, n); + if (tmp) { + CellMarkers2[val] = tv->markcell2; + SETPAIRSAUT(arg, val) + if (tv->preprocessed && Diff[arg]) + MakeTree(arg, val, tv->input_graph, n, tv, TRUE); + } + } + } while (tmp); + } + } + } + } + } + } + } + + if (isautom_sg_pair((graph*)tv->input_graph, AUTPERM, tv->options->digraph, m, n, tv)) { + if (!findperm(gensB, AUTPERM, n)) { + if (tv->options->verbosity >= 2) tv->schreier3 -= CPUTIME; + addgenerator(&gpB, &gensB, AUTPERM, n); + if (tv->options->verbosity >= 2) tv->schreier3 += CPUTIME; + if (tv->options->verbosity >= 2) { + fprintf(outfile, "[A(%d,%d)] ", CheckLevel, CheckAutList->name); + } + tv->lev_of_lastauto = tv->tolevel; + tv->stats->numgenerators++; + orbjoin_sp_perm(tv->orbits, AUTPERM, OrbList, n, &tv->stats->numorbits); + ti->thegrouphaschanged = TRUE; + ti->identitygroup = FALSE; + if (tv->options->verbosity >= 2 && tv->options->writeautoms) { + PRINT_RETURN + } + if (tv->options->writeautoms) { + fprintf(outfile, "Gen(A) #%d: ", tv->stats->numgenerators); + writeperm(outfile, AUTPERM, tv->options->cartesian, tv->options->linelength, n); + } + if (tv->options->userautomproc) { + (*tv->options->userautomproc)(tv->stats->numgenerators, AUTPERM, n); + } + } + else { + orbjoin_sp_perm(tv->orbits, AUTPERM, OrbList, n, &tv->stats->numorbits); + if (tv->options->verbosity >= 2) { + fprintf(outfile, "[A*(%d,%d)] ", CheckLevel, CheckAutList->name); + } + } + TrieCandFrom = NULL; + TrieCheckFrom = CheckAutList->stnode; + if (CurrCand->stnode->level <= 1) { + tgt_level = CurrCand->stnode->level + 1; + while (TrieCheckFrom->level > tgt_level) { + TrieCheckFrom = TrieCheckFrom->father; + } + } + else { + if (tv->tolevel <= TrieCheckFrom->level) { + tgt_level = tv->tolevel; + while (TrieCheckFrom->level != tgt_level) { + TrieCheckFrom = TrieCheckFrom->father; + } + } + else { + TrieCandFrom = CurrCand->stnode; + tgt_level = TrieCheckFrom->level; + while (TrieCandFrom->level != tgt_level) { + TrieCandFrom = TrieCandFrom->father; + } + } + } + if (TrieCandFrom) { + while (TrieCandFrom->father != TrieCheckFrom->father) { + TrieCandFrom = TrieCandFrom->father; + TrieCheckFrom = TrieCheckFrom->father; + } + } + else { + if ((TrieCheckFrom->level > 1) && (TrieCheckFrom->father != CurrCand->stnode)) { + TrieCandFrom = CurrCand->stnode; + TrieCheckFrom = TrieCheckFrom->father; + while (TrieCandFrom->father != TrieCheckFrom->father) { + TrieCandFrom = TrieCandFrom->father; + TrieCheckFrom = TrieCheckFrom->father; + } + } + } + + while (TrieCheckFrom->goes_to) { + TrieCheckFrom = TrieCheckFrom->goes_to; + } + + for (temp=1; temp<=tv->tolevel; temp++) { + if (CheckAutList->lab[Spine[temp].tgtpos] != NextCand->lab[Spine[temp].tgtpos]) { + break; + } + } + + if (temp == tv->tolevel) { + if (TempOrbits) { + if (tv->compstage == 0) { + for (j=0; j<tv->permInd; j++) { + orbjoin_sp_pair(TempOrbits, TempOrbList, n, + PrmPairs[j].arg, PrmPairs[j].val, &numtemporbits); + } + } + else { + orbjoin(TempOrbits, AUTPERM, n); + } + } else { + orbjoin(tv->currorbit, AUTPERM, n); + } + } + + switch (tv->compstage) { + case 0: + if (tv->strategy && (tv->steps == 1)) { + RemoveFromLevel(temp, tv->maxtreelevel-1, tv->strategy, FALSE); + if (TrieCandFrom) { + TrieCheckFrom->index += TrieCandFrom->index; + TrieCandFrom->goes_to = TrieCheckFrom; + PRINT_INDEX(TrieCheckFrom,4,1) + } + else { + TrieCheckFrom->index++; + PRINT_INDEX(TrieCheckFrom,4,2) + } + NextCand->do_it = FALSE; + } + else { + if (CheckAutList->lab[Spine[temp].tgtpos] >= NextCand->lab[Spine[temp].tgtpos]) { + CheckAutList->do_it = FALSE; + if (TrieCandFrom) { + TrieCandFrom->index += TrieCheckFrom->index; + tv->newindex = 0; + TrieCheckFrom->goes_to = TrieCandFrom; + PRINT_INDEX(TrieCandFrom,4,3) + } + else { + if (CurrCand->stnode->level > 1) { + tv->newgotonode = TrieCheckFrom; + tv->newindex = TrieCheckFrom->index; + } + else { + tv->newgotonode = NULL; + tv->newindex = 0; + } + } + } + else { + if (TrieCandFrom) { + TrieCheckFrom->index += TrieCandFrom->index; + TrieCandFrom->goes_to = TrieCheckFrom; + PRINT_INDEX(TrieCheckFrom,4,4) + } + else { + TrieCheckFrom->index++; + PRINT_INDEX(TrieCheckFrom,4,5) + } + NextCand->do_it = FALSE; + } + } + break; + case 1: + TrieCheckFrom->index ++; + PRINT_INDEX(TrieCheckFrom,4,6) + tv->gotonode = TrieCheckFrom; + break; + case 2: + if (TrieCandFrom) { + TrieCheckFrom->index += TrieCandFrom->index; + TrieCandFrom->goes_to = TrieCheckFrom; + PRINT_INDEX(TrieCheckFrom,4,7) + } + else { + TrieCheckFrom->index++; + PRINT_INDEX(TrieCheckFrom,4,8) + } + if (temp == tv->maxtreelevel) { + tmp1 = TempOrbits[NextCand->lab[Spine[temp].tgtpos]]; + + if (CheckAutList->lab[Spine[temp].tgtpos] == AutomCount[1]) { + for (i=1; i<AutomCount[0]; i++) if (AutomCount[i] == tmp1) break; + if (i == AutomCount[0]) { + AutomCount[AutomCount[0]++] = TempOrbits[NextCand->lab[Spine[temp].tgtpos]]; + } + } + + } + break; + default: + break; + } + return temp; + } + } + } + CheckAutList = CheckAutList->next; + } + CheckLevel++; + } + return FALSE; +} + + +int CheckForSingAutomorphisms(Candidate *CurrCand, Partition *NextPart, Candidate *NextCand, + struct TracesVars* tv, struct TracesInfo* ti, + int m, int n) { + int i, j, temp, tmp, tmp1, result, tgt_level, numtemporbits; + TracesSpine *SpineTL; + Candidate *CheckAutList; + searchtrie *TrieCandFrom, *TrieCheckFrom; + + SpineTL = Spine+tv->tolevel; + CheckAutList = SpineTL->liststart; + tv->gotonode = NULL; + + VERB_PRINT("CFSA",3,FALSE) + + result = 0; + while (CheckAutList != NULL) { + if (CheckAutList->do_it && (CheckAutList->stnode->father == CurrCand->stnode)) { + if (CheckAutList->firstsingcode == NextCand->firstsingcode) { + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + if ((tv->tolevel == 1) && (Spine[0].part->cells == 1)) tmp = 2; else tmp = tv->tolevel; + if (TreeFyTwo(tmp, CheckAutList, NextCand, NextPart, n, tv, ti)) { + if (isautom_sg((graph*)tv->input_graph, AUTPERM, tv->options->digraph, m, n)) { + if (!findperm(gensB, AUTPERM, n)) { + if (tv->options->verbosity >= 2) tv->schreier3 -= CPUTIME; + addgenerator(&gpB, &gensB, AUTPERM, n); + if (tv->options->verbosity >= 2) tv->schreier3 += CPUTIME; + result = CheckAutList->name; + if (TempOrbits) { + if (tv->compstage == 0) { + for (j=0; j<tv->permInd; j++) { + orbjoin_sp_pair(TempOrbits, TempOrbList, n, + PrmPairs[j].arg, PrmPairs[j].val, &numtemporbits); + } + } + else { + orbjoin(TempOrbits, AUTPERM, n); + } + } + tv->stats->numgenerators++; + orbjoin_sp_perm(tv->orbits, AUTPERM, OrbList, n, &tv->stats->numorbits); + + ti->thegrouphaschanged = TRUE; + ti->identitygroup = FALSE; + tv->lev_of_lastauto = tv->tolevel; + if (tv->options->verbosity >= 2) fprintf(outfile, "[a(%d)] ", CheckAutList->name); + if (tv->options->verbosity >= 2 && tv->options->writeautoms) { + PRINT_RETURN + } + if (tv->options->writeautoms) { + fprintf(outfile, "Gen(a) #%d: ", tv->stats->numgenerators); + writeperm(outfile, AUTPERM, tv->options->cartesian, tv->options->linelength, n); + } + if (tv->options->userautomproc) { + (*tv->options->userautomproc)(tv->stats->numgenerators, AUTPERM, n); + } + } + else { + if (tv->options->verbosity >= 2) { + fprintf(outfile, "[a*]"); + } + if (TempOrbits) { + if (tv->compstage == 0) { + for (j=0; j<tv->permInd; j++) { + orbjoin_sp_pair(TempOrbits, TempOrbList, n, + PrmPairs[j].arg, PrmPairs[j].val, &numtemporbits); + } + } + else { + orbjoin(TempOrbits, AUTPERM, n); + } + } + else { + orbjoin(tv->currorbit, AUTPERM, n); + } + orbjoin_sp_perm(tv->orbits, AUTPERM, OrbList, n, &tv->stats->numorbits); + + result = -CheckAutList->name; + } + + TrieCandFrom = NULL; + TrieCheckFrom = CheckAutList->stnode; + if (CurrCand->stnode->level <= 1) { + tgt_level = CurrCand->stnode->level + 1; + while (TrieCheckFrom->level > tgt_level) { + TrieCheckFrom = TrieCheckFrom->father; + } + } + else { + if (tv->tolevel <= TrieCheckFrom->level) { + tgt_level = tv->tolevel; + while (TrieCheckFrom->level != tgt_level) { + TrieCheckFrom = TrieCheckFrom->father; + } + } + else { + TrieCandFrom = CurrCand->stnode; + tgt_level = TrieCheckFrom->level; + while (TrieCandFrom->level != tgt_level) { + TrieCandFrom = TrieCandFrom->father; + } + } + } + if (TrieCandFrom) { + while (TrieCandFrom->father != TrieCheckFrom->father) { + TrieCandFrom = TrieCandFrom->father; + TrieCheckFrom = TrieCheckFrom->father; + } + } + else { + if ((TrieCheckFrom->level > 1) && (TrieCheckFrom->father != CurrCand->stnode)) { + TrieCandFrom = CurrCand->stnode; + TrieCheckFrom = TrieCheckFrom->father; + while (TrieCandFrom->father != TrieCheckFrom->father) { + TrieCandFrom = TrieCandFrom->father; + TrieCheckFrom = TrieCheckFrom->father; + } + } + } + + while (TrieCheckFrom->goes_to) { + TrieCheckFrom = TrieCheckFrom->goes_to; + } + + for (temp=1; temp<=tv->tolevel; temp++) { + if (CheckAutList->lab[Spine[temp].tgtpos] != NextCand->lab[Spine[temp].tgtpos]) { + break; + } + } + + switch (tv->compstage) { + case 0: + if (tv->strategy && (tv->steps == 1)) { + RemoveFromLevel(temp, tv->maxtreelevel-1, tv->strategy, FALSE); + if (TrieCandFrom) { + TrieCheckFrom->index += TrieCandFrom->index; + TrieCandFrom->goes_to = TrieCheckFrom; + PRINT_INDEX(TrieCheckFrom,4,9) + } + else { + TrieCheckFrom->index++; + PRINT_INDEX(TrieCheckFrom,4,10) + } + NextCand->do_it = FALSE; + } + else { + if (CheckAutList->lab[Spine[temp].tgtpos] >= NextCand->lab[Spine[temp].tgtpos]) { + CheckAutList->do_it = FALSE; + if (TrieCandFrom) { + TrieCandFrom->index += TrieCheckFrom->index; + tv->newindex = 0; + TrieCheckFrom->goes_to = TrieCandFrom; + PRINT_INDEX(TrieCandFrom,4,11) + } + else { + if (CurrCand->stnode->level > 1) { + tv->newgotonode = TrieCheckFrom; + tv->newindex = TrieCheckFrom->index; + } + else { + tv->newgotonode = NULL; + tv->newindex = 0; + } + } + } + else { + if (TrieCandFrom) { + TrieCheckFrom->index += TrieCandFrom->index; + TrieCandFrom->goes_to = TrieCheckFrom; + PRINT_INDEX(TrieCheckFrom,4,12) + } + else { + TrieCheckFrom->index++; + PRINT_INDEX(TrieCheckFrom,4,13) + } + NextCand->do_it = FALSE; + } + } + break; + case 1: + TrieCheckFrom->index++; + PRINT_INDEX(TrieCheckFrom,4,14) + tv->gotonode = TrieCheckFrom; + break; + case 2: + if (TrieCandFrom) { + TrieCheckFrom->index += TrieCandFrom->index; + TrieCandFrom->goes_to = TrieCheckFrom; + PRINT_INDEX(TrieCheckFrom,4,15) + } + else { + TrieCheckFrom->index++; + PRINT_INDEX(TrieCheckFrom,4,16) + } + if ((temp == tv->maxtreelevel) && (CheckAutList->lab[Spine[temp].tgtpos] == AutomCount[1])) { + tmp1 = TempOrbits[NextCand->lab[Spine[temp].tgtpos]]; + for (i=1; i<AutomCount[0]; i++) if (AutomCount[i] == tmp1) break; + if (i == AutomCount[0]) { + AutomCount[AutomCount[0]++] = TempOrbits[NextCand->lab[Spine[temp].tgtpos]]; + } + } + break; + default: + break; + } + return result; + } + } + } + } + CheckAutList = CheckAutList->next; + } + return result; +} + +int CheckForMatching(Candidate *CurrCand, Candidate *NextCand, Partition *Part, struct TracesVars* tv, struct TracesInfo* ti, int m, int n) { + int i, j, vtx, vtx1, temp, tmp1, tgt_level, numtemporbits, pos; + TracesSpine *SpineTL; + Candidate *CheckAutList; + int *cls; + searchtrie *TrieCandFrom, *TrieCheckFrom; + boolean CodeVerify; + + VERB_PRINT("CFM",3,FALSE) + + SpineTL = Spine+tv->tolevel; + CheckAutList = SpineTL->liststart; + cls = Part->cls; + numtemporbits = 0; + tv->gotonode = NULL; + + while (CheckAutList != NULL) { + if (CheckAutList->do_it && (CheckAutList->singcode == NextCand->singcode)) { + TrieCheckFrom = CheckAutList->stnode->father; + TrieCandFrom = CurrCand->stnode; + while (TrieCandFrom != TrieCheckFrom) { + TrieCandFrom = TrieCandFrom->father; + TrieCheckFrom = TrieCheckFrom->father; + } + + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + + CodeVerify = TRUE; + for (i=Spine[TrieCheckFrom->level+1].singstart; i<SpineTL->singend; i++) { + Markers[NextCand->lab[Singletons[i]]] = tv->mark; + } + for (i=Spine[TrieCheckFrom->level+1].singstart; i<SpineTL->singend; i++) { + pos = Singletons[i]; + vtx1 = CheckAutList->lab[pos]; + if (Markers[vtx1] != tv->mark) { + CodeVerify = FALSE; + break; + } + vtx = NextCand->lab[pos]; + SETPAIRSAUT(vtx, vtx1) + + if (tv->preprocessed && Diff[vtx1]) { + MakeTree(vtx, vtx1, tv->input_graph, n, tv, TRUE); + } + } + tv->conta7++; + + if (CodeVerify) { + if (isautom_sg_pair((graph*)tv->input_graph, AUTPERM, tv->options->digraph, m, n, tv)) { + + if (!findperm(gensB, AUTPERM, n)) { + if (tv->options->verbosity >= 2) tv->schreier3 -= CPUTIME; + if (tv->options->generators) addpermutation(&gensB, AUTPERM, n); + + if (tv->options->verbosity >= 2) tv->schreier3 += CPUTIME; + + if (CheckAutList->stnode->father == CurrCand->stnode) { + if (TempOrbits) { + if (tv->compstage == 0) { + for (j=0; j<tv->permInd; j++) { + orbjoin_sp_pair(TempOrbits, TempOrbList, n, PrmPairs[j].arg, PrmPairs[j].val, &numtemporbits); + } + } + else { + orbjoin(TempOrbits, AUTPERM, n); + } + } else { + orbjoin(tv->currorbit, AUTPERM, n); + } + } + + tv->stats->numgenerators++; + + for (j=0; j<tv->permInd; j++) { + orbjoin_sp_pair(tv->orbits, OrbList, n, PrmPairs[j].arg, PrmPairs[j].val, &tv->stats->numorbits); + } + + ti->thegrouphaschanged = TRUE; + ti->first_matching = TRUE; + tv->lev_of_lastauto = tv->tolevel; + if (tv->options->verbosity >= 2) fprintf(outfile, "[M(%d)] ", CheckAutList->name); + if (tv->options->verbosity >= 2 && tv->options->writeautoms) { + PRINT_RETURN + } + if (tv->options->writeautoms) { + fprintf(outfile, "Gen(M) #%d: ", tv->stats->numgenerators); + writeperm(outfile, AUTPERM, tv->options->cartesian, tv->options->linelength, n); + } + if (tv->options->userautomproc) { + (*tv->options->userautomproc)(tv->stats->numgenerators, AUTPERM, n); + } + + } + else { + if (tv->options->verbosity >= 2) { + fprintf(outfile, "[M*]"); + } + if (CheckAutList->stnode->father == CurrCand->stnode) { + if (TempOrbits) { + if (tv->compstage == 0) { + for (j=0; j<tv->permInd; j++) { + orbjoin_sp_pair(TempOrbits, TempOrbList, n, PrmPairs[j].arg, PrmPairs[j].val, &numtemporbits); + } + } + else { + orbjoin(TempOrbits, AUTPERM, n); + } + } else { + orbjoin(tv->currorbit, AUTPERM, n); + } + } + + for (j=0; j<tv->permInd; j++) { + orbjoin_sp_pair(tv->orbits, OrbList, n, PrmPairs[j].arg, PrmPairs[j].val, &tv->stats->numorbits); + } + } + + TrieCandFrom = NULL; + TrieCheckFrom = CheckAutList->stnode; + if (CurrCand->stnode->level <= 1) { + tgt_level = CurrCand->stnode->level + 1; + while (TrieCheckFrom->level > tgt_level) { + TrieCheckFrom = TrieCheckFrom->father; + } + } + else { + if (tv->tolevel <= TrieCheckFrom->level) { + tgt_level = tv->tolevel; + while (TrieCheckFrom->level != tgt_level) { + TrieCheckFrom = TrieCheckFrom->father; + } + } + else { + TrieCandFrom = CurrCand->stnode; + tgt_level = TrieCheckFrom->level; + while (TrieCandFrom->level != tgt_level) { + TrieCandFrom = TrieCandFrom->father; + } + } + } + if (TrieCandFrom) { + while (TrieCandFrom->father != TrieCheckFrom->father) { + TrieCandFrom = TrieCandFrom->father; + TrieCheckFrom = TrieCheckFrom->father; + } + } + else { + if ((TrieCheckFrom->level > 1) && (TrieCheckFrom->father != CurrCand->stnode)) { + TrieCandFrom = CurrCand->stnode; + TrieCheckFrom = TrieCheckFrom->father; + while (TrieCandFrom->father != TrieCheckFrom->father) { + TrieCandFrom = TrieCandFrom->father; + TrieCheckFrom = TrieCheckFrom->father; + } + } + } + + while (TrieCheckFrom->goes_to) { + TrieCheckFrom = TrieCheckFrom->goes_to; + } + + for (temp=1; temp<=tv->tolevel; temp++) { + if (CheckAutList->lab[Spine[temp].tgtpos] != NextCand->lab[Spine[temp].tgtpos]) { + break; + } + } + switch (tv->compstage) { + case 0: + if (tv->strategy && (tv->steps == 1)) { + RemoveFromLevel(temp, tv->maxtreelevel-1, tv->strategy, FALSE); + if (TrieCandFrom) { + TrieCheckFrom->index += TrieCandFrom->index; + TrieCandFrom->goes_to = TrieCheckFrom; + PRINT_INDEX(TrieCheckFrom,4,17) + } + else { + TrieCheckFrom->index++; + PRINT_INDEX(TrieCheckFrom,4,18) + } + NextCand->do_it = FALSE; + } + else { + if (CheckAutList->lab[Spine[temp].tgtpos] >= NextCand->lab[Spine[temp].tgtpos]) { + CheckAutList->do_it = FALSE; + if (TrieCandFrom) { + TrieCandFrom->index += TrieCheckFrom->index; + tv->newindex = 0; + TrieCheckFrom->goes_to = TrieCandFrom; + PRINT_INDEX(TrieCandFrom,4,19) + } + else { + if (CurrCand->stnode->level > 1) { + tv->newgotonode = TrieCheckFrom; + tv->newindex = TrieCheckFrom->index; + } + else { + tv->newgotonode = NULL; + tv->newindex = 0; + } + } + } + else { + if (TrieCandFrom) { + TrieCheckFrom->index += TrieCandFrom->index; + TrieCandFrom->goes_to = TrieCheckFrom; + PRINT_INDEX(TrieCheckFrom,4,20) + } + else { + TrieCheckFrom->index++; + PRINT_INDEX(TrieCheckFrom,4,21) + } + NextCand->do_it = FALSE; + } + } + break; + case 1: + TrieCheckFrom->index ++; + tv->gotonode = TrieCheckFrom; + PRINT_INDEX(TrieCheckFrom,4,22) + break; + case 2: + if (TrieCandFrom) { + TrieCheckFrom->index += TrieCandFrom->index; + TrieCandFrom->goes_to = TrieCheckFrom; + PRINT_INDEX(TrieCheckFrom,4,23) + } + else { + TrieCheckFrom->index++; + PRINT_INDEX(TrieCheckFrom,4,24) + } + if ((temp == tv->maxtreelevel) && (CheckAutList->lab[Spine[temp].tgtpos] == AutomCount[1])) { + tmp1 = TempOrbits[NextCand->lab[Spine[temp].tgtpos]]; + for (i=1; i<AutomCount[0]; i++) if (AutomCount[i] == tmp1) break; + if (i == AutomCount[0]) { + AutomCount[AutomCount[0]++] = TempOrbits[NextCand->lab[Spine[temp].tgtpos]]; + } + } + break; + default: + break; + } + return temp; + } + } + } + CheckAutList = CheckAutList->next; + } + return FALSE; +} + +void CodeClassify(int Level, int code, int cell) { + switch (EPCodes[Level].info) { + case 0: + EPCodes[Level].code = code; + EPCodes[Level].cell = cell; + EPCodes[Level].info = 1; + break; + case 1: + if (EPCodes[Level].cell != cell) { + EPCodes[Level].info = 3; + } else { + if (EPCodes[Level].code != code) { + EPCodes[Level].info = 2; + } + } + break; + case 2: + if (EPCodes[Level].cell != cell) { + EPCodes[Level].info = 3; + } + break; + default: + break; + } +} + +void Complete(sparsegraph *sg_orig, Candidate *Cand, Partition *Part, int cell, TracesVars *tv, + double *grpsize1, int *grpsize2, permnode **ring, int n) { + int i, j, k; + int arg, val; + int numtemporbits; + k = cell + Part->cls[cell]; + + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (i = cell; i < k; i++) { + tv->currorbit[Cand->lab[i]] = Cand->lab[k]; + arg = Cand->lab[i]; + val = Cand->lab[i+1]; + SETPAIRSAUTANDTREE(arg, val) + } + arg = Cand->lab[i]; + val = Cand->lab[cell]; + SETPAIRSAUTANDTREE(arg, val) + SPECIALGENERATORS + + if (Part->cls[cell] > 1) { + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + arg = Cand->lab[cell]; + val = Cand->lab[cell+1]; + SETPAIRSAUTANDTREE(arg, val) + arg = Cand->lab[cell+1]; + val = Cand->lab[cell]; + SETPAIRSAUTANDTREE(arg, val) + SPECIALGENERATORS + } +} + +int CompStage0(Partition *CurrPart, Partition *NextPart, Candidate *CurrCand, Candidate *NextCand, + int m, int n, struct TracesVars* tv, struct TracesInfo *ti) { + int i, j, i1, j2, k, cu, cu1, num_indv; + int temp, tmp, auxcode, search_vtx, gom_level; + boolean closeloop, firstsing, has_nexttcell; + Candidate *SpTLliststart, *AuxCand; + searchtrie *TreeNode, *TreeNode1, *TreeNode2; + +#ifdef NAUTY_IN_MAGMA + if (main_seen_interrupt) return NAUTY_KILLED; +#else + if (nauty_kill_request) return NAUTY_KILLED; +#endif + + PRINT_FROM_VERB(4,tv->tolevel) + if (TargetCell(CurrCand, CurrPart, n, tv, tv->tolevel)) { + ++tv->tolevel; + SpineTL = Spine+tv->tolevel; + SpineTL->tgtcell = tv->tcell; + SpineTL->tgtsize = CurrPart->cls[tv->tcell]; + SpineTL->tgtend = tv->tcell+SpineTL->tgtsize; + SpineTL->tgtpos = SpineTL->tgtend - 1; + } + else { + tv->finalnumcells = CurrPart->cells; + ti->thereisnextlevel = SelectNextLevel(n, tv, ti); + return 0; + } + + tv->newgotonode = NULL; + + /* CANDIDATE */ + temp = CurrCand->lab[Spine[1].tgtpos]; + k = SpineTL->tgtend; + + TreeNode = CurrCand->stnode; + while (TreeNode) { + if (TreeNode->goes_to) { + CurrCand->do_it = FALSE; + break; + } + TreeNode = TreeNode->father; + } + + if (CurrCand->do_it) { + if ((tv->orbits[temp] == temp) || tv->tolevel == 1) { + ti->minimalinorbits = TRUE; + + if ((tv->group_level >= tv->tolevel) && (FixedBase(fix, tv, CurrCand, 0, tv->fromlevel))) { + tv->nfix = tv->fromlevel; + tv->currorbit = findcurrorbits(gpB, tv->nfix); + } else { + if ((!ti->identitygroup) && + (((Spine[tv->fromlevel].liststart != Spine[tv->fromlevel].listend) + && (CurrPart->cls[tv->tcell] > 10)) + || tv->strategy + || (tv->expathlength <=10) + )) { + + TempOrbits = NULL; + tv->samepref = FixBase(fix, tv, CurrCand, 0, tv->fromlevel); + if ((tv->samepref != tv->nfix) || ti->thegrouphaschanged) { + if (tv->options->verbosity >= 2) tv->schreier1 -= CPUTIME; + gom_level = getorbitsmin(fix, tv->nfix, gpB, &gensB, &tv->currorbit, CurrCand->lab+tv->tcell, CurrPart->cls[tv->tcell], n, TRUE); + if (tv->options->verbosity >= 2) tv->schreier1 += CPUTIME; + ti->thegrouphaschanged = FALSE; + + if (gom_level < tv->nfix) { + PRINT_NOTMIN_VERB(4) + + TreeNode = CurrCand->stnode; + j2 = CurrCand->lab[Spine[gom_level+1].tgtpos]; + i1 = tv->currorbit[j2]; + for (j=0; j < tv->nfix - gom_level; j++) { + TreeNode = TreeNode->father; + } + TreeNode1 = TreeNode->first_child; + while (TreeNode1) { + if (TreeNode1->vtx == i1) { + break; + } + TreeNode1 = TreeNode1->next_sibling; + } + if (TreeNode1) { + while (TreeNode1->goes_to) { + TreeNode1 = TreeNode1->goes_to; + } + TreeNode2 = TreeNode1->next_sibling; + while (TreeNode2->vtx != j2) { + TreeNode2 = TreeNode2->next_sibling; + } + TreeNode1->index += TreeNode2->index; + TreeNode2->goes_to = TreeNode1; + PRINT_INDEX(TreeNode1,4,25) + + ti->minimalinorbits = FALSE; + } + else { + tv->currorbit = getorbits(fix, tv->nfix, gpB, &gensB, n); + } + } + } + else { + tv->currorbit = findcurrorbits(gpB, tv->nfix); + } + } + else { + TempOrbits = WorkArray1; + memcpy(TempOrbits, IDENTITY_PERM, n*sizeof(int)); + memcpy(TempOrbList, IDENTITY_PERM, n*sizeof(int)); + + tv->conta1++; + tv->currorbit = TempOrbits; + } + } + if (ti->minimalinorbits) { + memcpy(NextCand->lab, CurrCand->lab, n*sizeof(int)); + memcpy(NextCand->invlab, CurrCand->invlab, n*sizeof(int)); + tv->conta2++; + auxcode = CurrCand->code; + SpineTL->trcstart = CurrPart->cells; + TheTrace[SpineTL->trcstart] = SpineTL->tgtpos; + if (!CurrCand->sortedlab) { + quickSort(CurrCand->lab+tv->tcell, CurrPart->cls[tv->tcell]); + for (i=tv->tcell; i<tv->tcell+CurrPart->cls[tv->tcell]; i++) { + CurrCand->invlab[CurrCand->lab[i]] = i; + } + CurrCand->sortedlab = TRUE; + } + + tv->indivstart = tv->tcell+CurrCand->indnum; + tv->indivend = tv->indivstart+tv->steps; + if (tv->indivend > SpineTL->tgtend) { + tv->indivend = SpineTL->tgtend; + } + + temp = CurrCand->lab[tv->indivstart]; + for (k = tv->indivstart; k < tv->indivend; k++) { + CurrCand->indnum++; + NextCand->singcode = CurrCand->singcode; + NextCand->vertex = CurrCand->lab[k]; + NextCand->name = ++tv->name; + if (NextCand->name == (NAUTY_INFINITY-2)) { + NextCand->name = tv->name = 1; + } + + PRINT_INDIV_VERB(4,tv->tolevel) + if (tv->currorbit[NextCand->vertex] != NextCand->vertex) { + PRINT_SKIPPED_VERB(4) + + search_vtx = tv->currorbit[NextCand->vertex]; + TreeNode = CurrCand->stnode; + if (TreeNode->first_child) { + TreeNode = TreeNode->first_child; + while (TreeNode) { + if (TreeNode->vtx == search_vtx) { + break; + } + TreeNode = TreeNode->next_sibling; + } + if (TreeNode) { + while (TreeNode->goes_to) { + TreeNode = TreeNode->goes_to; + } + TreeNode->index++; + PRINT_INDEX(TreeNode,4,26) + continue; + } + } + } + else { + PRINT_REFINE_VERB(4,'a') + + memcpy(NextPart->cls, CurrPart->cls, n*sizeof(int)); + memcpy(NextPart->inv, CurrPart->inv, n*sizeof(int)); + + tv->conta3++; + + if (NextPart->cls[tv->tcell] == 2) { + num_indv = 2; + NextCand->singcode = MASHCOMM(NextCand->singcode, CurrCand->lab[tv->tcell]); + NextCand->singcode = MASHCOMM(NextCand->singcode, CurrCand->lab[tv->tcell+1]); + if (SpineTL->singstart == SpineTL->singend) { + Singletons[SpineTL->singend++] = tv->tcell; + Singletons[SpineTL->singend++] = tv->tcell+1; + } + } + else { + num_indv = 1; + NextCand->singcode = MASHCOMM(NextCand->singcode, NextCand->vertex); + if (SpineTL->singstart == SpineTL->singend) { + Singletons[SpineTL->singend++] = tv->tcell + NextPart->cls[tv->tcell] - 1; + } + } + + Individualize(NextPart, NextCand, NextCand->vertex, tv->tcell, CurrPart->cells, SpineTL->tgtpos); + tv->stats->numnodes++; + tv->answ = traces_refine(NextCand, + n, + NextPart, tv, ti, num_indv, TRUE); + switch (tv->answ) { + case 0: /* Interrupted refinement: do not add to the list */ + tv->stats->interrupted++; + SpineTL->levelcounter++; + break; + case 1 : /* The same trace has been found once more : add to the list */ + SpineTL->levelcounter++; + + NextCand->do_it = TRUE; + if (tv->options->verbosity >= 2) PRINT_CANDIDATE(NextCand, tv->tolevel); + + tv->tolevel_tl = tv->tolevel; + NextCand->pathsingcode = NextCand->singcode; + NextCand->firstsingcode = 0; + + if (tv->steps > 1) { + if (tv->fromlevel <= tv->lev_of_lastauto) { + closeloop = CheckForMatching(CurrCand, NextCand, NextPart, tv, ti, m, n); + } + if (NextCand->do_it) { + firstsing = TRUE; + + /* EXPERIMENTAL PATH */ + if (NextPart->cells != tv->finalnumcells) { /* 160712 */ + if (tv->options->verbosity >= 2) tv->expaths -= CPUTIME; + while (NextPart->cells < n) { + if (firstsing && BreakSteps[tv->tolevel]) { + firstsing = FALSE; + NextCand->firstsingcode = NextCand->pathsingcode; + if (CheckForSingAutomorphisms(CurrCand, NextPart, NextCand, tv, ti, m, n)) + if (!NextCand->do_it) { + break; + } + } + + has_nexttcell = TargetCellExpPath(NextCand, NextPart, tv); + + if (!has_nexttcell) { + NextCand->firstsingcode = NextCand->pathsingcode; + if (tv->options->verbosity >= 2) { + if (tv->tolevel_tl-tv->tolevel >= 6) { + PRINT_EXPPATHSTEP(NextCand, TRUE) + } + else { + fprintf(outfile, "(%d) ", tv->tolevel_tl); + } + } + break; + } + ExperimentalStep(NextPart, NextCand, tv, ti, m, n); + if (NextPart->cells == n) { + has_nexttcell = FALSE; + } + PRINT_EXPPATHSTEP(NextCand, TRUE) + } + if (tv->options->verbosity >= 2) tv->expaths += CPUTIME; + } + } + else { + if (closeloop < tv->tolevel) k = SpineTL->tgtend; + PRINT_RETURN + break; + } + + if (!tv->strategy && !tv->options->getcanon && (tv->tolevel_tl == tv->tolevel + 1) && ((NextPart->cells > tv->finalnumcells) || (NextPart->cells == n))) { /* 160717 */ + tv->levelfromCS0 = tv->tolevel; + tv->maxtreelevel = tv->tolevel_tl; + tv->finalnumcells = NextPart->cells; + if (tv->tolevel == 1) { + tv->newst_stage1 = searchtrie_make(CurrCand, NextCand, n, tv); + EXITFROMSTAGE0EXPATH1 + } + else { + temp = 0; + for (i=0; i<tv->tolevel; i++) { + temp += Spine[i].listcounter; + } + if (temp > 5) { + tv->newst_stage1 = searchtrie_make(CurrCand, NextCand, n, tv); + EXITFROMSTAGE0EXPATH1 + } + } + } + + /* ANY AUTOMORPHISM? */ + if (tv->options->verbosity >= 2) tv->autchk -= CPUTIME; + tv->newindex = 0; + if (NextCand->do_it) { + closeloop = CheckForAutomorphisms(CurrCand, NextCand, tv, ti, m, n, NextPart); + if (!NextCand->do_it && closeloop < tv->tolevel) k = SpineTL->tgtend; + } + if (tv->options->verbosity >= 2) tv->autchk += CPUTIME; + + if (NextCand->do_it) { + ADDTONEXTLEVEL; + SpineTL->keptcounter++; + searchtrie_make(CurrCand, SpineTL->listend, n, tv); + } + } + else { + if (BreakSteps[tv->tolevel]) { + NextCand->firstsingcode = NextCand->pathsingcode; + if (CheckForSingAutomorphisms(CurrCand, NextPart, NextCand, tv, ti, m, n)) + if (!NextCand->do_it) { + PRINT_RETURN + break; + } + } + + /* ANY AUTOMORPHISM? */ + if (tv->options->verbosity >= 2) tv->autchk -= CPUTIME; + tv->newindex = 0; + if (NextCand->do_it) { + closeloop = CheckForAutomorphisms(CurrCand, NextCand, tv, ti, m, n, NextPart); + if (!NextCand->do_it && closeloop < tv->tolevel) k = SpineTL->tgtend; + } + if (tv->options->verbosity >= 2) tv->autchk += CPUTIME; + + if (NextCand->do_it) { + ADDTONEXTLEVEL; + SpineTL->keptcounter++; + searchtrie_make(CurrCand, SpineTL->listend, n, tv); + } + } + PRINT_RETURN + break; + case 2 : /* Delete the old list and start a new one: a better trace has been found */ + + if (NextPart->cells > tv->finalnumcells) { + tv->finalnumcells = NextPart->cells; + } + tv->tolevel_tl = tv->tolevel; + has_nexttcell = FALSE; + if (NextPart->cells == n) { + tv->stats->canupdates++; + if (tv->options->usercanonproc != NULL) + { + (*tv->options->usercanonproc)((graph*)tv->input_graph, NextCand->lab, (graph*)tv->cangraph, tv->stats->canupdates, NextCand->code, m, n); + } + } + + if (tv->tolevel > tv->treedepth) { + tv->treedepth = tv->tolevel; + if (tv->strategy) { + SpineTL->part = NewPartition(n); + } + else { + NewPartSpine(tv->tolevel,n); + } + } + + if (!tv->strategy && (tv->tolevel > 1) && !SpineTL->liststart) { + /* First Candidate at current level */ + tv->maxtreelevel = tv->tolevel; + + SpineTL->liststart = NewCandidate(n, &GarbList, TRUE); + SpineTL->listend = SpineTL->liststart; + + tv->conta0++; + CopyCand(SpineTL->liststart, NextCand, n, TEMPLAB, TEMPINVLAB); + if (NextPart->cells < tv->finalnumcells) SpineTL->liststart->code = auxcode; + COPYPART(SpineTL->part, NextPart); + tv->newindex = 0; + tv->newst_stage1 = searchtrie_make(CurrCand, SpineTL->listend, n, tv); + + SpineTL->listcounter = 1; + SpTLliststart = SpineTL->liststart; + + i = tv->tolevel; + if (tv->brkstpcount) { + while ((i<n) && !BreakSteps[i]) { + i++; + } + if (i<n) SpineTL->liststart->firstsingcode = Spine[i].singcode; + } + + SpineTL->updates = 1; + SpineTL->levelcounter = 1; + SpineTL->keptcounter = 1; + + PRINT_LINE_PLUS(tv->fromlevel) + + if (tv->options->verbosity >= 2) PRINT_CANDIDATE(SpineTL->liststart, tv->tolevel); + PRINT_RETURN; + + if (!tv->strategy && !tv->options->getcanon && (tv->tolevel+1 == tv->firstpathlength) && ((NextPart->cells > tv->finalnumcells) || (NextPart->cells == n))) { + tv->finalnumcells = NextPart->cells; + if ((tv->tolevel == 1) && (CurrPart->cls[tv->tcell] > 5)) { + EXITFROMSTAGE0EXPATH2; + } + else { + temp = 0; + for (i=0; i<tv->tolevel; i++) { + temp += Spine[i].listcounter; + } + if (temp > 5) { + EXITFROMSTAGE0EXPATH2; + } + } + } + } + else { + memset(WorkArray, 0, n*sizeof(int)); + + tv->lastcell = tv->lastlev = -1; + has_nexttcell = TargetCellFirstPath(NextCand, NextPart, tv); + + if (!has_nexttcell) { + tv->stats->canupdates++; + if (tv->options->usercanonproc != NULL) { + (*tv->options->usercanonproc)((graph*)tv->input_graph, NextCand->lab, (graph*)tv->cangraph, tv->stats->canupdates, NextCand->code, m, n); + } + } + + tv->tcellevel = tv->maxtreelevel = tv->tolevel; + SpineTL->levelcounter++; + SpineTL->updates++; + SpineTL->keptcounter = 1; + + RemoveFromLevel(tv->tolevel, tv->treedepth, tv->strategy, TRUE); + SpineTL->liststart = NewCandidate(n, &GarbList, TRUE); + SpineTL->listend = SpineTL->liststart; + + tv->conta0++; + CopyCand(SpineTL->liststart, NextCand, n, NULL, NULL); + COPYPART(SpineTL->part, NextPart); + + tv->newindex = 0; + + tv->newst_stage1 = searchtrie_make(CurrCand, SpineTL->listend, n, tv); + + SpineTL->listcounter = 1; + SpTLliststart = SpineTL->liststart; + + SpTLliststart->pathsingcode = SpineTL->singcode = SpTLliststart->singcode; + SpTLliststart->firstsingcode = 0; + + PRINT_LINE + if (tv->options->verbosity >= 2) PRINT_CANDIDATE(SpTLliststart, tv->tolevel); + + memset(BreakSteps, 0, n*sizeof(int)); + tv->brkstpcount = 0; + + if (tv->steps > 1) { + + /* EXPERIMENTAL PATH */ + if (tv->options->verbosity >= 2) tv->expaths -= CPUTIME; + PRINTF2("CStage0 2: %d\n", tv->finalnumcells); + tv->finalnumcells = n; + + while (has_nexttcell) { + ExperimentalStep(NextPart, SpTLliststart, tv, ti, m, n); + + Spine[tv->tolevel_tl].singcode = SpTLliststart->pathsingcode; + has_nexttcell = TargetCellFirstPath(SpTLliststart, NextPart, tv); + PRINT_EXPPATHSTEP(SpTLliststart, TRUE) + } + if (NextPart->cells < n) { + PRINTF2("CStage0 3: %d\n", tv->finalnumcells); + tv->finalnumcells = minint(NextPart->cells,tv->finalnumcells); /* 160712 */ + tv->finalnumcells = NextPart->cells; + + PRINTF2("CStage0 3<: %d\n", tv->finalnumcells); + } + + PRINTF2("CS0 2?: finalnumcells: %d\n", tv->finalnumcells); + if (NextPart->cells == tv->finalnumcells) { + UPDATEMIN(tv->expathlength, tv->tolevel_tl); + } + + if (tv->options->verbosity >= 2) tv->expaths += CPUTIME; + + tv->firstpathlength = tv->tolevel_tl; + PRINT_RETURN + if (!tv->strategy && !tv->options->getcanon && (NextPart->cells == tv->finalnumcells) && (tv->tolevel_tl == tv->tolevel + 1) && ((NextPart->cells > tv->finalnumcells) || (NextPart->cells == n))) { + tv->maxtreelevel = tv->tolevel_tl; + tv->finalnumcells = NextPart->cells; + if ((tv->tolevel == 1) && (CurrPart->cls[tv->tcell] > 5)) { + EXITFROMSTAGE0EXPATH2 + } + else { + temp = 0; + for (i=0; i<tv->tolevel; i++) { + temp += Spine[i].listcounter; + } + if (temp > 5) { + EXITFROMSTAGE0EXPATH2 + } + } + } + memcpy(TEMPLAB, SpTLliststart->lab, n*sizeof(int)); + memcpy(TEMPINVLAB, SpTLliststart->invlab, n*sizeof(int)); + tv->conta5++; + } + else { + PRINT_RETURN + } + } + + break; + default: + break; + } + } + } /* end for */ + } + } + } + + /* REMOVE CURRENT CANDIDATE */ + if (SpineFL->liststart && (k >= SpineTL->tgtend)) { + SpineFL->liststart = CurrCand->next; + if (CurrCand->next == NULL) { + SpineFL->listend = NULL; + } + SpineFL->listcounter--; + CurrCand->next = GarbList; + GarbList = CurrCand; + } + ti->thereisnextlevel = SelectNextLevel(n, tv, ti); + return 0; +} + +int CompStage1(Partition *CurrPart, Partition *NextPart, Candidate *CurrCand, Candidate *NextCand, + int m, int n, + struct TracesVars* tv, struct TracesInfo *ti) { + int i, k, cu, cu1, tmp, gom_level, search_vtx, temp; + searchtrie *TreeNode, *TrieNode; + +#ifdef NAUTY_IN_MAGMA + if (main_seen_interrupt) return NAUTY_KILLED; +#else + if (nauty_kill_request) return NAUTY_KILLED; +#endif + + CurrCand->stnode = tv->newst_stage1; + + tv->tolevel++; + SpineTL = Spine+tv->tolevel; + tv->tcell = SpineTL->tgtcell; + SpineTL->levelcounter = 0; + SpineTL->keptcounter = 0; + SpineTL->updates = 1; + + + if (tv->options->verbosity >= 2) { + LINE(32, "=") + NEXTLINE + } + + memset(RefCells, 0, n*sizeof(int)); + memset(MultRefCells, 0, n*sizeof(int)); + ti->thegrouphaschanged = TRUE; + + /* CANDIDATE */ + memcpy(NextCand->lab, CurrCand->lab, n*sizeof(int)); + memcpy(NextCand->invlab, CurrCand->invlab, n*sizeof(int)); + NextCand->do_it = TRUE; + SpineTL->trcstart = CurrPart->cells; + + tv->indivstart = tv->tcell; + tv->indivend = SpineTL->tgtend; + if (TheGraph[CurrCand->lab[tv->indivstart]].d == 1) { + tv->indivstart = SpineTL->tgtend-1; + } + + FixBase(fix, tv, NextCand, 0, tv->fromlevel); + + if (!ti->identitygroup) { + if (tv->options->verbosity >= 2) tv->schreier2 -= CPUTIME; + tv->currorbit = getorbits(fix, tv->nfix, gpB, &gensB, n); + if (tv->options->verbosity >= 2) tv->schreier2 += CPUTIME; + } + else { + memcpy(tv->currorbit, IDENTITY_PERM, n*sizeof(int)); + } + + if (!CurrCand->sortedlab) { + quickSort(CurrCand->lab+tv->tcell, CurrPart->cls[tv->tcell]); + for (i=tv->tcell; i<tv->tcell+CurrPart->cls[tv->tcell]; i++) { + CurrCand->invlab[CurrCand->lab[i]] = i; + } + CurrCand->sortedlab = TRUE; + } + for (k = tv->indivstart; k < tv->indivend; k++) { + NextCand->vertex = CurrCand->lab[k]; + NextCand->name = ++tv->name; + if (NextCand->name == (NAUTY_INFINITY-2)) { + NextCand->name = tv->name = 1; + } + if (tv->currorbit[CurrCand->lab[k]] != CurrCand->lab[k]) { + search_vtx = tv->currorbit[NextCand->vertex]; + TreeNode = CurrCand->stnode; + if (TreeNode->first_child) { + TreeNode = TreeNode->first_child; + while (TreeNode) { + if (TreeNode->vtx == search_vtx) { + break; + } + TreeNode = TreeNode->next_sibling; + } + if (TreeNode) { + while (TreeNode->goes_to) { + TreeNode = TreeNode->goes_to; + } + TreeNode->index++; + PRINT_INDEX(TreeNode,4,27) + } + } + continue; + } + PRINT_REFINE_VERB(4,'b') + memcpy(NextPart->cls, CurrPart->cls, n*sizeof(int)); + memcpy(NextPart->inv, CurrPart->inv, n*sizeof(int)); + + Individualize(NextPart, NextCand, CurrCand->lab[k], tv->tcell, CurrPart->cells, SpineTL->tgtpos); + + tv->stats->numnodes++; + SpineTL->levelcounter++; + tv->tolevel_tl = tv->tolevel; + trieref = trieroot; + SpineTL->levelcounter++; + + traces_refine_maketrie(NextCand, + n, + NextPart, tv, ti); + + RefCells[CurrCand->lab[k]] = NextPart->cells; + PRINTF2("CS1 1?: finalnumcells: %d\n", tv->finalnumcells); + if ((NextPart->cells == tv->finalnumcells) || (NextPart->cells == n)) { + if (tv->options->verbosity >= 2) PRINT_CANDIDATE(NextCand, tv->tolevel); + + /* ANY AUTOMORPHISM? */ + if (tv->options->verbosity >= 2) tv->autchk -= CPUTIME; + + PRINTF2("CS1 2?: finalnumcells: %d\n", tv->finalnumcells); + CheckForAutomorphisms(CurrCand, NextCand, tv, ti, m, n, NextPart); + if (tv->options->verbosity >= 2) tv->autchk += CPUTIME; + + PRINT_RETURN + + /* ADD TO NEXT LEVEL */ + SpineTL->keptcounter++; + if (!Spine[tv->tolevel].listend) COPYPART(Spine[tv->tolevel].part, NextPart); + ADDTONEXTLEVEL; + searchtrie_make(CurrCand, SpineTL->listend, n, tv); + } + } /* end for */ + PRINTF2("CS1 3: finalnumcells: %d\n", tv->finalnumcells); + for (k = tv->indivstart; k < tv->indivend; k++) { + MultRefCells[RefCells[tv->currorbit[CurrCand->lab[k]]] % n]++; + } + + if (tv->options->verbosity >= 2) { + if (MultRefCells[0]) { + fprintf(outfile, tv->digstring, n); + fprintf(outfile, "cells: %d; ", MultRefCells[0]); + } + for (k=1; k<n; k++) { + if (MultRefCells[k]) { + fprintf(outfile, tv->digstring, k); + fprintf(outfile, "cells: %d; ", MultRefCells[k]); + } + } + NEXTLINE + + } + +#if !MAXN + DYNALLOC1(searchtrie*, RefPath, RefPath_sz, tv->tolevel, "Traces-CS1"); +#endif + + TreeNode = CurrCand->stnode; + while (TreeNode) { + RefPath[TreeNode->level] = TreeNode; + TreeNode = TreeNode->father; + } + + /* REMOVE CURRENT CANDIDATE */ + SpineFL->liststart = CurrCand->next; + if (CurrCand->next == NULL) { + SpineFL->listend = NULL; + SpineFL->listcounter = 1; + } + SpineFL->listcounter--; + CurrCand->next = GarbList; + GarbList = CurrCand; + + if (tv->options->verbosity >= 2) { + LINE(32, "=") + NEXTLINE + } + tv->compstage = 2; + tv->steps = n; + + if (tv->options->verbosity >= 2) tv->schreier1 -= CPUTIME; + + gom_level = getorbitsmin(fix, tv->nfix, gpB, &gensB, &tv->currorbit, + CurrCand->lab+tv->tcell, CurrPart->cls[tv->tcell], n, TRUE); + if (tv->options->verbosity >= 2) tv->schreier1 += CPUTIME; + ORBITSIZES + ti->thereisnextlevel = SelectNextLevel(n, tv, ti); + PRINTF2("CS1 4: finalnumcells: %d\n", tv->finalnumcells); + SpineTL->part->cells = tv->finalnumcells; + + AutomCount[0] = 2; + AutomCount[1] = CurrCand->vertex; + + return 0; +} + +int CompStage2(Partition *CurrPart, Partition *NextPart, Candidate *CurrCand, Candidate *NextCand, + int m, int n, + struct TracesVars* tv, struct TracesInfo *ti) { + int i, j, i1, j2, k, cu, cu1, vertex, gom_level; + int temp, tmp, autom; + Candidate *AuxCand; + searchtrie *TreeNode, *TreeNode1, *TreeNode2; + int *CuOrb,*AuxOrb; + boolean has_nexttcell = FALSE; + searchtrie *TrieNode; + boolean schreierwrong; + +#ifdef NAUTY_IN_MAGMA + if (main_seen_interrupt) return NAUTY_KILLED; +#else + if (nauty_kill_request) return NAUTY_KILLED; +#endif + + autom = 0; + schreierwrong = FALSE; + + TreeNode = CurrCand->stnode; + tv->cand_level = 0; + + while (TreeNode) { + if (TreeNode->goes_to) { + CurrCand->do_it = FALSE; + } + if (!tv->cand_level && TreeNode == RefPath[TreeNode->level]) { + tv->cand_level = TreeNode->level; + } + TreeNode = TreeNode->father; + } + if (tv->cand_level+1 == tv->maxtreelevel) { + ti->useTempOrbits1 = TRUE; + } + else { + ti->useTempOrbits1 = FALSE; + } + if (tv->cand_level == tv->fromlevel) { + ti->useTempOrbits2 = TRUE; + } + else { + ti->useTempOrbits2 = FALSE; + } + + PRINT_FROM_VERB(4,tv->tolevel) + + if (CurrCand->do_it) { + if (tv->tolevel == 0) { + vertex = Spine[tv->maxtreelevel+1].liststart->lab[Spine[1].tgtpos]; + k = n; + + tv->fromlevel = tv->tolevel++; + SpineFL = Spine+tv->fromlevel; + SpineTL = Spine+tv->tolevel; + tv->tcell = Spine[tv->tolevel].tgtcell; + + memcpy(NextCand->lab, CurrCand->lab, n*sizeof(int)); + memcpy(NextCand->invlab, CurrCand->invlab, n*sizeof(int)); + SpineTL->trcstart = CurrPart->cells; + TheTrace[SpineTL->trcstart] = SpineTL->tgtpos; + + tv->indivstart = tv->tcell+CurrCand->indnum; + tv->indivend = tv->indivstart+tv->steps; + if (tv->indivend > SpineTL->tgtend) { + tv->indivend = SpineTL->tgtend; + } + memset(CurrRefCells, 0, n*sizeof(int)); + ti->thegrouphaschanged = TRUE; + + if (!CurrCand->sortedlab) { + quickSort(CurrCand->lab+tv->tcell, CurrPart->cls[tv->tcell]); + for (i=tv->tcell; i<tv->tcell+CurrPart->cls[tv->tcell]; i++) { + CurrCand->invlab[CurrCand->lab[i]] = i; + } + CurrCand->sortedlab = TRUE; + } + + for (k = tv->indivstart; k < tv->indivend; k++) { + if ((tv->orbits[CurrCand->lab[k]] == CurrCand->lab[k]) && ((tv->finalnumcells < n) || (OrbSize[tv->orbits[CurrCand->lab[k]]] >= OrbSize[tv->orbits[vertex]]))) { + + CurrCand->indnum++; + NextCand->singcode = CurrCand->singcode; + NextCand->vertex = CurrCand->lab[k]; + NextCand->name = ++tv->name; + if (NextCand->name == (NAUTY_INFINITY-2)) { + NextCand->name = tv->name = 1; + } + + if (ti->thegrouphaschanged) { + if (tv->fromlevel == tv->maxtreelevel) { + CURRORBITSIZES + } + ti->thegrouphaschanged = FALSE; + } + + if (tv->currorbit[CurrCand->lab[k]] != CurrCand->lab[k]) { + continue; + } + + memcpy(NextPart->cls, CurrPart->cls, n*sizeof(int)); + memcpy(NextPart->inv, CurrPart->inv, n*sizeof(int)); + if (NextPart->cls[tv->tcell] == 2) { + NextCand->singcode = MASHCOMM(NextCand->singcode, CurrCand->lab[tv->tcell]); + NextCand->singcode = MASHCOMM(NextCand->singcode, CurrCand->lab[tv->tcell+1]); + } + else { + NextCand->singcode = MASHCOMM(NextCand->singcode, CurrCand->lab[k]+labelorg); + } + + Individualize(NextPart, NextCand, CurrCand->lab[k], tv->tcell, CurrPart->cells, SpineTL->tgtpos); + + tv->stats->numnodes++; + Spine[tv->tolevel+1].levelcounter++; + if (tv->fromlevel == tv->maxtreelevel) { + tv->tolevel_tl = tv->tolevel; + trieref = trieroot; + + tv->answ = traces_refine_comptrie(NextCand, + n, + NextPart, tv, ti); + if (tv->answ) { + if (NextPart->cells != tv->finalnumcells) { + CurrRefCells[NextPart->cells % n] += CurrOrbSize[CurrCand->lab[k]]; + if (CurrRefCells[NextPart->cells % n] > MultRefCells[NextPart->cells % n]) { + k = n; + break; + } + continue; + } + if (tv->options->verbosity >= 2) PRINT_CANDIDATE(NextCand, tv->tolevel) + } + } + else { + tv->answ = traces_refine_sametrace(NextCand, + n, + NextPart, tv, ti); + + if (tv->answ) { + if (tv->options->verbosity >= 2) PRINT_CANDIDATE(NextCand, tv->tolevel) + if (tv->tolevel == tv->maxtreelevel) { + tv->tolevel_tl = tv->tolevel; + if (tv->options->verbosity >= 2) tv->expaths -= CPUTIME; + TargetCellExpPath(NextCand, NextPart, tv); + ExperimentalStep(NextPart, NextCand, tv, ti, m, n); + PRINT_EXPPATHSTEP(NextCand, tv->answ) + PRINTF2("CS2 1?: finalnumcells: %d\n", tv->finalnumcells); + if ((NextPart->cells == tv->finalnumcells) || (NextPart->cells == n)) { + UPDATEMIN(tv->expathlength, tv->tolevel_tl); + } + + if (tv->options->verbosity >= 2) tv->expaths += CPUTIME; + if (!tv->answ) { + PRINT_RETURN + } + } + } + } + if (tv->answ) { + PRINTF2("CS2 2?: finalnumcells: %d\n", tv->finalnumcells); + if ((NextPart->cells == tv->finalnumcells) || (NextPart->cells == n)) { + if (tv->options->verbosity >= 2) tv->autchk -= CPUTIME; + temp = (tv->tolevel_tl == tv->tolevel+1); + autom = CheckForAutomorphisms(CurrCand, NextCand, + tv, ti, temp, n, NextPart); + if (tv->options->verbosity >= 2) tv->autchk += CPUTIME; + + if (ti->thegrouphaschanged) { + ORBITSIZES + } + } + PRINT_RETURN + + /* ADD TO NEXT LEVEL */ + PRINTF2_2("CS2 3?: cells: %d, finalnumcells: %d\n", NextPart->cells, tv->finalnumcells); + if ((NextPart->cells != tv->finalnumcells) || (tv->tolevel != tv->maxtreelevel) || (tv->tolevel_tl != tv->tolevel+1)) { + ADDTONEXTLEVEL; + searchtrie_make(CurrCand, SpineTL->listend, n, tv); + } + } + else { + tv->stats->interrupted++; + } + if (tv->fromlevel == tv->maxtreelevel) { + k = n; + break; + } + } + } /* end for */ + } + else { + + temp = CurrCand->lab[Spine[1].tgtpos]; + vertex = Spine[tv->maxtreelevel+1].liststart->lab[Spine[1].tgtpos]; + k = n; + + if (tv->cand_level || + ((tv->orbits[temp] == temp) && ((tv->finalnumcells < n) || (OrbSize[tv->orbits[temp]] >= OrbSize[tv->orbits[vertex]])))) { + tv->fromlevel = tv->tolevel++; + SpineFL = Spine+tv->fromlevel; + SpineTL = Spine+tv->tolevel; + tv->tcell = Spine[tv->tolevel].tgtcell; + + ti->minimalinorbits = TRUE; + + if (!ti->identitygroup) { + + if (ti->useTempOrbits1 && ti->useTempOrbits2) { + CuOrb = TempOrbits; + } + else { + FixBase(fix, tv, CurrCand, 0, tv->fromlevel); + if (ti->useTempOrbits1 && tv->fromlevel == tv->maxtreelevel) { + tv->currorbit = getorbits(fix, tv->nfix, gpB, &gensB, n); + CuOrb = tv->currorbit; + } + else { + if (tv->options->verbosity >= 2) tv->schreier1 -= CPUTIME; + + gom_level = getorbitsmin(fix, tv->nfix, gpB, &gensB, &tv->currorbit, + CurrCand->lab+tv->tcell, CurrPart->cls[tv->tcell], n, TRUE); + if (tv->options->verbosity >= 2) tv->schreier1 += CPUTIME; + + CuOrb = tv->currorbit; + if (gom_level < tv->nfix) { + PRINT_NOTMIN_VERB(4) + if (ti->useTempOrbits1) { + for (i=1; i<AutomCount[0]; i++) if (AutomCount[i] == CuOrb[tv->currorbit[CurrCand->vertex]]) break; + if (i < AutomCount[0]) { + AutomCount[AutomCount[0]++] = CurrCand->vertex; + } + ti->minimalinorbits = FALSE; + } + else { + TreeNode = CurrCand->stnode; + j2 = CurrCand->lab[Spine[gom_level+1].tgtpos]; + i1 = tv->currorbit[j2]; + for (j=0; j < tv->nfix - gom_level; j++) { + TreeNode = TreeNode->father; + } + TreeNode1 = TreeNode->first_child; + while (TreeNode1) { + if (TreeNode1->vtx == i1) { + break; + } + TreeNode1 = TreeNode1->next_sibling; + } + schreierwrong = FALSE; + if (TreeNode1) { + while (TreeNode1->goes_to) { + TreeNode1 = TreeNode1->goes_to; + } + TreeNode2 = TreeNode->first_child; + while (TreeNode2->vtx != j2) { + TreeNode2 = TreeNode2->next_sibling; + } + + TreeNode1->index += TreeNode2->index; + TreeNode2->goes_to = TreeNode1; + PRINT_INDEX(TreeNode1,4,28) + PRINT_INDEX(TreeNode2,4,29) + ti->minimalinorbits = FALSE; + } + else { + tv->currorbit = getorbits(fix, tv->nfix, gpB, &gensB, n); + schreierwrong = TRUE; + } + } + } + } + } + ti->thegrouphaschanged = FALSE; + } + else { + CuOrb = IDENTITY_PERM; + } + + if (ti->minimalinorbits) { + memcpy(NextCand->lab, CurrCand->lab, n*sizeof(int)); + memcpy(NextCand->invlab, CurrCand->invlab, n*sizeof(int)); + SpineTL->trcstart = CurrPart->cells; + TheTrace[SpineTL->trcstart] = SpineTL->tgtpos; + + tv->indivstart = tv->tcell+CurrCand->indnum; + tv->indivend = tv->indivstart+tv->steps; + if (tv->indivend > SpineTL->tgtend) { + tv->indivend = SpineTL->tgtend; + } + memset(CurrRefCells, 0, n*sizeof(int)); + ti->thegrouphaschanged = TRUE; + + if (!CurrCand->sortedlab) { + quickSort(CurrCand->lab+tv->tcell, CurrPart->cls[tv->tcell]); + for (i=tv->tcell; i<tv->tcell+CurrPart->cls[tv->tcell]; i++) { + CurrCand->invlab[CurrCand->lab[i]] = i; + } + CurrCand->sortedlab = TRUE; + } + + for (k = tv->indivstart; k < tv->indivend; k++) { + CurrCand->indnum++; + NextCand->singcode = CurrCand->singcode; + NextCand->vertex = CurrCand->lab[k]; + NextCand->name = ++tv->name; + if (NextCand->name == (NAUTY_INFINITY-2)) { + NextCand->name = tv->name = 1; + } + + if (ti->thegrouphaschanged) { + if (tv->fromlevel == tv->maxtreelevel) { + CURRORBITSIZES + } + ti->thegrouphaschanged = FALSE; + } + + if (!schreierwrong) { + if (CuOrb[CurrCand->lab[k]] != CurrCand->lab[k]) { + continue; + } + } + + memcpy(NextPart->cls, CurrPart->cls, n*sizeof(int)); + memcpy(NextPart->inv, CurrPart->inv, n*sizeof(int)); + if (NextPart->cls[tv->tcell] == 2) { + NextCand->singcode = MASHCOMM(NextCand->singcode, CurrCand->lab[tv->tcell]); + NextCand->singcode = MASHCOMM(NextCand->singcode, CurrCand->lab[tv->tcell+1]); + } + else { + NextCand->singcode = MASHCOMM(NextCand->singcode, CurrCand->lab[k]); + } + + Individualize(NextPart, NextCand, CurrCand->lab[k], tv->tcell, CurrPart->cells, SpineTL->tgtpos); + + tv->stats->numnodes++; + Spine[tv->tolevel+1].levelcounter++; + if (tv->fromlevel == tv->maxtreelevel) { + tv->tolevel_tl = tv->tolevel; + trieref = trieroot; + + tv->answ = traces_refine_comptrie(NextCand, + n, + NextPart, tv, ti); + + if (tv->answ) { + PRINTF2("CS2 4?: finalnumcells: %d\n", tv->finalnumcells); + if (NextPart->cells != tv->finalnumcells) { + CurrRefCells[NextPart->cells % n] += CurrOrbSize[CurrCand->lab[k]]; + if (CurrRefCells[NextPart->cells % n] > MultRefCells[NextPart->cells % n]) { + k = n; + break; + } + continue; + } + if (tv->options->verbosity >= 2) PRINT_CANDIDATE(NextCand, tv->tolevel); + } + } + else + { + tv->answ = traces_refine_sametrace(NextCand, + n, + NextPart, tv, ti); + + if (tv->answ) { + if (tv->options->verbosity >= 2) PRINT_CANDIDATE(NextCand, tv->tolevel) + if (tv->tolevel == tv->maxtreelevel) { + tv->tolevel_tl = tv->tolevel; + if (tv->options->verbosity >= 2) tv->expaths -= CPUTIME; + if (TargetCellExpPath(NextCand, NextPart, tv)) { + ExperimentalStep(NextPart, NextCand, tv, ti, m, n); + PRINT_EXPPATHSTEP(NextCand, tv->answ) + PRINTF2("CS2 5?: finalnumcells: %d\n", tv->finalnumcells); + if ((NextPart->cells == tv->finalnumcells) || (NextPart->cells == n)) { + UPDATEMIN(tv->expathlength, tv->tolevel_tl); + } + + } + if (tv->options->verbosity >= 2) tv->expaths += CPUTIME; + if (!tv->answ) { + PRINT_RETURN + } + } + } + } + if (tv->answ) { + PRINTF2("CS2 6?: finalnumcells: %d\n", tv->finalnumcells); + if ((NextPart->cells == tv->finalnumcells) || (NextPart->cells == n)) { + if (tv->options->verbosity >= 2) tv->autchk -= CPUTIME; + temp = (tv->tolevel_tl == tv->tolevel+1); + autom = CheckForAutomorphisms(CurrCand, NextCand, + tv, ti, temp, n, NextPart); + if (tv->options->verbosity >= 2) tv->autchk += CPUTIME; + if (autom) { + for (i=autom; i<=tv->maxtreelevel; i++) { + AuxCand = Spine[i].liststart; + while (AuxCand && Prefix(AuxCand, NextCand, autom)) { + AuxCand->do_it = FALSE; + AuxCand = AuxCand->next; + } + } + if (autom == tv->tolevel) { + autom = 0; + } + } + + if (ti->thegrouphaschanged) { + ORBITSIZES + } + } + PRINT_RETURN + + /* ADD TO NEXT LEVEL */ + PRINTF2("CS2 7?: finalnumcells: %d\n", tv->finalnumcells); + if ((NextPart->cells != tv->finalnumcells) || (tv->tolevel != tv->maxtreelevel) || (tv->tolevel_tl != tv->tolevel+1)) { + ADDTONEXTLEVEL; + searchtrie_make(CurrCand, SpineTL->listend, n, tv); + } + } + else { + tv->stats->interrupted++; + } + if (autom) { + k = n; + autom = 0; + break; + } + if (tv->fromlevel == tv->maxtreelevel) { + k = n; + break; + } + } /* end for */ + TreeNode = RefPath[tv->maxtreelevel]; + } + } + else SpineTL = &Spine[tv->tolevel+1]; + } + + } + + /* REMOVE CURRENT CANDIDATE */ + if (!CurrCand->do_it || k >= SpineTL->tgtend) { + SpineFL->liststart = CurrCand->next; + if (CurrCand->next == NULL) { + SpineFL->listend = NULL; + } + CurrCand->next = GarbList; + GarbList = CurrCand; + } + ti->thereisnextlevel = SelectNextLevel(n, tv, ti); + return 0; +} + +void CopyCand(Candidate *W, Candidate *V,int n, int *lab, int *invlab) { + + if (lab) { + memcpy(W->lab, lab, n*sizeof(int)); + memcpy(W->invlab, invlab, n*sizeof(int)); + } + else { + memcpy(W->lab, V->lab, n*sizeof(int)); + memcpy(W->invlab, V->invlab, n*sizeof(int)); + } + W->name = V->name; + W->vertex = V->vertex; + W->code = V->code; + W->singcode = V->singcode; + W->firstsingcode = V->firstsingcode; + W->do_it = V->do_it; + W->sortedlab = FALSE; +} + +sparsegraph* copy_sg_structure(sparsegraph *sg2, sparsegraph *sg1) { + int *d1, *e1, *d2, *e2; + int i, n; + size_t *v1, *v2, k; + + if (!sg2) + { + if ((sg2 = (sparsegraph*)ALLOCS(1, sizeof(sparsegraph))) == NULL) + { + fprintf(ERRFILE, "copy_sg: malloc failed\n"); + exit(1); + } + SG_INIT(*sg2); + } + + SG_VDE(sg1, v1, d1, e1); + + n = sg1->nv; + + k = 0; + for (i = 0; i < n; ++i) + if (v1[i]+d1[i]>k) k = v1[i] + d1[i]; + SG_ALLOC(*sg2, n, k, "copy_sg malloc"); + + sg2->nv = n; + sg2->nde = sg1->nde; + sg2->elen = k; + /* sg2->wlen = k; */ + return sg2; +} + +void Edge_Delete(int vertex, int sons, Candidate *Cand, TracesVars *tv) { + int d_vtx, j1, temp; + int *sge, *sgw; + + if (TheGraph[vertex].d <= 1) { + return; + } + + d_vtx = TheGraph[vertex].d = TheGraph[vertex].d - sons; + sge = TheGraph[vertex].e; + sgw = TheGraph[vertex].w; + + for (j1=0; j1<d_vtx; j1++) { + if (TheGraph[sge[j1]].one) { + while (TheGraph[sge[TheGraph[vertex].d]].d == -1) { + (TheGraph[vertex].d)++; + } + temp = sge[j1]; + sge[j1] = sge[TheGraph[vertex].d]; + sge[TheGraph[vertex].d] = temp; + if (sgw) { + temp = sgw[j1]; + sgw[j1] = sgw[TheGraph[vertex].d]; + sgw[TheGraph[vertex].d] = temp; + } + } + } + TheGraph[vertex].d = d_vtx; +} + +void ExperimentalStep(Partition *NextPart, Candidate *NextCand, + TracesVars *tv, TracesInfo *ti, int m, int n) { + int i, iend, min, tmp; + + SpineTL_tl = Spine+tv->tolevel_tl; + NextPart->active = 1; + VERB_PRINT("EXSTP ",3,FALSE) + if (SpineTL_tl) { + } + + /* EXPERIMENTAL PATH INDIVIDUALIZATION AND REFINEMENT */ + if (tv->answ == 2) { + min = NextCand->lab[tv->tcellexpath]; + tmp = tv->tcellexpath; + iend = tv->tcellexpath + NextPart->cls[tv->tcellexpath]; + for (i=tv->tcellexpath + 1; i<iend ; i++) { + if (NextCand->lab[i] < min) { + min = NextCand->lab[i]; + tmp = i; + } + } + } + else { + tmp = tv->tcellexpath+KRAN(NextPart->cls[tv->tcellexpath]); + } + if (NextPart->cls[tv->tcellexpath] == 2) { + NextCand->pathsingcode = MASHCOMM(NextCand->pathsingcode, NextCand->lab[tv->tcellexpath]); + NextCand->pathsingcode = MASHCOMM(NextCand->pathsingcode, NextCand->lab[tv->tcellexpath+1]); + } + else { + NextCand->pathsingcode = MASHCOMM(NextCand->pathsingcode, NextCand->lab[tmp]); + } + + tv->indiv_vtx = NextCand->lab[tmp]; + Individualize(NextPart, NextCand, NextCand->lab[tmp], tv->tcellexpath, NextPart->cells, tv->tcellexpath + NextPart->cls[tv->tcellexpath]-1); + + tv->stats->numnodes++; + if (tv->compstage == 0) { + traces_refine_notrace(NextCand, + n, + NextPart, tv, ti); + } + else { + if (tv->tolevel_tl == tv->maxtreelevel+1) { + trieref = trieroot; + tv->answ = traces_refine_comptrie(NextCand, + n, + NextPart, tv, ti); + if (tv->answ == 0 ) { + tv->stats->interrupted++; + } + } + else { + traces_refine_notrace(NextCand, + n, + NextPart, tv, ti); + } + } + + CodeClassify(tv->tolevel_tl, NextCand->code, tv->tcellexpath); + +} + +void factorial(double *size1, int *size2, int k) { + int i; + + for(i = k; i; i--) { + MULTIPLY(*size1, *size2, i); + } +} + +void factorial2(double *size1, int *size2, int k) { + int i; + + for(i = k; i > 0; i -= 2) { + MULTIPLY(*size1, *size2, i); + } +} + +boolean findperm(permnode *pn, int *p, int n) { + permnode *rn; + + if (!pn) { + return FALSE; + } + rn = pn; + do { + if (!memcmp(rn->p, p, n*sizeof(int))) { + return TRUE; + } + rn = rn->next; + } while (rn != pn); + return FALSE; +} + +int *findcurrorbits(schreier *gp, int k) { + int i; + schreier *sh; + + sh = gp; + for (i = 0; i < k; i++) { + sh = sh->next; + } + return sh->orbits; +} + +int FirstNeighbour(int vtx, Candidate *Cand, Partition *Part, int* Markers, int mark, int *ngh, int n) { + int *e_vtx; + int i, k, deg; + int ngh1, ngh2, cell1, cell2; + + k = 0; + + deg = TheGraph[vtx].d; + e_vtx = TheGraph[vtx].e; + + if (deg == n-1) { + return 0; + } + + for (i=0; i<deg; i++) { + if (Markers[e_vtx[i]] != mark) { + cell1 = Part->inv[Cand->invlab[e_vtx[i]]]; + if (Part->cls[cell1] > 1) { + ngh1 = e_vtx[i++]; + k++; + break; + } + } + } + for (; i<deg; i++) { + if (Markers[e_vtx[i]] != mark) { + cell2 = Part->inv[Cand->invlab[e_vtx[i]]]; + if (Part->cls[cell2] > 1) { + ngh2 = e_vtx[i]; + k++; + break; + } + } + } + switch (k) { + case 0: + break; + + case 1: + *ngh = ngh1; + break; + + case 2: + if (cell1 < cell2) { + *ngh = ngh1; + } + else { + *ngh = ngh2; + } + break; + + default: + break; + } + return k; +} + +int FixBase(int *fix, struct TracesVars *tv, Candidate *Cand, int from, int to) { + int i, j, k, go, nfix; + + nfix = j = 0; + go = TRUE; + for (i = from; i < to; i++) { + k = Cand->lab[Spine[i+1].tgtpos]; + if (go && (nfix < tv->nfix) && (fix[nfix] == k)) { + j++; + } + else { + fix[nfix] = k; + if (go) go = FALSE; + } + nfix++; + } + tv->nfix = nfix; + return j; +} + +boolean FixedBase(int *fix, struct TracesVars *tv, Candidate *Cand, int from, int to) { + int i, k, nfix; + + nfix = 0; + for (i = from; i < to; i++) { + k = Cand->lab[Spine[i+1].tgtpos]; + if (fix[nfix] != k) { + return FALSE; + } + nfix++; + } + return TRUE; +} + +int FreeList(Candidate *List, int cond) { + Candidate *Temp; + int conta = 0; + int conta1 = 0; + + while (List) { + if (List->do_it == cond) { + conta1++; + } + conta++; + Temp = List; + if (List->lab) free(List->lab); + if (List->invlab) free(List->invlab); + List = List->next; + free(Temp); + } + + if (cond) { + return conta1; + } + else { + return conta; + } +} + +/* Check if the permutations in the list gens are automorphisms, + * also set mark and refcount fields and initialise orbits. */ +int given_gens(sparsegraph *g, permnode *gens, int *orbits, boolean digraph) { + int i, m, n, norbs; + permnode *pn; + + n = g->nv; + for (i = 0; i < n; ++i) orbits[i] = i; + memcpy(IDENTITY_PERM, orbits, n*sizeof(int)); + norbs = n; + + if (!gens) return norbs; + + m = SETWORDSNEEDED(n); + pn = gens; + do { + if (!isautom_sg((graph*)g, pn->p, digraph, m, n)) { + fprintf(ERRFILE, "Input permutation is not an automorphism\n"); + exit(1); + } + norbs = orbjoin(orbits, pn->p, n); + pn->mark = 1; + pn->refcount = 0; + pn = pn->next; + } while (pn != gens); + + return norbs; +} + +void grouporderplus(sparsegraph *sg_orig, Candidate *Cand, Partition *Part, permnode **ring, + double *grpsize1, int *grpsize2, int n, TracesVars *tv, TracesInfo *ti) { + + int i, i1, j, j0, j2, k, k1, k2, w, w1, w2, c, c1, c2, n1, n2; + int prev, step, start, counts, StInd, CyInd, cycnum; + int tmp, temp, halfsize, nghcell, numvertices; + int arg, val; + + searchtrie *TrieNode; + int NSFCInd, ind; + boolean do_ngh = FALSE; + + numvertices = n; + memcpy(CanonIndices, IDENTITY_PERM, n*sizeof(int)); + memset(TreeNodes, 0, n*sizeof(int)); + + TrieNode = Spine[tv->maxtreelevel].liststart->stnode; + if (TrieNode->father) { + if (tv->options->verbosity >= 2) { + LINE(32, "-") + NEXTLINE + fprintf(outfile, "group structure: "); + while (TrieNode->father) { + if (Factorials[TrieNode->level]) { + fprintf(outfile, "%d (%d!), ", TrieNode->name, TrieNode->index); + factorial(grpsize1, grpsize2, TrieNode->index); + } else { + if (TrieNode->father->name) { + fprintf(outfile, "%d (%d), ", TrieNode->name, TrieNode->index); + MULTIPLY(tv->stats->grpsize1, tv->stats->grpsize2, TrieNode->index); + } + else { + temp = spinelementorbsize(tv->orbits, Spine[tv->maxtreelevel].liststart->lab+Spine[1].tgtcell, Spine[1].tgtsize, TrieNode->vtx); + MULTIPLY(*grpsize1, *grpsize2, temp); + fprintf(outfile, "%d (%d)\n", + TrieNode->name, temp); + } + } + TrieNode = TrieNode->father; + } + } + else { + while (TrieNode->father) { + if (Factorials[TrieNode->level]) { + factorial(grpsize1, grpsize2, TrieNode->index); + } else { + if (TrieNode->father->name) { + MULTIPLY(tv->stats->grpsize1, tv->stats->grpsize2, TrieNode->index); + } + else { + temp = spinelementorbsize(tv->orbits, Spine[tv->maxtreelevel].liststart->lab+Spine[1].tgtcell, Spine[1].tgtsize, TrieNode->vtx); + MULTIPLY(*grpsize1, *grpsize2, temp); + } + } + TrieNode = TrieNode->father; + } + } + } + + if (Part->cells < n) { + if (!ti->deg_one) { + if (sg_orig->e) { + memcpy(tv->graph->e, sg_orig->e, tv->graph->elen*sizeof(int)); + for (i=0; i<n; i++) { + TheGraph[i].e = tv->graph->e + sg_orig->v[i]; + } + } + } + NSFCInd = 0; + + /* Trees */ + if (tv->options->getcanon && tv->preprocessed) { + for (i = 0; i < n; i += Part->cls[i]) { + if (Part->cls[i] == 1) { + tmp = Cand->lab[i]; + if ((TheGraph[tmp].d >= 0) && (TheGraph[tmp].d < sg_orig->d[tmp])) { + for (j=i; j<i+Part->cls[i]; j++) { + MakeCanTree(Cand->lab[j], sg_orig, n, Cand, Part, tv); + } + } + } + } + } + + memset(SingNonSing, 0, n*sizeof(int)); + + for (i = 0; i < n; i += Part->cls[i]) { + if (Part->cls[i] > 1) { + if (TheGraph[Cand->lab[i]].d > 2) { + for (j=i; j<i+Part->cls[i]; j++) { + SingNonSing[Cand->lab[j]] = 2; + } + } + } + else { + SingNonSing[Cand->lab[i]] = 1; + } + } + + for (i = 0; i < n; i += Part->cls[i]) { + if (Part->cls[i] > 1) { + if (TheGraph[Cand->lab[i]].d > 2) NonSingDegPlus1(Cand, Part, i, tv); + NSFCells[NSFCInd++] = i; + } + else { + NonSingDegPlus2(Cand, Part, i, tv); + numvertices--; + } + } + + /* Degree 2 and at least one nghb with deg > 2 */ + SETMARK(StackMarkers, tv->stackmark) + for (ind = 0; ind < NSFCInd; ind++) { + i = NSFCells[ind]; + SETMARK(Markers, tv->mark) + if (Part->cls[i] > 1) { + tmp = Cand->lab[i]; + if ((TheGraph[tmp].d == 2) && ((TheGraph[TheGraph[tmp].e[0]].d > 2) || ((TheGraph[TheGraph[tmp].e[1]].d > 2)))) { + n1 = TheGraph[tmp].e[0]; + n2 = TheGraph[tmp].e[1]; + if (TheGraph[n1].d > 2) { + if (TheGraph[n2].d > 2) { + if (Cand->invlab[n1] < Cand->invlab[n2]) { + start = n1; + } + else { + start = n2; + } + } + else { + start = n1; + } + } + else { + start = n2; + } + counts = 0; + StInd = 0; + for (j=i; j<i+Part->cls[i]; j++) { + step = Cand->lab[j]; + if (Markers[step] != tv->mark) { + prev = start; + counts++; + do { + Markers[step] = tv->mark; + PERMSTACK[StInd++] = step; + if (TheGraph[step].e[0] != prev) { + prev = step; + step = TheGraph[step].e[0]; + } + else { + prev = step; + step = TheGraph[step].e[1]; + } + } while (TheGraph[step].d == 2); + + if (TheGraph[step].d == 1) { + PERMSTACK[StInd++] = step; + } + } + } + + if (counts == Part->cls[i]) { + factorial(grpsize1, grpsize2, Part->cls[i]); + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (k=0; k<StInd/counts; k++) { + i1 = PERMSTACK[k]; + for (j0=0; j0<counts-1; j0++) { + SETPAIRSAUTANDTREE(PERMSTACK[j0*(StInd/counts)+k], PERMSTACK[(j0+1)*(StInd/counts)+k]) + } + SETPAIRSAUTANDTREE(PERMSTACK[j0*(StInd/counts)+k], i1) + } + SPECIALGENERATORS + if (counts > 2) { + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (k=0; k<StInd/counts; k++) { + i1 = PERMSTACK[k]; + for (j0=0; j0<1; j0++) { + SETPAIRSAUTANDTREE(PERMSTACK[j0*(StInd/counts)+k], PERMSTACK[(j0+1)*(StInd/counts)+k]) + } + SETPAIRSAUTANDTREE(PERMSTACK[j0*(StInd/counts)+k], i1) + } + SPECIALGENERATORS + } + } + else { + factorial2(grpsize1, grpsize2, Part->cls[i]); + for (j=0; j<counts; j++) { + j0 = j*(StInd/counts); + k1 = (j+1)*(StInd/counts); + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (k=j0, i1=k1-1; k<k1; k++, i1--) { + SETPAIRSAUTANDTREE(PERMSTACK[k], PERMSTACK[i1]) + } + SPECIALGENERATORS + } + if (counts > 1) { + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (k=0; k<StInd/counts; k++) { + i1 = PERMSTACK[k]; + for (j0=0; j0<counts-1; j0++) { + SETPAIRSAUTANDTREE(PERMSTACK[j0*(StInd/counts)+k], PERMSTACK[(j0+1)*(StInd/counts)+k]) + } + SETPAIRSAUTANDTREE(PERMSTACK[j0*(StInd/counts)+k], i1) + } + SPECIALGENERATORS + } + if (counts > 2) { + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (k=0; k<StInd/counts; k++) { + i1 = PERMSTACK[k]; + for (j0=0; j0<1; j0++) { + SETPAIRSAUTANDTREE(PERMSTACK[j0*(StInd/counts)+k], PERMSTACK[(j0+1)*(StInd/counts)+k]) + } + SETPAIRSAUTANDTREE(PERMSTACK[j0*(StInd/counts)+k], i1) + } + SPECIALGENERATORS + } + } + for (j=0; j<StInd; j++) { + Place(PERMSTACK[j], Cand, Part); + if ((TheGraph[PERMSTACK[j]].d >= 0) && (TheGraph[PERMSTACK[j]].d < sg_orig->d[PERMSTACK[j]])) { + MakeCanTree(PERMSTACK[j], sg_orig, n, Cand, Part, tv); + } + } + } + } + } + + /* Degree 2 and at least one nghb with == 1 */ + for (ind = 0; ind < NSFCInd; ind++) { + SETMARK(Markers, tv->mark) + i = NSFCells[ind]; + if (Part->cls[i] > 1) { + tmp = Cand->lab[i]; + if ((TheGraph[tmp].d == 2) && ((TheGraph[TheGraph[tmp].e[0]].d == 1) || ((TheGraph[TheGraph[tmp].e[1]].d == 1)))) { + counts = 0; + StInd = 0; + for (j=i; j<i+Part->cls[i]; j++) { + step = Cand->lab[j]; + if (Markers[step] != tv->mark) { + n1 = TheGraph[step].e[0]; + n2 = TheGraph[step].e[1]; + if (TheGraph[n1].d == 1) { + if (TheGraph[n2].d == 1) { + if (Cand->invlab[n1] < Cand->invlab[n2]) { + start = n1; + } + else { + start = n2; + } + } + else { + start = n1; + } + } + else { + start = n2; + } + PERMSTACK[StInd++] = start; + prev = start; + counts++; + + do { + Markers[step] = tv->mark; + PERMSTACK[StInd++] = step; + if (TheGraph[step].e[0] != prev) { + prev = step; + step = TheGraph[step].e[0]; + } else { + prev = step; + step = TheGraph[step].e[1]; + } + } while (TheGraph[step].d == 2); + PERMSTACK[StInd++] = step; + } + } + + if (counts == Part->cls[i]) { + if (Part->inv[Cand->invlab[PERMSTACK[0]]] != Part->inv[Cand->invlab[PERMSTACK[StInd/counts-1]]]) { + factorial(grpsize1, grpsize2, Part->cls[i]); + } + else { + factorial2(grpsize1, grpsize2, 2*Part->cls[i]); + for (j=0; j<counts; j++) { + j0 = j*(StInd/counts); + k1 = (j+1)*(StInd/counts); + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (k=j0, i1=k1-1; k<k1; k++, i1--) { + SETPAIRSAUTANDTREE(PERMSTACK[k], PERMSTACK[i1]) + } + SPECIALGENERATORS + } + } + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (k=0; k<StInd/counts; k++) { + i1 = PERMSTACK[k]; + for (j0=0; j0<counts-1; j0++) { + SETPAIRSAUTANDTREE(PERMSTACK[j0*(StInd/counts)+k], PERMSTACK[(j0+1)*(StInd/counts)+k]) + } + SETPAIRSAUTANDTREE(PERMSTACK[j0*(StInd/counts)+k], i1) + } + SPECIALGENERATORS + if (counts > 2) { + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (k=0; k<StInd/counts; k++) { + i1 = PERMSTACK[k]; + for (j0=0; j0<1; j0++) { + SETPAIRSAUTANDTREE(PERMSTACK[j0*(StInd/counts)+k], PERMSTACK[(j0+1)*(StInd/counts)+k]) + } + SETPAIRSAUTANDTREE(PERMSTACK[j0*(StInd/counts)+k], i1) + } + SPECIALGENERATORS + } + } + else { + factorial2(grpsize1, grpsize2, Part->cls[i]); + for (j=0; j<counts; j++) { + j0 = j*(StInd/counts); + k1 = (j+1)*(StInd/counts); + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (k=j0, i1=k1-1; k<k1; k++, i1--) { + SETPAIRSAUTANDTREE(PERMSTACK[k], PERMSTACK[i1]) + } + SPECIALGENERATORS + } + if (counts > 1) { + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (k=0; k<StInd/counts; k++) { + i1 = PERMSTACK[k]; + for (j0=0; j0<counts-1; j0++) { + SETPAIRSAUTANDTREE(PERMSTACK[j0*(StInd/counts)+k], PERMSTACK[(j0+1)*(StInd/counts)+k]) + } + SETPAIRSAUTANDTREE(PERMSTACK[j0*(StInd/counts)+k], i1) + } + SPECIALGENERATORS + } + if (counts > 2) { + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (k=0; k<StInd/counts; k++) { + i1 = PERMSTACK[k]; + for (j0=0; j0<1; j0++) { + SETPAIRSAUTANDTREE(PERMSTACK[j0*(StInd/counts)+k], PERMSTACK[(j0+1)*(StInd/counts)+k]) + } + SETPAIRSAUTANDTREE(PERMSTACK[j0*(StInd/counts)+k], i1) + } + SPECIALGENERATORS + } + } + for (j=0; j<StInd; j++) { + Place(PERMSTACK[j], Cand, Part); + if ((TheGraph[PERMSTACK[j]].d >= 0) && (TheGraph[PERMSTACK[j]].d < sg_orig->d[PERMSTACK[j]])) { + MakeCanTree(PERMSTACK[j], sg_orig, n, Cand, Part, tv); + } + } + } + } + } + + /* Cycles */ + for (ind = 0; ind < NSFCInd; ind++) { + i = NSFCells[ind]; + SETMARK(Markers, tv->mark) + if (Part->cls[i] > 1) { + tmp = Cand->lab[i]; + if (TheGraph[tmp].d == 2) { + CyInd = StInd = cycnum = 0; + for (j=i; j<i+Part->cls[i]; j++) { + start = Cand->lab[j]; + if (Markers[start] != tv->mark) { + counts = 1; + CYCLES[StInd] = start; + CYCOLR[StInd++] = Part->inv[Cand->invlab[start]]; + Markers[start] = tv->mark; + k = Cand->invlab[TheGraph[start].e[0]]; + k1 = Cand->invlab[TheGraph[start].e[1]]; + if (Part->inv[k] < Part->inv[k1]) { + step = TheGraph[start].e[0]; + } + else { + step = TheGraph[start].e[1]; + } + prev = start; + do { + counts++; + Markers[step] = tv->mark; + CYCLES[StInd] = step; + CYCOLR[StInd++] = Part->inv[Cand->invlab[step]]; + + if (TheGraph[step].e[0] != prev) { + prev = step; + step = TheGraph[step].e[0]; + } + else { + prev = step; + step = TheGraph[step].e[1]; + } + } while (step != start); + CYLGTH[CyInd++] = counts; + cycnum++; + } + } + + CYCPOS[0] = 0; + for (j=1; j<CyInd; j++) { + CYCPOS[j] = CYCPOS[j-1]+CYLGTH[j-1]; + } + memcpy(WorkArray, CYLGTH, CyInd*sizeof(int)); + sort2ints(WorkArray, CYCPOS, CyInd); + + k = 0; + for (i1=0; i1<CyInd; i1++) { + k1 = CYCOLR[k]; + k2 = CYCOLR[k+1]; + for (j=1; j<=CYLGTH[i1]/2; j++) { + w1 = CYCOLR[j+k]; + w2 = CYCOLR[j+1+k]; + if ((w1 == k1) && (w2 == k2)) { + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (w=0; w<CYLGTH[i1]; w++) { + if (CYCOLR[w+k] == CYCOLR[((w+j) % CYLGTH[i1]) + k]) { + SETPAIRSAUTANDTREE(CYCLES[w+k], CYCLES[((w+j) % CYLGTH[i1]) + k]) + } + else { + break; + } + } + if (w == CYLGTH[i1]) { SPECIALGENERATORS } + if (w == CYLGTH[i1]) { + MULTIPLY(*grpsize1, *grpsize2, CYLGTH[i1]/j); + break; + } + } + } + + if (Part->cls[k1] >= Part->cls[k2]) { + for (j=CYLGTH[i1]-1; j>0; j--) { + w1 = CYCOLR[j % CYLGTH[i1] + k]; + w2 = CYCOLR[(j-1) % CYLGTH[i1] + k]; + if ((w1 == k1) && (w2 == k2)) { + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (w=0; w<CYLGTH[i1]; w++) { + SETPAIRSAUTANDTREE(CYCLES[w+k], CYCLES[((j-w+(w>j)*CYLGTH[i1]) % CYLGTH[i1]) + k]) + } + SPECIALGENERATORS + MULTIPLY(*grpsize1, *grpsize2, 2); + break; + } + } + } + else { + j=CYLGTH[i1]-1; + w2 = CYCOLR[j % CYLGTH[i1] + k]; + if (w2 == k2) { + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (w=1; w<CYLGTH[i1]; w++) { + SETPAIRSAUTANDTREE(CYCLES[w+k], CYCLES[CYLGTH[i1]-w+k]) + } + SPECIALGENERATORS + MULTIPLY(*grpsize1, *grpsize2, 2); + } + } + k += CYLGTH[i1]; + } + k = 0; + for (i1=0; i1<CyInd; i1++) { + if (CYLGTH[i1] > 0) { + CYMULT[0] = k; + k1 = k; + counts = 1; + for (j0=i1+1; j0<CyInd; j0++) { + k1 += abs(CYLGTH[j0]); + if (CYLGTH[j0] == CYLGTH[i1]) { + CYMULT[counts++] = k1; + CYLGTH[j0] = -CYLGTH[j0]; + } + } + if (counts > 1) { + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (j0=0; j0<CYLGTH[i1]; j0++) { + for (j2 = 0; j2<counts-1; j2++) { + SETPAIRSAUTANDTREE(CYCLES[CYMULT[j2]+j0], CYCLES[CYMULT[j2+1]+j0]) + } + SETPAIRSAUTANDTREE(CYCLES[CYMULT[j2]+j0], CYCLES[CYMULT[0]+j0]) + } + SPECIALGENERATORS + if (counts > 2) { + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (j0=0; j0<CYLGTH[i1]; j0++) { + SETPAIRSAUTANDTREE(CYCLES[CYMULT[1]+j0], CYCLES[CYMULT[0]+j0]) + if (tv->build_autom) { + SETPAIRSAUT(CYCLES[CYMULT[0]+j0], CYCLES[CYMULT[1]+j0]) + } + MakeTree(CYCLES[CYMULT[0]+j0], CYCLES[CYMULT[1]+j0], sg_orig, n, tv, FALSE); + } + SPECIALGENERATORS + } + factorial(grpsize1, grpsize2, counts); + } + } + k += abs(CYLGTH[i1]); + CYLGTH[i1] = -CYLGTH[i1]; + } + + for (c1=0; c1<CyInd; c1++) { + c = CYCPOS[c1]+WorkArray[c1]; + for (c2=CYCPOS[c1]; c2<c; c2++) { + Place(CYCLES[c2], Cand, Part); + if ((TheGraph[CYCLES[c2]].d >= 0) && (TheGraph[CYCLES[c2]].d < sg_orig->d[CYCLES[c2]])) { + MakeCanTree(CYCLES[c2], sg_orig, n, Cand, Part, tv); + } + } + } + } + } + } + + /* Degree 1, and nghb too */ + SETMARK(Markers, tv->mark) + for (ind = 0; ind < NSFCInd; ind++) { + i = NSFCells[ind]; + if (Part->cls[i] > 1) { + tmp = Cand->lab[i]; + if ((TheGraph[tmp].d == 1) && (TheGraph[TheGraph[tmp].e[0]].d == 1) && (i == Part->inv[Cand->invlab[TheGraph[tmp].e[0]]])) { + factorial2(grpsize1, grpsize2, Part->cls[i]); + /* the cell has size two */ + if (Part->cls[i] == 2) { + val = Cand->lab[i+1]; + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + arg = tmp; + SETPAIRSAUTANDTREE(arg, val) + SETPAIRSAUTANDTREE(val, arg) + SPECIALGENERATORS + } + else { + /* the cell has size greater than two */ + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + SETMARK(Markers, tv->mark) + halfsize = Part->cls[i]/2; + i1 = 0; + for (j=i; j<i+Part->cls[i]; j++) { + if (Markers[Cand->lab[j]] != tv->mark) { + Markers[TheGraph[Cand->lab[j]].e[0]] = tv->mark; + PERMSTACK[i1] = Cand->lab[j]; + PERMSTACK[i1+halfsize] = TheGraph[Cand->lab[j]].e[0]; + i1++; + } + } + temp = PERMSTACK[0]; + for (j=0; j<Part->cls[i]-1; j++) { + SETPAIRSAUTANDTREE(PERMSTACK[j], PERMSTACK[j+1]) + } + SETPAIRSAUTANDTREE(PERMSTACK[j], temp) + SPECIALGENERATORS + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + memmove(PERMSTACK+halfsize, PERMSTACK+halfsize+1, (halfsize-1)*sizeof(int)); + temp = PERMSTACK[1]; + for (j=1; j<Part->cls[i]-2; j++) { + SETPAIRSAUTANDTREE(PERMSTACK[j], PERMSTACK[j+1]) + } + SETPAIRSAUTANDTREE(PERMSTACK[j], temp) + SPECIALGENERATORS + } + + SETMARK(Markers, tv->mark) + for (j=i; j<i+Part->cls[i]; j++) { + temp = Cand->lab[j]; + if (Markers[temp] != tv->mark) { + if ((TheGraph[temp].d >= 0) && (TheGraph[temp].d < sg_orig->d[temp])) { + MakeCanTree(temp, sg_orig, n, Cand, Part, tv); + } + tmp = Cand->lab[j+1]; + Markers[TheGraph[temp].e[0]] = tv->mark; + i1 = Cand->invlab[TheGraph[temp].e[0]]; + Cand->lab[j+1] = TheGraph[temp].e[0]; + + if ((TheGraph[TheGraph[temp].e[0]].d >= 0) && (TheGraph[TheGraph[temp].e[0]].d < sg_orig->d[TheGraph[temp].e[0]])) { + MakeCanTree(TheGraph[temp].e[0], sg_orig, n, Cand, Part, tv); + } + Cand->invlab[TheGraph[temp].e[0]] = j+1; + Cand->lab[i1] = tmp; + Cand->invlab[tmp] = i1; + } + } + } + } + } + + /* Degree 0 */ + for (ind = 0; ind < NSFCInd; ind++) { + i = NSFCells[ind]; + if (Part->cls[i] > 1) { + tmp = Cand->lab[i]; + if ((TheGraph[0].e != NULL) && (TheGraph[tmp].d != 0) && (TheGraph[tmp].d != numvertices-1)) + nghcell = Part->inv[Cand->invlab[TheGraph[tmp].e[0]]]; else nghcell = i; + if ((TheGraph[tmp].d == 0) || + ((TheGraph[tmp].d == numvertices-1) && (TheGraph[tmp].d > 2)) || + ((TheGraph[tmp].d == 1) && (TheGraph[TheGraph[tmp].e[0]].d == 1) && (i < nghcell))) { + do_ngh = FALSE; + if ((TheGraph[tmp].d == 1) && (TheGraph[TheGraph[tmp].e[0]].d == 1) && (i != nghcell)) { + do_ngh = TRUE; + } + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (j=i; j<i+Part->cls[i]-1; j++) { + arg = Cand->lab[j]; + val = Cand->lab[j+1]; + SETPAIRSAUTANDTREE(arg, val) + if (do_ngh) { + SETPAIRSAUTANDTREE(TheGraph[arg].e[0], TheGraph[val].e[0]) + + } + } + arg = Cand->lab[j]; + val = tmp; + SETPAIRSAUTANDTREE(arg, val) + if (do_ngh) { + SETPAIRSAUTANDTREE(TheGraph[arg].e[0], TheGraph[val].e[0]) + } + SPECIALGENERATORS + if (Part->cls[i] > 2) { + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + arg = tmp; + val = Cand->lab[i+1]; + SETPAIRSAUTANDTREE(arg, val) + if (do_ngh) { + SETPAIRSAUTANDTREE(TheGraph[arg].e[0], TheGraph[val].e[0]) + } + arg = Cand->lab[i+1]; + val = tmp; + SETPAIRSAUTANDTREE(arg, val) + if (do_ngh) { + SETPAIRSAUTANDTREE(TheGraph[arg].e[0], TheGraph[val].e[0]) + } + SPECIALGENERATORS + } + factorial(grpsize1, grpsize2, Part->cls[i]); + if (do_ngh) { + for (j=i; j<i+Part->cls[i]; j++) { + temp = TheGraph[Cand->lab[j]].e[0]; + Cand->lab[nghcell] = temp; + Cand->invlab[temp] = nghcell; + nghcell++; + } + } + + k = i+Part->cls[i]; + for (j=i; j<k; j++) { + Place(Cand->lab[j], Cand, Part); + if ((TheGraph[Cand->lab[j]].d >= 0) && (TheGraph[Cand->lab[j]].d < sg_orig->d[Cand->lab[j]])) { + MakeCanTree(Cand->lab[j], sg_orig, n, Cand, Part, tv); + if (do_ngh) { + MakeCanTree(TheGraph[Cand->lab[j]].e[0], sg_orig, n, Cand, Part, tv); + } + } + } + } + } + } + + } + + /* Orbit Count */ + SETMARK(Markers, tv->mark) + i1=0; + for (c1=0; c1<n; c1++) { + if (Markers[tv->orbits[c1]] != tv->mark) { + i1++; + Markers[tv->orbits[c1]] = tv->mark; + } + } + tv->stats->numorbits = i1; + return; +} + +void Individualize(Partition *NextPart, Candidate *NextCand, int K, int Tc, int Cl, int Pos) { + int i, j; + + NextCand->do_it = TRUE; + if (NextPart->cls[Tc] > 1) { + NextPart->cells = Cl+1; + NextPart->active = 1; + NextPart->cls[Tc]--; + NextPart->cls[Pos] = 1; + } + NextPart->inv[Pos] = Pos; + + j = NextCand->lab[Pos]; + i = NextCand->invlab[K]; + NextCand->lab[Pos] = K; + NextCand->invlab[K] = Pos; + NextCand->lab[i] = j; + NextCand->invlab[j] = i; + return; +} + +void Initialize_Traces_Variables(TracesVars *tv, TracesOptions *options_arg, + TracesStats *stats_arg, int *orbits_arg, + sparsegraph *g_arg, sparsegraph *canong_arg, + int n) { + tv->augmented_cells = n; + tv->canlist = 0; + tv->compstage = 0; + tv->expathlength = n; + tv->finalnumcells = n; + tv->firstpathlength = 0; + tv->group_level = 0; + tv->lev_of_lastauto = 0; + tv->linelgth = 0; + tv->name = 0; + tv->maxspineorblevel = 0; + tv->nfix = 0; + tv->options = options_arg; + tv->orbits = orbits_arg; + tv->permInd = 0; + tv->maxdeg = 0; + tv->mindeg = n; + + if (tv->options->generators || tv->options->writeautoms || tv->options->userautomproc) + tv->build_autom = TRUE; + else + tv->build_autom = FALSE; + + tv->specialgens = 0; + tv->stats = stats_arg; + tv->treedepth = 0; + tv->gotonode = NULL; + tv->input_graph = tv->graph = g_arg; + tv->cangraph = canong_arg; + tv->mark = tv->stackmark = tv->treemark = tv->autmark = tv->markcell1 = tv->markcell2 = NAUTY_INFINITY-1; + tv->conta0 = tv->conta1 = tv->conta2 = tv->conta3 = tv->conta4 = tv->conta5 = tv->conta6 = tv->conta7 = tv->contatc = 0; + + if (tv->options->strategy == 0) { + tv->steps = n; + tv->strategy = 0; + } + else { + tv->strategy = 1; + tv->steps = tv->options->strategy; + if (tv->steps > n) { + tv->steps = n; + } + } +} + +void Initialize_Traces_Statistics (TracesStats *stats_arg, int n) { + stats_arg->grpsize1 = 1; + stats_arg->grpsize2 = 0; + stats_arg->numorbits = n; + stats_arg->treedepth= 0; + stats_arg->numgenerators = 0; + stats_arg->numnodes = 1; + stats_arg->errstatus = 0; + stats_arg->interrupted = 0; + stats_arg->canupdates = 0; + stats_arg->peaknodes = 0; +} + +void Initialize_Traces_Time_Variables (TracesVars *tv) { + tv->autchk = 0; + tv->expaths = 0; + tv->schreier1 = 0; + tv->schreier2 = 0; + tv->schreier3 = 0; +} + +boolean isautom_sg_pair(graph *g, int *p, boolean digraph, int m, int n, struct TracesVars *tv) { + int *d, *e; + size_t *v; + int i, k, pi, di; + size_t vi, vpi, j; + + SG_VDE(g, v, d, e); + + for (k = 0; k < tv->permInd; ++k) + { + i = PrmPairs[k].arg; + pi = p[i]; + di = d[i]; + if (d[pi] != di) return FALSE; + + vi = v[i]; + vpi = v[pi]; + SETMARK(AutMarkers, tv->autmark) + for (j = 0; j < di; ++j) AutMarkers[p[e[vi+j]]] = tv->autmark; + for (j = 0; j < di; ++j) if (AutMarkers[e[vpi+j]] != tv->autmark) { + return FALSE; + } + } + + return TRUE; +} + +boolean lookup(searchtrie *t) { + searchtrie *TreeNode; + + TreeNode = t; + while (TreeNode->level >= 1) { + if (TreeNode->goes_to) { + return FALSE; + } + TreeNode = TreeNode->father; + } + return TRUE; +} + +void MakeCanTree(int v1, sparsegraph *sg_orig, int n, Candidate *Cand, Partition *Part, struct TracesVars* tv) { + int ind, vtx, ngh, trind, deg0, deg1; + size_t j1; + int *sge1; + + trind = 1; + ind = 0; + TreeStack[0] = v1; + SETMARK(TreeMarkers, tv->treemark); + + while (ind < trind) { + vtx = TreeStack[ind++]; + if (TreeNodes[vtx]) { + return; + } + + if (TheGraph[vtx].d == -1) { + Place(vtx, Cand, Part); + TreeNodes[vtx] = TRUE; + } + + TreeMarkers[vtx] = tv->treemark; + deg0 = maxint(TheGraph[vtx].d, 0); + deg1 = sg_orig->d[vtx]; + sge1 = TheGraph[vtx].e; + + for (j1 = deg0; j1 < deg1; j1++) { + ngh = sge1[j1]; + if ((TheGraph[ngh].d == -1) && (TreeMarkers[ngh] != tv->treemark)) { + TreeStack[trind++] = ngh; + } + } + } + return; +} + +void MakeDiscrete(Partition *Part, int cell) { + int i, k; + + Part->cells += (Part->cls[cell] - 1); + k = cell + Part->cls[cell]; + + for (i = cell; i < k; i++) { + Part->cls[i] = 1; + Part->inv[i] = i; + } +} + +void MakeTree(int v1, int v2, sparsegraph *sg, int n, struct TracesVars* tv, boolean forceautom) { + int ind, vtx1, vtx2, ngh1, ngh2, trind, deg0, deg1; + size_t j1; + int *sge1, *sge2; + boolean build_autom; + + if (v1 == v2) return; + build_autom = tv->build_autom || forceautom; + trind = 2; + ind = 0; + TreeStack[0] = v1; + TreeStack[1] = v2; + SETMARK(TreeMarkers, tv->treemark); + + while (ind < trind) { + vtx1 = TreeStack[ind++]; + vtx2 = TreeStack[ind++]; + + TreeMarkers[vtx1] = tv->treemark; + TreeMarkers[vtx2] = tv->treemark; + + deg0 = maxint(TheGraph[vtx1].d, 0); + deg1 = sg->d[vtx1]; + sge1 = TheGraph[vtx1].e; + sge2 = TheGraph[vtx2].e; + for (j1 = deg0; j1 < deg1; j1++) { + ngh1 = sge1[j1]; + ngh2 = sge2[j1]; + if ((TreeMarkers[ngh1] != tv->treemark) && (ngh1 != ngh2)) { + TreeStack[trind++] = ngh1; + TreeStack[trind++] = ngh2; + if (ngh1 != ngh2) { + if (build_autom) { + AUTPERM[ngh1] = ngh2; + PrmPairs[tv->permInd].arg = ngh1; + PrmPairs[tv->permInd].val = ngh2; + tv->permInd++; + } + orbjoin_sp_pair(tv->orbits, OrbList, n, + ngh1, ngh2, &tv->stats->numorbits); + } + } + } + } + return; +} + +int maxint(int u, int v) { + if (u > v) { + return u; + } + else { + return v; + } +} + +int minint(int u, int v) { + if (u < v) { + return u; + } + else { + return v; + } +} + +int NextNeighbour(int vtx, Candidate *Cand, Partition *Part, int* Markers, int mark, int *ngh, int n) { + int *e_vtx; + int i, j, deg, cell1, nghi; + int cell[2]; + int vert[2]; + + deg = TheGraph[vtx].d; + e_vtx = TheGraph[vtx].e; + + if (deg == n-1) { + return 0; + } + j = 0; + cell[0] = cell[1] = n; + for (i=0; i<deg; i++) { + nghi = e_vtx[i]; + if (Markers[nghi] != mark) { + cell1 = Part->inv[Cand->invlab[nghi]]; + if (Part->cls[cell1] > 1) { + cell[j] = cell1; + vert[j] = nghi; + j++; + if (j==2) break; + } + } + } + if (j>0) { + if (cell[0] < cell[1]) { + *ngh = vert[0]; + } else { + *ngh = vert[1]; + } + return 1; + } + else return 0; +} + +int NonSingDeg(int vtx, Candidate *Cand, Partition *Part) { + int *e_vtx; + int i, deg, retdeg; + + retdeg = TheGraph[vtx].d; + deg = retdeg; + e_vtx = TheGraph[vtx].e; + for (i=0; i<deg; i++) { + if (Part->cls[Part->inv[Cand->invlab[e_vtx[i]]]] == 1) { + retdeg--; + } + } + return retdeg; +} + +int NonSingDegPlus1(Candidate *Cand, Partition *Part, int cell, TracesVars *tv) { + + int *e_vtx; + int vtx, sing; + int i, j, deg, retdeg, n, singcount; + + n = tv->input_graph->nv; + singcount = 0; + + SETMARK(StackMarkers, tv->stackmark) + + for (j=cell; j<cell+Part->cls[cell]; j++) { + vtx = Cand->lab[j]; + deg = TheGraph[vtx].d; + retdeg = 0; + e_vtx = TheGraph[vtx].e; + + for (i=0; i<deg; i++) { + if (SingNonSing[e_vtx[i]] != 1) { + e_vtx[retdeg++] = e_vtx[i]; + } + else { + if (StackMarkers[e_vtx[i]] != tv->stackmark) { + sing = e_vtx[i]; + WorkArray2[singcount] = Part->inv[Cand->invlab[sing]]; + WorkArray[singcount++] = sing; + + StackMarkers[e_vtx[i]] = tv->stackmark; + } + } + } + if (j == cell) { + sort2ints(WorkArray2, WorkArray, singcount); + } + if (deg != retdeg) { + memcpy(e_vtx+retdeg, WorkArray, singcount*sizeof(int)); + TheGraph[vtx].d = retdeg; + } + } + return retdeg; +} + +void NonSingDegPlus2(Candidate *Cand, Partition *Part, int cell, TracesVars *tv) { + + int *e_sing; + int sing; + int k, deg1, singdeg, singcount; + + singcount = 0; + + sing = Cand->lab[cell]; + singdeg = 0; + deg1 = TheGraph[sing].d; + e_sing = TheGraph[sing].e; + + for (k=0; k<deg1; k++) { + if (SingNonSing[e_sing[k]] != 2) { + e_sing[singdeg++] = e_sing[k]; + } + } + TheGraph[sing].d = singdeg; +} + +void orbjoin_sp_pair(int *orbits, int *list, int n, int u, int v, int *numorbs) { + int j1, j2, k1, k2; + + j1 = orbits[u]; + while (orbits[j1] != j1) j1 = orbits[j1]; + j2 = orbits[v]; + while (orbits[j2] != j2) j2 = orbits[j2]; + + if (j1 != j2) { + k1 = j1; + k2 = j2; + if (k1 < k2) { + (*numorbs)--; + while (list[j2] != k2) { + orbits[j2] = k1; + j2 = list[j2]; + } + orbits[j2] = k1; + k1 = list[k1]; + list[j2] = k1; + list[j1] = k2; + } + else if (k1 > k2) { + (*numorbs)--; + while (list[j1] != k1) { + orbits[j1] = k2; + j1 = list[j1]; + } + orbits[j1] = k2; + k2 = list[k2]; + list[j1] = k2; + list[j2] = k1; + } + } + return; +} + +void orbjoin_sp_perm(int *orbits, int *map, int *list, int n, int *numorbs) { + int i, j1, j2, k1, k2; + + for (i = 0; i < n; ++i) + if (map[i] != i) + { + j1 = orbits[i]; + while (orbits[j1] != j1) j1 = orbits[j1]; + j2 = orbits[map[i]]; + while (orbits[j2] != j2) j2 = orbits[j2]; + k1 = j1; + k2 = j2; + if (k1 < k2) { + (*numorbs)--; + while (OrbList[j2] != k2) { + orbits[j2] = k1; + j2 = OrbList[j2]; + } + orbits[j2] = k1; + k1 = OrbList[k1]; + OrbList[j2] = k1; + OrbList[j1] = k2; + } + else if (k1 > k2) { + (*numorbs)--; + while (OrbList[j1] != k1) { + orbits[j1] = k2; + j1 = OrbList[j1]; + } + orbits[j1] = k2; + k2 = OrbList[k2]; + OrbList[j1] = k2; + OrbList[j2] = k1; + } + } +} + +struct Partition *NewPartition(int n) { + struct Partition *P; + + P = malloc(sizeof(*(P))); + if (P == NULL) { + fprintf(ERRFILE, "\nError, memory not allocated.\n"); + exit(1); + } + P->cls = malloc(n*sizeof(int)); + if (P->cls == NULL) { + fprintf(ERRFILE, "\nError, memory not allocated.\n"); + exit(1); + } + P->inv = malloc(n*sizeof(int)); + if (P->inv == NULL) { + fprintf(ERRFILE, "\nError, memory not allocated.\n"); + exit(1); + } + P->code = -1; + P->cells = 0; + return P; +} + +void NewPartSpine(int Lev, int n) { + + if (Lev > 3) { + Spine[Lev].part = malloc(sizeof(*(Spine[Lev].part))); + if (Spine[Lev].part == NULL) { + fprintf(ERRFILE, "\nError, memory not allocated.\n"); + exit(1); + } + Spine[Lev].part->cls = Spine[Lev-3].part->cls; + Spine[Lev].part->inv = Spine[Lev-3].part->inv; + Spine[Lev-3].part->cls = Spine[Lev-3].part->inv = NULL; + Spine[Lev].part->code = -1; + Spine[Lev].part->cells = 0; + } + else { + Spine[Lev].part = NewPartition(n); + } +} + +void Place(int vtx, Candidate *Cand, Partition *Part) { + int vtxto, vtxpos; + + vtxpos = Cand->invlab[vtx]; + vtxto = CanonIndices[Part->inv[vtxpos]]++; + if (Cand->lab[vtxpos] != Cand->lab[vtxto]) { + Cand->lab[vtxpos] = Cand->lab[vtxto]; + Cand->lab[vtxto] = vtx; + Cand->invlab[Cand->lab[vtxpos]] = vtxpos; + Cand->invlab[Cand->lab[vtxto]] = vtxto; + } + if (Part->cls[vtxto] > 1) { + Part->cls[vtxto+1] = Part->cls[vtxto]-1; + Part->cls[vtxto] = 1; + } +} + +boolean Prefix(Candidate *Cand1, Candidate *Cand2, int k) { + int i; + + for (i=1; i<=k; i++) { + if (Cand1->lab[Spine[k].tgtpos] != Cand2->lab[Spine[k].tgtpos]) { + break; + } + } + return (i>k); +} + +int Preprocess(sparsegraph *sg, + permnode **ring, + Candidate *Cand, + int n, + Partition *Part, + struct TracesVars* tv) { + + int i, j, j0, k, curr_cell, ind, ind0, ind1, ind2; + int *sge; + int HitClsInd, labi, nghb, value, SplInd, SplCntInd, sc, iend, CStackInd, newcell, TraceInd; + +#define SETPAIRSAUTANDTREE_PREPROC(arg, val) \ +if (tv->build_autom) SETPAIRSAUT(arg, val) \ +if (arg != val) \ +orbjoin_sp_pair(tv->orbits, OrbList, n, arg, val, &tv->stats->numorbits); \ +MakeTree(arg, val, sg, n, tv, FALSE); + + CStackInd = 0; + for (i = 0; i < n; i += Part->cls[i]) { + if (TheGraph[Cand->lab[i]].d == 1) { + CStack[CStackInd++] = i; + } + } + + TraceInd = Part->cells; + + if (CStackInd > 0) { + ind = 0; + while (ind < CStackInd) { + + if (tv->mark > (NAUTY_INFINITY-2)) { + memset(Markers, 0, n*sizeof(int)); + memset(MarkHitVtx, 0, n*sizeof(int)); + tv->mark = 0; + } + tv->mark++; + + curr_cell = CStack[ind++]; + ind2 = curr_cell+Part->cls[curr_cell]; + HitClsInd = 0; + for (i = curr_cell; i < ind2; i++) { + labi = Cand->lab[i]; + nghb = *(TheGraph[labi].e); + + if (TheGraph[nghb].d != 1) { + TheGraph[labi].d = -1; + TheGraph[labi].one = TRUE; + } + + if (MarkHitVtx[nghb] == tv->mark) { + NghCounts[nghb]++; + } + else { + value = Part->inv[Cand->invlab[nghb]]; + MarkHitVtx[nghb] = tv->mark; + NghCounts[nghb] = 1; + if (Markers[value] != tv->mark) { + HitCls[HitClsInd++] = value; + Markers[value] = tv->mark; + HitVtx[value] = nghb; + ElmHitCll[value] = 1; + } + else { + HitVtx[value+ElmHitCll[value]++] = nghb; + } + } + } + tv->mark++; + + sort_Split_Array(HitCls,HitClsInd); + SplInd = 0; + SplCls[0] = n; + for (j = 0; j < HitClsInd; j++) { + ind1 = HitCls[j]; + if ((ElmHitCll[ind1] > 0) && (ElmHitCll[ind1] < Part->cls[ind1])) { + SplCls[SplInd++] = ind1; + } + else { + ind2 = ind1+Part->cls[ind1]; + value = NghCounts[Cand->lab[ind1++]]; + for (i = ind1; i < ind2; i++) { + if (NghCounts[Cand->lab[i]] != value) { + SplCls[SplInd++] = HitCls[j]; + break; + } + } + if (i == ind2) { + ind1 = HitCls[j]; + if (TheGraph[Cand->lab[ind1]].d != 1) { + for (i = ind1; i < ind2; i++) { + value = Cand->lab[i]; + Edge_Delete(value, NghCounts[value], Cand, tv); + sge = TheGraph[value].e+TheGraph[value].d; + if (NghCounts[value]>1) { + factorial(&(tv->stats->grpsize1), &(tv->stats->grpsize2), NghCounts[value]); + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (j0=0; j0<NghCounts[value]-1; j0++) { + SETPAIRSAUTANDTREE_PREPROC(sge[j0], sge[j0+1]) + } + SETPAIRSAUTANDTREE_PREPROC(sge[j0], sge[0]) + SPECIALGENERATORS + if (NghCounts[value] > 2) { + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + SETPAIRSAUTANDTREE_PREPROC(sge[0], sge[1]) + if (tv->build_autom) { + SETPAIRSAUT(sge[1], sge[0]) + } + MakeTree(sge[1], sge[0], sg, n, tv, FALSE); + SPECIALGENERATORS + } + } + } + if (TheGraph[Cand->lab[ind1]].d == 1) { + CStack[CStackInd++] = ind1; + } + } + } + } + } + + if (SplInd) { + + for (sc = 0; sc < SplInd; sc++) { /* For each cell C to be split */ + ind0 = SplCls[sc]; + ind1 = ind0 + Part->cls[ind0]; + SplCntInd = 0; + if (ElmHitCll[ind0] < Part->cls[ind0]) { + SplCnt[SplCntInd++] = 0; + SplPos[0] = Part->cls[ind0] - ElmHitCll[ind0]; + } + + /* According to the numbers of neighbors of C into the current cell */ + /* compute how many vertices in C will be placed into the same new cell */ + iend = ind0 + ElmHitCll[ind0]; + for (i = ind0; i < iend; i++) { + value = NghCounts[HitVtx[i]]; + if (Markers[value] != tv->mark) { + Markers[value] = tv->mark; + SplCnt[SplCntInd++] = value; + SplPos[value] = 1; + } + else { + SplPos[value]++; + } + } + tv->mark++; + + /* Sort the values deriving from the previous step */ + sort_Split_Array(SplCnt, SplCntInd); + + Part->cells += SplCntInd-1; + + /* Split the cell C and update the information for sizes of new cells */ + /* Put the new cells into the stack */ + i = ind0; + for (k = 0; k < SplCntInd; k++) { + value = SplPos[SplCnt[k]]; + Part->cls[i] = value; + SplPos[SplCnt[k]] = i; + i += value; + if (i < ind1) { + TheTrace[TraceInd++] = i; + } + } + + /* Permute elements of the cell C */ + iend = ind0 + ElmHitCll[ind0]; + + for (i = ind0; i < iend; i++) { + value = HitVtx[i]; + Edge_Delete(value, NghCounts[value], Cand, tv); + sge = TheGraph[value].e+TheGraph[value].d; + if (NghCounts[value] > 1) { + factorial(&(tv->stats->grpsize1), &(tv->stats->grpsize2), NghCounts[value]); + + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + for (j0=0; j0<NghCounts[value]-1; j0++) { + SETPAIRSAUTANDTREE_PREPROC(sge[j0], sge[j0+1]) + } + SETPAIRSAUTANDTREE_PREPROC(sge[j0], sge[0]) + SPECIALGENERATORS + if (NghCounts[value] > 2) { + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + SETPAIRSAUTANDTREE_PREPROC(sge[0], sge[1]) + if (tv->build_autom) { + SETPAIRSAUT(sge[1], sge[0]) + } + MakeTree(sge[1], sge[0], sg, n, tv, FALSE); + SPECIALGENERATORS + } + } + + j = SplPos[NghCounts[value]]++; /* where HitVtx[i] goes */ + k = Cand->invlab[value]; /* where HitVtx[i] is in lab */ + Cand->lab[k] = Cand->lab[j]; + Cand->lab[j] = value; + Cand->invlab[value] = j; + Cand->invlab[Cand->lab[k]] = k; + NghCounts[value] = 0; + } + + /* Reconstruct the cell C and update the inverse partition */ + newcell = ind1 - ElmHitCll[ind0]; + i = newcell; + ind2 = newcell+Part->cls[newcell]-1; + do { + Part->inv[i] = newcell; + if (i == ind2) { + newcell = i+1; + if (newcell < n) ind2 = newcell+Part->cls[newcell]-1; + } + } + while (++i < ind1); + + for (i = ind0, k = 0; k < SplCntInd; i+=Part->cls[i], k++) { + if ((k > 0) || (SplCnt[0] > 0)) { + if (TheGraph[Cand->lab[i]].d == 1) { + CStack[CStackInd++] = i; + } + } + if (Part->cls[i] == 1) { + Cand->singcode = MASHCOMM(Cand->singcode, Cand->lab[i]); + } + } + + } + } + } + return 1; + } + else { + return 0; + } +} + +void PrintPartition(int *v, int *cls, int n, int l, int line) { + int i, j, k; + + k=0; + fprintf(outfile, "[ "); + for (i=0; i<n; i+=cls[i]) { + if ((cls[i]<=0) || i>=n) { + printf("WRONG"); + break; + } + for (j=i; j<i+cls[i]; j++) { + fprintf(outfile, "%d ", v[j]+l); + if (k++ > 50) { + fprintf(outfile,"\n"); + k=0; + } + } + if ((i+cls[i])<n) fprintf(outfile, "| "); + } + fprintf(outfile, "] at line %d\n", line); + return; +} + +void PrintVect(int *v, int z, int n, int l) { + int i; + printf("["); + for (i = z; i<n; i++) + printf(" %2d", v[i]+l); + printf(" ]\n"); + return; +} + +void PrintWeightedGraph1(sparsegraph *g_arg, int n, char msg[30]) { + int i, j; + int *ngh1, *wgh1; + + printf("%s\n",msg); + for (i=0; i<n; i++) { + ngh1 = g_arg->e+g_arg->v[i]; + wgh1 = g_arg->w+g_arg->v[i]; + printf("%2d: ",i+labelorg); + for (j=0; j<g_arg->d[i]; j++) { + printf("%2d ",ngh1[j]); + printf("(%d) ",wgh1[j]); + } + printf("\n"); + } + printf("\n"); +} + +void PrintWeightedGraph2(int n, char msg[30]) { + int i, j; + int *ngh1, *wgh1; + + printf("%s\n",msg); + for (i=0; i<n; i++) { + ngh1 = TheGraph[i].e; + printf("%2d: ",i+labelorg); + for (j=0; j<TheGraph[i].d; j++) { + printf("%2d ",ngh1[j]+labelorg); + } + printf(";\n"); + } + printf("\n"); +} + +void PrintBlissGraph(int n) { + int i, j; + int *ngh1, *wgh1; + + fprintf(outfile,"p edge %d\n",n); + for (i=0; i<n; i++) { + ngh1 = TheGraph[i].e; + for (j=0; j<TheGraph[i].d; j++) { + if (i < ngh1[j]) { + fprintf(outfile, "e %d %d\n",i+labelorg,ngh1[j]+labelorg); + } + } + } + printf("\n"); +} + +void putgraphplus_sg(FILE *f, sparsegraph *sg, int linelength) +{ + int i,n,curlen,slen; + int *d,*e; + size_t *v,j; + char s[60]; + + n = sg->nv; + SG_VDE(sg,v,d,e); + + for (i = 0; i < n; ++i) + { + fprintf(f,"%3d : ",i+labelorg); + curlen = 7; + + for (j = v[i]; j < v[i]+d[i]; ++j) + { + if (sg->w) { + if (sg->w[j] != 1) { + slen = itos(sg->w[j],s); + if (linelength > 0 && curlen + slen + 1 > linelength) + { + putstring(f,"\n "); + curlen = 2; + } + PUTC(' ',f); + PUTC('w',f); + putstring(f,s); + curlen += slen + 3; + } + } + + slen = itos(e[j]+labelorg,s); + if (linelength > 0 && curlen + slen + 1 > linelength) + { + putstring(f,"\n "); + curlen = 2; + } + PUTC(' ',f); + putstring(f,s); + curlen += slen + 1; + } + putstring(f,";\n"); + } +} + +void quickSort(int *arr, int elements) { + +#define MAX_LEVELS 300 + + int piv, beg[MAX_LEVELS], end[MAX_LEVELS], i = 0, L, R, swap; + int k, value; + + beg[0] = 0; + end[0] = elements; + while (i>= 0) { + L = beg[i]; + R = end[i]-1; + if (L<R-8) { + piv = arr[(L+R)/2]; + arr[(L+R)/2] = arr[L]; + arr[L] = piv; + while (L<R) { + while (arr[R]>= piv && L<R) R--; + if (L<R) arr[L++] = arr[R]; + while (arr[L]<= piv && L<R) L++; + if (L<R) arr[R--] = arr[L]; + } + arr[L] = piv; + beg[i+1] = L+1; + end[i+1] = end[i]; end[i++] = L; + if (end[i]-beg[i]>end[i-1]-beg[i-1]) { + swap = beg[i]; + beg[i] = beg[i-1]; + beg[i-1] = swap; + swap = end[i]; + end[i] = end[i-1]; + end[i-1] = swap; + } + } + else { + i--; + } + } + for (k = 1; k < elements; ++k) { + value = arr[k]; + i = k - 1; + while ((i >= 0) && (value < arr[i])) { + arr[i + 1] = arr[i]; + --i; + } + arr[i + 1] = value; + } +} + +void RemoveFromLevel(int from, int to, int strategy, boolean reinit) { + int i; + + for (i=from; i<=to; i++) { + if (Spine[i].listend) { + (Spine[i].listend)->next = GarbList; + GarbList = Spine[i].liststart; + Spine[i].liststart = Spine[i].listend = NULL; + } + if (strategy == 0 || reinit) { + Spine[i].listcounter = 0; + if (i>from) { + Spine[i].thetracexists = FALSE; + Spine[i].part->code = -1; + } + } + } +} + +searchtrie *searchtrie_make(Candidate *CurrCand, Candidate *NextCand, int n, struct TracesVars *tv) { + + searchtrie *st; + if (tv->strienext == n) { + tv->strienext = 0; + tv->strielist->next = malloc(sizeof(struct trielist)); + if (tv->strielist->next == NULL) { + fprintf(ERRFILE, "\nError, memory not allocated.\n"); + exit(1); + } + tv->strielist->next->prev = tv->strielist; + tv->strielist = tv->strielist->next; + tv->strielist->next = NULL; + tv->strielist->triearray = malloc(n*sizeof(searchtrie)); + if (tv->strielist->triearray == NULL) { + fprintf(ERRFILE, "\nError, memory not allocated.\n"); + exit(1); + } + } + st = &(tv->strielist->triearray[tv->strienext]); + st->father = CurrCand->stnode; + st->name = NextCand->name; + st->index = tv->newindex+1; + st->vtx = NextCand->vertex; + st->level = tv->tolevel; + st->first_child = st->next_sibling = st->last_child = st->goes_to = NULL; + if (st->father) { + if (st->father->first_child) { + st->father->last_child->next_sibling = st; + st->father->last_child = st; + } + else { + st->father->first_child = st->father->last_child = st; + } + } + NextCand->stnode = st; + if (tv->newgotonode) { + tv->newgotonode->goes_to = st; + } + if (tv->gotonode) { + st->goes_to = tv->gotonode; + tv->gotonode = NULL; + } + tv->strienext++; + return st; +} + +trielist *searchtrie_new(int n, struct TracesVars *tv) { + + tv->strielist = malloc(sizeof(struct trielist)); + if (tv->strielist == NULL) { + fprintf(ERRFILE, "\nError, memory not allocated.\n"); + exit(1); + } + tv->strielist->prev = tv->strielist->next = NULL; + tv->strielist->triearray = malloc(n*sizeof(searchtrie)); + if (tv->strielist->triearray == NULL) { + fprintf(ERRFILE, "\nError, memory not allocated.\n"); + exit(1); + } + tv->strielist->triearray[0].father = tv->strielist->triearray[0].first_child = NULL; + tv->strielist->triearray[0].next_sibling = tv->strielist->triearray[0].last_child = NULL; + tv->strielist->triearray[0].goes_to = NULL; + tv->strielist->triearray[0].index = 1; + tv->strielist->triearray[0].name = tv->strielist->triearray[0].level = 0; + tv->strielist->triearray[0].vtx = n; + + tv->strienext = 1; + return tv->strielist; +} + +int Select_from_CStack(int *cls, int CStackInd) { + int j, k; + + j = CStackInd; + k = CStackInd; + while (--j > 0) { + if (cls[CStack[j]] < cls[CStack[k]]) { + k = j; + } + if ((cls[CStack[k]] == 1) || (j < CStackInd - 12)) { + break; + } + } + return k; +} + +boolean SelectNextLevel(int n, struct TracesVars *tv, struct TracesInfo *ti) { + int i, j, val; + Candidate *FirstCand; + boolean orbitcell; + VERB_PRINT("SelNxtLev",3,FALSE) + + switch (tv->compstage) { + case 2: + tv->nextlevel = tv->maxtreelevel; + while (tv->nextlevel >=0) { + if (Spine[tv->nextlevel].liststart) { + break; + } + tv->nextlevel--; + } + if (tv->nextlevel < 0) { + return FALSE; + } + break; + default: + switch (tv->strategy) { + case 0: + tv->nextlevel = tv->fromlevel; + while (!Spine[tv->nextlevel].liststart) { + (tv->nextlevel)++; + } + PRINTF2("SelectNextLevel 1?: finalnumcells: %d; ", tv->finalnumcells); + PRINTF2("Spine[tv->nextlevel].part->cells: %d; ", Spine[tv->nextlevel].part->cells); + PRINTF2("tv->maxtreelevel: %d; ", tv->maxtreelevel); + PRINTF2("tv->nextlevel: %d\n", tv->nextlevel); + if ((Spine[tv->nextlevel].part->cells == tv->finalnumcells) || (tv->nextlevel > tv->maxtreelevel)) { + return FALSE; + } + else { + /* Check the whole group */ + if ((tv->group_level < tv->tolevel) && !ti->first_matching && ti->thegrouphaschanged) { + + FirstCand = Spine[tv->nextlevel].liststart; + val = tv->orbits[FirstCand->lab[Spine[1].tgtcell]]; + for (i=Spine[1].tgtcell; i<Spine[1].tgtend; i++) { + if (tv->orbits[FirstCand->lab[i]] != val) { + break; + } + } + if (i<Spine[1].tgtend) { + orbitcell = FALSE; + } else { + orbitcell = TRUE; + } + if (orbitcell) { + FirstCand = Spine[tv->nextlevel].liststart; + FixBase(fix, tv, FirstCand, 0, tv->firstpathlength); + if (tv->options->verbosity >= 2) tv->schreier1 -= CPUTIME; + getorbitsmin(fix, tv->nfix, gpB, &gensB, &tv->currorbit, NULL, n, n, TRUE); + if (tv->options->verbosity >= 2) tv->schreier1 += CPUTIME; + for (j=2; j<=tv->firstpathlength; j++) { + tv->currorbit = findcurrorbits(gpB, j-1); + val = tv->currorbit[FirstCand->lab[Spine[j].tgtcell]]; + for (i=Spine[j].tgtcell; i<Spine[j].tgtend; i++) { + if (tv->currorbit[FirstCand->lab[i]] != val) { + break; + } + } + if (i<Spine[j].tgtend) { + break; + } + } + tv->group_level = j-1; + if (tv->group_level >= tv->tolevel) { + ti->thegrouphaschanged = FALSE; + } + } + /* End check the whole group */ + } + + } + break; + case 1: + tv->nextlevel = tv->maxtreelevel; + PRINTF2("SelectNextLevel 2?: finalnumcells: %d; ", tv->finalnumcells); + PRINTF2("Spine[tv->nextlevel].part->cells: %d; ", Spine[tv->nextlevel].part->cells); + if (Spine[tv->nextlevel].part->cells == tv->finalnumcells) { + (tv->nextlevel)--; + } + while (tv->nextlevel >= 0) { + if (Spine[tv->nextlevel].liststart) { + break; + } + tv->nextlevel--; + } + if (tv->nextlevel < 0) { + return FALSE; + } + break; + default: + break; + } + break; + } + return TRUE; +} + +void SetAutom(int q, int n, struct TracesVars *tv) { + int i; + + for (i=0; i<q; i++) { + AUTPERM[PrmPairs[i].arg] = PrmPairs[i].val; + } + return; +} + +void ResetAutom(int q, int n, struct TracesVars *tv) { + int i; + + if (n/q < 256) { + memcpy(AUTPERM, IDENTITY_PERM, n*sizeof(int)); + } + else { + for (i=0; i<q; i++) { + AUTPERM[PrmPairs[i].arg] = PrmPairs[i].arg; + } + } + tv->permInd = 0; + return; +} + +void sort_Split_Array(int *Array, int Ind){ + int i, k, value; + + switch (Ind) { + case 0: + case 1: + break; + case 2: + if (Array[0] > Array[1]) { + value = Array[0]; + Array[0] = Array[1]; + Array[1] = value; + } + break; + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + for (k = 1; k < Ind; ++k) { + value = Array[k]; + i = k - 1; + while ((i >= 0) && (value < Array[i])) { + Array[i + 1] = Array[i]; + --i; + } + Array[i + 1] = value; + } + break; + default: + quickSort(Array, Ind); + break; + } +} + +int spinelementorbsize(int *orbits, int *lab, int size, int elem) { + int i, j, val; + + j = 0; + val = orbits[elem]; + for (i = 0; i < size; ++i) { + if (orbits[lab[i]] == val) ++j; + } + return j; +} + +boolean TargetCell(Candidate *TargCand, Partition *Part, int n, struct TracesVars* tv, int Lv) { + int TCell = -1, TCSize = 1; + int i; + VERB_PRINT("TCELL",3,FALSE) + if (Part->cells == n) { + tv->finalnumcells = n; + return FALSE; + } + if (tv->maxdeg <=2) { + return FALSE; + } + + if (Lv < tv->tcellevel) { + tv->tcell = Spine[Lv+1].tgtcell; + return TRUE; + } + else { + if (Part->cls[0] == n) { + tv->tcell = 0; + return TRUE; + } + while (TCell < 0) { + for (i = Spine[Lv].tgtcell; i < Spine[Lv].tgtend; i += Part->cls[i]) { + if (Part->cls[i] > TCSize) { + if (NonSingDeg(TargCand->lab[i], TargCand, Part) > 2) { + TCSize = Part->cls[i]; + TCell = i; + } + } + } + Lv--; + if ((Lv < 0) && (TCell < 0)) return FALSE; + } + tv->tcell = TCell; + return TRUE; + } +} + +int TargetCellExpPath(Candidate *TargCand, Partition *Part, struct TracesVars* tv) { + int Lv, n; + VERB_PRINT("TCEP",3,FALSE) + + n = tv->input_graph->nv; + if (Part->cells == n) { + return 0; + } + + Lv = tv->tolevel_tl+1; + SpineTL_tl = Spine+Lv; + if (tv->tolevel_tl < tv->tcellevel) { + tv->tcellexpath = Part->inv[SpineTL_tl->tgtcell]; + tv->tolevel_tl++; + if (Part->cls[tv->tcellexpath] == 1) { + if (tv->options->verbosity >= 2) { + if (tv->tolevel_tl-tv->tolevel == 6) { + fprintf(outfile, "... "); + } + } + return TargetCellExpPath(TargCand, Part, tv); + } else { + return 1+((Spine[tv->tolevel_tl].tgtcell >= Spine[tv->tolevel_tl-1].tgtcell) && (Spine[tv->tolevel_tl].tgtend <= Spine[tv->tolevel_tl-1].tgtend)); + } + } + else { + if (TargetCellFirstPath(TargCand, Part, tv)) { + return 1+((Spine[tv->tolevel_tl].tgtcell >= Spine[tv->tolevel_tl-1].tgtcell) && (Spine[tv->tolevel_tl].tgtend <= Spine[tv->tolevel_tl-1].tgtend)); + } + else { + return 0; + } + } +} + +boolean TargetCellFirstPath(Candidate *TargCand, Partition *Part, struct TracesVars* tv) { + int n, TCell, TCSize, TCell1, TCSize1; + int Lv, i, Lev, vtx, vtx_d; + int loopstart, loopend; + boolean divided; + VERB_PRINT("TCFP",3,FALSE) + + n = tv->input_graph->nv; + + if (Part->cells == n) { + return 0; + } + + Lev = tv->tolevel_tl; + Lv = tv->tolevel_tl; + + TCell = TCell1 = -1; + TCSize = TCSize1 = 1; + + while (TCell < 0) { + + if (tv->compstage == 2) { + loopstart = Spine[Lv].tgtcell; + divided = FALSE; + } else { + loopstart = Part->inv[Spine[Lv].tgtcell]; + divided = FALSE; + + if (Lv == tv->lastlev) { + loopstart = Part->inv[tv->lastcell]; + divided = TRUE; + } + } + + i = loopstart; + loopend = Spine[Lv].tgtend; + while (i < loopend) { + if (Part->cls[i] > TCSize) { + vtx = TargCand->lab[i]; + vtx_d = TheGraph[vtx].d; + if (vtx_d > 2) { + if (NonSingDeg(vtx, TargCand, Part) > 2) { + TCSize = Part->cls[i]; + TCell = i; + if (TCSize == WorkArray[Lv]) { + break; + } + } + } + } + i += Part->cls[i]; + if (divided && (i == loopend)) { + i = loopstart = Part->inv[Spine[Lv].tgtcell]; + loopend = tv->lastcell; + divided = FALSE; + TCSize1 = TCSize; + TCell1 = TCell; + TCell = -1; + TCSize = 1; + } + } + + if (TCSize1 > TCSize) { + TCell = TCell1; + TCSize = TCSize1; + } + + if (TCell < 0) { + if (Lv == 0) { + if (tv->answ == 2) { + tv->finalnumcells = minint(Part->cells,tv->finalnumcells); /* 160712 */ + tv->finalnumcells = Part->cells; + } + return FALSE; + } else { + Lv = Spine[Lv].tgtfrom; + } + } + } + + tv->tcellexpath = tv->lastcell = TCell; + tv->tolevel_tl++; + + Spine[tv->tolevel_tl].tgtfrom = tv->lastlev = Lv; + Spine[tv->tolevel_tl].tgtcell = tv->tcellexpath; + Spine[tv->tolevel_tl].tgtsize = WorkArray[Lv] = TCSize; + Spine[tv->tolevel_tl].tgtend = Spine[tv->tolevel_tl].tgtcell + TCSize; + Spine[tv->tolevel_tl].tgtpos = Spine[tv->tolevel_tl].tgtend - 1; + tv->tcellevel = tv->tolevel_tl; + + if (Lv != Lev) { + BreakSteps[Lev] = ++tv->brkstpcount; + if (Spine[tv->tolevel].liststart) { + if (!Spine[tv->tolevel].liststart->firstsingcode) { + Spine[tv->tolevel].liststart->firstsingcode = Spine[tv->tolevel].liststart->pathsingcode; + } + } + } + return TRUE; +} + +void traces_freedyn(void) { + /* Free the static dynamic memory used by Traces */ +#if !MAXN + DYNFREE(AUTPERM, AUTPERM_sz); + DYNFREE(BreakSteps, BreakSteps_sz); + DYNFREE(CStack, CStack_sz); + DYNFREE(CurrOrbSize, CurrOrbSize_sz); + DYNFREE(CurrRefCells, CurrRefCells_sz); + DYNFREE(Diff, Diff_sz); + DYNFREE(Factorials, Factorials_sz); + DYNFREE(fix, fix_sz); + DYNFREE(IDENTITY_PERM, IDENTITY_PERM_sz); + DYNFREE(Markers, Markers_sz); + DYNFREE(TreeMarkers, TreeMarkers_sz); + DYNFREE(AutMarkers, AutMarkers_sz); + DYNFREE(MarkHitVtx, MarkHitVtx_sz); + DYNFREE(MultRefCells, MultRefCells_sz); + DYNFREE(NghCounts, NghCounts_sz); + DYNFREE(OrbSize, OrbSize_sz); + DYNFREE(OrbList, OrbList_sz); + DYNFREE(PrmPairs, PrmPairs_sz); + DYNFREE(TempOrbList, TempOrbList_sz); + DYNFREE(RefCells, RefCells_sz); + DYNFREE(RefPath, RefPath_sz); + DYNFREE(Singletons, Singletons_sz); + DYNFREE(SplCls, SplCls_sz); + DYNFREE(SplCnt, SplCnt_sz); + DYNFREE(SplPos, SplPos_sz); + DYNFREE(StackMarkers, StackMarkers_sz); + DYNFREE(TheTrace, TheTrace_sz); + DYNFREE(TheTraceCC, TheTraceCC_sz); + DYNFREE(TheTraceSplNum, TheTraceSplNum_sz); + DYNFREE(TheTraceSteps, TheTraceSteps_sz); + DYNFREE(TEMPLAB, TEMPLAB_sz); + DYNFREE(TEMPINVLAB, TEMPINVLAB_sz); + DYNFREE(WeightsSeq, WeightsSeq_sz); + DYNFREE(WorkArray, WorkArray_sz); + DYNFREE(WorkArray0, WorkArray0_sz); + DYNFREE(WorkArray1, WorkArray1_sz); + DYNFREE(WorkArray2, WorkArray2_sz); + DYNFREE(WorkArray3, WorkArray3_sz); + DYNFREE(WorkArray4, WorkArray4_sz); + DYNFREE(WorkArray5, WorkArray5_sz); + DYNFREE(WorkArray6, WorkArray6_sz); + DYNFREE(WorkArray7, WorkArray7_sz); + DYNFREE(Neighbs1, Neighbs1_sz); + DYNFREE(Neighbs2, Neighbs2_sz); + DYNFREE(TreeStack, TreeStack_sz); + DYNFREE(Spine, Spine_sz); + DYNFREE(TrieArray, TrieArray_sz); + DYNFREE(TheGraph, TheGraph_sz); + DYNFREE(EPCodes, EPCodes_sz); + DYNFREE(CyclesPart, CyclesPart_sz); + DYNFREE(CyclesLength, CyclesLength_sz); +#endif +} + +boolean TreeFyTwo(int From, Candidate *Cand1, Candidate *Cand2, Partition *Part, int n, + struct TracesVars* tv, struct TracesInfo *ti) { + int i, i1, i2, j1, j2, k; + int vtx1, vtx2, ngh1, ngh2, arg, val; + int *tgtc1, *tgtc2, *adj1, *adj2; + int iend; + + SETMARK(Markers, tv->mark) + + i2=0; + + if (tv->permInd) ResetAutom(tv->permInd, n, tv); + i1 = Spine[From].tgtsize; + tgtc1 = Cand1->lab+Spine[From].tgtcell; + tgtc2 = Cand2->lab+Spine[From].tgtcell; + for (i=0; i<i1; i++) { + arg = tgtc1[i]; + val = tgtc2[i]; + if ((Markers[arg] != tv->mark) && (Markers[val] != tv->mark)) { + SETPAIRSAUT(arg, val) + SETPAIRSAUT(val, arg) + Markers[arg] = tv->mark; + Markers[val] = tv->mark; + } else { + return FALSE; /* 160715 */ + } + } + + while (i2 < tv->permInd) { + vtx1 = PrmPairs[i2].arg; + vtx2 = PrmPairs[i2++].val; + adj1 = TheGraph[vtx1].e; + adj2 = TheGraph[vtx2].e; + iend = TheGraph[vtx1].d; + j1 = j2 = 0; + for (k=0; k < iend; k++) { + ngh1 = adj1[k]; + if (Markers[ngh1] != tv->mark) { + Neighbs1[j1++] = Cand1->invlab[ngh1]; + } + ngh2 = adj2[k]; + if (Markers[ngh2] != tv->mark) { + Neighbs2[j2++] = Cand2->invlab[ngh2]; + } + } + + k = tv->permInd; + if (j1 == j2) { + quickSort(Neighbs1, j1); + quickSort(Neighbs2, j2); + for (i=0; i<j1; i++) { + arg = Cand1->lab[Neighbs1[i]]; + val = Cand2->lab[Neighbs2[i]]; + if ((Markers[arg] != tv->mark) && (Markers[val] != tv->mark)) { + SETPAIRSAUT(arg, val) + SETPAIRSAUT(val, arg) + Markers[arg] = tv->mark; + Markers[val] = tv->mark; + } + } + } + } + return TRUE; +} + +/***************************************************************************** + * * + * trie_class(t,c) classifies vertices according to weights of their edges * + * * + *****************************************************************************/ + +void trie_class(trie *t, int *count) { + + if (t->first_child == NULL) { + WeightsSeq[t->value] = *count; + if (t->next_sibling == NULL) (*count)++; + return; + } + else { + t = t->first_child; + while (t) { + trie_class(t,count); + t = t->next_sibling; + } + } +} + +int trie_classify(int n, TracesVars *tv) { + + int i, j, ord; + int *ngh1, *wgh1; + + trieroot = trie_new(n, tv); + ord = 0; + + for (i=0; i<n; i++) { + ngh1 = TheGraph[i].e; + wgh1 = TheGraph[i].w; + sort2ints(wgh1, ngh1, TheGraph[i].d); + + trieref = trieroot; + for (j=0; j<TheGraph[i].d; j++) { + trieref = trie_make(trieref, wgh1[j], n, tv); + } + trieref = trie_make(trieref, n, n, tv); + trie_make(trieref, i, n, tv); + } + trie_class(trieroot,&ord); + + for (i=0; i<=tv->triepos; i++) { + free(TrieArray[i]); + } + trieroot = NULL; + return ord-1; +} + +struct trie *trie_comp(trie *t, int value) { + + if (t->first_child) { + t = t->first_child; + while (t) { + if (value != t->value) { + t = t->next_sibling; + } + else { + break; + } + } + return t; + } + else { + return NULL; + } +} + +void trie_dump(trie *t) { + if (t->first_child == NULL) return; + else { + printf("( "); + t = t->first_child; + while (t) { + printf("%d ",t->value); + trie_dump(t); + t = t->next_sibling; + } + printf(") "); + } +} + +/***************************************************************************** + * * + * trie_make(t,v,n,tv) places the value v into the trie t * + * * + *****************************************************************************/ + +struct trie *trie_make(trie *t, int value, int n, struct TracesVars* tv) { + trie *t1; + + t1 = t; + if (tv->trienext == n) { + tv->trienext = 0; + tv->triepos++; + TrieArray[tv->triepos] = malloc(n*sizeof(trie)); + if (TrieArray[tv->triepos] == NULL) { + fprintf(ERRFILE, "\nError, memory not allocated.\n"); + exit(1); + } + } + if (t->first_child) { + t = t->first_child; + if (value < t->value) { + t1->first_child = &TrieArray[tv->triepos][tv->trienext++]; + t1->first_child->next_sibling = t; + t1->first_child->first_child = NULL; + t = t1->first_child; + t->value = value; + return t; + } + while (value > t->value) { + t1 = t; + if (t->next_sibling) { + t = t->next_sibling; + } + else break; + } + if (value == t->value) { + return t; + } + t1->next_sibling = &TrieArray[tv->triepos][tv->trienext++]; + t1->next_sibling->first_child = t1->next_sibling->next_sibling = NULL; + if (t != t1) { + t1->next_sibling->next_sibling = t; + } + t = t1->next_sibling; + } + else { + t->first_child = &TrieArray[tv->triepos][tv->trienext++]; + t = t->first_child; + t->first_child = t->next_sibling = NULL; + } + t->value = value; + return t; +} + +struct trie *trie_new(int n, struct TracesVars* tv) { + + TrieArray[0] = malloc(n*sizeof(trie)); + if (TrieArray[0] == NULL) { + fprintf(ERRFILE, "\nError, memory not allocated.\n"); + exit(1); + } + TrieArray[0][0].first_child = TrieArray[0][0].next_sibling = NULL; + tv->triepos = 0; + tv->trienext = 1; + return TrieArray[0]; +} + +boolean VerifyCand(Candidate *Cand, int n, int line) { + int i, k; + + for (i=0; i<n; i++) { + k=Cand->lab[i]; + if (Cand->invlab[k] != i) { + printf("Cand->invlab wrong at %d (vtx: %d), line %d\n", i, k, line); + PrintVect(Cand->lab, 0, n, 0); + PrintVect(Cand->invlab, 0, n, 0); + return FALSE; + } + } + return TRUE; +} + +boolean VerifyId(int *p, int n) { + int i, r; + + r = TRUE; + for (i=0; i<n; i++) { + if (p[i] != i) { + printf("p[%d] = %d\n", i, p[i]); + r = FALSE; + } + } + return r; +} + +boolean VerifyPart(Partition *Part, int start, int end) { + int i,j; + + for (i=start; i<end; i+=Part->cls[i]) { + if (Part->cls[i] == 0 || i>=end) { + printf("WRONG cls\n"); + return FALSE; + } + for (j=0; j<Part->cls[i]; j++) { + if (Part->inv[i+j] != i) { + printf("WRONG inv\n"); + return FALSE; + } + } + } + printf("OK\n"); + return TRUE; +} + +int VerifyPerm(int *perm, int n,int where) { + int i; + + memset(Markers, 0, n*sizeof(int)); + + for (i=0; i<n; i++) { + if ((perm[i] >= n) || (Markers[perm[i]])) { + fprintf(stderr,"wrong permutation @ %d\n",where); + PrintVect(perm,0,i+1,labelorg); + } + Markers[perm[i]] = TRUE; + } + return TRUE; +} + +/***************************************************************************** + * * + * WeightCodes(n) transforms the weight w(u,v) of an edge into a new weight * + * W(u,v) such that W(a,b) = W(c,d) iff w(a,b) = w(c,d) and w(b,a) = w(d,c). * + * * + *****************************************************************************/ + +void WeightCodes(int n) { + int i,j,aux; + int sumdegs; + int deg, vtx1, vtx2, *ngh1, *ngh2, *wgh1, *wgh2, ord; + + sumdegs = 0; + for (i=0; i<n; i++) { + sumdegs += TheGraph[i].d; + } + + DYNALLSTAT(int, VArray, VArray_sz); + DYNALLSTAT(weightwhere, WArray, WArray_sz); + DYNALLSTAT(grph_strct, TheAuxGraph, TheAuxGraph_sz); + + DYNALLOC1(int, VArray, VArray_sz, sumdegs, "WeightCodes"); + DYNALLOC1(weightwhere, WArray, WArray_sz, sumdegs, "WeightCodes"); + DYNALLOC1(grph_strct, TheAuxGraph, TheAuxGraph_sz, n, "WeightCodes"); + + memcpy(TheAuxGraph,TheGraph,n*sizeof(grph_strct)); + + ord = 0; + for (vtx1=0; vtx1<n; vtx1++) { + ngh1 = (TheAuxGraph[vtx1].e)++; + wgh1 = TheAuxGraph[vtx1].w; + deg = TheAuxGraph[vtx1].d; + for (i=0; i<deg; i++) { + vtx2 = ngh1[i]; + ngh2 = (TheAuxGraph[vtx2].e)++; + wgh2 = (TheAuxGraph[vtx2].w)++; + (TheAuxGraph[vtx1].d)--; + (TheAuxGraph[vtx2].d)--; + VArray[ord] = wgh1[i]; + WArray[ord].weight = wgh2[0]; + WArray[ord++].ref = (TheAuxGraph[vtx1].w)++; + VArray[ord] = wgh2[0]; + WArray[ord].weight = wgh1[i]; + WArray[ord++].ref = wgh2; + } + } + + sortweights(VArray,WArray,ord); + + /* swap VArray and WArray.weight */ + for (i=0; i<sumdegs; i++) { + aux = VArray[i]; + VArray[i] = WArray[i].weight; + WArray[i].weight = aux; + } + + i = j = 0; + do { + if (WArray[i].weight == WArray[j].weight) { + j++; + } else { + sortweights(VArray+i,WArray+i,j-i); + i = j; + } + } while (j<sumdegs); + sortweights(VArray+i,WArray+i,j-i); + + /* weight class */ + ord = 0; + *(WArray[0].ref) = 0; + for (i=1; i<sumdegs; i++) { + if ((WArray[i].weight != WArray[i-1].weight) || (VArray[i] != VArray[i-1])) { + ord++; + } + *(WArray[i].ref) = ord; + } + + DYNFREE(VArray, VArray_sz); + DYNFREE(WArray, WArray_sz); + DYNFREE(TheAuxGraph, TheAuxGraph_sz); + +} + + + +boolean TargetCellSmall(Candidate *TargCand, Partition *Part, int n, struct TracesVars* tv, int Lv) { + int TCell = -1, TCSize = n; + int i; + + if (tv->maxdeg <=2) { + return FALSE; + } + + if (Lv < tv->tcellevel) { + tv->tcell = Spine[Lv+1].tgtcell; + return TRUE; + } + else { + if (Part->cls[0] == n) { + tv->tcell = 0; + return TRUE; + } + while (TCell < 0) { + for (i = Spine[Lv].tgtcell; i < Spine[Lv].tgtend; i += Part->cls[i]) { + if (Part->cls[i] < TCSize) { + if (NonSingDeg(TargCand->lab[i], TargCand, Part) > 2) { + TCSize = Part->cls[i]; + TCell = i; + } + } + } + Lv--; + if ((Lv < 0) && (TCell < 0)) return FALSE; + } + tv->tcell = TCell; + return TRUE; + } +} + +int TargetCellExpPathSmall(Candidate *TargCand, Partition *Part, struct TracesVars* tv) { + int Lv, n; + + n = tv->input_graph->nv; + if (Part->cells == n) { + return 0; + } + + Lv = tv->tolevel_tl+1; + SpineTL_tl = Spine+Lv; + if (tv->tolevel_tl < tv->tcellevel) { + tv->tcellexpath = Part->inv[SpineTL_tl->tgtcell]; + tv->tolevel_tl++; + if (Part->cls[tv->tcellexpath] == 1) { + if (tv->options->verbosity >= 2) { + if (tv->tolevel_tl-tv->tolevel == 6) { + fprintf(outfile, "... "); + } + } + return TargetCellExpPath(TargCand, Part, tv); + } else { + return 1+((Spine[tv->tolevel_tl].tgtcell >= Spine[tv->tolevel_tl-1].tgtcell) && (Spine[tv->tolevel_tl].tgtend <= Spine[tv->tolevel_tl-1].tgtend)); + } + } + else { + if (TargetCellFirstPath(TargCand, Part, tv)) { + return 1+((Spine[tv->tolevel_tl].tgtcell >= Spine[tv->tolevel_tl-1].tgtcell) && (Spine[tv->tolevel_tl].tgtend <= Spine[tv->tolevel_tl-1].tgtend)); + } + else { + return 0; + } + } +} + +boolean TargetCellFirstPathSmall(Candidate *TargCand, Partition *Part, struct TracesVars* tv) { + int n, TCell, TCSize, TCell1, TCSize1; + int Lv, i, Lev, vtx, vtx_d; + int loopstart, loopend; + boolean divided; + + n = tv->input_graph->nv; + if (Part->cells == n) { + return 0; + } + Lev = tv->tolevel_tl; + Lv = tv->tolevel_tl; + TCell = TCell1 = -1; + TCSize = TCSize1 = n; + + while (TCell < 0) { + loopstart = Part->inv[Spine[Lv].tgtcell]; + divided = FALSE; + + if (Lv == tv->lastlev) { + loopstart = Part->inv[tv->lastcell]; + divided = TRUE; + } + + i = loopstart; + loopend = Spine[Lv].tgtend; + + while (i < loopend) { + if ((Part->cls[i] > 1) && (Part->cls[i] < TCSize)) { + vtx = TargCand->lab[i]; + vtx_d = TheGraph[vtx].d; + + if (vtx_d > 2) { + if (NonSingDeg(vtx, TargCand, Part) > 2) { + TCSize = Part->cls[i]; + TCell = i; + if (TCSize == WorkArray[Lv]) { + break; + } + } + } + } + i += Part->cls[i]; + if (divided && (i == loopend)) { + i = loopstart = Spine[Lv].tgtcell; + loopend = tv->lastcell; + divided = FALSE; + TCSize1 = TCSize; + TCell1 = TCell; + TCell = -1; + TCSize = n; + } + } + + if (TCSize1 < TCSize) { + TCell = TCell1; + TCSize = TCSize1; + } + + if (TCell < 0) { + if (Lv == 0) { + tv->finalnumcells = minint(Part->cells,tv->finalnumcells); /* 160712 */ + tv->finalnumcells = Part->cells; + return FALSE; + } else { + Lv = Spine[Lv].tgtfrom; + } + } + } + tv->tcellexpath = tv->lastcell = TCell; + tv->tolevel_tl++; + + Spine[tv->tolevel_tl].tgtfrom = tv->lastlev = Lv; + Spine[tv->tolevel_tl].tgtcell = tv->tcellexpath; + Spine[tv->tolevel_tl].tgtsize = WorkArray[Lv] = TCSize; + Spine[tv->tolevel_tl].tgtend = Spine[tv->tolevel_tl].tgtcell + TCSize; + Spine[tv->tolevel_tl].tgtpos = Spine[tv->tolevel_tl].tgtend - 1; + tv->tcellevel = tv->tolevel_tl; + + if (Lv != Lev) { + BreakSteps[Lev] = ++tv->brkstpcount; + if (Spine[tv->tolevel].liststart) { + if (!Spine[tv->tolevel].liststart->firstsingcode) { + Spine[tv->tolevel].liststart->firstsingcode = Spine[tv->tolevel].liststart->pathsingcode; + } + } + } + return TRUE; +} |