mila-iqia / myia

Myia prototyping
MIT License
455 stars 46 forks source link

Myia backend python #379

Closed notoraptor closed 3 years ago

notoraptor commented 3 years ago

Integration done, but not all operations yet implemented. Running all tests should help me detect some other issues.

notoraptor commented 3 years ago

Hi @breuleux @abergeron ! I think Python backend works now. Tests passed on Jenkins.

However, it seems there is a recurring timeout error in Travis, and I have a certificate issue when I try to access jenkins results.

Do you know how to fix travis/jenkins issues ?

About timeout, should I remove some tests to speed up whole testing ?

breuleux commented 3 years ago

@notoraptor Is the timeout issue a result of running all the tests for a third backend? If so, I'm not sure what the proper solution would be.

For Jenkins, it's a recurrent problem, but I don't know how it was solved before. @abergeron?

notoraptor commented 3 years ago

@breuleux I think it's indeed related to running all tests for 3 backends, as tests seems to have succeeded on Jenkins (though I cannot access Jenkins report ...). Only Travis fails.

notoraptor commented 3 years ago

Hi @breuleux ! I updated the PR and addressed your requests.

I also split travis tests to make this PR succeed: there is now 1 travis run per backend. To do it, I introduced a new environment variable MYIA_TEST_BACEND to specify backend(s) to test. However, each run stills execute all static non-backend tests. Now both Travis and Jenkins pass, but I still can't check coverage, because Jenkins is unavailable.

About variable names, I added a new class Labeler in Python backend inspired from NodeLabeler in myia/debug/label.py . As example, this is the generated code obtained for test tests/test_algos.py::test_sumtree[python-cpu-grad0]:

(myia) notoraptor@notoraptor-linux:~/mila/dev/git/myia$ pytest -xvvs tests/test_algos.py::test_sumtree[python-cpu-grad0]
=========================================================================================== test session starts ===========================================================================================
platform linux -- Python 3.7.9, pytest-6.1.2, py-1.9.0, pluggy-0.13.1 -- /home/notoraptor/anaconda3/envs/myia/bin/python
cachedir: .pytest_cache
rootdir: /media/win/Users/notoraptor/mila/dev/git/myia, configfile: pytest.ini
plugins: cov-2.8.1, xdist-2.1.0, forked-1.3.0
collected 1 item                                                                                                                                                                                          

tests/test_algos.py::test_sumtree[python-cpu-grad0] <- myia/testing/multitest.py import math
import numpy as np
from myia.utils import RandomStateWrapper
from myia.lib import TaggedValue
import myia_backend_python.implementations as IMPL
def _graph(_param_v3):
    _int_1_v2 = 1
    _named_DEAD = None
    def _const_graph(_param_v4):
        _int_0_v2 = 0
        _int_0_v3 = 0
        _empty_env = {}
        _result_const_graph_v3 = _graph_v3(_param_v3)
        _result_apply_prim_tuple_getitem_v3 = _apply_prim_tuple_getitem_v7(_param_v4)
        _apply_prim_tuple_getitem_v8 = _result_apply_prim_tuple_getitem_v3[_int_0_v3]
        _apply_prim_env_getitem = _apply_prim_tuple_getitem_v8.get(_int_0_v2, _result_const_graph_v3)
        _apply_prim_make_tuple_v4 = (_empty_env, _apply_prim_env_getitem,)
        return _apply_prim_make_tuple_v4

    _apply_prim_hastag = _param_v3.has(_int_1_v2)
    _apply_prim_switch = _graph_v6 if _apply_prim_hastag else _graph_v7
    _result_apply_prim_switch = _apply_prim_switch(_param_v3)
    _apply_prim_tuple_getitem_v7 = _result_apply_prim_switch[_int_1_v2]
    _apply_prim_make_tuple_v3 = (_named_DEAD, _const_graph,)
    return _apply_prim_make_tuple_v3

def _graph_v2(_param_v5):
    _int_0_v4 = 0
    _int_0_v5 = 0
    _empty_env_v2 = {}
    _result_const_graph_v4 = _graph_v3(_param_v6)
    _result_apply_prim_tuple_getitem_v4 = _apply_prim_tuple_getitem_v10(_param_v5)
    _apply_prim_tuple_getitem_v9 = _result_apply_prim_tuple_getitem_v4[_int_0_v5]
    _apply_prim_env_getitem_v2 = _apply_prim_tuple_getitem_v9.get(_int_0_v4, _result_const_graph_v4)
    _apply_prim_make_tuple_v5 = (_empty_env_v2, _apply_prim_env_getitem_v2,)
    return _apply_prim_make_tuple_v5

