@x a change file for SSXCC [not SSXCC-BINARY] @ After this program finds all solutions, it normally prints their total @y This program differs from {\mc SSXCC} by choosing the item on which to branch based on a ``weighted'' heuristic motivated by the paper of Li, Yin, and Li in @^Li, Hongbo@> @^Yin, Minghao@> @^Li, Zhanshan@> {\sl Leibniz International Proceedings in Informatics\/ \bf210} (2021), 9:1--9:10 [the proceedings of the 27th International Conference on Principles and Practice of Constraint Programming, CP~2021]. When the option chosen for branching on some primary item~$i$ causes another primary item~$i'$ to be wiped out, we say that a failure has occurred with respect to~$i$. We branch on an item that has a small number of options and a relatively high failure rate. Details are discussed below. It's the same heuristic as in {\mc SSXCC-FRB}. But that version uses binary branching, while this one (like {\mc SSXCC} itself) uses $d$-way branching. @ After this program finds all solutions, it normally prints their total @z @x done:@+if (vbose&show_profile) @; @y if (vbose&show_profile) @; done:@+if (vbose&show_profile) @; if (vbose&show_final_stats) { fprintf(stderr,"Final primary item stats:\n"); print_item_stats(); } @z @x @d show_max_deg 2048 /* |vbose| code for reporting maximum branching degree */ @y @d show_max_deg 2048 /* |vbose| code for reporting maximum branching degree */ @d show_final_stats 4096 /* |vbose| code to display item stats at the end */ @z @x The given options are stored sequentially in the |nd| array, with one node @y Each primary item in the |set| array also contains two special fields called |assigns| and |fails|, which are used in the {\mc FRB} heuristic. Their significance is described below. The given options are stored sequentially in the |nd| array, with one node @z @x @d primextra 4 /* this many extra entries of |set| for each primary item */ @d secondextra 4 /* and this many for each secondary item */ @d maxextra 4 /* maximum of |primextra| and |secondextra| */ @y @d assigns(x) set[(x)-5] /* number of assignments tried so far for |x|, plus 1 */ @d fails(x) set[(x)-6] /* how many of them failed? */ @d primextra 6 /* this many extra entries of |set| for each primary item */ @d secondextra 4 /* and this many for each secondary item */ @d maxextra 6 /* maximum of |primextra| and |secondextra| */ @z @x if (c; @y if (t==infty) @; @z @x @; @y @; @; @z @x abort:@+if (o,cur_choice+1>=best_itm+size(best_itm)) goto backup; @y goto try_again; abort:@+@; try_again:@+if (o,cur_choice+1>=best_itm+size(best_itm)) goto backup; @z @x @ The ``best item'' is considered to be an item that minimizes the number of remaining choices. All candidates of size~1, if any, are put on the |force| stack. If there are several candidates of size $>1$, we choose the leftmost. Notice that a secondary item is active if and only if it has not been purified (that is, if and only if it hasn't yet appeared in a chosen option). (This program explores the search space in a slightly different order from {\mc DLX2}, because the ordering of items in the active list is no longer fixed. But ties are broken in the same way when $s>1$.) @= t=max_nodes,tmems=mems; if ((vbose&show_details) && level=maxl-show_choices_gap) fprintf(stderr,"Level "O"d:",level); for (k=0;k=maxl-show_choices_gap) { print_item_name(item[k],stderr); fprintf(stderr,"("O"d)",s); } if (s<=1) { if (s==0) fprintf(stderr,"I'm confused.\n"); /* |hide| missed this */ else o,force[forced++]=item[k]; }@+else if (s<=t) { if (s=maxl-show_choices_gap) { if (forced) fprintf(stderr," found "O"d forced\n",forced); else if (t==max_nodes) fprintf(stderr," solution\n"); else { fprintf(stderr," branching on"); print_item_name(best_itm,stderr); fprintf(stderr,"("O"d)\n",t); } } if (t>maxdeg && t @^Yin, Minghao@> @^Li, Zhanshan@> @= oo,assigns(best_itm)++; if (assigns(best_itm)<=0) { fprintf(stderr,"Too many assignments (2^{31})!\n"); exit(-6); } cmems+=2; @ @= oo,assigns(best_itm)++; if (assigns(best_itm)<=0) { fprintf(stderr,"Too many assignments (2^{31})!\n"); exit(-66); } oo,fails(best_itm)++; cmems+=4; @ @= void print_item_stats(void) { register int k; for (k=0;k= { register float score,tscore,w; tmems=mems,score=finfty,t=infty; if ((vbose&show_details) && level=maxl-show_choices_gap) fprintf(stderr,"Level "O"d:",level); for (k=0;k; o,force[forced++]=item[k]; }@+else { o,w=(float)fails(item[k])+0.5; o,w/=assigns(item[k]); tscore=s/w; if (tscore>=finfty) tscore=dangerous; if (tscore=maxl-show_choices_gap) { print_item_name(item[k],stderr);@+ if (s==1) fprintf(stderr,"(1)"); else fprintf(stderr,"("O"d,"O"d/"O"d)",s,fails(item[k]),assigns(item[k])); } } if ((vbose&show_details) && level=maxl-show_choices_gap) { if (forced) fprintf(stderr," found "O"d forced\n",forced); else if (t==infty) fprintf(stderr," solution\n"); else { fprintf(stderr," branching on"); print_item_name(best_itm,stderr); fprintf(stderr,"("O"d), score "O".4f\n",t,score); } } if (t>maxdeg && tmaxdeg && t= @y @ Oops --- we've run into a case where the current choice at |level-1| has wiped out |item[k]|. Thus |item[k]|, which manifestly has the smallest option list, is a |best_item| doomed to fail. @= { if ((vbose&show_details) && level=maxl-show_choices_gap) { fprintf(stderr,"\n--- Item "); print_item_name(item[k],stderr); fprintf(stderr," has been wiped out!\n"); } best_itm=item[k]; @; forced=0; goto backup; } @ @= @z