blink1073 / oct2py

Run M Files from Python - GNU Octave to Python bridge
http://blink1073.github.io/oct2py/
MIT License
261 stars 54 forks source link

Capturing Multiple Returns #66

Closed cancan101 closed 9 years ago

cancan101 commented 9 years ago

I have a function that looks like:

function [f, h1f, h2f, A, theta, psi] = ...
    monofilt(im, nscale, minWaveLength, mult, sigmaOnf, orientWrap)

Doing this:

ret = %octave monofilt(b, 3, 4, 2, 0.65) -i b

yields only the f return value. How do I capture the remaining values?

blink1073 commented 9 years ago

Nargout is inferred by oct2py, so you need to put all of the variables on the lhs.

cancan101 commented 9 years ago

This does not seem to work either:

In [77]: f,h1f,h2f,A,theta,psi = %octave monofilt(b, 3, 4, 2, 0.65) -i b

ans = 
{
  [1,1] =

    -0.41105  -0.13702
    0.13702  0.41105

  [1,2] =

  1.0e-03  *

    -8.45872  -2.81957
    2.81957  8.45872

  [1,3] =

  1.0e-05  *

    -1.30714  -0.43571
    0.43571  1.30714

}
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-77-2bec253f83ef> in <module>()
----> 1 f,h1f,h2f,A,theta,psi = get_ipython().magic(u'octave monofilt(b, 3, 4, 2, 0.65) -i b')

ValueError: need more than 3 values to unpack
blink1073 commented 9 years ago

Whoops, I was thinking from a direct command perspective. You need to use the -o option for the magic. Try:

%octave monofilt(b, 3, 4, 2, 0.65) -i b -o f,h1f,h2f,A,theta,psi
print(f,h1f,h2f,A,theta,psi)
cancan101 commented 9 years ago

That worked. So the first argument is automatically / implicitly copied from Octave to Python but the remaining but be specified?

blink1073 commented 9 years ago

When you call a method of an Oct2Py object or eval, the number of items on the LHS is reflected in the call to Octave, but if there aren't any then ans is caputured. The magic works differently to be consistent with other magics.

cancan101 commented 9 years ago

This might be related to that. I am getting different results for these two different calls:

In [101]:

octave.monofilt(b, 3, 4, 2, 0.65)
Out[101]:
[array([[ 0.,  0.],
        [ 0.,  0.]]), array([[ 0.,  0.],
        [ 0.,  0.]]), array([[ 0.,  0.],
        [ 0.,  0.]])]

vs this:

In [102]:

%octave monofilt(b, 3, 4, 2, 0.65) -i b -o f,h1f,h2f,A,theta,psi
ans = 
{
  [1,1] =

    -0.41105  -0.13702
    0.13702  0.41105

  [1,2] =

  1.0e-03  *

    -8.45872  -2.81957
    2.81957  8.45872

  [1,3] =

  1.0e-05  *

    -1.30714  -0.43571
    0.43571  1.30714

}
Out[102]:
[array([[-0.41104991, -0.13701664],
        [ 0.13701664,  0.41104991]]), array([[-0.00845872, -0.00281957],
        [ 0.00281957,  0.00845872]]), array([[ -1.30713648e-05,  -4.35712159e-06],
        [  4.35712159e-06,   1.30713648e-05]])]
blink1073 commented 9 years ago

So in the first case nargout is 1, is that the expect output? For the second, you need to put a semicolon after the function call to suppress the output since it is evaled. Otherwise, are those the expected outputs when nargout=6?

cancan101 commented 9 years ago

Ok. Adding the semicolon to improve readability:

In [101]:

octave.monofilt(b, 3, 4, 2, 0.65)
Out[101]:
[array([[ 0.,  0.],
        [ 0.,  0.]]), array([[ 0.,  0.],
        [ 0.,  0.]]), array([[ 0.,  0.],
        [ 0.,  0.]])]
In [113]:

%octave monofilt(b, 3, 4, 2, 0.65); -i b -o f,h1f,h2f,A,theta,psi
Out[113]:
[array([[-0.41104991, -0.13701664],
        [ 0.13701664,  0.41104991]]), array([[-0.00845872, -0.00281957],
        [ 0.00281957,  0.00845872]]), array([[ -1.30713648e-05,  -4.35712159e-06],
        [  4.35712159e-06,   1.30713648e-05]])]

All 0s is not the expected output.

The second case it my reference and I believe the values look good.

cancan101 commented 9 years ago

Actually on closer inspection, I do not think this is working right:

In [28]:

b = np.array([[1, 2], [3, 4]])
%octave monofilt(b, 3, 4, 2, 0.65); -i b -o f,h1f,h2f,A,theta,psi
print(f,h1f,h2f,A,theta,psi)
(None, None, None, None, None, None)
blink1073 commented 9 years ago

I don't think you can define an input and use it in the same block. Same for output.

