modelx v0.4.0 (15 March 2020)#

This release introduces major improvement in calculation tracing as well as some bug fixes. The calculation speed is also improved by 15% to 20%.

Enhancements#

Reference tracing

References are now traced. Prior to this release, when References were reassigned or deleted, the values of Cells calculated by referring the References in their formulas remained unchanged. From this release, the dependent values are cleared when References in their formulas change:

SpaceA.bar = 3

@mx.defcells(SpaceA)
def foo():
    return bar

foo()   # ==> 3
SpaceA.bar = 4
foo()   # ==> 4

Unlike Cells tracing, all the values of dependent Cells are cleared, whether they are actually used in the calculation of the values or not, as long as the References are referenced in the formulas of the Cells. In the example blow, foo(0) is not dependent on SpaceA.bar but its value is cleared upon the reassignment to SpaceA.bar:

SpaceA.bar = 3

@mx.defcells(SpaceA)
def foo(x):
    if x > 0:
        return bar
    else:
        return 0

foo(0)      # ==> 0
foo(1)      # ==> 3
dict(foo)   # ==> {0: 0, 1: 3}

SpaceA.bar = 4
dict(foo)    # ==> {}   (Both foo(0) and foo(1) are cleared.)

Attribute reference tracing

When References are referenced in formulas as attributes of Spaces, they are also traced, but unlike the case above, the dependency is determined based on whether the attributes are used in then calculation, in the same way as Cells tracing. In the example below, foo(0) is not dependent on SpaceA.SpaceB.bar, so they are not cleared upon the reassignment to SpaceA.SpaceB.bar:

SpaceA.SpaceB.bar = 3

@mx.defcells(SpaceA)
def foo(x):
    if x > 0:
        return SpaceB.bar   # bar is referenced as an attribute of SpaceB
    else:
        return 0

foo(0)      # ==> 0
foo(1)      # ==> 3
dict(foo)   # ==> {0: 0, 1: 3}

SpaceA.SpaceB.bar = 4
dict(foo)    # ==> {0: 0}   (Only foo(1) is cleared)

Space formula tracing

Cells and References in Space formulas are now also traced. When the values of Cells or References in Space formulas are updated, all the ItemSpaces created from the formula are cleared:

def formula(i):
    return {"refs": {"foo0": bar(), "foo1": baz}}

SpaceA = mx.new_space("SpaceA", formula=formula)

@mx.defcells
def foo(x):
    return 2 if x > 1 else foo1 if x > 0 else foo0

@mx.defcells
def bar():
    return 0

SpaceA.baz = 1

SpaceA[1].foo(2)    # ==> 2
SpaceA[1].foo(1)    # ==> 1
SpaceA[1].foo(0)    # ==> 0
dict(SpaceA[1].foo)     # ==> {2: 2, 1: 1, 0: 0}

SpaceA.bar = 2
dict(SpaceA[1].foo)     # ==> {}

SpaceA[1].foo(2)    # ==> 2
SpaceA[1].foo(1)    # ==> 1
SpaceA[1].foo(0)    # ==> 2
dict(SpaceA[1].foo)     # ==> {2: 2, 1: 1, 0: 2}

SpaceA.baz = 3
dict(SpaceA[1].foo)     # ==> {}

SpaceA[1].foo(2)    # ==> 2
SpaceA[1].foo(1)    # ==> 3
SpaceA[1].foo(0)    # ==> 2
dict(SpaceA[1].foo)     # ==> {2: 2, 1: 3, 0: 2}

Bug Fixes#

  • Bug with Spyder modelx plug-in which MxAnalyzer did not trace Cells in ItemSpaces properly.