Viper and return values

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
PappaPeppar
Posts: 30
Joined: Thu Dec 18, 2014 10:38 pm

Viper and return values

Post by PappaPeppar » Wed Oct 28, 2015 9:31 pm

Is it possible to return more than one value from a viper optimized method/function? E.g.

Code: Select all

@micropython.viper
def foo(v):
	return (v*2, v*3)
gives
ViperTypeError: can't do binary op between 'object' and 'int'

pagano.paganino
Posts: 89
Joined: Fri Sep 11, 2015 10:47 pm
Location: Italy

Re: Viper and return values

Post by pagano.paganino » Wed Oct 28, 2015 10:32 pm

Try this:

Code: Select all

@micropython.viper
def foo(v:int):
    return (v*2, v*3)

PappaPeppar
Posts: 30
Joined: Thu Dec 18, 2014 10:38 pm

Re: Viper and return values

Post by PappaPeppar » Thu Oct 29, 2015 8:14 am

I now realize that my simplified code extract does not show what I want to do. I want to use floats in the calculation.

Code: Select all

@micropython.viper
def foo(v:int):
	return (v*3.6, v*2.3)
Does not work.
Neither does

Code: Select all

@micropython.viper
def foo(v:int):
	a = int(v*3.6)
	b = int(v*2.3)
	return (a, b)
So it looks like viper can not do floats at all

PappaPeppar
Posts: 30
Joined: Thu Dec 18, 2014 10:38 pm

Re: Viper and return values

Post by PappaPeppar » Fri Oct 30, 2015 8:14 am

Nope, does not work. looking in the code it seems that viper does not support float.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Viper and return values

Post by pythoncoder » Fri Oct 30, 2015 9:10 am

As I understand it Viper can't handle heap allocations and hence can't do floats. Viper is somewhat experimental and is undocumented but is best suited for integer bit banging types of code. You could get around this with a little inline assembler, thus:

Code: Select all

from array import array

@micropython.asm_thumb
def calc(r0, r1):
    vldr(s0, [r0, 0])
    vldr(s1, [r0, 1])
    vcvt_f32_s32(s0, s0)    # convert 1st arg to float in s0
    vcvt_f32_s32(s1, s1)    # ditto 2nd arg in s1
    vldr(s2, [r1, 0])       # Coeffs in s2, s3
    vldr(s3, [r1, 1]) 
    vmul(s0, s0, s2)        # Products in s0, s1
    vmul(s1, s1, s3)
    vcvt_s32_f32(s0, s0)    # Convert to integer
    vcvt_s32_f32(s1, s1)
    vstr(s0, [r0, 0])
    vstr(s1, [r0, 1])       # Put in result array

coeffs = array('f', (3.6, 2.3))
result = array('i', (0,0))

@micropython.viper
def foo(x: int, y: int):
    result[0] = x
    result[1] = y
    calc(result, coeffs)

foo(7, 8)
print(result)
Peter Hinch
Index to my micropython libraries.

Damien
Site Admin
Posts: 647
Joined: Mon Dec 09, 2013 5:02 pm

Re: Viper and return values

Post by Damien » Fri Oct 30, 2015 11:32 am

Floats and memory allocation work just fine in viper. It's just that floats are not compiled into native code (yet...).

You need to make sure you do operations on like-types (eg object and object, or int and int). A float is of type object. Eg:

Code: Select all

@micropython.viper
def foo(x, y):
    return (x * 1.2 + y, x - 3.4 / y)
print(foo(3, 4.5))

PappaPeppar
Posts: 30
Joined: Thu Dec 18, 2014 10:38 pm

Re: Viper and return values

Post by PappaPeppar » Fri Oct 30, 2015 10:29 pm

Thanks for your answers.
There are obviously some constraints on how viper can be used.
This is the actual calculations I were trying to optimize.

Code: Select all

import math
import sys

L=220
R=170.0/2
K = (R/2*1.7320508075688772)**2
Rh = R/2
Lsq = L * L

def d(x ,y):
	yplusK = y+K

	Az = math.sqrt(Lsq - (x)**2 - (y-R)**2)
	Bz = math.sqrt(Lsq - (x-Rh)**2 - yplusK)
	Cz = math.sqrt(Lsq - (x+Rh)**2 - yplusK)
	return (Az, Bz, Cz)
It is the transform from cartesian coordinates to the z-position of the cars on the three towers on a delta style 3D printer. I might try to do it in assembler if it needs to be faster than it is now.

/Henrik

Damien
Site Admin
Posts: 647
Joined: Mon Dec 09, 2013 5:02 pm

Re: Viper and return values

Post by Damien » Sat Oct 31, 2015 10:08 am

If you just decorate that function with @micropython.native then it will run roughly twice as fast.

Using assembler will definitely give you the best performance, and shouldn't be too difficult to write.

If/when viper mode can optimise floats then it would be ideal for your case. Otherwise there is also a WIP feature to write module extensions in C and then dynamically load them using the import statement.

Finally, you could write the code in C and add it as an extension to the current firmware, a custom function.

PappaPeppar
Posts: 30
Joined: Thu Dec 18, 2014 10:38 pm

Re: Viper and return values

Post by PappaPeppar » Sat Oct 31, 2015 6:09 pm

Using @micropython.native like

Code: Select all

import math
import sys

L=220
R=170.0/2
K = (R/2*1.7320508075688772)**2
Rh = R/2
Lsq = L * L

@micropython.native
def d(x ,y):
	yplusK = y+K

	Az = math.sqrt(Lsq - (x)**2 - (y-R)**2)
	Bz = math.sqrt(Lsq - (x-Rh)**2 - yplusK)
	Cz = math.sqrt(Lsq - (x+Rh)**2 - yplusK)
	return (Az, Bz, Cz)
Gives me: NameError: name 'K' is not defined.
Anyway, the speed of this function is not that important for me at the moment.
Thanks for your support.

Damien
Site Admin
Posts: 647
Joined: Mon Dec 09, 2013 5:02 pm

Re: Viper and return values

Post by Damien » Sat Oct 31, 2015 10:11 pm

PappaPeppar wrote:Using @micropython.native like
...
Gives me: NameError: name 'K' is not defined.
Sorry, I can't reproduce this error. Running your above code (with an extra line to call d: print(d(1, 2))) works just fine on unix and pyboard.

Post Reply