Re: Wrong copy of sequences?

2018-03-17 Thread lscrd
Yes, I know it works with **var**. I have once written a statement  let b = a 
in a program, **a** being a sequence, with a comment  # No copy. Reading this 
some months later, I was not sure that there is actually no copy (and I thought 
that, in fact, a copy is needed). So I done some checks and found these strange 
behaviors.


Re: Wrong copy of sequences?

2018-03-17 Thread StasB
Interestingly, this seems to work correctly: 


proc p() =
  var a = @[0, 1, 2, 3]
  discard a.pop
  var b = a # note the change from `let` to `var`
  a.add(5)
  echo a  # @[0, 1, 2, 5]
  echo b  # @[0, 1, 2]

p()


Looks like an optimization gone wrong. Perhaps the intent was for the sharing 
to happen between two `let` s.

[EDIT]

Looks like Iscrd beat me to it.


Re: Wrong copy of sequences?

2018-03-17 Thread lscrd
I use 0.18.0, so the results may differ, of course. When running in the 
browser, I get the same results as with version 0.18.0.

Maybe the compiler does some optimization but it cannot consider that _a_ and 
_b_ are not used in another place: they are used by _echo_.

Assigning with **var** works, of course, so, it 's clearly an optimization when 
assigning to a read-only object. I suppose, this has been done for performance 
reason.

I have tried with version 0.17.2. Indeed, I get a strange result in the first 
case, i.e.


@[0, 1, 2, 3]
@[54014246935360, 1]


So it seems that some bug has been fixed in version 0.18.0. For the other 
tests, the results are indeed the same.


Re: Wrong copy of sequences?

2018-03-17 Thread mashingan
I ran your code, using 0.17.2, it gave wrong seq in example 1, other than that 
it's same with your result.

Is that because the compiler infer that variable a and b didn't used at other 
place so it's safe to be shared? Just a guess tho


Wrong copy of sequences?

2018-03-17 Thread lscrd
I would like to discuss a problem I have encountered and for which I have 
submitted a report on the bug tracker with a different version using 
_newSeqOfCap_.

Here is a simple program:


proc p() =
  var a = @[0, 1, 2]
  let b = a
  a.add(3)
  echo a  # @[0, 1, 2, 3]
  echo b  # @[0, 1, 2]

p()


The result is logical: _a_ and _b_ are different sequences and modifying _a_ 
doesn 't change _b_.

Now, a somewhat different program.


proc p() =
  var a = @[0, 1, 2, 3]
  discard a.pop
  let b = a
  a.add(5)
  echo a  # @[0, 1, 2, 5]
  echo b  # @[0, 1, 2, 5]

p()


It seems that now _a_ and _b_ are sharing some memory. Looking at the generated 
C code, it appears that in the first case, when adding an element, there is a 
reallocation. This is not the case in the second program as there is enough 
room to receive the new value but it is not clear for me why the length of _b_ 
is modified.

But, what if we don't change the length at all?


proc p() =
  var a = @[0, 1, 2, 3]
  let b = a
  a[^1] = 4
  echo a  # @[0, 1, 2, 4]
  echo b  # @[0, 1, 2, 4]

p()


This seems clearly wrong to me. Now if we replace the sequence by an array.


proc p() =
  var a = [0, 1, 2, 3]
  let b = a
  a[^1] = 4
  echo a  # [0, 1, 2, 4]
  echo b  # [0, 1, 2, 3]

p()


And looking at the C code, there is clearly a copy, which was expected.

We can also get some odd behavior with parameters.


var a = @[0, 1, 2, 3]

proc p(s: seq[int]) =
  echo s  # @[0, 1, 2, 3]
  a[^1] = 4
  echo s  # @[0, 1, 2, 4]

p(a)


I think this problem is not likely to happen frequently, but it may cause some 
troubles. What do you think of it? And how could this been solved?


Re: Compiler won't scale (still)

2018-03-17 Thread jzakiya
OK, I set `MaxLoopIterations* = 1_000_000_000` (1 Billion) in 
`~/nim-0.18.0/compiler/vmdef.nim` and rebuilt doing `./koch boot -d:release` 
and was able to compile P17.

I think this value is way more reasonable, because as stated previously, on 
modern machines (or really any system with gigahertz clock speeds) we're only 
talking second for even a billion iterations.

I really hope you will up the value. Until so, I'll patch my own systems. 
Thanks for instructing how to do this.

`Again, I strongly urge you to PROMINENTLY DOCUMENT this capability too.`


