/*
 * Copyright (C) Andrew Wuensche
 *
 *  This file is part of DDLab (Discrete Dynamics Lab) <www.ddlab.org>
 *
 *  DDLab is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with DDLab.  If not, see <http://www.gnu.org/licenses/>.
 */

/***************** RUN CA/Random Boolean Network ***********************/

#include "edecfunc.h"

/***************  list of functions in this file ************/
/*void change_net_size(unsigned int newL)*/
/*void wire_rule_extra_cell(char increace)*/
/*void draw_range_single(void)*/
/*void draw_range_field(void)*/
/*void mutant_one_screen_single(void)*/
/*void upstream_only(void)*/
/*void draw_field(void)*/
void show_neutral_info(void);
void show_average_pp_hist(void);
/*void progress_bar(void)*/
/*void print_field_data(void)*/
/*void draw_basin(void)*/
void show_seed(char *this_firstseed);
void draw_att_state(char one_or_all);
void free_basin_memory(void);
/*void reset_neutral_buffs(void);*/
/*void restore_network_buffs(void);*/

/*for neutral orders*/
unsigned int **comp_type, comp_type_tot;/*count of component types*/
char temp_nonlocal;

/************** restore original size after range *****************/
/*void restore_size_after_range(unsigned int newL){*/
void change_net_size(unsigned int newL){
  signed int poss,zz,z,tablemax,sod;

    free_mem_CA_states();
    free_mem_wiring();
    if (rulemix){
       if (tot_only==0) free_mem_rulemix();
       free_mem_tcodemix();
    }
    
    L=lineL-1;
    bytesL=(signed int)ceil(((double)(value_bits*lineL))/8);
    allocate_mem_CA_states();

    if ((nhoodm=(char*)realloc(nhoodm,lineL*sizeof(char)))
					==NULL) outof_memory("nhoodm");
    if (nhood_mixed){
       for (poss=lineL-1;poss>=0;poss--){
	  while(!(nhoodm[poss]>=nhood_lb && nhoodm[poss]<=nhood))
						 nhoodm[poss]=myrand()%10;
       }
    }
    allocate_mem_wiring();
    if (whatwire==1) for (poss=lineL-1;poss>=0;poss--)
		  oneD_local_wire_cell(poss,lineL-1); /*rewire local*/
    else{  /*rewire random*/
       zonesize=lineL;
       for (poss=L;poss>=0;poss--) randomly_wire_cell(poss,L);
       cell_out_freq();
    }
    if (rulemix){
       if (tot_only==0) allocate_mem_rulemix(nhood);
       allocate_mem_tcodemix(nhood);
       for (poss=lineL-1;poss>=0;poss--){
	  if (nhood_mixed)
            tablemax=(signed int)pow(value_range,(double)nhood)-1;
	  if (totalistic==0){
	     for (zz=tablemax;zz>=0;zz--)
		 if (value_range==2){ 
                     set_bit(carule[poss],zz,(myrand()%100)/50);
                 }
                 else set_value(carule[poss],zz,myrand()%value_range);
	  }
	  else{
	     for (zz=nhoodm[poss];zz>=0;zz--)
				set_bit(cacode[poss],zz,(myrand() % 100)/50);
	     for (zz=tablemax;zz>=0;zz--){
		sod=0;
		for (z=nhoodm[poss]-1;z>=0;z--) sod+=get_bit(nm[z],zz);
		set_bit(carule[poss],zz,get_bit(cacode[poss],sod));
	     }
	  }
       }
    }
}

/************** add one cell, wire in and assigm rule *****************/
void wire_rule_extra_cell(char increace){ /*increace= -1 or +1*/
 signed int tablemax,tablebytes,z,zz,temp=0,
	      wire,codemax;
 unsigned int poss,depthL,rposs,tw;

   if (increace==0) return;
   tablemax=(signed int)pow(value_range,(double)nhood)-1;
   if (nhood_mixed && totalistic>0) return;
   if (increace==1){
      reallocate_mem_wiring(increace);/*for one more cell*/
      sprintf(textb[0],"nhoodm");
      if ((nhoodm=(char*)realloc(nhoodm,lineL*sizeof(char)))
					==NULL) outof_memory(textb[0]);
      if (!nhood_mixed) nhoodm[L]=nhood;
      else{
	 while(!(nhoodm[L]>=nhood_lb && nhoodm[L]<=nhood))
				     nhoodm[L]=myrand()%(nhood+1);
      }
   }
   /*rewire both ends for nhood/2 cells, local 1-D wiring*/
   if (nonlocal==0 || whatwire==1){
      
      /*if not watcom crashes if range start =1 (borland ok)*/
      if (nhood*2>=lineL){
	 for (poss=0;poss<=lineL-1;poss++) oneD_local_wire_cell(poss,L);
      }
      else{
	 depthL=(unsigned int)ceil((double)nhood/2);

	 /*right end*/
	 for (poss=0;poss<=depthL;poss++) oneD_local_wire_cell(poss,L);
	 /*left end*/
	 if (depthL<L){
	    for (poss=L-depthL;poss<=L;poss++)
		       oneD_local_wire_cell(poss,L);
	 }
      }
   }
   else if (increace==1){ /*wireup extra cell*/
      randomly_wire_cell(L,L);
      tw=0;/*total wires*/
      if (!nhood_mixed) tw=nhood*lineL;
      else{
	 for (poss=0;poss<=L;poss++) tw+=nhoodm[poss];
      }
      /*move av no of existing outwires to the new cell*/
      for (z=0;z<=tw/lineL;z++){
	 rposs=myrand()%lineL;/*random position*/
	 wiring[rposs][myrand()%(nhoodm[rposs]+1)]=L;
      }
   }
   else if (increace==-1){ /*re-wire all wires from removed cell*/
      for (poss=0;poss<=L+1;poss++){
	 for (wire=0;wire<=nhoodm[poss]-1;wire++){
	    /*rewire at random position*/
	    if (wiring[poss][wire]>L) wiring[poss][wire]=myrand()%lineL;
	 }
      }
   }
   if (increace==-1){
      reallocate_mem_wiring(increace);/*for one more cell*/
      sprintf(textb[0],"nhoodm");
      if ((nhoodm=(char*)realloc(nhoodm,lineL*sizeof(char)))
					==NULL) outof_memory(textb[0]);
   }
   cell_out_freq();

   if (rulemix){
      reallocate_mem_rulemix(nhood,increace);
      reallocate_mem_tcodemix(nhood,increace);
      if (increace==1){ /*this need updating $$$*/
	 if (nhood_mixed){/*assign a random rule at new cell*/
	    if (!totalistic){  
	       for (z=tablemax;z>=0;z--){
                   if (value_range==2){
                       set_bit(carule[L],z,(myrand()%100)/50);
                   }
                   else set_value(carule[L],z,myrand()%value_range);
               }
	    }
	    else{
	       codemax=(signed int)pow(2,(double)nhoodm[L]+1)-1;
	       for (z=codemax;z>=0;z--) set_bit(cacode[L],z,(myrand()%100)/50);
	       //convert code to rule
	       for (zz=tablemax;zz>=0;zz--){
		  temp=0;
		  for (z=nhoodm[L]-1;z>=0;z--) temp+=get_bit(nm[z],zz);
		  set_bit(carule[L],zz,
			       get_bit(cacode[L],temp));
	       }
	    }
	 }
	 else{ /*this need updating $$$*/
	    /*copy an exist rule from random pos to new cell*/
            tablebytes=(signed int)(value_bits * ceil(pow(value_range,(double)nhood)/8));
	    rposs=myrand()%L;
	    if (!totalistic) memmove(carule[L],carule[rposs],tablebytes);
	    else{ /*this need updating $$$*/
	       memmove(cacode[L],cacode[rposs],
			(signed int)ceil((double)(nhood+1)/8));
	       //convert code to rule
	       for (zz=tablemax;zz>=0;zz--){
		  temp=0;
		  for (z=nhood-1;z>=0;z--) temp+=get_bit(nm[z],zz);
		  set_bit(carule[L],zz,get_bit(cacode[L],temp));
	       }
	    }
	 }
      }
   }
   return;
}

/**** draw several single basins or trees for range of L, Sept 93 *******/
void draw_range_single(void){
 signed int z,basinrangecount=0;/*count of range of single basins or trees*/
 char *rangeseed;      /*constant seed for range of CA sizes*/
 char allbitssame;

   new_basin_row=1;
   firstxspacing=xspacing;
   firstyspacing=yspacing;

   allbitssame=1;/*check if this is a uniform state, all values same*/
   for (z=L;z>=1;z--){
	 if (get_value(bitseed,z)!=get_value(bitseed,z-1)){
            allbitssame=0;
            break;
         }
   }
   /*remember seed state*/
   if ((rangeseed=(char*)calloc(rangebytesL,sizeof(char)))
				      ==NULL) outof_memory("rangeseed");
   memmove(rangeseed,bitseed,rangebytesL);
   zonesize=lineL;
   for (L=startL-1;L<=endL-1;L++){
      if (is[0]=='q') break;
      totatt_states=isexception=0;
      /*next tree space-time pattern from the top*/
      if (stp){
	 setviewport(0, 0, (L+1)*scale+2, Maxy, 0);
	 clearviewport();
	 setviewport(0, 0, Maxx, Maxy, 0);
	 moveto(0,0);
      }
      if (!rulemix) show_rule_bottom(nhood,1,carule[0],0);
      basinrangecount+=1;
      if (basinrangecount>1){
	 free_mem_CA_states();
	 lineL=L+1;
         bytesL=(signed int)ceil(((double)(value_bits*lineL))/8);
	 wire_rule_extra_cell((char)1);
	 allocate_mem_CA_states();
         if (allbitssame==1){
            for (z=L;z>=0;z--) set_value(bitseed,z,get_value(rangeseed,0));
	 }
	 else memmove(bitseed,rangeseed,rangebytesL);

	 xspacing*=xspacefact;
	 yspacing*=yspacefact;
	 /*move position of next basin to the right*/
	 ox+=xspacing;
	 /*if too close to right edge of screen, start new row*/
	 if ((Maxx-ox)<(signed int)((float)xspacing*rightborder)){
	    ox=firstox;
	    oy+=yspacing;
            if (stagger_even_rows==1){
                new_basin_row++; /*stagger even rows*/
                if (new_basin_row%2==0) ox+=xspacing*.5;
	    }
	 }
      }
      i2d=lineL;
      j2d=1;
      if (basin_postScript) prepare_basinPS(1,0); /*redefine size of boxed nodes*/      
      /*draw basin of attraction*/
      if (direction=='f'){
	 bitflipcount=0;
         memmove(state1,bitseed,bytesL);/*to set basin seed*/
	 run_forward(carule);
      }
      /*if backward, upstream only, draw trees*/
      else upstream_only();
      if (pre_fansize_freq_hist) show_pre_fansize_freq_hist();
   }
   L-=1;
   lineL=L+1;
   bytesL=(signed int)ceil(((double)(value_bits*lineL))/8);
   if (mutantdontpause==0){
       /*close the postScript file -- for DOS to work*/ 
       if (basin_postScript) close(fid_PS);
       finish_options(1);
   }
   /*restore positions and spacing, for next mutant*/
   ox=firstox;
   oy=firstoy;	
   xspacing=firstxspacing;
   yspacing=firstyspacing;
   /*restore to original size*/
   change_net_size(startL);
   memmove(bitseed,rangeseed,bytesL);
   free(rangeseed);
   memory_box(1,NULL);
}