def _graph_v3(_param_v7):
    _int_0_v6 = 0
    _apply_prim_hastag_v2 = _param_v7.has(_int_0_v6)
    _apply_prim_switch_v2 = _graph_v4 if _apply_prim_hastag_v2 else _graph_v5
    _result_apply_prim_switch_v2 = _apply_prim_switch_v2(_param_v7)
    return _result_apply_prim_switch_v2

def _graph_v4(_param_v8):
    _int_0_v7 = 0
    _int_1_v3 = 1
    _apply_prim_casttag = _param_v8.cast(_int_0_v7)
    _apply_prim_tuple_getitem_v11 = _apply_prim_casttag[_int_1_v3]
    _result_const_graph_v5 = _graph_v3(_apply_prim_tuple_getitem_v11)
    _apply_prim_tuple_getitem_v12 = _apply_prim_casttag[_int_0_v7]
    _result_const_graph_v6 = _graph_v3(_apply_prim_tuple_getitem_v12)
    _apply_prim_make_tuple_v6 = (_result_const_graph_v6, _result_const_graph_v5,)
    _apply_prim_tagged = _apply_prim_make_tuple_v6 if _int_0_v7 is None else TaggedValue(_int_0_v7, _apply_prim_make_tuple_v6)
    return _apply_prim_tagged

def _graph_v5(_param_v9):
    _int_1_v4 = 1
    _int_0_v8 = np.float64(0)
    _apply_prim_tagged_v2 = _int_0_v8 if _int_1_v4 is None else TaggedValue(_int_1_v4, _int_0_v8)
    return _apply_prim_tagged_v2

def _graph_v6(_param_v10):
    _named_DEAD_v2 = None
    _apply_prim_make_tuple_v7 = (_named_DEAD_v2, _graph_v11,)
    return _apply_prim_make_tuple_v7

def _graph_v7(_param_v11):
    _int_1_v5 = 1
    _int_0_v9 = 0
    _named_DEAD_v3 = None
    def _const_graph_v2(_param_v12):
        _int_1_v6 = 1
        _int_0_v10 = 0
        _empty_env_v3 = {}
        _apply_prim_tuple_getitem_v14 = _apply_prim_casttag_v2[_int_1_v5]
        _result_const_graph_v8 = _graph_v3(_apply_prim_tuple_getitem_v14)
        _apply_prim_tuple_getitem_v15 = _apply_prim_casttag_v2[_int_0_v9]
        _result_const_graph_v9 = _graph_v3(_apply_prim_tuple_getitem_v15)
        _apply_prim_make_tuple_v9 = (_result_const_graph_v9, _result_const_graph_v8,)
        _result_apply_prim_tuple_getitem_v5 = _apply_prim_tuple_getitem_v13(_param_v12)
        _apply_prim_tuple_getitem_v16 = _result_apply_prim_tuple_getitem_v5[_int_0_v9]
        _apply_prim_env_getitem_v3 = _apply_prim_tuple_getitem_v16.get(_int_1_v6, _apply_prim_make_tuple_v9)
        _apply_prim_tagged_v3 = _apply_prim_env_getitem_v3 if _int_0_v9 is None else TaggedValue(_int_0_v9, _apply_prim_env_getitem_v3)
        _apply_prim_unsafe_static_cast = _apply_prim_tagged_v3
        _empty_env_v3[_int_0_v10] = _apply_prim_unsafe_static_cast
        _apply_prim_env_setitem = _empty_env_v3
        _apply_prim_make_tuple_v10 = (_apply_prim_env_setitem,)
        return _apply_prim_make_tuple_v10

    _apply_prim_casttag_v2 = _param_v11.cast(_int_0_v9)
    _result_const_graph_v7 = _graph_v9(_apply_prim_casttag_v2)
    _apply_prim_tuple_getitem_v13 = _result_const_graph_v7[_int_1_v5]
    _apply_prim_make_tuple_v8 = (_named_DEAD_v3, _const_graph_v2,)
    return _apply_prim_make_tuple_v8