cancan101 commented 9 years ago

Still does not look to work:

In [30]:

b = np.array([[1, 2], [3, 4]])
In [31]:

%octave monofilt(b, 3, 4, 2, 0.65); -i b -o f,h1f,h2f,A,theta,psi
Out[31]:
[array([[-0.41104991, -0.13701664],
        [ 0.13701664,  0.41104991]]), array([[-0.00845872, -0.00281957],
        [ 0.00281957,  0.00845872]]), array([[ -1.30713648e-05,  -4.35712159e-06],
        [  4.35712159e-06,   1.30713648e-05]])]
In [32]:

print(f,h1f,h2f,A,theta,psi)
(None, None, None, None, None, None)
blink1073 commented 9 years ago

Hmm, try with no space after -o

cancan101 commented 9 years ago

Nope. Using the roundtrip from the docs (with semicolons added to assignments):

In [44]:

%octave roundtrip(b); -i b -o q,g
Out[44]:
array([[1, 2],
       [3, 4]])
In [45]:

print(q,g)
(None, None)
In [46]:

%octave roundtrip(b); -i b -oq,g
Out[46]:
array([[1, 2],
       [3, 4]])
In [47]:

print(q,g)
(None, None)
blink1073 commented 9 years ago

Ah, I finally see the problem with the magic:

%octave f,h1f,h2f,A,theta,psi = octave.monofilt(b, 3, 4, 2, 0.65); -i b -o f,h1f,h2f,A,theta,psi 

or without using magic:

f,h1f,h2f,A,theta,psi = octave.monofilt(b, 3, 4, 2, 0.65)
print(f,h1f,h2f,A,theta,psi)
blink1073 commented 9 years ago

Whoops, you'll need brackets:

%octave [f,h1f,h2f,A,theta,psi] = octave.monofilt(b, 3, 4, 2, 0.65); -i b -o f,h1f,h2f,A,theta,psi 
blink1073 commented 9 years ago

Time to add a few more examples to the notebook methinks...

cancan101 commented 9 years ago

Should be:

%octave [f,h1f,h2f,A,theta,psi] = monofilt(b, 3, 4, 2, 0.65); -i b -o f,h1f,h2f,A,theta,psi
cancan101 commented 9 years ago

The example without the magic does not work:

In [79]:

f,h1f,h2f,A,theta,psi = octave.monofilt(b, 3, 4, 2, 0.65)
print(f,h1f,h2f,A,theta,psi)
([array([[ 0.,  0.],
       [ 0.,  0.]]), array([[ 0.,  0.],
       [ 0.,  0.]]), array([[ 0.,  0.],
       [ 0.,  0.]])], [array([[ 0.,  0.],
       [ 0.,  0.]]), array([[ 0.,  0.],
       [ 0.,  0.]]), array([[ 0.,  0.],
       [ 0.,  0.]])], [array([[ 0.,  0.],
       [ 0.,  0.]]), array([[ 0.,  0.],
       [ 0.,  0.]]), array([[ 0.,  0.],
       [ 0.,  0.]])], [array([[ 0.,  0.],
       [ 0.,  0.]]), array([[ 0.,  0.],
       [ 0.,  0.]]), array([[ 0.,  0.],
       [ 0.,  0.]])], [array([[ 0.,  0.],
       [ 0.,  0.]]), array([[ 0.,  0.],
       [ 0.,  0.]]), array([[ 0.,  0.],
       [ 0.,  0.]])], [array([[ 0.,  0.],
       [ 0.,  0.]]), array([[ 0.,  0.],
       [ 0.,  0.]]), array([[ 0.,  0.],
       [ 0.,  0.]])])

whereas this works:

In [81]:

%octave [f,h1f,h2f,A,theta,psi] = monofilt(b, 3, 4, 2, 0.65); -i b -o f,h1f,h2f,A,theta,psi
print(f,h1f,h2f,A,theta,psi)
([array([[-0.41104991, -0.13701664],
       [ 0.13701664,  0.41104991]]), array([[-0.00845872, -0.00281957],
       [ 0.00281957,  0.00845872]]), array([[ -1.30713648e-05,  -4.35712159e-06],
       [  4.35712159e-06,   1.30713648e-05]])], [array([[ 0.,  0.],
       [ 0.,  0.]]), array([[ 0.,  0.],
       [ 0.,  0.]]), array([[ 0.,  0.],
       [ 0.,  0.]])], [array([[ 0.,  0.],
       [ 0.,  0.]]), array([[ 0.,  0.],
       [ 0.,  0.]]), array([[ 0.,  0.],
       [ 0.,  0.]])], [array([[ 0.41104991,  0.13701664],
       [ 0.13701664,  0.41104991]]), array([[ 0.00845872,  0.00281957],
       [ 0.00281957,  0.00845872]]), array([[  1.30713648e-05,   4.35712159e-06],
       [  4.35712159e-06,   1.30713648e-05]])], [array([[ 0.,  0.],
       [ 0.,  0.]]), array([[ 0.,  0.],
       [ 0.,  0.]]), array([[ 0.,  0.],
       [ 0.,  0.]])], [array([[-1.57079633, -1.57079633],
       [ 1.57079633,  1.57079633]]), array([[-1.57079633, -1.57079633],
       [ 1.57079633,  1.57079633]]), array([[-1.57079633, -1.57079633],
       [ 1.57079633,  1.57079633]])])