/**** draw several basin fields for range of L, Oct 93 ******************/
void draw_range_field(void){
 signed int startnumber;
    zonesize=lineL;
    /*position of CA size for each field*/
    if (stp) startnumber=vgax(13+scale*endL);
    else startnumber=vgax(3);
    if (firstox<startnumber+vgax(40)){
       firstox=startnumber+vgax(40);
       ox=firstox;
    }
    if (!rulemix) show_rule_bottom(nhood,1,carule[0],0);
    for (L=startL-1;L<=endL-1;L++){
       isexception=0;

       if (is[0]=='q') break;

       fieldno+=1;
       free_mem_CA_states();
       lineL=L+1;
       bytesL=(signed int)ceil(((double)(value_bits*lineL))/8);

       allocate_mem_CA_states();
       if (fieldno>1){
	  wire_rule_extra_cell((char)1);
	  /*start field on new line*/
	  xspacing*=xspacefact;
	  yspacing*=yspacefact;
	  ox=firstox;
	  oy+=yspacing;
          
          if (oy>Max_oy) oy=Max_oy; /*limit of oy for draw_fan()*/
       }
       i2d=lineL;
       j2d=1;   
       /*show CA size for each field*/
       moveto(startnumber,oy-CHeight/2);
       sprintf(textb[0],"%d.",lineL);
       outtext(textb[0]);       
       if (basin_postScript){
          sprintf(textb[0],"\n%%basin-field %d\n",lineL);
          vret=write(fid_PS,textb[0],strlen(textb[0]));
          sprintf(textb[0],
             "\ngsave /Times-Roman  findfont 18 scalefont setfont");
          vret=write(fid_PS,textb[0],strlen(textb[0]));
          sprintf(textb[0],
	     "\nnewpath %d %d moveto 0 setgray (%d.) show grestore",
		 startnumber,Maxy-(oy+CHeight/2),lineL);
          vret=write(fid_PS,textb[0],strlen(textb[0]));
          prepare_basinPS(1,0); /*redefine size of boxed nodes*/ 
       }
       moveto(ox,oy);
       draw_field();       
       print_field_data();
       if (fieldpause==1 && !pre_fansize_freq_hist){
          if (fieldpause==1 && lineL!=endL){
            signed int xbox;
              xbox=memory_box(-4.4,NULL);
	      moveto(xbox+vgax(3),vgay(3));
	      outtext("next field-ret nopause-q ops-o layout-a:");
	      input_string(1,0);
              if (is[0]=='q'){
	         datapause=0;
                 fieldpause=0;
              }
              else if (is[0]=='o') finish_options(1);
	      else if (is[0]=='a') amend_layout();
              is[0]='0';
              erase_memory_box(-4.4);
          }
          else finish_options(1);
       }
       if (pre_fansize_freq_hist) show_pre_fansize_freq_hist();
    }
    L-=1;
    lineL=L+1;
    bytesL=(signed int)ceil(((double)(value_bits*lineL))/8);
    if (mutantdontpause==0){
       /*close the postScript file -- for DOS to work*/
       if (basin_postScript) close(fid_PS);
       finish_options(1);      
    }
    /*restore to original size*/
    change_net_size(startL);
}

/************************  draw mautants on one screen *******************/
void mutant_one_screen_single(void){
 signed int basinrangecount=0,/*count of range of single basins or trees*/
             temp_ox,temp_oy;

   new_basin_row=1;
   temp_ox=ox;
   temp_oy=oy;
   mut=startmut+1;
   while(1){
      if (is[0]=='q') break;
      totatt_states=isexception=0;
      /*next tree space-time pattern from the top*/
      if (stp){
	 setviewport(0, 0, (L+1)*scale+2, Maxy, 0);
	 clearviewport();
	 setviewport(0, 0, Maxx, Maxy, 0);
	 moveto(0,0);
      }
      if (!rulemix) show_rule_bottom(nhood,1,carule[0],0);
      memmove(state1,bitseed,bytesL);   
      if (basinrangecount>0){         
         if (mutate<=1){
             mut-=1;
	     if (mut==endmut-1) break;
         }
	 /*mutate*/
	 mutate_rule(nhood);	 
	 /*move position of next basin to the right*/
	 ox+=xspacing;
	 /*if too close to right edge of screen, start new row*/
	 if ((Maxx-ox)<(signed int)((float)xspacing*rightborder)){
	    ox=firstox;
	    oy+=yspacing;
            if (stagger_even_rows==1){
               new_basin_row++; /*stagger even rows*/
               if (new_basin_row%2 == 0) ox+=xspacing*.5;
	    }
	 }
         if (oy>Maxy) break;
      }
      if (!twod && shownumbers==3 && showbits_1d_as_2d==1){
         if (i2d==0) set_i2dxj2d();
      }
      /*draw basin of attraction*/
      if (direction=='f') run_forward(carule);
      /*if backward, upstream only, draw trees*/
      else upstream_only();
      if (pre_fansize_freq_hist) show_pre_fansize_freq_hist();      
      if (mutate<=1 && basinrangecount==0){ 
	 ox=firstox-xspacing;  /*if 1bit sequential/cumulative mutants*/
	 oy+=yspacing;  /*isolate original rule in top row*/  	   
      }
      basinrangecount+=1;
      /*input_string(1,0);*/
   }
   ox=temp_ox;
   oy=temp_oy;
   if (mutantdontpause==0) finish_options(1);
}