def _graph_v8(_param_v13):
    _int_0_v11 = 0
    _int_1_v7 = 1
    _int_1_v8 = 1
    _int_0_v12 = 0
    _empty_env_v4 = {}
    _apply_prim_tuple_getitem_v17 = _apply_prim_casttag_v3[_int_1_v7]
    _result_const_graph_v10 = _graph_v3(_apply_prim_tuple_getitem_v17)
    _apply_prim_tuple_getitem_v18 = _apply_prim_casttag_v3[_int_0_v11]
    _result_const_graph_v11 = _graph_v3(_apply_prim_tuple_getitem_v18)
    _apply_prim_make_tuple_v11 = (_result_const_graph_v11, _result_const_graph_v10,)
    _result_apply_prim_tuple_getitem_v6 = _apply_prim_tuple_getitem_v20(_param_v13)
    _apply_prim_tuple_getitem_v19 = _result_apply_prim_tuple_getitem_v6[_int_0_v11]
    _apply_prim_env_getitem_v4 = _apply_prim_tuple_getitem_v19.get(_int_1_v8, _apply_prim_make_tuple_v11)
    _apply_prim_tagged_v4 = _apply_prim_env_getitem_v4 if _int_0_v11 is None else TaggedValue(_int_0_v11, _apply_prim_env_getitem_v4)
    _apply_prim_unsafe_static_cast_v2 = _apply_prim_tagged_v4
    _empty_env_v4[_int_0_v12] = _apply_prim_unsafe_static_cast_v2
    _apply_prim_env_setitem_v2 = _empty_env_v4
    _apply_prim_make_tuple_v12 = (_apply_prim_env_setitem_v2,)
    return _apply_prim_make_tuple_v12

def _graph_v9(_param_v14):
    _int_1_v9 = 1
    _int_0_v13 = 0
    _named_DEAD_v4 = None
    def _const_graph_v3(_param_v15):
        _int_1_v10 = 1
        _empty_env_v5 = {}
        _result_apply_prim_tuple_getitem_v7 = _apply_prim_tuple_getitem_v24(_param_v15)
        _apply_prim_tuple_getitem_v25 = _result_apply_prim_tuple_getitem_v7[_int_1_v9]
        _result_apply_prim_tuple_getitem_v8 = _apply_prim_tuple_getitem_v22(_param_v15)
        _apply_prim_tuple_getitem_v26 = _result_apply_prim_tuple_getitem_v8[_int_1_v9]
        _apply_prim_make_tuple_v14 = (_apply_prim_tuple_getitem_v26, _apply_prim_tuple_getitem_v25,)
        _empty_env_v5[_int_1_v10] = _apply_prim_make_tuple_v14
        _apply_prim_env_setitem_v3 = _empty_env_v5
        _apply_prim_make_tuple_v15 = (_apply_prim_env_setitem_v3,)
        return _apply_prim_make_tuple_v15

    _apply_prim_tuple_getitem_v21 = _param_v14[_int_0_v13]
    _result_const_graph_v12 = _graph(_apply_prim_tuple_getitem_v21)
    _apply_prim_tuple_getitem_v22 = _result_const_graph_v12[_int_1_v9]
    _apply_prim_tuple_getitem_v23 = _param_v14[_int_1_v9]
    _result_const_graph_v13 = _graph(_apply_prim_tuple_getitem_v23)
    _apply_prim_tuple_getitem_v24 = _result_const_graph_v13[_int_1_v9]
    _apply_prim_make_tuple_v13 = (_named_DEAD_v4, _const_graph_v3,)
    return _apply_prim_make_tuple_v13

def _graph_v10(_param_v16):
    _int_1_v11 = 1
    _int_1_v12 = 1
    _empty_env_v6 = {}
    _result_apply_prim_tuple_getitem_v9 = _apply_prim_tuple_getitem_v29(_param_v16)
    _apply_prim_tuple_getitem_v27 = _result_apply_prim_tuple_getitem_v9[_int_1_v11]
    _result_apply_prim_tuple_getitem_v10 = _apply_prim_tuple_getitem_v30(_param_v16)
    _apply_prim_tuple_getitem_v28 = _result_apply_prim_tuple_getitem_v10[_int_1_v11]
    _apply_prim_make_tuple_v16 = (_apply_prim_tuple_getitem_v28, _apply_prim_tuple_getitem_v27,)
    _empty_env_v6[_int_1_v12] = _apply_prim_make_tuple_v16
    _apply_prim_env_setitem_v4 = _empty_env_v6
    _apply_prim_make_tuple_v17 = (_apply_prim_env_setitem_v4,)
    return _apply_prim_make_tuple_v17

