This notebook is a brief interlude: we suspend for the moment our discussion of abstraction to concentrate on coding aspects. The results of this reflections will lay the architecture of the code which will be the bedrock of future work.
So far, we have been implemented code to instantiate abstraction, analyze them, provide insights into them, compute abstraction errors as well as other measures. One by one we have integrated all these functions in a single monolithic class $\mathtt{Abstraction}$ in the src/SCMMappings.py file.
The structure of code looks as follows:
where we have a three classes:
Starting from the previous implementation, we refactored the code by externalizing all those functions that are not essential to the various abstraction classes. The classes $\mathtt{SCMMapping}$ and $\mathtt{Abstraction}$ are reduced to the essential functions used to access properties and perform internal manipulations.
Printing and evaluating functions are externalized in classes that will take care of these functions; these new classes are defined in src/printing.py and src/evaluating.py, respectively. This restructuring loosely follow the proxy design pattern, by giving charge of specific abstraction functions to a proxy class.
Furthermore, a few functions are made generic and exported into a src/utils.py file.
The new structure of code looks as follows:
where we have three main sections:
All the functions are substantially identical, only the overall architecture of the project has changes.
We run here a few tests to check the compatibility between the two implementations.
Let us import basic libraries:
import numpy as np
from src.legacy.SCMMappings_1_0 import Abstraction as legacyAbs
from src.SCMMappings_1_1 import Abstraction as newAbs
from src.printing import AbstractionPrinter
from src.evaluating import AbstractionErrorEvaluator
from src.evaluating import AbstractionInfoLossEvaluator
from src.evaluating import AbstractionEffectiveInformationEvaluator
from src.examples import smokingmodels as ex
import sys,io
We first testing the identity of printing and evaluation functions in our standard smoking toy example.
M0,M1,R,a,alphas = ex.standardA_M0chainSTC_M1chainSC()
We instantiate a model using the legacy code.
Al = legacyAbs(M0,M1,R,a,alphas)
And a model using the new code.
An = newAbs(M0,M1,R,a,alphas)
We now move on to assess the equality of the printing functions. Notice that for the new model we need to instantiate an AbstractionPrinter object.
Ap = AbstractionPrinter(An)
allmethods = dir(AbstractionPrinter)
methods = [m for m in allmethods if (m[0:2]!='__' and m[0:4]!='plot')]
old_stdout = sys.stdout
for m in methods:
sys.stdout = io.StringIO()
getattr(Al,m)()
output1 = sys.stdout.getvalue()
sys.stdout = io.StringIO()
getattr(Ap,m)()
output2 = sys.stdout.getvalue()
assert(output1==output2)
sys.stdout = old_stdout
Next we assess the equality in the evaluating functions. As before, for the new model, we instantiate a specific AbstractionEvaluator object.
Ae = AbstractionErrorEvaluator(An)
assert(Al.evaluate_abstraction_error() == Ae.evaluate_abstraction_errors())
The two objects behave in the same way.
For further confirmation, we run the test on another smoking toy model.
M0,M1,R,a,alphas = ex.standardA_M0chainSC_M1indepSC()
We instantiate old and new objects.
Al = legacyAbs(M0,M1,R,a,alphas)
An = newAbs(M0,M1,R,a,alphas)
We verify the identity for printing functions.
Ap = AbstractionPrinter(An)
allmethods = dir(AbstractionPrinter)
methods = [m for m in allmethods if (m[0:2]!='__' and m[0:4]!='plot')]
for m in methods:
sys.stdout = io.StringIO()
getattr(Al,m)()
output1 = sys.stdout.getvalue()
sys.stdout = io.StringIO()
getattr(Ap,m)()
output2 = sys.stdout.getvalue()
assert(output1==output2)
sys.stdout = old_stdout
We verify the identity for evaluating functions.
Ae = AbstractionErrorEvaluator(An)
assert(Al.evaluate_abstraction_error() == Ae.evaluate_abstraction_errors())
The two objects behave in the same way.
We have reorganized the code to manage our abstraction in a more modular way. The old code will still be available as legacy code in src/legacy/SCMMappings_1_0.py. The new code will be available in src/SCMMappings_1_1.py.
[Rischel2020] Rischel, Eigil Fjeldgren. "The Category Theory of Causal Models." (2020).
[Rubenstein2017] Rubenstein, Paul K., et al. "Causal consistency of structural equation models." arXiv preprint arXiv:1707.00819 (2017).