/*************** backwards upstream from given state, Aug 93 ********/
void upstream_only(void){
    
  signed int tempx,tempy,xbox,timemin;
  unsigned long totsubtreegofE=0,elapsedtime,tickoffbytes;
  unsigned int zu;
  
#if __WATCOM__
  clock_t starttime, endtime;
#elif __UNIX__
  unsigned long starttime,starttime_m,
                endtime,endtime_m;
  long  elapsedtime_m;
  struct timeval  tp;
  struct timezone tzp;
#endif
  float timesec;
  char printhex=0,this_isrepeat=0; 
  /* char *this_firstseed, now a global variable*/


/*----------------------------------------------------------------*/
      /*all possible orders = factorial of size*/
   if (neutral_order==1 && basinfield==0){
       /*
       unsigned int z;
       char wire;
       for (z=0;z<=lineL-1;z++){
           for (wire=nhood-1;wire>=0;wire--){ 	 
	      if (wire<=nhoodm[z]-1){
	          fprintf(stderr,"A:%d z=%d wire=%d %d\n",
	            nhoodm[z],z,wire,wiring[z][wire]); 
              }	 
           }
       }	
       */
       show_rule_bottom(nhood,1,carule[0],0);       
       reset_neutral_buffs();      
       moveto(vgax(200),vgay(315));
       sprintf(textb[6],"order seed, max=(dec)%lu=(hex)%lx ",
                             statespace,statespace);
        
       select_seed(0,bitseed, textb[6], 1);       
       
       setviewport(0,0,Maxx,Maxy,0);
       clearviewport();

       tickspace=statespace;
       tickoffbytes=(unsigned long)ceil( (double) (tickspace+1)/8 );
       if ((tickoff=(char *)calloc(tickoffbytes,sizeof(char)))
					==NULL) outof_memory("tickoff");
             
   }
   /*----------------------------------------------------------------*/
   justonepreimage_found=0;/* to prevent level problems in multi_value*/

   #  if __WATCOM__
      starttime = clock();  /*start time*/
#  elif __UNIX__   
      sprintf(textb[0],"tp");
      sprintf(textb[0],"tzp");
       
      gettimeofday(&tp,&tzp);
      starttime=(unsigned long)tp.tv_sec; /*xwindows*/
      starttime_m=(unsigned long)tp.tv_usec;
#  endif

   if (exhaustive_testing){
      prestate_successor_pairs();
      if (is[0]=='q'){
	 if (screensavedemo==0) mutantdontpause=0;
         return;
      }
   }
   else if (neutral_order); /*do nothing*/
   else if (nonlocal || nhood_mixed) prepair_pre_rand();
   
   /* now a global calloced in allocx.c */
   /*if ((this_firstseed=(char *)calloc(bytesL,sizeof(char)))
            ==NULL) outof_memory("this_firstseed");*/

   if (show_ss_matrix) show_statespace_matrix(NULL);

   attperiod=cyclematch=totsubtree=isexception=0;
   totatt_states=maxtreefan=0;
   totsubtreegofE=0;
   totsubgofEdensity=0;

   memmove(state1,bitseed,bytesL);
   if (stepforward>0) run_forward(carule);
   memmove(firstseed,state1,bytesL);
   memmove(this_firstseed,state1,bytesL);

 
   if (NULLboundaries==1) dontcompress=1;
   /*{ signed int z;
     fprintf(stderr,"\nNULLboundaries=%d dontcompress=%d lineL=%d",
                           NULLboundaries,dontcompress,lineL);
   fprintf(stderr,"\nbseed=");
   for (z=L;z>=0;z--) fprintf(stderr,"%d",get_value(bitseed,z));
   fprintf(stderr,"\nfseed=");
   for (z=L;z>=0;z--) fprintf(stderr,"%d",get_value(firstseed,z));
   fprintf(stderr,"\ntseed=");
   for (z=L;z>=0;z--) fprintf(stderr,"%d",get_value(this_firstseed,z));
   }*/

   linec=black;
   if ((nonlocal==0 || compress_1d_local==1 || regular2d)
	&& !dontcompress && !rulemix && exhaustive_testing!=2){
      /*allocate mem for pre-images of all 0s and 1s*/
      if (regular2d){
	 sprintf(textb[0],"seg_2d_0");
	 if ((seg_2d_h=(signed int*)calloc(1, sizeof(signed int)))
				 ==NULL) outof_memory(textb[0]);
	 sprintf(textb[0],"seg_2d_1");
	 if ((seg_2d_v=(signed int*)calloc(1, sizeof(signed int)))
				 ==NULL) outof_memory(textb[0]);
      }
      else{
	 sprintf(textb[0],"seg");
	 if ((seg = (signed int*)calloc(1, sizeof(signed int)))
				 ==NULL) outof_memory(textb[0]);
      }
      sprintf(textb[0],"segseed");
      if( (segseed =(char**) calloc(2,sizeof(char*)))
				 ==NULL) outof_memory(textb[0]);
   }
   maxtreelevel=justonepreimage=insegloop=0;
   if (!rulemix) show_rule_bottom(nhood,1,carule[0],0);
   else if ((neutral_order==1 || seq_update) && basinfield==0)
                             show_rule_bottom(nhood,1,carule[0],0);   
   earlyexit=0;  
   if (show_one_att_state) show_seed(this_firstseed);

   if (neutral_order==1){
      if (dec_equiv(state1,L)<=tickspace)
			  set_bitlong(tickoff,dec_equiv(state1,L),1);     
   }
   run_backward();
   
   this_isrepeat=isrepeat;
   if (segfan){  /*run back from each segfan state*/     
      if (pdata==2 || filedata==2){  /*tree data*/
	 sprintf(textb[0],"   tree. root  no  s  g  gd  ml  mp\n");
	 if (pdata==2) print_out(textb[0]);
	 if (filedata==2) save_data(textb[0]);
      }
      insegloop=1;
      segfan=0;
      for (segindex=1;segindex<=segno;segindex++){
	 memmove(firstseed,segseed[segindex],bytesL);

         /*fprintf(stderr,"\nfseed%d=",segindex);
	   for (z=L;z>=0;z--) fprintf(stderr,"%d",get_value(firstseed,z));*/

	 startsegfan=1;
	 run_backward();
         if (this_isrepeat==0) this_isrepeat=isrepeat;         
	 /*to interrupt*/
	 if (is[0]=='q'){
	    earlyexit=1;
	    if (screensavedemo==0) mutantdontpause=0;
	    break;
	 }
	 /*interrupt tree, continue with next tree*/
	 if (is[0]=='n'){
	    earlyexit=1;
	    memory_box(1,NULL);
	    continue;
	 }
	 if (regular2d){
	    totsubtree+=treesize*
	            seg_2d_h[segindex]*seg_2d_v[segindex];
	    totsubtreegofE+=gofEno*seg_2d_h[segindex]*seg_2d_v[segindex];
	 }
	 else{
	    totsubtree+=treesize*seg[segindex];
	    totsubtreegofE+=gofEno*seg[segindex];
            /*fprintf(stderr,"\n %d totsubtreegofE=%lu gofEno=%lu seg[%d]=%d", 
              segindex,totsubtreegofE, gofEno, segindex,seg[segindex]);*/
	 }
      }
      insegloop=0;
      /*free fanseg memory*/
      free(segx); 		/*free fanseg co-ords*/
      free(segy); 		/*free fanseg states*/
      if (justonepreimage) totsubtree+=2;
      else totsubtree+=1;
      /*if attractor cycle included*/
      if (this_isrepeat==1) totsubtreegofE-=1;
      /*fprintf(stderr,"\n ir=%d %lu : %lu", 
	this_isrepeat,totsubtreegofE,gofEno);*/
   }
   else{
      /*to interrupt*/
      if (is[0]=='q'){
	 earlyexit=1;
	 memory_box(1,NULL);
	 if (screensavedemo==0) mutantdontpause=0;
      }
      totsubtree=treesize;
      /*if attractor cycle included*/
      if (this_isrepeat==1) totsubtreegofE=gofEno-1;
      else totsubtreegofE=gofEno;
   }
   if (exhaustive_testing){
      free(exh_pairs);
      free(tickoff);
      //fprintf(stderr,"\n 1:free(tickoff)"); //fprintf?? 
   }
   else if (!neutral_order && (nonlocal || nhood_mixed)) free_pre_rand();

   if ((nonlocal==0 || compress_1d_local==1 || regular2d)
      && !dontcompress && !rulemix && exhaustive_testing!=2){
      if (segno>0) for (zu=1;zu<=segno;zu++) free(segseed[zu]);
      free(segseed);
      if (regular2d){
	 free(seg_2d_h);
	 free(seg_2d_v);
      }
      else free(seg);
   }
   totsubgofEdensity=(float)totsubtreegofE/totsubtree;
   
   if (neutral_order==1){
      tempx=getx;
      tempy=gety;
      moveto(ox,oy);
      putpixel(getx,gety,white);
      moveto(tempx,tempy);
   }
   else if (show_one_att_state) show_seed(this_firstseed);
   
   /*pause to show tree data*/
   if (screensavedemo) return;

   xbox=draw_prompt_box(2);
   setcolor(white);

   if (neutral_order==1) sprintf(textb[0],"NTO");
   else if (seq_update) sprintf(textb[0],"SEQ");
   else if (exhaustive_testing==2) sprintf(textb[0],"MAP");
   else if (exhaustive_testing==1) sprintf(textb[0],"EXH");   
   else if (nonlocal==0) sprintf(textb[0],"CAW");
   else if (nonlocal==1) sprintf(textb[0],"NLW");
   inset_prompt_box(0,6,textb[0],'d');

   if (earlyexit){
      sprintf(textb[2],"EarlyExit part ");
      maxtreelevel=level;
      if (screensavedemo==0) mutantdontpause=0;
   }
   else if (neutral_order==0){
        if (NULLboundaries==1) sprintf(textb[2],"%s","NBC ");
        else sprintf(textb[2],"%s","PBC ");
   }
   else sprintf(textb[2],"%s","");

   if (neutral_order==1){
       sprintf(textb[0],"%sneutral component size=%lu ",textb[2],totsubtree);
       outtext(textb[0]);
   }
   /*subtree only*/
   else{
       if (this_isrepeat==0) 
              sprintf(textb[0],"%ssubtree=%lu ",textb[2],totsubtree);
       else sprintf(textb[0],"%ssubtree=basin=%lu ",textb[2],totsubtree);
       outtext(textb[0]);
   }
   /*states with maj of given value -- highlighted in basins*/
   if (show_maj>=0){ 
	sprintf(textb[0],
           " maj%d=%lu=%.3g ",show_maj,isexception,(double)isexception/totsubtree);
	outtext(textb[0]);
    }

   sprintf(textb[1],"root(hex)=");   
   if (lineL<=56) outtext(textb[1]);
   
   /*data for display when component field is complete*/
   if (basinfield && neutral_order==1){
      char ctype_found;
      
      totbasinsinfield+=1; 
      fieldsize+=totsubtree;      
      fieldgofE+=totsubtreegofE;
      if (fieldsize>0) fieldgofEdensity=(float)fieldgofE/fieldsize;

      ctype_found=0;
      if (comp_type_tot>0){
         for (zu=0; zu<=comp_type_tot-1; zu++){
	    if (comp_type[zu][0]==totsubtree){
	       comp_type[zu][1]+=1;
	       ctype_found=1;
	       break;
            }
	 }
      }
      if (ctype_found==0){
	  comp_type_tot+=1;
	  /*for new type*/	  
	  if (comp_type_tot>0){	     
	     if ((comp_type=(unsigned int **)realloc
	       (comp_type,comp_type_tot*sizeof(unsigned int *)))
				==NULL) outof_memory("(comp_type");
	     if ((comp_type[comp_type_tot-1]=
	       (unsigned int *)calloc(2,sizeof(unsigned int)))
				 ==NULL) outof_memory("comp_type[]");
	  }
	  comp_type[comp_type_tot-1][0]=totsubtree;
	  comp_type[comp_type_tot-1][1]+=1;
      }	  
   }
     
   if (pdata || filedata){
      printhex=1;
      if (pdata){
	 print_out(textb[0]);
	 print_out(textb[1]);
      }
      if (filedata){
	 save_data(textb[0]);
	 save_data(textb[1]);
      }
   }
   if (lineL<=56) /*7 bytes max to fit in box*/
     print_current_bitstring_hexbytes(0,0,this_firstseed,0,Maxx,white,printhex);
   else { /*printer or file only*/
     print_current_bitstring_hexbytes(0,0,this_firstseed,0,Maxx,white,3);
   }
   moveto(xbox,gety+CHeight);
   sprintf(textb[0],"g=%lu=%.3g ml=%d mp=%lu",
			totsubtreegofE,totsubgofEdensity,
						maxtreelevel,maxtreefan);
   outtext(textb[0]);
   if (pdata){
      print_out("\n");
      print_out(textb[0]);
      print_out("\n");
   }
   if (filedata){
      save_data("\n");
      save_data(textb[0]);
      save_data("\n\n");
   }

#  if __WATCOM__
      endtime = clock();  /*start time*/
#  elif __UNIX__  
      gettimeofday(&tp,&tzp);
      endtime=(unsigned long)tp.tv_sec; /*xwindows*/
      endtime_m=(unsigned long)tp.tv_usec;
#  endif   

   if (earlyexitfield==0){
#     if __WATCOM__      
         elapsedtime=(unsigned long)(endtime-starttime);
         timesec=(float)elapsedtime/(unsigned long)CLK_TCK;
         if (timesec>59){
	    timemin=(signed int)(timesec/60);
	    timesec-=timemin*60;
	    sprintf(textb[2],"  %dmin %.3fsec",timemin,timesec);
         }
         else sprintf(textb[2],"  %.3fsec",timesec);
         outtext(textb[2]);
#     elif __UNIX__  
         elapsedtime=endtime-starttime;
         elapsedtime_m=endtime_m-starttime_m;     
         if (elapsedtime_m<0){ 
            elapsedtime-=1;
            elapsedtime_m=(1000000-starttime_m)+endtime_m;
         }
         timesec=(float)
               ((elapsedtime%60)+((float)elapsedtime_m/1000000));
         if (elapsedtime>=60){
            timemin=elapsedtime/60;
            sprintf(textb[2],"  %dmin %.3fsec",timemin,timesec);
         }
         else sprintf(textb[2],"  %.3fsec",timesec);     
         outtext(textb[2]);
#    endif

   }

   /*to show average stack histogram*/
   if (see_ppstack && (nonlocal || nhood_mixed)) show_average_pp_hist();

   if (basinfield && datapause){ 
	xbox=memory_box(-4,NULL);
	moveto(xbox+vgax(3),vgay(3));
	outtext("next basin-ret nopause-q ops-o layout-a:");
	input_string(1,0);
	if (is[0]=='a') amend_layout();
	if (is[0]=='o') finish_options(1);
        erase_memory_box(-4);        
   }

   else if (!basinfield && rangeL && datapause){
      if (lineL!=endL){
	 xbox=memory_box(-4,NULL);
	 moveto(xbox+vgax(3),vgay(3));
	 outtext("options-o layout-a:");
	 input_string(1,0);
	 if (is[0]=='a') amend_layout();
	 if (is[0]=='o') finish_options(1);
         erase_memory_box(-4);
      }
      else finish_options(1);
   }
   /*free(this_firstseed);*/ /* now global, freed in allocx.c */
   /*----------------------------------------------------------*/
   if (neutral_order==1 && basinfield==0){   
       free(tickoff);
       //fprintf(stderr,"\n 2:free(tickoff)"); //fprintf??
       restore_network_buffs();
       neutral_order=0;
   }

    /*fprintf(stderr,"\nin upsteam_only istr_graph=%d ibaf_graph=%d jump_graph=%d",
      istr_graph,ibaf_graph,jump_graph);*/
   
    if (istr_graph==1 && jump_graph==0){
     unsigned int zw,node_no;
        /*graph_type=='t' for istr graph (interactive state transition graph), May 2025*/
        jump_graph_table(0,NULL,'t');
    }
}

