1:  // -----------------------------------------------------------
   2:  // --   An Asymptote package for drawing orbitals.
   3:  // --      Free under any GNU public license.
   4:  // --      (C) Copyright: Peter Luschny, 2008
   5:  // --             Version 1 Release 1
   6:  // -----------------------------------------------------------
   7:  // --
   8:  // --  This file is accompanying the package orbital.asy and
   9:  // --  provides structures and routines to generate orbitals.
  10:  // --  See also the file orbitalusage.asy, which illustrates
  11:  // --  the use of the structure 'orbitalgenerator'.
  12:  // --
  13:  // --  For more information see
  14:  // --  http://www.luschny.de/math/swing/orbital/orbitaldoc.pdf
  15:  // --
  16:  // -----------------------------------------------------------
  17:   
  18:  typedef void VISIT(int[]);
  19:   
  20:  struct OrbitalGenerator
  21:  {
  22:      private VISIT userhook;
  23:      private int N, n, t, count;
  24:      private bool isOdd;
  25:   
  26:      private void write(int[] jump)
  27:      {
  28:         string s;
  29:         for(int j : jump) { s += (string)j + ","; }
  30:         write(s);
  31:      }
  32:   
  33:      private void visit(int[] jump)
  34:      {
  35:          count = count + 1;
  36:   
  37:          if(userhook != null)
  38:          {
  39:              userhook(jump);
  40:          }
  41:          else { this.write(jump); }
  42:      }
  43:   
  44:      private void assemble(int[] c)
  45:      {
  46:          int[] q = new int[N];
  47:   
  48:          for(int i = 0; i < N; ++i){ q[i] = 1; }
  49:          for(int i = 0; i < t; ++i){ q[N-c[i+1]-1] = -1; }
  50:   
  51:          if(isOdd)
  52:          {
  53:              int[] s = {0};
  54:              for(int i = 0; i < n; ++i)
  55:              {
  56:                  visit(concat(q[0:i],s,q[i:n]));
  57:              }
  58:          }
  59:          else { visit(q); }
  60:      }
  61:   
  62:      restricted static OrbitalGenerator
  63:                 OrbitalGenerator(int len, VISIT hook = null)
  64:      {
  65:          if(len > 12)
  66:          {
  67:              write("Error! n is too big, n <= 12 required.");
  68:              write("I set n = 1.");
  69:              len = 1;
  70:          }
  71:   
  72:          OrbitalGenerator og = new OrbitalGenerator;
  73:   
  74:          bool isodd = len % 2 == 1;
  75:          int Len = isodd ? len - 1 : len;
  76:   
  77:          og.isOdd = isodd;
  78:          og.n = len;
  79:          og.N = Len;
  80:          og.t = quotient(Len, 2);
  81:          og.count = 0;
  82:          og.userhook = hook;
  83:   
  84:          return og;
  85:      }
  86:   
  87:      public int generate()
  88:      {
  89:          int[] c = new int[t + 3];
  90:          for(int j = 1; j <= t; ++j) { c[j] = j - 1; }
  91:          c[t + 1] = N; c[t + 2] = 0;
  92:   
  93:          // -- Algorithm L in Donald E. Knuth TAOCP 7.2.1.3
  94:          while(true)
  95:          {
  96:              assemble(c);
  97:              int j = 1;
  98:              while(c[j] + 1 == c[j + 1]) { c[j] = j - 1; ++j; }
  99:              if(j > t) { break; }
 100:              c[j] += 1 ;
 101:          }
 102:   
 103:          return count;
 104:      }
 105:   
 106:  }   from OrbitalGenerator unravel OrbitalGenerator;
 107:   
 108:   
 109:  // ------------- End of struct OrbitalGenerator --------------
 110:   
 111:   
 112:  struct PrimeOrbital
 113:  {
 114:      restricted int[] jumps;
 115:      restricted int numer, denom;
 116:      restricted real balance;
 117:   
 118:      private static int[] primes = {
 119:              2,3,5,7,11,13,17,19,23,29,31,37,41};
 120:   
 121:      private void primorial(int[] jump)
 122:      {
 123:          int i = 0; numer = 1; denom = 1;
 124:   
 125:          for(int j : jump)
 126:          {
 127:                   if(j > 0) numer *= primes[i];
 128:              else if(j < 0) denom *= primes[i];
 129:              ++i;
 130:          }
 131:          balance = numer / denom ;
 132:      }
 133:   
 134:      restricted static PrimeOrbital PrimeOrbital(int[] jumps)
 135:      {
 136:          PrimeOrbital o = new PrimeOrbital;
 137:          o.jumps = jumps;
 138:          o.primorial(jumps);
 139:          return o;
 140:      }
 141:   
 142:      public void write()
 143:      {
 144:         string s;
 145:         for(int j : jumps) { s += (string)j + " " ; }
 146:   
 147:         string p = " ["+(string)numer+ "/" +(string)denom+"] "
 148:                   +" "+format("%.3g", balance);
 149:   
 150:         write(s + p);
 151:      }
 152:   
 153:  }   from PrimeOrbital unravel PrimeOrbital;
 154:   
 155:   
 156:  // --------------- End of struct PrimeOrbital ----------------
 157:   
 158:   
 159:  struct PrimeOrbitalGenerator
 160:  {
 161:      private PrimeOrbital[] urbi;
 162:      private OrbitalGenerator og;
 163:      private int urbI;
 164:   
 165:      private void insertOrbit(int[] jumps)
 166:      {
 167:          urbi[++urbI] = PrimeOrbital(jumps);
 168:          if(urbI == 0) return;
 169:   
 170:          PrimeOrbital temp;
 171:   
 172:          for(int top = 0; top < urbI; ++top)
 173:          {
 174:              for(int j = top ; j >= 0; --j)
 175:              {
 176:                  if(urbi[j].balance < urbi[j+1].balance)
 177:                  {
 178:                      break;
 179:                  }
 180:                  temp = urbi[j];
 181:                  urbi[j] = urbi[j+1];
 182:                  urbi[j+1] = temp;
 183:              }
 184:          }
 185:      }
 186:   
 187:      private void visit(int[] jumps)
 188:      {
 189:          insertOrbit(jumps);
 190:      }
 191:   
 192:      restricted static PrimeOrbitalGenerator
 193:                        PrimeOrbitalGenerator(int len)
 194:      {
 195:          PrimeOrbitalGenerator psog = new PrimeOrbitalGenerator;
 196:          psog.og = OrbitalGenerator(len, psog.visit);
 197:          return psog;
 198:      }
 199:   
 200:      public PrimeOrbital[] generate()
 201:      {
 202:          urbI = -1;
 203:          og.generate();
 204:          return urbi;
 205:      }
 206:   
 207:      public void write()
 208:      {
 209:          for(PrimeOrbital po : urbi) po.write();
 210:      }
 211:   
 212:  }   from PrimeOrbitalGenerator unravel PrimeOrbitalGenerator;
 213:   
 214:   
 215:  // ----------- End of struct PrimeOrbitalGenerator -----------