def _graph_v11(_param_v17):
    _int_1_v13 = 1
    _int_0_v14 = 0
    _empty_env_v7 = {}
    _apply_prim_tagged_v5 = _param_v17 if _int_1_v13 is None else TaggedValue(_int_1_v13, _param_v17)
    _apply_prim_unsafe_static_cast_v3 = _apply_prim_tagged_v5
    _empty_env_v7[_int_0_v14] = _apply_prim_unsafe_static_cast_v3
    _apply_prim_env_setitem_v5 = _empty_env_v7
    _apply_prim_make_tuple_v18 = (_apply_prim_env_setitem_v5,)
    return _apply_prim_make_tuple_v18

def main(_param, _param_v2):
    _int_1 = 1
    _int_0 = 0
    _apply_prim_tuple_getitem = _param[_int_1]
    _result_const_graph = _graph(_apply_prim_tuple_getitem)
    _apply_prim_tuple_getitem_v2 = _result_const_graph[_int_1]
    _result_apply_prim_tuple_getitem = _apply_prim_tuple_getitem_v2(_param_v2)
    _apply_prim_tuple_getitem_v3 = _result_apply_prim_tuple_getitem[_int_1]
    _apply_prim_tuple_getitem_v4 = _param[_int_0]
    _result_const_graph_v2 = _graph(_apply_prim_tuple_getitem_v4)
    _apply_prim_tuple_getitem_v5 = _result_const_graph_v2[_int_1]
    _result_apply_prim_tuple_getitem_v2 = _apply_prim_tuple_getitem_v5(_param_v2)
    _apply_prim_tuple_getitem_v6 = _result_apply_prim_tuple_getitem_v2[_int_1]
    _apply_prim_make_tuple = (_apply_prim_tuple_getitem_v6, _apply_prim_tuple_getitem_v3,)
    _apply_prim_make_tuple_v2 = (_apply_prim_make_tuple,)
    return _apply_prim_make_tuple_v2

In:  in0=Pair(left=Pair(left=Pair(left=8.0, right=9.0), right=Pair(left=10.0, right=11.0)), right=Pair(left=Pair(left=12.0, right=13.0), right=Pair(left=14.0, right=15.0)))
Out: test_sumtree=92.0
dtest_sumtree/din0.left.left.left OK: == 1.0
dtest_sumtree/din0.left.left.right OK: == 1.0
dtest_sumtree/din0.left.right.left OK: == 1.0
dtest_sumtree/din0.left.right.right OK: == 1.0
dtest_sumtree/din0.right.left.left OK: == 1.0
dtest_sumtree/din0.right.left.right OK: == 1.0
dtest_sumtree/din0.right.right.left OK: == 1.0
dtest_sumtree/din0.right.right.right OK: == 1.0
PASSED

============================================================================================ warnings summary =============================================================================================
tests/test_algos.py::test_sumtree[python-cpu-grad0]
tests/test_algos.py::test_sumtree[python-cpu-grad0]
  /home/notoraptor/anaconda3/envs/myia/lib/python3.7/importlib/_bootstrap.py:219: RuntimeWarning: numpy.ufunc size changed, may indicate binary incompatibility. Expected 192 from C header, got 216 from PyObject
    return f(*args, **kwds)

-- Docs: https://docs.pytest.org/en/stable/warnings.html
====================================================================================== 1 passed, 2 warnings in 1.78s ======================================================================================
breuleux commented 3 years ago

@notoraptor Regarding the variable names, what I meant to say is that as much as possible, the names that the user gives to the functions and variables in the source code should be preserved. The information is there, it's just a matter or formatting it appropriately. For instance, the labeler might generate the name ▶✓sumtree for a graph, which if you look at the short_relation_symbols table in label.py corresponds to the sequence of transformations sumtree -> if_true -> grad_fprop (so it just displays the if_true transform to for brevity, and grad_fprop is mapped to ). So we could generate a name like sumtree__if_true__grad_fprop instead, by using a different map and a separator like __.