/**************** reset buffers for neutral orders  **********************/
void reset_neutral_buffs(void){
   signed int z1;
   
       statespace=fact((char)lineL)-1;
       /*fprintf(stderr,"%d!==%lu \n",lineL,statespace);*/
       /*re-allocate seed states (fact(n)>2^n)*/
       free(bitseed);
       free(firstseed);
       free(state1);
       free(state2);
       free(all_0s);       
       /*no of bits required for fact(lineL)?*/
       for (z1=1;z1<=31;z1++){ /*check if this still works $$$*/
	 /*fprintf(stderr,"z1=%d %lu\n",z1,(unsigned long)pow(2,z1));*/
	   if (pow(2,z1)>=statespace) break;
       }
       temp_nonlocal=nonlocal;
       nonlocal=1;
       templineL=lineL; //templineL is global, use to restore
       
       lineL=z1;
       /*fprintf(stderr,"lineL=%d\n",lineL);*/
       L=lineL-1;
       bytesL=(signed int)ceil(((double)(value_bits*lineL))/8);
       /*fprintf(stderr,"lineL=%d bytesL=%d hyper_prob=%d\n",
	       lineL,bytesL,hyper_prob);*/
       temp_i2d=i2d;
       temp_j2d=j2d;
       set_i2dxj2d();
       
       if ((bitseed=(char *)calloc(bytesL,sizeof(char)))
				     ==NULL) outof_memory("bitseed");
       if ((firstseed=(char *)calloc(bytesL,sizeof(char)))
				     ==NULL) outof_memory("firstseed");
       if ((state1=(char *)calloc(bytesL,sizeof(char)))
	                             ==NULL) outof_memory("state1");
       if ((state2=(char *)calloc(bytesL,sizeof(char)))
	                             ==NULL) outof_memory("state2");
       if ((all_0s=(char *)calloc(bytesL,sizeof(char)))
				     ==NULL) outof_memory("all_0s");


}
/**************************** draw field, Aug 93 **********************/
void restore_network_buffs(void){
       
       /*restore re-allocate seed states (fact(n)>2^n)*/
       free(bitseed);
       free(firstseed);
       free(state1);
       free(state2);
       free(all_0s);
       
       nonlocal=temp_nonlocal;
       lineL=templineL;
       L=lineL-1;
       bytesL=(signed int)ceil(((double)(value_bits*lineL))/8);
       i2d=temp_i2d;
       j2d=temp_j2d;
       
       if ((bitseed=(char *)calloc(bytesL,sizeof(char)))
				     ==NULL) outof_memory("bitseed");
       if ((firstseed=(char *)calloc(bytesL,sizeof(char)))
				     ==NULL) outof_memory("firstseed");
       if ((state1=(char *)calloc(bytesL,sizeof(char)))
	                             ==NULL) outof_memory("state1");
       if ((state2=(char *)calloc(bytesL,sizeof(char)))
	                             ==NULL) outof_memory("state2");
       if ((all_0s=(char *)calloc(bytesL,sizeof(char)))
				     ==NULL) outof_memory("all_0s");
}

/**************************** draw field, Aug 93 **********************/
void draw_field(void){
 
 signed int z,timemin;
 unsigned long elapsedtime,tickoffbytes;
 float timesec;
#if __WATCOM__
 clock_t starttime, endtime;
#elif __UNIX__
 unsigned long starttime, starttime_m,
               endtime,endtime_m;
 long elapsedtime_m;
 struct timeval tp;
 struct timezone tzp;
#endif
 char stoprange=0;
 unsigned long zu;

 //fprintf(stderr,"\nin draw_field");

#  if __WATCOM__
      starttime = clock();  /*start time*/
#  elif __UNIX__   
      sprintf(textb[0],"tp");
      sprintf(textb[0],"tzp");
      gettimeofday(&tp,&tzp);
      starttime=(unsigned long)tp.tv_sec; /*xwindows*/
      starttime_m=(unsigned long)tp.tv_usec;
#  endif 

   Max_oy=Maxy*2; //reset if changed
   if (ibaf_graph==1 && exhaustive_testing && jump_graph==0) Max_oy=Maxint;    
   //usually if way below screen dont'draw -- but for ibaf-graph draw all as can be shrunk
      
   new_basin_row=1;
   if (jump_graph && use_preset_basin_pos==0){   
      /*initialise memory for jump-graph*/
      /*fprintf(stderr,"\n about to calloc nominal att period array m_att_period");*/  
      if ((m_att_period=(unsigned int*)calloc(1,sizeof(unsigned int)))
				     ==NULL) outof_memory("m_att_period");
      m_att_period[0]=0;

      //fprintf(stderr,"\ninitial calloc m_basin_volume for just 1");
      /*changed to long from int because of big basins, Dec 2001*/
      if ((m_basin_volume=(unsigned long*)calloc(1,sizeof(unsigned long)))
				     ==NULL) outof_memory("m_basin_volume");
      m_basin_volume[0]=0;

      /*fprintf(stderr,"\n about to calloc m_att***");*/  
      if ((m_att=(char***) calloc(1,sizeof(char**)))
               ==NULL) outof_memory("m_att***");

      /*fprintf(stderr,"\n about to calloc m_att**"); */
      if ((m_att[0]=(char**) calloc(1,sizeof(char*)))
               ==NULL) outof_memory("m_att**");

      if ((m_att[0][0]=(char *)calloc(1,sizeof(char)))
				     ==NULL) outof_memory("m_att*");
   }

   maxfieldfan=1;
   /*firstox=ox;*/
   limitcheck=Maxu-1; /*was 10000*/
   earlyexitbasin=earlyexitfield=0;
   basintypeno=totbasinsinfield=fieldgofE=fieldgofEdensity=0;
   fieldsize=0;
   if (show_ss_matrix) show_statespace_matrix(NULL);
   /*keep track of cycle length frequency*/
   if ((cycles=(unsigned int*)calloc(10,sizeof(unsigned int)))
					==NULL) outof_memory("cycles");
   
   
   if (exhaustive_testing){
     if (ibaf_graph==1  && jump_graph==0){
         /*create array of basin positions [node_no][0]=x, [node_no][1]=y
         to be filled-in in drawxx.c
         otherwize done in grahpxx.c*/
       
       /*calloc and free now done in main for both istr and ibaf graphs 19/06/25
       unsigned int zw,node_no;
	 node_no=(unsigned int)(pow(value_range,(double)lineL)); //size of state-space
         if ((basin_pos=(signed int**)calloc(node_no+1,
		   sizeof(signed int*)))==NULL) outof_memory("basin_pos");
	 for (zw=0;zw<=node_no;zw++){
	          if ((basin_pos[zw]=(signed int *)calloc(
			2,sizeof(signed int)))==NULL) outof_memory("basin_pos[]");
	 }*/
      }
      is[0]=0;

      //fprintf(stderr,"\ndraw_field -- ep_in_jump_nodes=%d",exh_pairs_in_jump_nodes);
      prestate_successor_pairs();
      
      if (is[0]=='q'){
	 earlyexitfield=1;
	 mutantdontpause=0;
      	 free(cycles);
	 return;
      }
   }
   else if (neutral_order); /*do nothing*/
   else if (nonlocal || nhood_mixed) prepair_pre_rand();

   if ((!rulemix && !rangeL && neutral_order==0) || seq_update)
          show_rule_bottom(nhood,1,carule[0],0);
   /*key to basin data*/
   if (pdata || filedata){
      sprintf(textb[0],"\nty.  at  no  (p)  s  %%  g  gd  ml  mp\n");
      if (pdata) print_out(textb[0]);
      if (filedata) save_data(textb[0]);
      if (pdata==2 || filedata==2){  /*tree data*/
	 sprintf(textb[0],"   tree. root  no  s  g  gd  ml  mp\n");
	 if (pdata==2) print_out(textb[0]);
	 if (filedata==2) save_data(textb[0]);
      }
   }
   /*------------------------------------------------------------*/
   /*all possible orders = factorial of size*/
   if (neutral_order==1){
       show_rule_bottom(nhood,1,carule[0],0);
      
       reset_neutral_buffs();
              
       /*allocate mem for component types*/
       comp_type_tot=0;
       if ((comp_type=
	       (unsigned int **)calloc(1,sizeof(unsigned int *)))
			    ==NULL) outof_memory("comp_type");
       if ((comp_type[0]=
	       (unsigned int *)calloc(2,sizeof(unsigned int)))
			    ==NULL) outof_memory("comp_type[]");
       tickspace=statespace;
       tickoffbytes=(unsigned long)ceil( (double) (tickspace+1)/8 );
       if ((tickoff=(char *)calloc(tickoffbytes,sizeof(char)))
					==NULL) outof_memory("tickoff");	  
   }
   /*------------------------------------------------------------*/
   else{ 
      statespace=(unsigned long)(pow(value_range,(double)lineL)-1);

      /*fprintf(stderr,"\nn=%d statespace=%lu",lineL,statespace+1);*/
      tickspace=statespace;   
      tickoffbytes=(unsigned long)ceil( (double) (tickspace+1)/8 );
      /*fprintf(stderr,"\ntickoffbytes=%lu GiB=%f",tickoffbytes, 
	                          (double)tickoffbytes/1073741824);*/
      if ((tickoff=(char *)calloc(tickoffbytes,sizeof(char)))
					==NULL) outof_memory("tickoff-FIELD");
   }
   
   memory_box(1,NULL);
   progress_bar(); /* for progress through statespace bar*/
   progbar=segstates=totatt_states=0;

   for (sspace=0;sspace<=tickspace;sspace++){      
      /*interrupt the field*/
      if (is[0]=='q'){
	 if (rangeL){
	    startinterrupt:
	    draw_prompt_box(1);
	    outtext("getout-q, options-o, nextfield-RET:");
	    input_string(1,0);
	    if (is[0]=='q'){
	       erase_prompt_box(1);
	       stoprange=1; 
	    }
	    if (is[0]=='o'){
	       finish_options(1);
	       goto startinterrupt;
	    }
	 }
	 earlyexitfield=1;
	 mutantdontpause=0; 
	 break;
      }
      if (get_bitlong(tickoff,sspace)){
	//fprintf(stderr,"\ntickoff,sspace:%lu",sspace); //added
              continue;
      }
      //check??01
      //fprintf(stderr,"\n next free=%lu",sspace); //fprintf??
      //for (zu=0;zu<=tickspace;zu++) fprintf(stderr,"%d",get_bitlong(tickoff,zu));
      
      basintypeno+=1;
      if (basin_postScript){
	 sprintf(textb[0],"\n%%basin %d\n",basintypeno);
         vret=write(fid_PS,textb[0],strlen(textb[0]));
      }
      /*draw line in progress bar indicating pos of seed*/
      moveto(barxl+(signed int)((float)(barxr-barxl)*
		       ((float)(sspace+1)/(statespace+1))),baryt-2);
      lineto(getx,baryb+2);
      if (use_preset_basin_pos==1){
         ox=basin_pos[basintypeno][0];
         oy=basin_pos[basintypeno][1];
      }
      else{
         if (basintypeno>1){	 
	    /*show each basin in field on whole screen in succession*/
	    if (successive_basins==1){
	       clearviewport();
	       ox=firstox;
	       oy=firstoy;
               if (oy>Max_oy) oy=Max_oy; /*limit of oy for draw_fan()*/               
	       progress_bar(); /* for progress through statespace bar*/
	    }
	    else{
	       /*move position of next basin to the right*/
	       ox+=xspacing;
	       /*if too close to right edge of screen, start new row*/
	       if ((Maxx-ox)<(signed int)((float)xspacing*rightborder)){
	          ox=firstox;
	          oy+=yspacing;
                  if (oy>Max_oy) oy=Max_oy; /*limit of oy for draw_fan()*/
                  if (stagger_even_rows==1){
                    new_basin_row++; /*stagger even rows*/
                    if (new_basin_row%2 == 0) ox+=xspacing*.5;
	         }
	       }
	    }
         }
      }

      memmove(bitseed,all_0s,bytesL); /*set seed array to null*/
      if (value_range==2) dec_to_bit_line(bitseed,sspace,lineL); 
      else dec_to_value_line(bitseed,sspace,lineL);

      //fprintf??
      //fprintf(stderr,"\nnext sspace:%lu ----------next basin----------------\n",sspace);
  
      memmove(state1,bitseed,bytesL);
      if (neutral_order==1) upstream_only();   
      else run_forward(carule);
        
      if (stp){
	  moveto(0,0);
	  if (nowscrolling==1){
#            if __WATCOM__
	        freeimage(stpimage);
#            endif
	     nowscrolling=0;
	 }
      }
   }
    
   free(tickoff);
   //fprintf(stderr,"\n end field 3:free(tickoff)"); //fprintf??
   memory_box(1,NULL);
  
   if ((!rulemix && neutral_order==0) || seq_update)
          show_rule_bottom(nhood,0,carule[0],0);
   
#  if __WATCOM__
      endtime = clock();  /*start time*/
#  elif __UNIX__   
      gettimeofday(&tp,&tzp);
      endtime=(unsigned long)tp.tv_sec; /*xwindows*/
      endtime_m=(unsigned long)tp.tv_usec;
#  endif   

   sprintf(textb[2],"%s","");
   if (earlyexitfield==0){
#     if __WATCOM__
         elapsedtime=(unsigned long)(endtime-starttime);
         timesec=(float)elapsedtime/(unsigned long)CLK_TCK;
         if (timesec>59){
	    timemin=(signed int)(timesec/60);
	    timesec-=timemin*60;
	    sprintf(textb[2],"  %dmin %.3fsec",timemin,timesec);
         }
         else sprintf(textb[2],"  %.3fsec",timesec);         
         /*sprintf(textb[0],"progbar=%lu statespace=%lu segstates=%d",
     				   progbar,statespace+1,segstates);*/
#    elif __UNIX__
         elapsedtime=endtime-starttime;
         elapsedtime_m=endtime_m-starttime_m;
         if (elapsedtime_m<0){ 
            elapsedtime-=1;
            elapsedtime_m=(1000000-starttime_m)+endtime_m;
         }
         timesec=(float)
               ((elapsedtime%60)+((float)elapsedtime_m/1000000));
         if (elapsedtime>=60){
            timemin=elapsedtime/60;
            sprintf(textb[2],"  %dmin %.3fsec",timemin,timesec);
         }
         else sprintf(textb[2],"  %.3fsec",timesec);
         /*print times to the terminal*/
         /*fprintf(stderr,"\n %d: %s",lineL,textb[2]);*/

#    endif
      sprintf(textb[0],"ERROR excess states=%ld",
			(signed long)progbar-(statespace+1));
      if (progbar != statespace+1){
	 setcolor(white);
	 moveto(barxl+2,baryb+vgay(4));
	 setfillstyle(SOLID_FILL,black);
	 bar(getx,gety,barxr-2,baryb+vgay(12));
	 outtext(textb[0]);
         //input_string(1,0); //fprintf??
      }
      if (fieldpause==1) stoprange=1;
   }

   if (stoprange) is[0]='q';
   else is[0]=0;

   /*to show average stack histogram*/
   if (see_ppstack && (nonlocal || nhood_mixed)) show_average_pp_hist();
   if (exhaustive_testing==2){
       /*draw_box(-1,vgax(200),Maxy-vgay(30),Maxx-vgay(2),Maxy-vgay(130),1,0);*/
      moveto(vgax(230),rule_box_top+CHeight*.5);
      outtext("cycle period: ");
      moveto(vgax(300),rule_box_top+CHeight*.5);
      for (z=1;z<=9;z++){
         sprintf(textb[3],"%d",z);
         outtext(textb[3]);
	 moveto(vgax(300)+CWidth*3*z,rule_box_top+CHeight*.5);
      }
      
      outtext("10+");
      
      moveto(vgax(230),rule_box_top+CHeight*1.5);
      outtext("cycle frequency: ");
      moveto(vgax(300),rule_box_top+CHeight*1.5);
      for (z=1;z<=9;z++){
         sprintf(textb[3],"%d ",cycles[z]);
         outtext(textb[3]);
	 moveto(vgax(300)+CWidth*3*z,rule_box_top+CHeight*1.5);
      }
      sprintf(textb[3],"%d ",cycles[0]);
      outtext(textb[3]);
   }
   
   /*----- section of code moved to end of  of print_field_data, April 2021 -----------*/
   
}


