OK, **I finally got it to compile with the original iteration count** , but 
man, did I have to jump through hoops to do it. 

To reduce the number of loops, instead of doing `brute force trial-and-error` 
to test each residue against the others to find its inverse, I found the code 
here

`https://rosettacode.org/wiki/Modular_inverse#Nim`

on Rosetta Code, that had a Nim version already done. [Notice: the code there 
doesn't compile without changing `proc mulInv(a0, b0): int =` to `proc 
mulInv(a0, b0: int): int =`. In fact, quite a few of those old Rosetta code Nim 
examples don't compile, but I digress.]
    
    
    proc mulInv(a0, b0: int): int =
      var (a, b, x0) = (a0, b0, 0)
      result = 1
      if b == 1: return
      while a > 1:
        let q = a div b
        a = a mod b
        swap a, b
        result = result - q * x0
        swap x0, result
      if result < 0: result += b0
    

Then I was able to eliminate the loop-in-a-loop construct, and just do this:
    
    
      var inverses: seq[int] = @[]
      for res in residues: inverses.add(mulInv(res,modpg))
    

I was trying to avoid using another function just to do this, since I don't use 
it at runtime, but you do what you gotta do. 

Does Nim already have this function in its library? If not, can you please add 
it (math lib, etc).

Below is final code that compiles with original compiler iteration value, with 
some added diagnostic checks.
    
    
    # Compute modular inverse of a to base b, e.g.  a*a_invese mod m = 1
    proc mulInv(a0, b0: int): int =
      var (a, b, x0) = (a0, b0, 0)
      result = 1
      if b == 1: return
      while a > 1:
        let q = a div b
        a = a mod b
        swap a, b
        result = result - q * x0
        swap x0, result
      if result < 0: result += b0
    
    # Create constant parameters for chosen PG at compile time
    proc genPGparameters(prime: int): (int, int, int, seq[int], seq[int], 
seq[int]) =
      echo("generating parameters for P", prime)
      let primes = [2, 3, 5, 7, 11, 13, 17, 19, 23]
      var modpg = 1
      for prm in primes: (modpg *= prm; if prm == prime: break)
      
      var pc = 1
      var residues: seq[int] = @[]
      while pc < modpg: (pc += 2; if gcd(modpg, pc) == 1: residues.add(pc))
      let rescnt = residues.len
      
      var restwins: seq[int] = @[]
      var j = 0
      while j < rescnt-1:
        if residues[j]+2 == residues[j+1]:
          restwins.add residues[j]; restwins.add residues[j+1]; j += 1
        j += 1
      let rescntp = restwins.len
      
      inverses: seq[int] = @[]
      for res in residues: inverses.add(mulInv(res,modpg))
      
      echo("residues size = ", residues.len)
      echo("inverses size = ", inverses.len)
      
      for j in 0..residues.len-1: (if residues[j]*inverses[j] mod modpg != 1: 
echo("error at index ",j))
      
      result = (modpg, rescnt, rescntp, residues, restwins, inverses)
    
    # Generate at compile time the parameters for P13
    const parameters = genPGparameters(13)
    
    

This must be is under the `Magical Limit` using P13. 

So what will it do with P17? And the answer is.......Nope! It bombs (again) 
when trying to compute the 92,160 values for the `residues` array, as it never 
gets to the inverse array computation. I ultimately tried changing the 
iteration variable upto 1 trillion again before giving up. I think I will need 
to rebuild Nim with a new value in that file to make it take. That's for 
tomorrow (maybe), unless someone can instruct me how to do it without 
rebuilding Nim.

So, at least partial success, and I have learned something new and useful.

**But Please, FIX THIS!, and DOCUMENT IT!**

Reply via email to