The information is in a chain starting from node.debug or graph.debug and then going through the about field. In the above case, graph.debug.about.relation == "grad_fprop", and graph.debug.about.debug.about.relation == "if_true", and graph.debug.about.debug.about.debug.name == "sumtree", more or less. There's already code that handles this in label.py.

breuleux commented 3 years ago

I introduced a new environment variable MYIA_TEST_BACEND to specify backend(s) to test.

Couldn't this be achieved more simply with the -m flag? pytest -m relay, pytest -m pytorch, pytest -m python, and pytest -m "not relay and not pytorch and not python" for non-backend tests? The appropriate tests already have the right marks, as far as I know.

notoraptor commented 3 years ago

Hi @breuleux ! Sorry, I didn't see your latest messages at time! Anyways:

notoraptor commented 3 years ago

Hi @breuleux , PR updated !

As example, see below is the code generated for tests/test_algos.py::test_sumtree[python-cpu-grad0] (to compare with code posted above). Code still keeps some original parameter names, but no internal variable names.

(myiagpu) notoraptor@notoraptor-linux:~/mila/dev/git/myia$ pytest -xvvs tests/test_algos.py::test_sumtree[python-cpu-grad0]
=========================================================================================== test session starts ===========================================================================================
platform linux -- Python 3.7.9, pytest-6.1.2, py-1.9.0, pluggy-0.13.1 -- /home/notoraptor/anaconda3/envs/myiagpu/bin/python
cachedir: .pytest_cache
rootdir: /media/win/Users/notoraptor/mila/dev/git/myia, configfile: pytest.ini
plugins: cov-2.10.1, xdist-2.1.0, forked-1.3.0
collected 1 item                                                                                                                                                                                          

tests/test_algos.py::test_sumtree[python-cpu-grad0] <- myia/testing/multitest.py 
import math
import numpy as np
from myia.utils import RandomStateWrapper
from myia.lib import TaggedValue
from myia.utils.universe import HandleInstance
import myia_backend_python.implementations as IMPL
def _21_sumtree(_t):
    def _22_sumtree_v2(_apply0_v3):
        # Constants
        _var__v2 = {}

        _23_zeros_like_U__apply0 = _23_zeros_like_U(_t)
        _apply0_v4 = _tuple_getitem__apply0_v3(_apply0_v3)
        _tuple_getitem_reroute__apply0 = _apply0_v4[0]
        _env_getitem__apply0 = _tuple_getitem_reroute__apply0.get(0, _23_zeros_like_U__apply0)
        return (_var__v2, _env_getitem__apply0,)

    _hastag_out = _t.has(1)
    _switch_rval = _31_sumtree if _hastag_out else _27_sumtree
    _var_ = _switch_rval(_t)
    _tuple_getitem__apply0_v3 = _var_[1]
    return (None, _22_sumtree_v2,)

def _22_sumtree(_apply0_v5):
    # Constants
    _var__v3 = {}

    _23_zeros_like_U__apply0_v2 = _23_zeros_like_U(_t_v2)
    _apply0_v6 = _tuple_getitem__apply0_v4(_apply0_v5)
    _tuple_getitem_reroute__apply0_v2 = _apply0_v6[0]
    _env_getitem__apply0_v2 = _tuple_getitem_reroute__apply0_v2.get(0, _23_zeros_like_U__apply0_v2)
    return (_var__v3, _env_getitem__apply0_v2,)

def _23_zeros_like_U(_apply0_v7):
    _hastag__apply0 = _apply0_v7.has(0)
    _switch__apply0 = _25_zeros_like_U_0 if _hastag__apply0 else _24__apply0
    return _switch__apply0(_apply0_v7)

def _25_zeros_like_U_0(_apply0_v8):
    _casttag__apply0 = _apply0_v8.cast(0)
    _tuple_getitem__apply0_v5 = _casttag__apply0[1]
    _23_zeros_like_U__apply0_v3 = _23_zeros_like_U(_tuple_getitem__apply0_v5)
    _tuple_getitem__apply0_v6 = _casttag__apply0[0]
    _23_zeros_like_U__apply0_v4 = _23_zeros_like_U(_tuple_getitem__apply0_v6)
    _make_tuple__apply0_v4 = (_23_zeros_like_U__apply0_v4, _23_zeros_like_U__apply0_v3,)
    return _make_tuple__apply0_v4 if 0 is None else TaggedValue(0, _make_tuple__apply0_v4)