/***** show neutral component info in a window on the right of the screen ****/
void show_neutral_info(void){ 
   signed int leftbox,topbox;
       unsigned int zu,* tempbuf;      
       char sortneeded;

       char indexjump;   
       unsigned long index,maxindex=0,startindex=0;
       signed int xbox;
        restore_network_buffs();
        while(1){
           sortneeded=0;
	   for (zu=1;zu<=comp_type_tot-1;zu++){              
	       if (comp_type[zu-1][0]>comp_type[zu][0]){		 
		      /*swap buffers*/
		      tempbuf=comp_type[zu-1];
		      comp_type[zu-1]=comp_type[zu];
                      comp_type[zu]=tempbuf;
                      sortneeded=1;		  
	      }	      
	   }
	   if (sortneeded==0) break;
       }
       
       leftbox=Maxx-vgax(120);
       topbox=vgay(45);
        
       /*
       for (zu=0;zu<=comp_type_tot-1;zu++){
	   fprintf(stderr,"%d:%d,%d ",
		   zu,comp_type[zu][0],comp_type[zu][1]);
	   if (zu%5==0) fprintf(stderr,"\n"); 
       }*/
       maxindex=comp_type_tot-1;
    startjump:
   
       if (!indexjump) startindex=0;
       indexjump=0;
       
       draw_box(-1,leftbox,topbox,Maxx-2,Maxy-2,1,0);
       xbox=leftbox+vgax(3);
       sprintf(textb[0],"total components=%d",totbasinsinfield);
       outtext(textb[0]);
       moveto(xbox,gety+CHeight);
       outtext("type: size freq"); 	   	   	   
       moveto(xbox,gety+CHeight);
	
       /*for (zu=0;zu<=comp_type_tot-1;zu++){*/
       for (index=startindex;index<=maxindex;index++){
           if (gety>=Maxy-vgay(20)-3*CHeight){
              moveto(xbox,gety-CHeight);
	      break;
	   }
       	   
	   sprintf(textb[0],"%lu:  ",index+1);
	   outtext(textb[0]); 
	   sprintf(textb[0],"%d  %d ",
		   comp_type[index][0],comp_type[index][1]);
	   outtext(textb[0]);	   	   
	   moveto(xbox,gety+CHeight);
       }
       moveto(xbox,gety+CHeight);
       if (index<maxindex) sprintf(textb[0],
	           "quit-q jump-j more-ret:");
       else sprintf(textb[0],"quit-q jump-j top-ret:");
       outtext(textb[0]);
       input_string(1,0);
       if (is[0]=='q'); /*do nout*/
       
       else if (is[0]=='j'){ /*jump to new cell poss*/
          setfillstyle(SOLID_FILL,black);
          bar(xbox,gety+2,Maxx-3,gety+CHeight+2);
          sprintf(textb[0],"jump to index (0-%lu):",maxindex);
          moveto(xbox,gety);
          outtext(textb[0]);
          sprintf(textb[0],"%lu",maxindex);
          input_string(strlen(textb[0]),0);

          if (atol(is)>=0 && atoi(is)<=maxindex){
	     startindex=atol(is);
	     indexjump=1;
	     draw_box(-1,leftbox,topbox,Maxx-2,Maxy-2,1,0);	   
	     goto startjump;
          }
        }
        else if (is[0]==13){ /*continue to next index*/
           if (index<maxindex) startindex=index;
           else startindex=0;
           indexjump=1;
	   /*draw_box(-1,leftbox,topbox,Maxx-2,Maxy-2,1,0);*/
           goto startjump;
        }

       
       for (zu=0;zu<=comp_type_tot-1;zu++){	   
	   free(comp_type[zu]);
       }
       free(comp_type);     
}

/******** to show average partial pre-image histogram, Aug 94 *******/
void show_average_pp_hist(void){
  signed int z/*,xbox*/;
  float pp_temp;

      pp_hist_max=pp_temp=0;
      for (z=lineL-1;z>=0;z--){
	 pp_temp=(float)pp_hist_total[z]/pp_histcount;
	 if ((float)pp_hist_max <= pp_temp)
		     pp_hist_max=(signed int)ceil(pp_temp);
      }
      /*rescale y axis*/
      pp_ymax=pp_hist_max*1.5;
      ppL=0;
      setup_ppstack_hist();
      for (z=lineL-1;z>=0;z--){
	 pp_temp=(float)pp_hist_total[z]/pp_histcount;
	 pp_heighty=(signed int)(vgax(120)*pp_temp/pp_ymax);
	 bar(pp_startx,pp_starty-pp_heighty,
				   pp_startx+pp_barwidth,pp_starty);
	 pp_startx+=pp_bartotw;
	 /*
	 xbox=draw_prompt_box(2);
	 sprintf(textb[0],"htot[%d]/hc=%lu/%lu = pp_temp=%g",
		      z,pp_hist_total[z],pp_histcount,pp_temp);
	 sprintf(textb[1],"hmax=%d,pp_ht=%d,wild=%lu",
		   pp_hist_max,pp_heighty,pp_wild_tot);
	 outtext(textb[0]);
	 moveto(xbox,gety+CHeight);
	 outtext(textb[1]);
	 getch();
	 */
      }
      if (pp_wild_tot>0){
	 pp_startx-=pp_bartotw;
	 setfillstyle(INTERLEAVE_FILL,red);
	 bar(pp_startx,pp_starty-pp_heighty-1
	    -(signed int)vgax(120)*
	       ((float)pp_wild_tot/pp_histcount)/pp_ymax,
		     pp_startx+pp_barwidth,pp_starty-pp_heighty-1);

      }
      moveto(pp_startx0+vgax(4),pp_starty0-pp_depthy+1);
      setfillstyle(SOLID_FILL,black);
      bar(getx,gety,getx+textwidth("average p-pre-image histogram"),
					       gety+CHeight);
      outtext("average p-pre-image histogram");
}

/**** for progress through state space Aug 93, or mixed rules, Aug 93 *******/
void progress_bar(void){
 signed int xbox;
 unsigned char tempcolor;

   xbox=trboxw;
   draw_box(-1,xbox,vgay(30),Maxx-2,vgay(30)+vgay(9)+vgay(3),1,0);
   barxl=xbox+2;
   baryt=vgay(30)+vgay(3);
   barxr=Maxx-vgax(6);
   baryb=vgay(30)+vgay(9);
   tempcolor=getcolor();
   setcolor(lightred);
   rectangle(barxl,baryt,barxr,baryb);
   setcolor(tempcolor);
}