Re: Nim syntax Quiz

2018-03-17 Thread Allin
Ok, correct answer to the quiz is: 8

You'll find the corrected code below.

As any decent quiz should, one trick question was included: although " 
_inheritance only works with non-final objects_ " is reported as syntax error, 
there's no syntax error at that line; _MyObject_ just should have been declared 
as  " _of RootObj_ ".


type MyTuple = tuple[a: int, b: int]

var myTuple: MyTuple = (a: 10, b: 10)

type MyObject = ref object of RootObj
  a: int

var myObject: MyObject = MyObject(a: 5)

type MySpecialObject = ref object of MyObject

var seqOfStrings: seq[int] = @[]

proc silentProc*() = discard

proc inc(a: var int) = a += 1


Btw1. This discussion is also relevant: 
[https://forum.nim-lang.org/t/3647](https://forum.nim-lang.org/t/3647) It's a 
fact that when the parser gets carried away, it may state some irrelevant line 
as the source of your error. (Due to what StasB stated above).

Again, use the error message line number as a hint, not as a fact.

Btw2. Below is an example of a program that produces - while being a 
pedantically correct error message - quite scary output for a newcomer. A 
friendlier (and admittedly unrealistic to achieve) alternative would be 
something like: _The & operator concatenates two strings, but the procedure 
debug does not return a string. Did you mean: debug("foo" & "bar")_


import logging
debug("foo") & "bar"


The lesson to be learned: Just take nim error messages with a grain of salt (at 
least until Nim 1.x). After all, nim is more programmer-friendly language than 
it's error messages might first suggest. 


Re: db_mysql & threads

2018-03-17 Thread Araq
Doesn't this mean that you have to use multiple connections? Which seems easy 
enough to do.


Re: Resolve: Error: parallel 'fields' iterator does not work for 'case' objects

2018-03-17 Thread GULPF
In the other tests you have posted you are not comparing case objects. E.g 
`boolValueAV.boolValue == boolValue` is fine because you are comparing bools, 
but `anyseqValueAV.anyseqValue == anyseqValue` will use the `==` proc for seqs, 
which internally will use the generic `==` proc for objects to compare the 
`AnyValue` objects in the seq. Since that proc doesn't support case objects, 
and `AnyValue` is a case object, it fails. The same thing happens with 
`boolValueAV == boolValueAV`, since in that case you are also comparing case 
objects.


Re: Case type and float: compiler seems to confuse float and float64

2018-03-17 Thread GULPF
`system.nim` has this comment: `'float64' is now an alias to 'float'; this 
solves many problems`. I don't know what the actual motivation for the behavior 
is, but it's definitely intended.


Re: Resolve: Error: parallel 'fields' iterator does not work for 'case' objects

2018-03-17 Thread GULPF
This happens because the built in `==` operator for objects simply doesn't work 
for case objects. You can get the same behavior by doing `boolValueAV == 
boolValueAV`. It should be possible to fix it by defining your own `==` 
operator for `AnyValue`.


Re: Resolve: Error: parallel 'fields' iterator does not work for 'case' objects

2018-03-17 Thread monster
In my "full modules", I have something like 22 types supported now. avAnySeq is 
the _last_ one to be checked, and the only one to fail (except for the float 
/float64 case). If I understand your reply properly, it's just "luck" that it 
only fails for avAnySeq? Maybe I shouldn't use "42" everywhere as test value...


Re: Case type and float: compiler seems to confuse float and float64

2018-03-17 Thread monster
So, it's a "feature" and not a bug? Is there any known rational, to act 
differently with float, than with int and uint?


Re: Case type and float: compiler seems to confuse float and float64

2018-03-17 Thread GULPF
`float` and `float64` are equivalent, even on 32bit architectures. `int` and 
`int64` on the other hand are distinct types which may or may not have the same 
underlying type. So you only need `avFloat64`, not `avFloat`.

You can observe this by naming the two converters the same - the compiler will 
complain that they have the same signature. Perhaps the compiler should 
complain when there are multiple converters with the same arguments/return type 
in the scope, since it's not clear which one will be called.


Resolve: Error: parallel 'fields' iterator does not work for 'case' objects

2018-03-17 Thread monster
As I said in the previous post, I'm trying to create a "Any Value" case type. 
Another problem I have is supporting "seq[AnyValue]". Seq of anything else 
seems to work. Maybe it's a type recursion problem? Is there a work-around?

Here's the example:


type
  AnyValueType* = enum
avBool,
# ...
avBoolSeq,
# ...
avAnySeq
  
  AnyValue* = object
case kind*: AnyValueType
of avBool: boolValue*: bool
# ...
of avBoolSeq: boolSeqValue*: seq[bool]
# ...
of avAnySeq: anyseqValue*: seq[AnyValue]

converter toBoolAnyValue*(v: bool): AnyValue {.inline, noSideEffect.} =
  result.kind = avBool
  result.boolValue = v

converter toBoolSeqAnyValue*(v: seq[bool]): AnyValue {.inline, 
noSideEffect.} =
  result.kind = avBoolSeq
  result.boolSeqValue = v

converter toSeqAnyValueAnyValue*(v: seq[AnyValue]): AnyValue {.inline, 
noSideEffect.} =
  result.kind = avAnySeq
  result.anyseqValue = v

when isMainModule:
  let boolValue: bool = true
  let boolValueAV: AnyValue = boolValue
  let boolSeqValue: seq[bool] = @[boolValue]
  let boolSeqValueAV: AnyValue = boolSeqValue
  let anyseqValue: seq[AnyValue] = @[boolValueAV]
  let anyseqValueAV: AnyValue = anyseqValue
  
  assert(boolValueAV.boolValue == boolValue)
  assert(boolSeqValueAV.boolSeqValue == boolSeqValue)
  assert(anyseqValueAV.anyseqValue == anyseqValue) # Compiler bug :(



Case type and float: compiler seems to confuse float and float64

2018-03-17 Thread monster
I'm trying to write a "Any Value" type, so I can create a type-safe 
string-to-any-value table. First I noticed the compiler seems to "confuse" byte 
and uint8, but I think it's normal, since I've read byte is just an alias for 
uint8. Unfortunately, it also has problems with float vs float64 (on 64bit 
architecture), which is strange, because it has no problem with int vs int64 
and uint vs uint64. Therefore, I think it's a bug.

Here's the code that compiles but fails to run:


type
  AnyValueType* = enum
avBool,
# ...
avFloat,
avFloat64
  
  AnyValue* = object
case kind*: AnyValueType
of avBool: boolValue*: bool
# ...
of avFloat: floatValue*: float
of avFloat64: float64Value*: float64

converter toBoolAnyValue*(v: bool): AnyValue {.inline, noSideEffect.} =
  result.kind = avBool
  result.boolValue = v

converter toFloatAnyValue*(v: float): AnyValue {.inline, noSideEffect.} =
  result.kind = avFloat
  result.floatValue = v

converter toFloat64AnyValue*(v: float64): AnyValue {.inline, noSideEffect.} 
=
  result.kind = avFloat64
  result.float64Value = v

when isMainModule:
  let boolValue: bool = true
  let floatValue: float = 42.0
  let float64Value: float64 = 42.0'f64
  
  let boolValueAV: AnyValue = boolValue
  let floatValueAV: AnyValue = floatValue
  let float64ValueAV: AnyValue = float64Value
  
  assert(boolValueAV.boolValue == boolValue)
  assert(floatValueAV.floatValue == floatValue)
  assert(float64ValueAV.float64Value == float64Value) # Compiler bug :(


And returns:


float64value.nim(38) float64value
system.nim(2839) sysFatal
Error: unhandled exception: float64Value is not accessible [FieldError]
Error: execution of an external program failed: 'bin/float64value '
The terminal process terminated with exit code: 1



Re: Stein's (binary) GCD algorithm (iterative version)

2018-03-17 Thread jzakiya
Here's a gist of the code.

[https://gist.github.com/jzakiya/b096b92c181ed343dab8c130c88f1d39](https://gist.github.com/jzakiya/b096b92c181ed343dab8c130c88f1d39)


Re: Stein's (binary) GCD algorithm (iterative version)

2018-03-17 Thread jzakiya
Back in the day I had that book, when I wore a younger man's clothes, and also 
**Applied Cryptography**. I wonder what happened to them

[https://www.goodreads.com/book/show/351301.Applied_Cryptography](https://www.goodreads.com/book/show/351301.Applied_Cryptography)


Re: How to turn thread spawn call into an async call

2018-03-17 Thread adrianv
I agree that would be fine. The two are very similar. To avoid the polling, 
threadpool should be able to transfer the result of its work to the async 
dispatch list of the calling thread when its done.

expanding my example you could do:


import os, asyncdispatch, threadpool

type Noise = distinct bool

proc doWork(param: int): Noise =
   # staff use sql
   echo "starting with ", param, " ..."
   sleep(5000)
   
   # complete the future var
   echo "... ok"

proc doOtherWork(p1:int, p2: int): Noise =
  echo "other starting with ", p1, " and ", p2, " ..."
  sleep(4000)
  
  # complete the future var
  echo "... other ok"

proc doRealWork(p1, p2, p3: int): int =
  echo "real starting with ", p1, " and ", p2, " and ", p3, " ..."
  sleep(3000)
  
  result = p1 + p2 + p3
  echo "... done real work"

proc asyncWaitFor (work: FlowVar[Noise], sleepTime: int = 500) {.async.} =
  ## waits asynchron for a FlowVar to finish
  while not work.isReady :
await sleepAsync(sleepTime)

proc asyncWaitFor[T: not Noise] (work: FlowVar[T], sleepTime: int = 
500):Future[T] {.async.} =
  ## waits asynchron for a FlowVar to finish
  while not work.isReady :
await sleepAsync(sleepTime)
  return ^work

proc callWorkAsync() {.async.} =
   let work = spawn doWork(1)
   let other = spawn doOtherWork(2, 3)
   let real = spawn doRealWork(4, 5, 6)
   let res = await asyncWaitFor(real)
   echo "real work returned: ", res
   await asyncWaitFor(work)
   await asyncWaitFor(other)


let call = callWorkAsync()
echo "do so more"
waitFor call
echo "done"




Re: Stein's (binary) GCD algorithm (iterative version)

2018-03-17 Thread mratsim
Relevant [Handbook of Applied 
Cryptography](http://cacr.uwaterloo.ca/hac/about/chap14.pdf) on page 17 of the 
this chapter 14 PDF (page 606 - chapter 14.4 of the whole book)

It has the binary GCD, extended binary GCD and Lehmer's GCD algorithm.


Re: db_mysql & threads

2018-03-17 Thread sky_khan
> can of worms ?

Yes, according to this : [MySql 
Reference](https://dev.mysql.com/doc/refman/5.7/en/c-api-threaded-clients.html) 
"Multiple threads cannot send a query to the MySQL server at the same time on 
the same connection"

So you'll have to serialize your queries anyway, what's the point then?


Re: Compiler won't scale (still)

2018-03-17 Thread StasB
Such a limit would probably be around a few seconds, rather than a fixed number 
of iterations, because that's where most people start to suspect that their 
computation is either too long or stuck in an infinite loop.


Re: Compiler won't scale (still)

2018-03-17 Thread Araq
Then the limit would depend on the used CPU. Bad idea IMO.


Re: Compiler won't scale (still)

2018-03-17 Thread Araq
> Why not add a flag to set/disable the iteration limit like he wants? I'm sure 
> that as the user base grows, more people are going to hit the limit and get 
> annoyed.

Because I am curious whether it can be supported out of the box by a 
"reasonable" limit first.


Re: What can we learn from the SO 2018 Dev Survey?

2018-03-17 Thread StasB
> It means that you're used to The Python Way of doing things, and don't want 
> to deviate from it without good reason

Developing/testing stuff out interactively is part of the Python Way of doing 
things for many people, at least in my experience.


Re: Compile-time type reflection API?

2018-03-17 Thread StasB
@Araq:

> An object does not only consist of fields, it can have case and when etc.

Which is part of the reason why doing something as simple as getting the fields 
robustly gets difficult when dealing directly with the AST; there isn't just 
one canonical representation. I thought the compiler might have such a 
canonical representation internally which can be queried, but I guess not.

@chrisheller:

> Keep in mind that you can write some of your own compile time methods

I did write my own (partial) solution. It just doesn't work for every valid 
tree configuration as of yet. If the plan is to write an API on top of the AST 
one anyway, then I guess I'll just keep building up on mine and release it 
eventually as a library when it becomes robust. Then someone could integrate 
into Nim core if it comes out any good.


Re: Compiler won't scale (still)

2018-03-17 Thread StasB
Why not add a flag to set/disable the iteration limit like he wants? I'm sure 
that as the user base grows, more people are going to hit the limit and get 
annoyed.


db_mysql & threads

2018-03-17 Thread lightness1024
Is it possible to have a thread that update contents on the table A, and 
another thread that queries table A on the same connexion, or I need 2 DbConn 
objects ? I guess it doesn't make much sense to share anyway since nim 
supposedly separates all memory, though I could copy the conn object on a 
channel ? can of worms ?


Re: What can we learn from the SO 2018 Dev Survey?

2018-03-17 Thread Libman
> To really appeal to Python programmers, Nim would have to support dynamic 
> compilation and a REPL.

Not necessarily. Being a Python programmer doesn't mean you can't do anything 
other than Python. It means that you're used to _The Python Way_ of doing 
things, and don 't want to deviate from it without good reason. Python 
programmers routinely optimize in C/C++ (and now Go), and Nim should offer a 
better alternative. Some aspects of Nim seem very Python-like, but some do not.

> > Since vscode doesn't work on all platforms
> 
> Wait, what?
> 
> [https://code.visualstudio.com/Download](https://code.visualstudio.com/Download)
>  \- you can have it on Windows, Linux, and Mac.

Yes, which is what most people use, and that's why I said vscode was the right 
choice as the default recommended code editor for Nim. (There's [some progress 
with 
FreeBSD](https://github.com/prash-wghats/Electron-VSCode-Atom-For-FreeBSD), but 
still not stable.)

But it doesn't run in restricted environments, Android / Termux, OpenBSD, 
HaikuOS, etc. Which is why, if vscode is the primary focus, I think vim should 
be second.

> If Nim can get REPL, that would be huge!!

Another random thought: [Anaconda now ships with 
vscode](https://www.anaconda.com/blog/company-blog/vs-code-in-anaconda-distribution-5-1/).
 I wonder if Nim would be a fitting component for that bundle... 


Stein's (binary) GCD algorithm (iterative version)

2018-03-17 Thread jzakiya
On the Ruby issue tracker replacing Euclid's gcd algorithm with Steins (binary) 
algorithm came up.

[https://bugs.ruby-lang.org/issues/13503](https://bugs.ruby-lang.org/issues/13503)

Here's the wikipedia article on it.

[https://en.wikipedia.org/wiki/Binary_GCD_algorithm](https://en.wikipedia.org/wiki/Binary_GCD_algorithm)

Here's a Nim implementation of the iterative version.


proc gcd(a, b: int): int =
  var (a, b) = (a, b)
  if a == 0: return b
  if b == 0: return a
  
  var k = 0
  while ((a or b) and 1) == 0:
a = a shr 1
b = b shr 1
k += 1
  
  while (a and 1) == 0: a = a shr 1
  
  while b != 0:
while (b and 1) == 0: b = b shr 1
if a > b: swap a,b
b -= a
  
  result = a shl k


Here's a Ruby implementation of it.


def gcd(a, b)
  return b if a.zero?
  return a if b.zero?
  
  k = 0
  while (a | b).even?
 a >>= 1; b >>= 1; k += 1
  end
  
  a >>= 1 while a.even?
  
  until b.zero?
b >>= 1 while b.even?
a, b = b, a if a > b
b -= a
  end
  
  a << k
end




Re: Compiler won't scale (still)

2018-03-17 Thread Araq
> Do I need to recompile|rebuild Nim to make the change?

Yup. `koch boot -d:release` creates the modified compiler if you have an 
installation where `koch boot` works (pick the "installation from source" 
route: 
[https://github.com/nim-lang/Nim#compiling](https://github.com/nim-lang/Nim#compiling)

> Why does this line cause this compiler iteration problem?

Because that line triggered the 1_500_000th iteration limit. This line is 
nothing special, any line could trigger this limit. 


Re: How to turn thread spawn call into an async call

2018-03-17 Thread slangmgh
I think what I really need is a new spawn which return a Future[T] rather than 
FlowVar[T].


Re: Compiler won't scale (still)

2018-03-17 Thread jzakiya
Compiling again for P17, with 0.18.0 and 0.17.2, the error messages point to 
`gcd` function in both cases:


# 0.18.0 error message

generating parameters for P17
stack trace: (most recent call last)
twinprimes_ssozp17par5d3.nim(87)
twinprimes_ssozp17par5d3.nim(65) genPGparameters
lib/pure/math.nim(452)   gcd
lib/pure/math.nim(452, 15) Error: interpretation requires too many iteratio



# 0.17.2 error message

generating parameters for P17
stack trace: (most recent call last)
twinprimes_ssozp17par5d3.nim(87)
twinprimes_ssozp17par5d3.nim(65) genPGparameters
lib/pure/math.nim(439)   gcd
lib/pure/math.nim(439, 15) Error: interpretation requires too many 
iterations


In both cases it points to the same line in `lib/pure/math.nim` (line 452 in 
0.18.0 or 439 in 0.17.2):


proc gcd*[T](x, y: T): T =
  ## Computes the greatest common divisor of ``x`` and ``y``.
  ## Note that for floats, the result cannot always be interpreted as
  ## "greatest decimal `z` such that ``z*N == x and z*M == y``
  ## where N and M are positive integers."
  var (x,y) = (x,y)# < this line is pointed to in both 
cases
  while y != 0:
x = x mod y
swap x, y
  abs x


Changing `var (x,y) = (x,y)` to `var x = x; var y = y` or changing variable 
names, in both cases, creates same results.

**Why does this line cause this compiler iteration problem?**


Re: How to turn thread spawn call into an async call

2018-03-17 Thread slangmgh
Now there is another problem. I hope I can write the code like this: 


proc ff1(p1: int): Result =
   # my db acess code here
   ..

proc ff2(p1, p2: int): Result =
   # my db acess code here
   ..

proc main() {.async.} =
   # async call ff1 with parameter
   let r1 = await callAsync(ff1(1))
   
   # async call ff2 with parameter
   let r2 = await callAsync(ff2(1, 2))
   ..


Because we pass the parameter 'ff1(1)' to callAsync, so callAsync must be a 
macro like this: 


macro callAsync*(p: untyped): untyped {.async.} =
   quote do:
  proc callme(evt: AsyncEvent): Result =
 let s = `p`
 evt.trigger()
 s
  
  let evt = newAsyncEvent()
  let fut = waitEvent(evt)
  let val = spawn callme(evt)
  await fut
  return ^val


But a macro cannot be {.async.}, so I cannot do this.

A limited way to resolve this problem is use an procval, here is the code: 


type
   Result* = ref object of RootObj
  body*: string
   Action = proc(): Result

proc waitEvent(evt: AsyncEvent): Future[void] =
   let fut = newFuture[void]("callAsync")
   addEvent(evt, (fd: AsyncFD) => (fut.complete(); true))
   return fut

proc callp(evt: AsyncEvent, p: Action): Result =
   let v = p()
   evt.trigger()
   v

proc callAsync*(p: Action): Future[Result] {.async.} =
   let evt = newAsyncEvent()
   let fut = waitEvent(evt)
   let val = spawn callp(evt, p)
   await fut
   return ^val

proc ff(): Result =
   echo "work"
   sleep(1000)
   Result(body: "hello")

block:
   let val = waitFor callAsync(ff)
   echo "future return ", val.body


The limitation is I can only call Action type proc, and I cannot pass the 
paramter freely.

Any way to solve the problem? Thanks.


Re: How to turn thread spawn call into an async call

2018-03-17 Thread slangmgh
@adrianv Thank you 


Re: Compiler won't scale (still)

2018-03-17 Thread jzakiya
One (last?) trick to reduce the number of iterations.

I changed this:


  var residues: seq[int] = @[]
  var pc = 1
  while pc < modpg: (pc += 2; if gcd(modpg, pc) == 1: residues.add(pc))
  let rescnt = residues.len



to this:


  var residues: seq[int] = @[]
  var pc = 1
  var inc = 4
  while pc < modpg: (pc += inc; inc = inc xor 0b110; if gcd(modpg, pc) == 
1: residues.add(pc))
  let rescnt = residues.len


This reduces the number of times `gcd` is called from half the numbers (all the 
odds) upto modpg (modpg/2) to a third (modpg/3).

This change produces the P3 PG residue sequence: `pcs = 6m +|- 1`


  pc = 1, 5, 7, 11, 13, 17, 19...
+4 +2  +4  +2  +4  +2


So while it shaves off some iterations of `gcd` it's still not enough to get 
P17 to compile.

`A REQUEST:` It would be really, really nice to use the boolean operators like: 
`x ^= y; x &= y`; etc. 


Re: Compiler won't scale (still)

2018-03-17 Thread jzakiya
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!**


Re: Compiler won't scale (still)

2018-03-17 Thread jzakiya
I started changing the `MaxLoopIterations* = 1500_000 # max iterations of all 
loops` line in `compiler/vmdef.nim` in increments of 1 million, until it was 
20M, recompiling after each change, and still got error. Then I went up in 100M 
increments until 1 trillion, and still got error.

Do I need to recompile|rebuild Nim to make the change? Is merely changing the 
file sufficient? I doesn't seem so.


Re: Why is my destructor not called?

2018-03-17 Thread matkuki
Oh, seems the **\--newruntime** compiler flag is needed for destructors to work.