2
votes

I'm playing around with Julia and I'm using Sympy to which I think uses PyCall to call Python.

When I run the script below, I get a long error. It's too long to post all of it here, but here is the start of it:

LoadError: PyError (ccall(@pysym(:PyObject_Call), PyPtr, (PyPtr, PyPtr, 

PyPtr), o, arg, C_NULL)) <type 'exceptions.RuntimeError'>
RuntimeError('maximum recursion depth exceeded while calling a Python object',)
  File "d:\Users\OEM\AppData\Local\JuliaPro-0.6.0.1\pkgs-0.6.0.1\v0.6\Conda\deps\usr\lib\site-packages\sympy\core\cache.py", line 93, in wrapper
    retval = cfunc(*args, **kwargs)
  File "d:\Users\OEM\AppData\Local\JuliaPro-0.6.0.1\pkgs-0.6.0.1\v0.6\Conda\deps\usr\lib\site-packages\sympy\core\compatibility.py", line 809, in wrapper
    result = user_function(*args, **kwds)
  File "d:\Users\OEM\AppData\Local\JuliaPro-0.6.0.1\pkgs-0.6.0.1\v0.6\Conda\deps\usr\lib\site-packages\sympy\core\function.py", line 427, in __new__
    result = super(Function, cls).__new__(cls, *args, **options)
  File "d:\Users\OEM\AppData\Local\JuliaPro-0.6.0.1\pkgs-0.6.0.1\v0.6\Conda\deps\usr\lib\site-packages\sympy\core\cache.py", line 93, in wrapper
    retval = cfunc(*args, **kwargs)
  File "d:\Users\OEM\AppData\Local\JuliaPro-0.6.0.1\pkgs-0.6.0.1\v0.6\Conda\deps\usr\lib\site-packages\sympy\core\compatibility.py", line 809, in wrapper
    result = user_function(*args, **kwds)
  File "d:\Users\OEM\AppData\Local\JuliaPro-0.6.0.1\pkgs-0.6.0.1\v0.6\Conda\deps\usr\lib\site-packages\sympy\core\function.py", line 250, in __new__
    evaluated = cls.eval(*args)
  File "d:\Users\OEM\AppData\Local\JuliaPro-0.6.0.1\pkgs-0.6.0.1\v0.6\Conda\deps\usr\lib\site-packages\sympy\functions\elementary\integers.py", line 25, in eval
    if arg.is_imaginary or (S.ImaginaryUnit*arg).is_real:
  File "d:\Users\OEM\AppData\Local\JuliaPro-0.6.0.1\pkgs-0.6.0.1\v0.6\Conda\deps\usr\lib\site-packages\sympy\core\decorators.py", line 91, in __sympifyit_wrapper
    return func(a, b)
  File "d:\Users\OEM\AppData\Local\JuliaPro-0.6.0.1\pkgs-0.6.0.1\v0.6\Conda\deps\usr\lib\site-packages\sympy\core\decorators.py", line 132, in binary_op_wrapper
    return func(self, other)
  File "d:\Users\OEM\AppData\Local\JuliaPro-0.6.0.1\pkgs-0.6.0.1\v0.6\Conda\deps\usr\lib\site-packages\sympy\core\expr.py", line 140, in __mul__
    return Mul(self, other)
  File "d:\Users\OEM\AppData\Local\JuliaPro-0.6.0.1\pkgs-0.6.0.1\v0.6\Conda\deps\usr\lib\site-packages\sympy\core\cache.py", line 93, in wrapper
    retval = cfunc(*args, **kwargs)
  File "d:\Users\OEM\AppData\Local\JuliaPro-0.6.0.1\pkgs-0.6.0.1\v0.6\Conda\deps\usr\lib\site-packages\sympy\core\compatibility.py", line 809, in wrapper
    result = user_function(*args, **kwds)

And as you may be able to see, towards the end it repeats: see line 93 on the end, then line 140, then line 93...

Here is my code:

function oddPeriodSquareRoots()
#=
  Get the length of the continued fraction for square root of for the number i.
  E.g. √7=[2;(1,1,1,4)]
=#


irrationalNumber, intPart, fractionalPart = symbols(string("irrationalNumber intPart fractionalPart"))

for i in [6451]

    # For perfect squares, the period is 0
    irrationalNumber = BigFloat(sqrt(BigFloat(i)))
    if irrationalNumber == floor(irrationalNumber)
        continue
    end

    # Get the continued fraction using symbolic programming
    irrationalNumber = sqrt(Sym(i))

    continuedFractionLength = 0
    while true

        intPart = Sym(BigInt(floor(irrationalNumber)))
        if continuedFractionLength == 0
            firstContinuedFractionTimes2 = intPart*2
        end

        continuedFractionLength += 1
        if intPart == firstContinuedFractionTimes2
            break
        end

        fractionalPart = irrationalNumber - intPart
        irrationalNumber = 1 / fractionalPart

    end

    continuedFractionLength -= 1 # We ignore the first term.


end


return continuedFractionLength
end

This routine calculates the length of a continued fraction for the square root of some number. For the number 6451 it gives the error.

So my question is can this be resolved please?

2
also i don't see any recursion in your code - Azat Ibrakov
@AzatIbrakov Yes it's a project Euler thing. I changed it around a bit too! No but there is a while loop. So it goes around that 161 times and then I get the error. The continued fraction is 162 long in this case. Which makes me suspicious. - davo36
unfortunately i'm not familiar with julia and couldn't google out how to increase recursion limit through it, maybe you can use sys.setrecursionlimit for Python used by julia? - Azat Ibrakov
Yes this was how I did it, see answer below. - davo36

2 Answers

1
votes

I'm glad the recursionlimit solution was found. This hadn't been seen before. This comment is about how to streamline your SymPy code, as you seem to be confused about that. Basically, you just need to make your initial value symbolic, and then Julia's methods should (in most all cases) take care of the rest. Here is a slight rewrite:

using SymPy

using PyCall @pyimport sys sys.setrecursionlimit(10000)

""" Get the length of the continued fraction for square root of for the number i. E.g. √7=[2;(1,1,1,4)] """ function oddPeriodSquareRoots(n)

i = Sym(n)
# For perfect squares, the period is 0
continuedFractionLength = 0

irrationalNumber = sqrt(i)
if is_integer(irrationalNumber)
    return continuedFractionLength
end

# Get the continued fraction using symbolic programming

while true

    intPart = floor(irrationalNumber)
    if continuedFractionLength == 0
        firstContinuedFractionTimes2 = intPart*2
    end

        continuedFractionLength += 1
    if intPart == firstContinuedFractionTimes2
        break
    end

    fractionalPart = irrationalNumber - intPart
    irrationalNumber = 1 / fractionalPart

end

continuedFractionLength -= 1 # We ignore the first term.


return continuedFractionLength

end

0
votes

Thanks very much for everyone's input. I managed to solve this by putting these lines at the top of the file (in addition to the "Using Sympy" line which I had the whole time):

using SymPy

using PyCall
@pyimport sys
sys.setrecursionlimit(10000)

This sets the recursion limit in Python. Not sure why it has to be so large for this to work.

I did also remove some of my type conversions etc. I thought this might help with the error and/or speed. But it didn't really.

Also, removing the line where I declare the variables to by symbols doesn't stop the code from working.

irrationalNumber, intPart, fractionalPart = symbols(string("irrationalNumber intPart fractionalPart"))

Same in Python. So not sure what the point of it is.

But in Julia, either way I have to have that Sym() wrapper around these 2 lines:

irrationalNumber = sqrt(Sym(i))
...
intPart = Sym(floor(irrationalNumber))

By inspecting these types, with the use of typeof, I can see they are symbolic, not floats. Without them, everything turns into floats and so I'm not doing it symbolically.