/********************** print field data, Aug 93 ******************/
void print_field_data(void){
 signed int xbox;
 unsigned long this_statespace;

    xbox=draw_prompt_box(2);
    setcolor(white);
    if (neutral_order==1) sprintf(textb[0],"NTO");
    else if (seq_update) sprintf(textb[0],"SEQ");
    else if (exhaustive_testing==2) sprintf(textb[0],"MAP");
    else if (exhaustive_testing==1) sprintf(textb[0],"EXH");   
    else if (nonlocal==0) sprintf(textb[0],"CAW");
    else if (nonlocal==1) sprintf(textb[0],"NLW");
    inset_prompt_box(0,6,textb[0],'d');

    if (earlyexitfield || earlyexitbasin) outtext("EarlyExit ");
       
    if (neutral_order==1)        
        sprintf(textb[0],"total neutral components=%d",totbasinsinfield);
    
    else{
      if (NULLboundaries==1) sprintf(textb[0],"NBC basin types=%d total basins=%d",
					basintypeno,totbasinsinfield);
     else sprintf(textb[0],"PBC basin types=%d total basins=%d",
					basintypeno,totbasinsinfield);
    }          
    outtext(textb[0]);
    
    if (pdata){
       print_out(textb[0]);
       print_out("\n");
    }
    if (filedata){ 
       save_data(textb[0]);
       save_data("\n");
    }
    
    moveto(xbox,gety+CHeight);
    if (neutral_order==1) this_statespace=fact((char)templineL);
    else this_statespace=(unsigned long)pow(value_range,(double)lineL);
   
    if (fieldsize != this_statespace && neutral_order==0)
       sprintf(textb[0],"n=%d sspace=%lu field=%lu ",
		           lineL,this_statespace,fieldsize);                           
    else if (neutral_order==1) {
      /*sprintf(textb[0],"n=%d sspace=%lu field=%lu ",
	templineL,this_statespace,fieldsize);*/ //templineL is global
      sprintf(textb[0],"n=%d field=%lu ",
	templineL,fieldsize); //this_statespace should = fieldsize

      
      fprintf(stderr,"\nn=%d sspace=%lu field=%lu ",
	                     templineL,this_statespace,fieldsize);
      
    }
    else sprintf(textb[0],"n=%d field=%lu ",lineL,fieldsize);
    outtext(textb[0]);
    
    sprintf(textb[1],"g=%lu=%.3g",
			     fieldgofE,fieldgofEdensity);
    outtext(textb[1]);
    outtext(textb[2]);
    if (pdata){
       print_out(textb[0]);
       print_out("\n");
       print_out(textb[1]);
       print_out("\n");
    }
    if (filedata){
       save_data(textb[0]);
       save_data("\n");
       save_data(textb[1]);
       save_data("\n");
    }
    /*wont outtext top right box without this - ??*/
    while(event_ready()==0) break;
    
   /*----- moved from end of draw_field, A pril 2021 -------------------------*/
   if (neutral_order==1) show_neutral_info();          
   /*---------------------------------------------------*/
   
   //fprintf(stderr,"\nin print_field_data istr_graph=%d ibaf_graph=%d jump_graph=%d",
   //	   istr_graph,ibaf_graph,jump_graph);
   
   if (istr_graph==1 && jump_graph==0){
     unsigned int zw,node_no;
      jump_graph_table(0,NULL,'t');
   }
   
   if (exhaustive_testing && ibaf_graph==1 && jump_graph==0 && dontcompress==1){
     unsigned int zw,node_no;
      /*graph_type=='s' for ibaf graph (interactive basin of attraction field), March 2021*/
      jump_graph_table(0,NULL,'s');
      /*calloc and free now done in main for both istr and ibaf graphs 19/06/25
      node_no=(unsigned int)(pow(value_range,(double)lineL)); //size of state-space
      for (zw=0;zw<=node_no;zw++) free(basin_pos[zw]);
      free(basin_pos);*/
   }
      
   free(cycles);
   if (exhaustive_testing && exh_pairs_in_jump_nodes==0) free(exh_pairs);
   else if (!neutral_order && (nonlocal || nhood_mixed)) free_pre_rand();
   memory_box(1,NULL);
   
   /*jumpgraph set, and not repeating field in jump-graph positions*/   
   if (jump_graph && use_preset_basin_pos==0 && earlyexitfield==0){     
       jump_graph_table(0,NULL,'f');
   }
   use_preset_basin_pos=0;  
   /*----- above was moved from end of draw_field, A pril 2021 -------------------------*/

   if (neutral_order==1) neutral_order=0;
}