def _24__apply0(_apply0_v9):
    return 0.0 if 1 is None else TaggedValue(1, 0.0)

def _31_sumtree(_t_v3):
    return (None, _32_sumtree,)

def _27_sumtree(_t_v4):
    def _28_sumtree_v2(_apply0_v10):
        # Constants
        _var__v5 = {}

        _tuple_getitem__apply0_v8 = _casttag_out[1]
        _23_zeros_like_U__apply0_v5 = _23_zeros_like_U(_tuple_getitem__apply0_v8)
        _tuple_getitem__apply0_v9 = _casttag_out[0]
        _23_zeros_like_U__apply0_v6 = _23_zeros_like_U(_tuple_getitem__apply0_v9)
        _make_tuple__apply0_v7 = (_23_zeros_like_U__apply0_v6, _23_zeros_like_U__apply0_v5,)
        _apply0_v11 = _tuple_getitem__apply0_v7(_apply0_v10)
        _tuple_getitem_8_sumtree = _apply0_v11[0]
        _env_getitem_v3 = _tuple_getitem_8_sumtree.get(1, _make_tuple__apply0_v7)
        _tagged_v3 = _env_getitem_v3 if 0 is None else TaggedValue(0, _env_getitem_v3)
        _unsafe_static_cast = _tagged_v3
        _var__v5[0] = _unsafe_static_cast
        _env_setitem__apply0 = _var__v5
        return (_env_setitem__apply0,)

    _casttag_out = _t_v4.cast(0)
    _29_sumtree_v2 = _29_sumtree(_casttag_out)
    _tuple_getitem__apply0_v7 = _29_sumtree_v2[1]
    return (None, _28_sumtree_v2,)

def _28_sumtree(_apply0_v12):
    # Constants
    _var__v6 = {}

    _tuple_getitem__apply0_v10 = _casttag_out_v2[1]
    _23_zeros_like_U__apply0_v7 = _23_zeros_like_U(_tuple_getitem__apply0_v10)
    _tuple_getitem__apply0_v11 = _casttag_out_v2[0]
    _23_zeros_like_U__apply0_v8 = _23_zeros_like_U(_tuple_getitem__apply0_v11)
    _make_tuple__apply0_v9 = (_23_zeros_like_U__apply0_v8, _23_zeros_like_U__apply0_v7,)
    _apply0_v13 = _tuple_getitem__apply0_v12(_apply0_v12)
    _tuple_getitem_8_sumtree_v2 = _apply0_v13[0]
    _env_getitem_v5 = _tuple_getitem_8_sumtree_v2.get(1, _make_tuple__apply0_v9)
    _tagged_v5 = _env_getitem_v5 if 0 is None else TaggedValue(0, _env_getitem_v5)
    _unsafe_static_cast_v3 = _tagged_v5
    _var__v6[0] = _unsafe_static_cast_v3
    _env_setitem__apply0_v2 = _var__v6
    return (_env_setitem__apply0_v2,)

def _29_sumtree(_out):
    def _30_sumtree_v2(_8):
        # Constants
        _var__v7 = {}

        _apply0_v14 = _tuple_getitem__apply0_v14(_8)
        _tuple_getitem_v22 = _apply0_v14[1]
        _apply0_v15 = _tuple_getitem__apply0_v13(_8)
        _tuple_getitem_v23 = _apply0_v15[1]
        _make_tuple__apply3_v2 = (_tuple_getitem_v23, _tuple_getitem_v22,)
        _var__v7[1] = _make_tuple__apply3_v2
        _env_setitem__apply0_v3 = _var__v7
        return (_env_setitem__apply0_v3,)

    _tuple_getitem_out_v3 = _out[0]
    _21_sumtree__apply0_v3 = _21_sumtree(_tuple_getitem_out_v3)
    _tuple_getitem__apply0_v13 = _21_sumtree__apply0_v3[1]
    _tuple_getitem_out_v4 = _out[1]
    _21_sumtree__apply0_v4 = _21_sumtree(_tuple_getitem_out_v4)
    _tuple_getitem__apply0_v14 = _21_sumtree__apply0_v4[1]
    return (None, _30_sumtree_v2,)