blink1073 commented 9 years ago

I'm not sure what to say about the non-magic version not working. It is getting the right number of nargout... Can you share the monofilt function?

cancan101 commented 9 years ago

http://www.csse.uwa.edu.au/~pk/research/matlabfns/PhaseCongruency/monofilt.m

blink1073 commented 9 years ago

We've exposed a source of friction. Oct2Py sends integers to Octave as integer type, since they are interpreted as such by numpy. The following works:

f,h1f,h2f,A,theta,psi = octave.monofilt(b,3.,4.,2.,0.65)
cancan101 commented 9 years ago

Why does the magic version perform differently?

On Fri, Jan 2, 2015, 21:53 Steven Silvester notifications@github.com wrote:

We've exposed a source of friction. Oct2Py sends integers to Octave as integer type, since they are interpreted as such by numpy. The following works:

f,h1f,h2f,A,theta,psi = octave.monofilt(b,3.,4.,2.,0.65)

— Reply to this email directly or view it on GitHub https://github.com/blink1073/oct2py/issues/66#issuecomment-68580759.

blink1073 commented 9 years ago

In the magic version, everything is wrapped in octave.eval, so the arguments are sent as plain text, instead of through a MAT file.

— Sent from Mailbox

On Fri, Jan 2, 2015 at 10:08 PM, Alex Rothberg notifications@github.com wrote:

Why does the magic version perform differently? On Fri, Jan 2, 2015, 21:53 Steven Silvester notifications@github.com wrote:

We've exposed a source of friction. Oct2Py sends integers to Octave as integer type, since they are interpreted as such by numpy. The following works:

f,h1f,h2f,A,theta,psi = octave.monofilt(b,3.,4.,2.,0.65)

— Reply to this email directly or view it on GitHub https://github.com/blink1073/oct2py/issues/66#issuecomment-68580759.


Reply to this email directly or view it on GitHub: https://github.com/blink1073/oct2py/issues/66#issuecomment-68582498

cancan101 commented 9 years ago

Okay. If that fact isn't in the docs, it would be worth adding it. I assumed the two worked using the same mechanism.

On Fri Jan 02 2015 at 11:15:49 PM Steven Silvester notifications@github.com wrote:

In the magic version, everything is wrapped in octave.eval, so the arguments are sent as plain text, instead of through a MAT file.

— Sent from Mailbox

On Fri, Jan 2, 2015 at 10:08 PM, Alex Rothberg notifications@github.com wrote:

Why does the magic version perform differently? On Fri, Jan 2, 2015, 21:53 Steven Silvester notifications@github.com wrote:

We've exposed a source of friction. Oct2Py sends integers to Octave as integer type, since they are interpreted as such by numpy. The following works:

f,h1f,h2f,A,theta,psi = octave.monofilt(b,3.,4.,2.,0.65)

— Reply to this email directly or view it on GitHub https://github.com/blink1073/oct2py/issues/66#issuecomment-68580759.


Reply to this email directly or view it on GitHub: https://github.com/blink1073/oct2py/issues/66#issuecomment-68582498

— Reply to this email directly or view it on GitHub https://github.com/blink1073/oct2py/issues/66#issuecomment-68582622.

cancan101 commented 9 years ago

Something else is still not right between these two. I download this file: http://4.bp.blogspot.com/-ruV5mllFtxA/TjosZziIddI/AAAAAAAAAIw/o8aU8O1ZfqM/s1600/BlackWhite.gif and then load it using:

import numpy as np
from PIL import Image
a = np.asarray(Image.open('BlackWhite.gif'))/255.

This takes a few seconds:

%octave [f,h1f,h2f,A,theta,psi] = monofilt(a, 3, 4, 2, 0.65); -i a -o f,h1f,h2f,A,theta,psi

but this never returns / takes a VERY long time:

f,h1f,h2f,A,theta,psi = octave.monofilt(a, 3., 4., 2., 0.65)
blink1073 commented 9 years ago

Thanks for the feedback. The problem was that the output was not suppressed on the second version, causing it to print a lot to the console, (but not displayed on this end, since the logger is not set to DEBUG by default). I'm going to release version 3.0 that converts int -> float by default and suppresses that output (hopefully by this weekend).

blink1073 commented 9 years ago

I just released 3.0, which fixes this issue.