/*** draw the attractor cycle, loop then each transient tree, 13 May 93 ***/
void draw_basin(void){
 float cyheading,stangle,cyclerad,
       pointangle,pointrad,angle;
 signed int pointx,pointy,tempx,tempy,z,xbox;
 unsigned int zu;
 char earlyexittree=0,earlyexitseg=0;
 unsigned long totsubtreegofE=0,basingofE=0,
               thisbar,elapsedtime;
 float timesec;
#if __WATCOM__ 
   clock_t starttime, endtime;
#elif __UNIX__
  unsigned long starttime,starttime_m,
                endtime,endtime_m;
  long  elapsedtime_m;
  struct timeval tp;
  struct timezone tzp;
#endif 
signed int timemin;


  justonepreimage_found=0;/* to prevent level problems in multi_value*/

  if (!basinfield){ 
#     if __WATCOM__
         starttime = clock();  /*start time*/
#     elif __UNIX__   
         /*sprintf(textb[0],"tp");
	   sprintf(textb[0],"tzp");*/
         gettimeofday(&tp,&tzp);
         starttime=(unsigned long)tp.tv_sec; /*xwindows*/
         starttime_m=(unsigned long)tp.tv_usec;
#     endif  
  }
  
  if (show_ss_matrix){
     if (!basinfield || successive_basins) show_statespace_matrix(NULL);
     else{
	startmcolor:
	/*give each basin a diff color - cycle through colors in 2 steps*/
	if (matrixcolor==0) matrixcolor+=1;
	else matrixcolor+=2;
	if (matrixcolor==17) matrixcolor=2;
	if (matrixcolor==16){
	   matrixcolor=0;
	   goto startmcolor;
	}
     }
  }

  thisbar=progbar;
  earlyexit=0;
  earlyexittree=0;
  isexception=0; /*to show exception in density classification*/

  if (!basinfield){
     if (exhaustive_testing==1){ /*if ==2 (for rand maps) done in run_forward()*/
        is[0]=0;
	prestate_successor_pairs();
	if (screensavedemo==0) mutantdontpause=0;		
	if (is[0]=='q') return;
     }
     else if (exhaustive_testing!=2 &&
	   (nonlocal || nhood_mixed)) prepair_pre_rand();
  }
  totsubtree=0;
  if (!rulemix && ((basinfield==0 && !rangeL) || (successive_basins)))
				     show_rule_bottom(nhood,1,carule[0],0);
  /*allocate mem to cycle co-ords*/
  if ((cyclex=(signed int *)calloc(attperiod+1,sizeof(signed int)))
				      ==NULL) outof_memory("cyclex");
  if ((cycley=(signed int *)calloc(attperiod+1,sizeof(signed int)))
				      ==NULL) outof_memory("cycley");
  tempx=getx;
  tempy=gety;
  stangle=cyheading=0;
  stangle=deg*cyheading + orient_angle;  /*degrees anti-clockwise from x-axis*/
  /*cyclerad asymptotically approaches rad[0] with increacing attperiod*/
  cyclerad=(rad[0]/3)+((2*rad[0]/3)*((float)attperiod-2)/(float)attperiod);

  
  if (gd_z_graph){ /*watcom, confine graphics to rectangle*/
     if (stp) setviewport(lineL*scale+vgax(12),vgay(46),Maxx-3,vgay(157),1);
     else  setviewport(3,vgay(46),Maxx-3,vgay(157),1);
  }
  
  if (oy>Max_oy) oy=Max_oy; /*limit of oy for draw_fan()*/

  /*draw attractor cycle*/
  if (attperiod==1){
     pointangle=0;
     pointrad= pow(  ( pow( (startrad/4),2 ) *2 ), .5);
     pointangle=(deg*225)+stangle;
     pointx=(signed int) (cos(pointangle)*pointrad)+ox;
     pointy=(signed int) -(sin(pointangle)*pointrad)+oy;
     setcolor(yellow);
     circle(pointx,pointy,pow(2,.5)*startrad/4);
     setcolor(lightred);
     circle(ox,oy,startrad/20);
     
     if (basin_postScript){
        color_ps(basin_postScript-1,yellow); /*color or gray*/
        circle_ps(pointx,pointy,pow(2,.5)*startrad/4);
        color_ps(basin_postScript-1,lightred);
        circle_ps(ox,oy,startrad/20);
     }
     cyclex[1]=ox;
     cycley[1]=oy;
  }
  else if (attperiod==2){
     setcolor(cyan);
     stangle=2*PI-PI/6 + (deg* cyheading) + orient_angle;
     circle(ox,oy,cyclerad);
     if (basin_postScript){
        color_ps(basin_postScript-1,cyan);
        circle_ps(ox,oy,cyclerad);
     }
     angle=2*PI/attperiod;
     setcolor(lightred);
     if (basin_postScript) color_ps(basin_postScript-1,lightred);
     for (z=attperiod;z>=1;z--){
	/*co-ordinates of cycle nodes*/
	cyclex[z]=(signed int)(cos(stangle-(angle*z))*cyclerad)+ox;
	cycley[z]=-(signed int)(sin(stangle-(angle*z))*cyclerad)+oy;
	moveto(cyclex[z],cycley[z]);
        circle(cyclex[z],cycley[z],startrad/15);
        if (basin_postScript) circle_ps(cyclex[z],cycley[z],(double)startrad/15);
     }
  }
  else if (attperiod>2){
     angle=2*PI/attperiod;
     //setcolor(lightred);
     setcolor(cyan);
     if (basin_postScript) color_ps(basin_postScript-1,cyan);
     for (z=attperiod;z>=1;z--){
	/*co-ordinates of cycle nodes*/
	cyclex[z]=(signed int)(cos(stangle-(angle*z))*cyclerad)+ox;
	cycley[z]=-(signed int)(sin(stangle-(angle*z))*cyclerad)+oy;
	//setcolor(cyan);
	if (z==attperiod){
           moveto(cyclex[z],cycley[z]);
           if (basin_postScript) moveto_ps(cyclex[z],cycley[z]);
        } 
	else{ 
           lineto(cyclex[z],cycley[z]);
           if (basin_postScript){ 
              lineto_ps(cyclex[z],cycley[z]);
           }
        }
	circle(cyclex[z],cycley[z],cyclerad/(10+attperiod/2));
	/*print_current_state(att[z], green);*/
	moveto(cyclex[z],cycley[z]);
        if (basin_postScript){
	   circle_ps(cyclex[z],cycley[z],cyclerad/(10+attperiod/2));
        } 
     }
     lineto(cyclex[attperiod],cycley[attperiod]);
     if (basin_postScript){
          sprintf(textb[0]," closepath stroke\n"); 
          vret=write(fid_PS,textb[0],strlen(textb[0]));
     }
  }
# if (__WATCOM__||__UNIX__)
     /*watcom, release graphics from rectangle */
     if (gd_z_graph) setviewport(0, 0, Maxx, Maxy, 0);
# endif

  moveto(tempx,tempy);

  if  ((nonlocal==0  || compress_1d_local==1 || regular2d)
      && !dontcompress && !rulemix && exhaustive_testing!=2){

     if (regular2d){
	/*no of eq states in att cycle*/
	rot_cycle_equiv_2d(att[1]);
	/*    sets cyclematch_2d[0], horiz rotations
	      cyclematch_2d[1], vertical rotations
	      cyclematch_2d_diag[0], poss diagonal rotations
	      cyclematch_2d_diag[1], neg  diagonal rotations*/

	cyclematch=cyclematch_2d[0]*cyclematch_2d[1];
	if (cyclematch_2d_diag[0]>1) cyclematch=cyclematch_2d_diag[0];
	else if (cyclematch_2d_diag[1]>1) cyclematch=cyclematch_2d_diag[1];

	/*repseg_2d.. is size of segments..
	  no. of one cell translations required (vertical/horiz)
	  in toroidal bit array, to return to start
	  same for all states on att cycle,
	  overriden if vert=horiz translation*/
	attrepseg_2d_h=repseg_2d[0];
	attrepseg_2d_v=repseg_2d[1];

	basinno_2d_h=attrepseg_2d_h/cyclematch_2d[0];
	basinno_2d_v=attrepseg_2d_v/cyclematch_2d[1];

	attrepseg_2d_patch=attrepseg_2d_h*attrepseg_2d_v;
	basinno=basinno_2d_h*basinno_2d_v;

	if (cyclematch_2d_diag[0]>1)
		     basinno/=cyclematch_2d_diag[0];
	else if (cyclematch_2d_diag[1]>1)
		     basinno/=cyclematch_2d_diag[1];
     }
     else{
	/*no of eq states in att cycle*/
	cyclematch=rot_cycle_equiv(att[1]);
	/*no of repeating segs in circular bit string,
		      same for all states on att cycle*/
	attrepseg=repeating_seg(att[1]);
	basinno=attrepseg/cyclematch;
     }
     /*number of equivalent basins of this type*/
     if (basinfield) totatt_states+=attperiod*basinno;
     else totatt_states=attperiod;
  }
  else{
     cyclematch=1; /*no of eq states in att cycle*/
     if (regular2d){
	attrepseg_2d_h=1;
	attrepseg_2d_v=1;
	attrepseg_2d_patch=1;
     }
     else attrepseg=1; /*no of repeating segs in state hoop*/

     basinno=1;/*number of equivalent basins of this type*/
     totatt_states=attperiod;
  }
  basinsize=basingofE=maxbasinfan=maxbasinlevel=0;
  if ((nonlocal==0  || compress_1d_local==1 || regular2d)
      && !dontcompress && !rulemix && exhaustive_testing!=2){
     /*allocate mem for pre-images of all 0s and 1s*/
     if (regular2d){
	sprintf(textb[0],"seg_2d_0");
	if ((seg_2d_h=(signed int*)calloc(1, sizeof(signed int)))
				 ==NULL) outof_memory(textb[0]);
	sprintf(textb[0],"seg_2d_1");
	if ((seg_2d_v=(signed int*)calloc(1, sizeof(signed int)))
				 ==NULL) outof_memory(textb[0]);
     }
     else{
	sprintf(textb[0],"seg");
	if ((seg = (signed int*)calloc(1, sizeof(signed int)))
				 ==NULL) outof_memory(textb[0]);
     }
     sprintf(textb[0],"segseed");
     if( (segseed=(char**)calloc(1,sizeof(char*)))
				     ==NULL) outof_memory(textb[0]);
     /*nominal allocation*/
     sprintf(textb[0],"segseed[%d]",0);
     if ((segseed[0]=(char*)calloc(1,sizeof(char)))
				     ==NULL) outof_memory(textb[0]);
     memory_box(1,NULL);
  }

  
  if (show_one_att_state){    
    draw_att_state(1); /*either 1 state or all*/
  }
  if (level_limit==0 && shownumbers!=1) draw_att_state(2);//override id dec nodes
  
  //fprintf(stderr,"\nlevel_limit=%d\n",level_limit);//????
  
  /*run backwards, draw transienat tree, from each attractor state*/
  for (attindex=attperiod;attindex>=
		     attperiod+1-(attperiod/cyclematch);attindex--){
    
     //fprintf(stderr," %lu",attindex);//????
    
     memmove(firstseed,att[attindex],bytesL);
     if (attindex==attperiod) linec=black;
     maxtreelevel=maxtreefan=justonepreimage=insegloop=0;
     /*this added Nov 2004 to fix a bug reported by Dave*/
     totsubtree=totsubtreegofE=0;
     
     //for bare attractor
     if (level_limit>0) run_backward();
     
     /*to interrupt basin field*/
     if (is[0]=='q'){
	earlyexit=1;
	if (basinfield){
           if (jump_graph) basintypeno-=1;
	   free_basin_memory();
	   //fprintf(stderr,"\n 1:free_basin_memory"); //fprintf??
           return;
	}
	else break;
     }
     /*interrupt tree, continue with next tree*/
     if (is[0]=='n'){
	earlyexit=1;
	memory_box(1,NULL);
	continue;
     }
     if (earlyexit==1){
	earlyexittree=1;
	earlyexit=0;
     }
     if (segfan){  /*run back from each segfan state*/
	insegloop=1;
	segfan=totsubtreegofE=0;
        totsubtree=0;
	earlyexitseg=0;
	for (segindex=1;segindex<=segno;segindex++){
	   memmove(firstseed,segseed[segindex],bytesL);
	   startsegfan=1;

	   if (level_limit>0) run_backward();
	   /*interrupt basin or basin field*/
	   if (is[0]=='q'){
	      earlyexit=1;
	      if (basinfield){
		 free(segx);
		 free(segy);
		 free_basin_memory();
		 //fprintf(stderr,"\n 2:free_basin_memory"); //fprintf??
		 insegloop=0;
		 memory_box(1,NULL);

              return;
	      }
	      else break;
	   }
	   /*interrupt tree, continue with next tree*/
	   if (is[0]=='n'){
	      earlyexit=1;
	      memory_box(1,NULL);
	      continue;
	   }
	   if (earlyexit==1){
	      earlyexitseg=1;
	      earlyexit=0;
	   }
	    /*count data*/
	   if (regular2d){
	      totsubtree+=(treesize*seg_2d_h[segindex]*seg_2d_v[segindex]);
	      totsubtreegofE+=(gofEno*seg_2d_h[segindex]*seg_2d_v[segindex]);
	   }
	   else{
	      totsubtree+=treesize*seg[segindex];
	      totsubtreegofE+=gofEno*seg[segindex];
	   }
	   if (maxbasinfan<maxtreefan) maxbasinfan=maxtreefan;
	   if (maxbasinlevel<maxtreelevel) maxbasinlevel=maxtreelevel;
	}
        
	if (justonepreimage) totsubtree+=2;
	else totsubtree+=1;
	insegloop=0;
	treesize=gofEno=0;
	free(segx); /*free fanseg co-ords*/
	free(segy);
	if (segno>0) for (zu=1;zu<=segno;zu++) free(segseed[zu]);
	segno=0;
	memory_box(1,NULL);
     }
     
     basinsize+=((treesize*cyclematch)+totsubtree);
     basingofE+=((gofEno*cyclematch)+totsubtreegofE);
     if (maxbasinfan<maxtreefan) maxbasinfan=maxtreefan;
     if (maxbasinlevel<maxtreelevel) maxbasinlevel=maxtreelevel;
  } /*next attindex*/

  if (show_one_att_state){
    /* draw either one or all attractor states*/
     draw_att_state(show_one_att_state);
  }

  if (basinsize>0) basingofEdensity=(float)basingofE/(basinsize);
  if (maxfieldfan<maxbasinfan) maxfieldfan=maxbasinfan;
  /*keep track of cycle length frequency 1-9 for basin fields*/
  if (basinfield){
     if (attperiod<10) cycles[attperiod]+=basinno;
     else cycles[0]+=basinno;
  }   
  /*pause to show basin data*/
  if (datapause || (!basinfield && screensavedemo==0 /*&&!mutantdontpause*/)
               || (!basinfield && gd_z_graph==3)){
     
     xbox=draw_prompt_box(2);

     if (neutral_order==1) sprintf(textb[0],"NTO");
     else if (seq_update) sprintf(textb[0],"SEQ");
     else if (exhaustive_testing==2) sprintf(textb[0],"MAP");
     else if (exhaustive_testing==1) sprintf(textb[0],"EXH");   
     else if (nonlocal==0) sprintf(textb[0],"CAW");
     else if (nonlocal==1) sprintf(textb[0],"NLW");
     inset_prompt_box(0,6,textb[0],'d');

     if (earlyexitseg || earlyexittree || earlyexit){
	earlyexitbasin=1;
	outtext("EarlyExit ");
     }

     if (NULLboundaries==1) sprintf(textb[0],"%s","NBC ");
     else{
        if (dontcompress==1) sprintf(textb[0],"%s","PBC ");
        else{  
           sprintf(textb[2],"%s","PBC ");     
           if (basinfield) sprintf(textb[0],"%sbasin %d, equiv basins=%d ",
					textb[2],basintypeno,basinno);
           else sprintf(textb[0],"%sequiv basins=%d ",textb[2],basinno);
        }
	
     }
     outtext(textb[0]);

     if (basinfield){
	if ((progbar-thisbar)/basinno!=basinsize){
	   sprintf(textb[0],"ERROR count=%lu",progbar-thisbar);
	   outtext(textb[0]);
	}
     }
     
     /*states with maj of given value -- highlighted in basins*/  
     if (show_maj>=0){ 
	sprintf(textb[0],
           " maj%d=%lu=%.3g ",show_maj,isexception,(double)isexception/basinsize);
	outtext(textb[0]);
     }

     outtext("att(hex)=");
     setviewport(xbox, 0, Maxx,2+CHeight*2+vgay(6), 0);
     print_current_bitstring_hexbytes(0,0,att[1],0,Maxx,white,0);
     setviewport(0, 0, Maxx, Maxy, 0);

     moveto(xbox,gety+CHeight);
     sprintf(textb[0],
	  "period=%lu size=%lu=%.3g%% g=%lu=%.3g ml=%d mp=%lu",
	    attperiod,basinsize,
	      (double)(basinsize*basinno*100)/pow(value_range,(double)lineL),
		     basingofE,basingofEdensity,maxbasinlevel,maxbasinfan);

     outtext(textb[0]);
     /*wont outtext top right box without this - ??*/
     while(event_ready()==0) break;

     if (!basinfield || successive_basins){
#       if __WATCOM__
           endtime = clock();  
#       elif __UNIX__  
           gettimeofday(&tp,&tzp);
           endtime=(unsigned long)tp.tv_sec; /*xwindows*/
           endtime_m=(unsigned long)tp.tv_usec;
#       endif   
#       if __WATCOM__   
	   elapsedtime=(unsigned long)(endtime-starttime);
	   timesec=(float)elapsedtime/(unsigned long)CLK_TCK;
	   if (timesec>59){
	      timemin=(signed int)(timesec/60);
	      timesec-=timemin*60;
	      sprintf(textb[2],"  %dmin %.3fsec",timemin,timesec);
	   }
	   else sprintf(textb[2],"  %.3fsec",timesec);
	   outtext(textb[2]);
     
#       elif __UNIX__   
           elapsedtime=endtime-starttime;
           elapsedtime_m=endtime_m-starttime_m;     
           if (elapsedtime_m<0){ 
              elapsedtime-=1;
              elapsedtime_m=(1000000-starttime_m)+endtime_m;
           }
           timesec=(float)
               ((elapsedtime%60)+((float)elapsedtime_m/1000000));
           if (elapsedtime>=60){
              timemin=elapsedtime/60;
              sprintf(textb[2],"  %dmin %.3fsec",timemin,timesec);
           }
           else sprintf(textb[2],"  %.3fsec",timesec);     
           outtext(textb[2]);
#       endif
     }
     
     //fprintf(stderr,"\nin draw_basin in basin_field istr_graph=%d ibaf_graph=%d jump_graph=%d",
     //	     istr_graph,ibaf_graph,jump_graph);
     if (istr_graph==1 && jump_graph==0){
       //unsigned int zw,node_no;
        /*graph_type=='t' for istr graph (interactive state transition graph), May 2025*/
             
       /* fprintf(stderr,
		"\nbasintypeno=%d cyclematch=%d attperiod=%lu\n",
		                basintypeno,cyclematch,attperiod);*///????
	
	if (level_limit==0){ //for bare attractor istr_graph
	    istr_node_count=attperiod;

	    for (z=attperiod;z>=1;z--){ //position nodes in istr-graph
	      basin_pos[z][0]=cyclex[z];
	      basin_pos[z][1]=cycley[z];
	    }
	  
	    istr_node_count=attperiod; //size cycle of bare istr-graph
	    //specify links between nodes
	    for (attindex=attperiod;attindex>=2;attindex--){	     
	         memmove(pat_state0[attindex-1],att[attindex],bytesL);//state
                 memmove(pat_state1[attindex-1],att[attindex-1],bytesL);//root
		 //fprintf(stderr," (%lu>%lu)",attindex,attindex-1);//????
	    }
	    //fprintf(stderr,"\njoin the ends of the cycle\n");//????
	    memmove(pat_state0[0],att[1],bytesL);//state
            memmove(pat_state1[0],att[attperiod],bytesL);//root
	    //fprintf(stderr," [%d>%lu]",0,attperiod-1);//????
	}
	//fprintf(stderr,"\n-->jump_graph_table\n");//????
	
        jump_graph_table(0,NULL,'t');//draw the istr_graph if set
     }
      
     thisbar=progbar;

     if (basinfield && datapause){
	xbox=memory_box(-4.4,NULL);
	moveto(xbox+vgax(3),vgay(3));
	outtext("next basin-ret nopause-q ops-o layout-a:");
	input_string(1,0);
        if (is[0]=='q') datapause=0;
        else if (is[0]=='o') finish_options(1);
	else if (is[0]=='a') amend_layout();
        is[0]='0';
        erase_memory_box(-4.4);
     }

     else if (!basinfield && rangeL && datapause){
	if (lineL!=endL){
	    xbox=memory_box(-4.4,NULL);
	    moveto(xbox+vgax(3),vgay(3));
	    outtext("next basin-ret nopause-q ops-o layout-a:");
	    input_string(1,0);
            if (is[0]=='q') datapause=0;
            else if (is[0]=='o') finish_options(1);
	    else if (is[0]=='a') amend_layout();
            is[0]='0';
            erase_memory_box(-4.4);
	}
	else finish_options(1);
     }
  }

  /*print and/or file basin data*/
  if (pdata || filedata){
     if (earlyexitseg || earlyexittree){
	sprintf(textb[2],"EarlyExit! ");
	earlyexitbasin=1;
     }
     else sprintf(textb[2],"%s","");
     if (basinfield) sprintf(textb[0],"%d. %s",basintypeno,textb[2]);
     else sprintf(textb[0],"single basin. %s",textb[2]);
     if (pdata) print_out(textb[0]);
     if (filedata) save_data(textb[0]);
     print_current_bitstring_hexbytes(0,0,att[1],0,Maxx,white,3);
     sprintf(textb[3]," %d (%lu) %lu %.3g%% %lu %.3g %d %lu\n",
       basinno,attperiod,basinsize,
	 (double)(basinsize*basinno*100)/pow(value_range,(double)lineL),
	 basingofE,basingofEdensity,maxbasinlevel,maxbasinfan);
  
     if (pdata){
	print_out(textb[3]);
	if (!basinfield) print_out("\n");
     }
     if (filedata){
        save_data(textb[3]);       
	if (!basinfield) save_data("\n");
     }
  }
  /*data for display when field is complete*/
  if (basinfield){
     totbasinsinfield+=basinno;
     fieldsize+=basinno*basinsize;
     fieldgofE+=basinno*basingofE;
     if (fieldsize>0) fieldgofEdensity=(float)fieldgofE/fieldsize;
  }
  
  if (basinfield && jump_graph && use_preset_basin_pos==0){
        //fprintf(stderr,"\n %lu:realloc(m_att_period,",attindex);
        if ((m_att_period=
            (unsigned int*)realloc(m_att_period,
                          (basintypeno+1)*sizeof(unsigned int)))
				 ==NULL) outof_memory("m_att_period");
        m_att_period[basintypeno]=attperiod;

        if ((m_basin_volume=
            (unsigned long*)realloc(m_basin_volume,
                          (basintypeno+1)*sizeof(unsigned long)))
				 ==NULL) outof_memory("m_basin_volume"); 
        m_basin_volume[basintypeno]=basinsize;
        if ((m_att=(char***) realloc(m_att,sizeof(char**)*(basintypeno+1)))
				       ==NULL) outof_memory("m_att***");
        if ((m_att[basintypeno]=(char **)calloc(attperiod+1,sizeof(char*)))
				     ==NULL) outof_memory("m_att**");
       if ((m_att[basintypeno][0]=(char *)calloc(1,sizeof(char)))
	                             ==NULL) outof_memory("m_att*");

       for (z=1;z<=m_att_period[basintypeno];z++){
	    if ((m_att[basintypeno][z]=(char *)calloc(bytesL,sizeof(char)))
				     ==NULL) outof_memory("m_att*");
            memmove(m_att[basintypeno][z],att[z],bytesL);
       }
  }
  //fprintf(stderr,"\n tickoff(%lu) 1=",tickspace);
  //for (zu=0;zu<=tickspace;zu++) fprintf(stderr,"%d",get_bitlong(tickoff,zu));
  free_basin_memory();
  
  //fprintf(stderr,"\n 3:free_basin_memory"); //fprintf??
  //fprintf(stderr,"\n tickoff(%lu) 2=",tickspace);
  //for (zu=0;zu<=tickspace;zu++) fprintf(stderr,"%d",get_bitlong(tickoff,zu));
  
  if (basinfield==0 && rangeL==0 && !rulemix)
                                 show_rule_bottom(nhood,0,carule[0],0);
  /*to show average stack histogram*/
  if (!basinfield && see_ppstack && (nonlocal || nhood_mixed))
                                         show_average_pp_hist();
}

