Closed alebaran closed 4 years ago
modelx doesn't allow variable length parameters (*args or *kwargs). What's the reason you have to put `` before args?
*args
actually works, except for saving part.
I need a layer, which sums up results from all dynamic spaces for each of the variables. And I don't want to program it for each variable separately. Here is how I do it:
from modelx import *
m = new_model()
def s_arg(id):
pass
s = new_space('s', formula=s_arg)
@defcells
def a(i):
return i
@defcells
def b(i, j):
return i * j
def tot_arg(cell):
pass
tot = new_space('tot', formula=tot_arg)
m.m = m
@defcells
def Sum(*args):
return sum([m.s(id).cells[cell](*args[0]) for id in range(0,10)])
tot('a').Sum(2)
tot('b').Sum(2, 3)
In reality I go a bit further to make further referencing cleaner:
from modelx import *
m = new_model()
def s_arg(id):
pass
s = new_space('s', formula=s_arg)
@defcells
def a(i):
return i
@defcells
def b(i, j):
return i * j
def tot_cell_arg(cell):
pass
tot_cell = new_space('tot_cell', formula=tot_cell_arg)
m.m = m
@defcells
def Sum(*args):
return sum([m.s(id).cells[cell](*args[0]) for id in range(0,10)])
def tot_arg():
refs = {cell: m.tot_cell(cell).Sum for cell in m.s.cells}
return {'refs': refs}
tot = new_space('tot', formula=tot_arg)
tot().a(2)
tot().b(2, 3)
How about changing your first example to this
from modelx import *
m = new_model()
def s_arg(id):
pass
s = new_space('s', formula=s_arg)
@defcells
def a(i):
return i
@defcells
def b(i, j):
return i * j
def tot_arg(cell):
pass
tot = new_space('tot', formula=tot_arg)
m.m = m
@defcells
def Sum(args): # no *
return sum([m.s(id).cells[cell](*args) for id in range(0,10)]) # unpack with *
tot('a').Sum((2,)) # pass in tuple
tot('b').Sum((2,3)) # pass in tuple
In reality I go a bit further to make further referencing cleaner:
from modelx import * m = new_model() def s_arg(id): pass s = new_space('s', formula=s_arg) @defcells def a(i): return i @defcells def b(i, j): return i * j def tot_cell_arg(cell): pass tot_cell = new_space('tot_cell', formula=tot_cell_arg) m.m = m @defcells def Sum(*args): return sum([m.s(id).cells[cell](*args[0]) for id in range(0,10)]) def tot_arg(): refs = {cell: m.tot_cell(cell).Sum for cell in m.s.cells} return {'refs': refs} tot = new_space('tot', formula=tot_arg) tot().a(2) tot().b(2, 3)
How do you usually approach summing across dynamic spaces?
I've never tried it. Definitely need some work to make it more elegant. Did my solution above work?
How about changing your first example to this
from modelx import * m = new_model() def s_arg(id): pass s = new_space('s', formula=s_arg) @defcells def a(i): return i @defcells def b(i, j): return i * j def tot_arg(cell): pass tot = new_space('tot', formula=tot_arg) m.m = m @defcells def Sum(args): # no * return sum([m.s(id).cells[cell](*args) for id in range(0,10)]) # unpack with * tot('a').Sum((2,)) # pass in tuple tot('b').Sum((2,3)) # pass in tuple
The issue is that I need a clean syntax, which is fully interchangeable, with the original one. Here is the complete example:
from modelx import *
m = new_model()
def s_base_arg(id):
pass
s_base = new_space('s_base', formula=s_base_arg)
@defcells
def a(i):
return i
@defcells
def b(i, j):
return i * j
def tot_cell_arg(cell):
pass
tot_cell = new_space('tot_cell', formula=tot_cell_arg)
m.m = m
@defcells
def Sum(*args):
return sum([m.s_base(id).cells[cell](*args[0]) for id in range(0,10)])
def s_arg(id):
if id == -1:
refs = {cell: m.tot_cell(cell).Sum for cell in m.s_base.cells}
else:
refs = {cell: m.s_base(id).cells[cell] for cell in m.s_base.cells}
return {'refs': refs}
s = new_space('s', formula=s_arg)
s(-1).a(2)
s(0).a(2)
s(-1).b(2, 3)
s(0).b(2, 3)
Both s(-1)
and s(id)
are used in the further code in an interchangeable way. I mean with this that I need to perform the same calculations for both and I don't want to duplicate the code base.
I found a way:
from modelx import *
m = new_model()
def s_base_arg(id):
pass
s_base = new_space('s_base', formula=s_base_arg)
@defcells
def a(i):
return i
@defcells
def b(i, j):
return i * j
class Tot_func:
def __init__(self, space, cell):
self.cell = cell
self.space = space
def Sum(self, *args):
return sum([self.space(id).cells[self.cell](*args) for id in range(0, 10)])
m.Tot_func = Tot_func
m.m = m
def s_arg(id):
if id == -1:
refs = {cell: m.Tot_func(m.s_base, cell).Sum for cell in m.s_base.cells}
else:
refs = {cell: m.s_base(id).cells[cell] for cell in m.s_base.cells}
return {'refs': refs}
s = new_space('s', formula=s_arg)
s(-1).a(2)
s(0).a(2)
s(-1).b(2, 3)
s(0).b(2, 3)
Good. One minor improvement: no need to put []
within sum
There is a bug, when saving a model with a cell containing *args. The following code
Triggers an error
Note that the same call works for the model without saving:
m.s.b[()] = 2
It seems that saving adds an extra tuple layer to the *args:
(((1, 2),),)
This issue is blocking for me: if not fixed I'll need to significantly redesign / rebuild the code base.