def _30_sumtree(_8_v2):
    # Constants
    _var__v8 = {}

    _apply0_v16 = _tuple_getitem__apply0_v15(_8_v2)
    _tuple_getitem_v25 = _apply0_v16[1]
    _apply0_v17 = _tuple_getitem__apply0_v16(_8_v2)
    _tuple_getitem_v26 = _apply0_v17[1]
    _make_tuple__apply3_v3 = (_tuple_getitem_v26, _tuple_getitem_v25,)
    _var__v8[1] = _make_tuple__apply3_v3
    _env_setitem__apply0_v4 = _var__v8
    return (_env_setitem__apply0_v4,)

def _32_sumtree(_9):
    # Constants
    _var__v9 = {}

    _tagged_v7 = _9 if 1 is None else TaggedValue(1, _9)
    _unsafe_static_cast_v5 = _tagged_v7
    _var__v9[0] = _unsafe_static_cast_v5
    _env_setitem__apply0_v5 = _var__v9
    return (_env_setitem__apply0_v5,)

def main(_grad_x, _dout):
    _tuple_getitem_out = _grad_x[1]
    _21_sumtree__apply0 = _21_sumtree(_tuple_getitem_out)
    _tuple_getitem__apply0 = _21_sumtree__apply0[1]
    _apply0 = _tuple_getitem__apply0(_dout)
    _tuple_getitem = _apply0[1]
    _tuple_getitem_out_v2 = _grad_x[0]
    _21_sumtree__apply0_v2 = _21_sumtree(_tuple_getitem_out_v2)
    _tuple_getitem__apply0_v2 = _21_sumtree__apply0_v2[1]
    _apply0_v2 = _tuple_getitem__apply0_v2(_dout)
    _tuple_getitem_v2 = _apply0_v2[1]
    _make_tuple__apply3 = (_tuple_getitem_v2, _tuple_getitem,)
    return (_make_tuple__apply3,)

In:  in0=Pair(left=Pair(left=Pair(left=8.0, right=9.0), right=Pair(left=10.0, right=11.0)), right=Pair(left=Pair(left=12.0, right=13.0), right=Pair(left=14.0, right=15.0)))
Out: test_sumtree=92.0
dtest_sumtree/din0.left.left.left OK: == 1.0
dtest_sumtree/din0.left.left.right OK: == 1.0
dtest_sumtree/din0.left.right.left OK: == 1.0
dtest_sumtree/din0.left.right.right OK: == 1.0
dtest_sumtree/din0.right.left.left OK: == 1.0
dtest_sumtree/din0.right.left.right OK: == 1.0
dtest_sumtree/din0.right.right.left OK: == 1.0
dtest_sumtree/din0.right.right.right OK: == 1.0
PASSED

============================================================================================ warnings summary =============================================================================================
tests/test_algos.py::test_sumtree[python-cpu-grad0]
tests/test_algos.py::test_sumtree[python-cpu-grad0]
  /home/notoraptor/anaconda3/envs/myiagpu/lib/python3.7/importlib/_bootstrap.py:219: RuntimeWarning: numpy.ufunc size changed, may indicate binary incompatibility. Expected 192 from C header, got 216 from PyObject
    return f(*args, **kwds)

-- Docs: https://docs.pytest.org/en/stable/warnings.html
====================================================================================== 1 passed, 2 warnings in 1.81s ======================================================================================

Finally, as this backend might be used for debug purposes, I added a backend option debug to help print generated code (if debug == True). It is tested in myia_backend_python/tests/test_python_debug.py.

notoraptor commented 3 years ago

@breuleux I moved Travis changes into the latest commit. Is it right ? I also removed short_relation_symbols.

breuleux commented 3 years ago

@notoraptor If you can squash together all the commits for the new backend (so that we end up with two commits), I'd be able to do a rebase and merge.

notoraptor commented 3 years ago

@breuleux done ! There is now just 2 commits in the PR.

notoraptor commented 3 years ago

@breuleux Updated, I added {"copy": "", "opt": ""} as relation symbols.