/********* draw subtree root state  ************/
void show_seed(char *this_firstseed){
   signed int tempx,tempy;
   char hl_temp;

      tempx=getx;
      tempy=gety;
      moveto(ox,oy);
      hl_temp=hilight_learn;
      hilight_learn=1;
      if (show_one_att_state || twod || showbits_1d_as_2d){
	 print_current_state_twod(this_firstseed,yellow,0);
         if (basin_postScript) sp_node_ps(1,this_firstseed,getx,gety,yellow);
      }
      else{
         print_current_state_h(this_firstseed,yellow);
         if (basin_postScript) sp_node_ps(-1,this_firstseed,getx,gety,yellow);
      }	
      hilight_learn=hl_temp;
      moveto(tempx,tempy);

}
/********* draw_att_state ************/
void draw_att_state(char one_or_all){
   signed int z,tempx,tempy,last_state;
   char hl_temp;

        tempx=getx;
	tempy=gety;
        hl_temp=hilight_learn;
	hilight_learn=1;
        if (level_limit==0) hilight_learn=0;
       
#       if (__WATCOM__||__UNIX__)
	   if (gd_z_graph){ /*watcom, confine graphics to rectangle*/
	      if (stp) setviewport(lineL*scale+vgax(12),
				vgay(46),Maxx-3,vgay(157),1);
	      else  setviewport(3,vgay(46),Maxx-3,vgay(157),1);
	   }
#       endif

        if (one_or_all==1) last_state=attperiod;
        else if (one_or_all==2) 
              last_state=attperiod+1-(attperiod/cyclematch);

        for (z=attperiod;z>=last_state;z--){
	   moveto(cyclex[z],cycley[z]);	   
	   if (show_one_att_state || twod || showbits_1d_as_2d){
	       print_current_state_twod(att[z],yellow,0);
               if (basin_postScript) sp_node_ps(1,att[z],getx,gety,yellow);
           }
	   else{ 
              print_current_state_h(att[z],yellow);
              if (basin_postScript) sp_node_ps(-1,att[z],getx,gety,yellow);
           }	   
        }

#       if (__WATCOM__||__UNIX__)
	   /*watcom, release graphics from rectangle*/
	   if (gd_z_graph) setviewport(0, 0, Maxx, Maxy, 0);
#       endif
        if (level_limit>0){ /*state outline*/ 
           hilight_learn=hl_temp;
	   moveto(tempx,tempy);
        }
}

/********* free basin memory, Aug 93 ************/
void free_basin_memory(void){
 signed int z;
 unsigned int zu;

        //fprintf(stderr,"\n in free_basin_memory"); //fprintf??
 
	if (!basinfield){
	   if (exhaustive_testing){
	      free(exh_pairs);
	      free(tickoff);
	      //fprintf(stderr,"\n 4:fbm-free(tickoff)"); //fprintf??
	   }
	   else if (nonlocal || nhood_mixed) free_pre_rand();
	}
	if ((nonlocal==0 || compress_1d_local==1 || regular2d)
	      && !dontcompress&& !rulemix && exhaustive_testing!=2){
		/*free fanseg memory*/
		if (regular2d){
		   free(seg_2d_h);
		   free(seg_2d_v);
		}
		else free(seg);
		for (zu=0;zu<=segno;zu++) free(segseed[zu]);
		free(segseed);
	}
	/*free attractor memory*/
	for (z=1;z<=attperiod;z++) free(att[z]);
	free(att);
	free(cyclex);
	free(cycley);
	memory_box(1,NULL);
}

/********************************************************************/














