fumitoh / modelx

Use Python like a spreadsheet!
https://modelx.io
GNU Lesser General Public License v3.0
90 stars 20 forks source link

How to make dynamic space cross-referencing each other? #21

Open alebaran opened 4 years ago

alebaran commented 4 years ago

How to make dynamic space cross-referencing each other? I've tried the following and it doesn't work:

from modelx import *
m = new_model()
def try_param_x(a):
    return {'refs': {'y': y_base(a), 'bases': _self}}
m.new_space(name='x', formula=try_param_x)
def try_param_y(a):
    return {'refs': {'x': x_base(a), 'bases': _self}}
m.new_space(name='y', formula=try_param_y, refs={'x_base': m.x})
m.x.y_base = m.y
m.x(1)
fumitoh commented 4 years ago

This is a good question actually, and I don't think its possible at the moment.

from modelx import *
m = new_model()

def try_param_x(a):
    return {'refs': {'y': y_base(a)}}   # No 'bases' key means Space x is the base space of x[a] for any a.

m.new_space(name='x', formula=try_param_x)  

def try_param_y(a):
    return {'refs': {'x': x_base(a)}}

m.new_space(name='y', formula=try_param_y)

m.x.y_base = m.y    # `y_base` in m.x.formula refers to m.y
m.y.x_base = m.x    # `x_base` in m.y.formula refers to m.x

m.x(1)  # => Python crashes

Python crashes because of a circular reference::

m.x(1) calls m.x.formula(1), which calls m.y(1) through y_base(1), which in turn calls m.y.formula(1), which calls m.x(1) through x_base(1) -> back to start

An ugly workaround is to define y in m.x.formula as m.y and x in m.y.formula as m.x, and refer to dynamic spaces in cells formulas with their parameters, such as y[a] or x[a].

I was not aware of this cross-reference use case, but there might be some use cases in ALM contexts. I will take a look if this circular reference can be avoided after finishing some enhancements I'm currently working on.

alebaran commented 4 years ago

It is indeed ALM related

alebaran commented 4 years ago

This functionality would really help