|
@@ -6,24 +6,60 @@ version (by means of substitution).
|
|
|
|
|
|
|
|
from copy import deepcopy
|
|
from copy import deepcopy
|
|
|
|
|
|
|
|
-_LTX_ADD = []
|
|
|
|
|
-"""Additional statements to add in the LaTeX generation."""
|
|
|
|
|
-
|
|
|
|
|
-# TODO: better paths; i.e. remove common prefix and escape non-latex characters
|
|
|
|
|
-# TODO: change the delta?
|
|
|
|
|
-# TODO: variable step sizes?
|
|
|
|
|
class CBD2Latex:
|
|
class CBD2Latex:
|
|
|
"""
|
|
"""
|
|
|
Creates a corresponding set of LaTeX-equations for a CBD model.
|
|
Creates a corresponding set of LaTeX-equations for a CBD model.
|
|
|
|
|
|
|
|
Args:
|
|
Args:
|
|
|
model (CBD.CBD.CBD): The model to create the equations for.
|
|
model (CBD.CBD.CBD): The model to create the equations for.
|
|
|
|
|
+
|
|
|
|
|
+ Keyword Arguments:
|
|
|
|
|
+ show_steps (bool): When :code:`True`, all intermediary steps will
|
|
|
|
|
+ be shown. Defaults to :code:`False`.
|
|
|
|
|
+ ignore_path (bool): When :code:`True`, the name of the original model
|
|
|
|
|
+ will be removed from all path names. This name is
|
|
|
|
|
+ a common prefix over the system.
|
|
|
|
|
+ Defaults to :code:`True`.
|
|
|
|
|
+ escape_nonlatex (bool): When :code:`True`, non-latex characters are escaped
|
|
|
|
|
+ from the rendered result. Defaults to :code:`True`.
|
|
|
|
|
+ time_variable (str): The name for the variable that represents the time
|
|
|
|
|
+ (i.e., the current iteration). Defaults to :code:`'i'`.
|
|
|
|
|
+ render_latex (bool): When :code:`True`, the :func:`render` method will
|
|
|
|
|
+ output a latex-formatted string. Otherwise, simple
|
|
|
|
|
+ text formatting is done. Defaults to :code:`True`.
|
|
|
"""
|
|
"""
|
|
|
- def __init__(self, model):
|
|
|
|
|
|
|
+ def __init__(self, model, **kwargs):
|
|
|
self.model = model
|
|
self.model = model
|
|
|
|
|
+ self.config = {
|
|
|
|
|
+ "show_steps": False,
|
|
|
|
|
+ "ignore_path": True,
|
|
|
|
|
+ "escape_nonlatex": True,
|
|
|
|
|
+ "time_variable": 'i',
|
|
|
|
|
+ "render_latex": True
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for k in kwargs:
|
|
|
|
|
+ if k in self.config:
|
|
|
|
|
+ self.config[k] = kwargs[k]
|
|
|
|
|
+
|
|
|
self.equations = {}
|
|
self.equations = {}
|
|
|
- self.outputs = [self.model.getPath() + "." + x for x in self.model.getSignals().keys()]
|
|
|
|
|
|
|
+ self.outputs = [self._rename(self.model.getPath() + "." + x) for x in self.model.getSignals().keys()]
|
|
|
self._collect_equations()
|
|
self._collect_equations()
|
|
|
|
|
+ self._step = 0
|
|
|
|
|
+
|
|
|
|
|
+ def _rename(self, name):
|
|
|
|
|
+ """Makes the name of a path accurate.
|
|
|
|
|
+
|
|
|
|
|
+ Args:
|
|
|
|
|
+ name (str): The name to convert.
|
|
|
|
|
+ """
|
|
|
|
|
+ if self.config["ignore_path"]:
|
|
|
|
|
+ mname = self.model.getPath() + "."
|
|
|
|
|
+ if name.startswith(mname):
|
|
|
|
|
+ name = name[len(mname):]
|
|
|
|
|
+ if self.config["escape_nonlatex"]:
|
|
|
|
|
+ name = name.replace("_", r"\_")
|
|
|
|
|
+ return name
|
|
|
|
|
|
|
|
def _collect_equations(self):
|
|
def _collect_equations(self):
|
|
|
"""
|
|
"""
|
|
@@ -38,8 +74,8 @@ class CBD2Latex:
|
|
|
func = _BLOCK_MAP.get(block.getBlockType(), None)
|
|
func = _BLOCK_MAP.get(block.getBlockType(), None)
|
|
|
if func is None: continue
|
|
if func is None: continue
|
|
|
if isinstance(func, str):
|
|
if isinstance(func, str):
|
|
|
- func = lambda b, p, f=func: (p + ".OUT1", Fnc(f, [p + ".%s" % x for x in block.getInputPortNames()]))
|
|
|
|
|
- res = func(block, block.getPath())
|
|
|
|
|
|
|
+ func = lambda b, p, f=func: (p("OUT1"), Fnc(f, [p("%s") % x for x in block.getInputPortNames()]))
|
|
|
|
|
+ res = func(block, lambda x: self._rename(block.getPath() + "." + x))
|
|
|
if isinstance(res, tuple):
|
|
if isinstance(res, tuple):
|
|
|
self.equations[res[0]] = res[1]
|
|
self.equations[res[0]] = res[1]
|
|
|
elif isinstance(res, list):
|
|
elif isinstance(res, list):
|
|
@@ -52,41 +88,91 @@ class CBD2Latex:
|
|
|
path = block.getPath()
|
|
path = block.getPath()
|
|
|
for k, v in block.getLinksIn().items():
|
|
for k, v in block.getLinksIn().items():
|
|
|
if tp == "OutputPortBlock":
|
|
if tp == "OutputPortBlock":
|
|
|
- self.equations[path] = [v.block.getPath() + "." + v.output_port]
|
|
|
|
|
|
|
+ self.equations[self._rename(path)] = [self._rename(v.block.getPath() + "." + v.output_port)]
|
|
|
else:
|
|
else:
|
|
|
- self.equations[path + "." + k] = v.block.getPath() + "." + v.output_port
|
|
|
|
|
|
|
+ self.equations[self._rename(path + "." + k)] = self._rename(v.block.getPath() + "." + v.output_port)
|
|
|
|
|
|
|
|
- def render(self):
|
|
|
|
|
|
|
+ def render(self, rl=True):
|
|
|
"""
|
|
"""
|
|
|
Creates the LaTeX string for the model, based on the current level of simplifications.
|
|
Creates the LaTeX string for the model, based on the current level of simplifications.
|
|
|
|
|
+
|
|
|
|
|
+ Args:
|
|
|
|
|
+ rl (bool): Identifies if the rendering must result in a LaTeX-renderable string.
|
|
|
|
|
+ This argument basically overwrites the :attr:`render_latex` config
|
|
|
|
|
+ attribute. When :code:`None`, the value from the config is used.
|
|
|
|
|
+ Defaults to :code:`True`.
|
|
|
"""
|
|
"""
|
|
|
- # TODO: less code duplication
|
|
|
|
|
latex = ""
|
|
latex = ""
|
|
|
- for variable, value in self.equations.items():
|
|
|
|
|
- var = variable
|
|
|
|
|
- val = value
|
|
|
|
|
|
|
+ if rl is None:
|
|
|
|
|
+ rl = self.config["render_latex"]
|
|
|
|
|
+
|
|
|
|
|
+ def apply_eq(var, val, ltx):
|
|
|
|
|
+ """
|
|
|
|
|
+ Applies a dictionary of equations.
|
|
|
|
|
+
|
|
|
|
|
+ Args:
|
|
|
|
|
+ var: Lefthand-side of the equation.
|
|
|
|
|
+ val: Righthand-side of the equation, i.e. the function.
|
|
|
|
|
+ ltx: Latex-string to format var and val in.
|
|
|
|
|
+ """
|
|
|
if isinstance(val, Fnc):
|
|
if isinstance(val, Fnc):
|
|
|
- val = deepcopy(value)
|
|
|
|
|
- val.apply_time()
|
|
|
|
|
- val = val.latex()
|
|
|
|
|
- while val[0] == "(" and val[-1] == ")":
|
|
|
|
|
- val = val[1:-1]
|
|
|
|
|
- latex += r"{v}(t) &=& {val}\\".format(v=var, val=val)
|
|
|
|
|
|
|
+ val = deepcopy(val)
|
|
|
|
|
+ val.apply_time(t=self.config["time_variable"])
|
|
|
|
|
+ val = val.latex(rl)
|
|
|
|
|
+ if len(val) > 2:
|
|
|
|
|
+ while val[0] == "(" and val[-1] == ")":
|
|
|
|
|
+ val = val[1:-1]
|
|
|
|
|
+ return ltx.format(v=var, val=val, time=self.config["time_variable"])
|
|
|
|
|
+
|
|
|
|
|
+ for variable, value in self.equations.items():
|
|
|
|
|
+ x = "\t{v}({time}) = {val}\n"
|
|
|
|
|
+ if rl:
|
|
|
|
|
+ x = "\t" + r"{v}({time}) &=& {val}\\" + "\n"
|
|
|
|
|
+ if not isinstance(value, list):
|
|
|
|
|
+ value = [value]
|
|
|
|
|
+ latex += apply_eq(variable, Fnc('+', value), x)
|
|
|
|
|
|
|
|
ic = self.create_ic()
|
|
ic = self.create_ic()
|
|
|
for variable, value in ic.items():
|
|
for variable, value in ic.items():
|
|
|
- var = variable
|
|
|
|
|
- val = value
|
|
|
|
|
- if isinstance(val, Fnc):
|
|
|
|
|
- val = deepcopy(value)
|
|
|
|
|
- val.apply_time()
|
|
|
|
|
- val = val.latex()
|
|
|
|
|
- while val[0] == "(" and val[-1] == ")":
|
|
|
|
|
- val = val[1:-1]
|
|
|
|
|
- latex += r"{v} &=& {val}\\".format(v=var, val=val)
|
|
|
|
|
|
|
+ x = "\t{v} = {val}\n"
|
|
|
|
|
+ if rl:
|
|
|
|
|
+ x = "\t" + r"{v} &=& {val}\\" + "\n"
|
|
|
|
|
+ latex += apply_eq(variable, value, x)
|
|
|
|
|
|
|
|
|
|
+ if rl:
|
|
|
|
|
+ return "\\left\\{\\begin{array}{lcl}\n%s\\end{array}\\right." % latex
|
|
|
return latex
|
|
return latex
|
|
|
|
|
|
|
|
|
|
+ def create_ic(self):
|
|
|
|
|
+ """
|
|
|
|
|
+ Creates the equations for the initial conditions of a system.
|
|
|
|
|
+ """
|
|
|
|
|
+ # Maximal depth is the amount of nested delay blocks
|
|
|
|
|
+ stop = [0]
|
|
|
|
|
+ for e in self.equations.values():
|
|
|
|
|
+ if isinstance(e, Fnc):
|
|
|
|
|
+ stop.append(e.get_delay_depth())
|
|
|
|
|
+ stop = max(stop)
|
|
|
|
|
+
|
|
|
|
|
+ created = {}
|
|
|
|
|
+ for i in range(stop):
|
|
|
|
|
+ eqs = deepcopy(self.equations)
|
|
|
|
|
+ for k, e in eqs.items():
|
|
|
|
|
+ if isinstance(e, Fnc) and e.name == 'D':
|
|
|
|
|
+ eqs[k] = Fnc('+', [e])
|
|
|
|
|
+ eqs[k].apply_time(t=i)
|
|
|
|
|
+ eqs[k].apply_delay(i)
|
|
|
|
|
+ for c, v in created.items():
|
|
|
|
|
+ eqs[k].apply(c, v)
|
|
|
|
|
+
|
|
|
|
|
+ old = None
|
|
|
|
|
+ while old != eqs[k]:
|
|
|
|
|
+ old = eqs[k]
|
|
|
|
|
+ if isinstance(eqs[k], Fnc):
|
|
|
|
|
+ eqs[k] = eqs[k].simplify()
|
|
|
|
|
+ created["%s(%d)" % (k, i)] = eqs[k]
|
|
|
|
|
+ return created
|
|
|
|
|
+
|
|
|
def simplify_links(self):
|
|
def simplify_links(self):
|
|
|
"""
|
|
"""
|
|
|
First step to execute is a link simplification. Generally, there are more links
|
|
First step to execute is a link simplification. Generally, there are more links
|
|
@@ -172,14 +258,11 @@ class CBD2Latex:
|
|
|
i += 1
|
|
i += 1
|
|
|
return deps
|
|
return deps
|
|
|
|
|
|
|
|
- def simplify(self, show_steps=False, steps=-1):
|
|
|
|
|
|
|
+ def simplify(self, steps=-1):
|
|
|
"""
|
|
"""
|
|
|
Simplifies the system of equations to become a more optimal solution.
|
|
Simplifies the system of equations to become a more optimal solution.
|
|
|
|
|
|
|
|
Args:
|
|
Args:
|
|
|
- show_steps (bool): When :code:`True`, all intermediary results will
|
|
|
|
|
- be rendered with the :func:`render` method.
|
|
|
|
|
- Defaults to :code:`False`.
|
|
|
|
|
steps (int): When positive, this indicates the amount of steps
|
|
steps (int): When positive, this indicates the amount of steps
|
|
|
that must be taken. When negative, the equations
|
|
that must be taken. When negative, the equations
|
|
|
will be simplified until a convergence (i.e. no
|
|
will be simplified until a convergence (i.e. no
|
|
@@ -189,42 +272,33 @@ class CBD2Latex:
|
|
|
- :func:`simplify_links`
|
|
- :func:`simplify_links`
|
|
|
- :func:`substitute`
|
|
- :func:`substitute`
|
|
|
"""
|
|
"""
|
|
|
- if show_steps:
|
|
|
|
|
- print(self.render())
|
|
|
|
|
|
|
+ if self.config["show_steps"]:
|
|
|
|
|
+ self._trace("INITIAL SYSTEM")
|
|
|
self.simplify_links()
|
|
self.simplify_links()
|
|
|
|
|
+ txt = " substituted all connections and constant values"
|
|
|
peq = None
|
|
peq = None
|
|
|
i = 0
|
|
i = 0
|
|
|
while peq != self.equations:
|
|
while peq != self.equations:
|
|
|
if 0 <= steps <= i: break
|
|
if 0 <= steps <= i: break
|
|
|
- if show_steps:
|
|
|
|
|
- print(self.render())
|
|
|
|
|
peq = self.equations.copy()
|
|
peq = self.equations.copy()
|
|
|
|
|
+ if self.config["show_steps"]:
|
|
|
|
|
+ self._trace(txt)
|
|
|
self.substitute()
|
|
self.substitute()
|
|
|
i += 1
|
|
i += 1
|
|
|
|
|
+ txt = ""
|
|
|
|
|
|
|
|
- def create_ic(self):
|
|
|
|
|
- stop = [0]
|
|
|
|
|
- for e in self.equations.values():
|
|
|
|
|
- if isinstance(e, Fnc):
|
|
|
|
|
- stop.append(e.get_delay_depth())
|
|
|
|
|
- stop = max(stop)
|
|
|
|
|
- created = {}
|
|
|
|
|
- for i in range(stop):
|
|
|
|
|
- eqs = deepcopy(self.equations)
|
|
|
|
|
- for k in eqs.keys():
|
|
|
|
|
- eqs[k] = Fnc('+', [eqs[k]])
|
|
|
|
|
- eqs[k].apply_time(t=i)
|
|
|
|
|
- eqs[k].apply_delay(i)
|
|
|
|
|
- for c, v in created.items():
|
|
|
|
|
- eqs[k].apply(c, v)
|
|
|
|
|
-
|
|
|
|
|
- old = None
|
|
|
|
|
- while old != eqs[k]:
|
|
|
|
|
- old = eqs[k]
|
|
|
|
|
- if isinstance(eqs[k], Fnc):
|
|
|
|
|
- eqs[k] = eqs[k].simplify()
|
|
|
|
|
- created["%s(%d)" % (k, i)] = eqs[k]
|
|
|
|
|
- return created
|
|
|
|
|
|
|
+ def _trace(self, text=""):
|
|
|
|
|
+ """Traces a step in the solution.
|
|
|
|
|
+
|
|
|
|
|
+ Args:
|
|
|
|
|
+ text (str): Additional text to print.
|
|
|
|
|
+ """
|
|
|
|
|
+ if self._step == 0:
|
|
|
|
|
+ print("" + text + ":")
|
|
|
|
|
+ else:
|
|
|
|
|
+ print("STEP %d:" % self._step, text)
|
|
|
|
|
+ print(self.render(None))
|
|
|
|
|
+ self._step += 1
|
|
|
|
|
|
|
|
class Fnc:
|
|
class Fnc:
|
|
|
"""
|
|
"""
|
|
@@ -314,6 +388,8 @@ class Fnc:
|
|
|
nargs.append(Fnc("*", [a, c]))
|
|
nargs.append(Fnc("*", [a, c]))
|
|
|
if len(nargs) == 1:
|
|
if len(nargs) == 1:
|
|
|
return nargs[0]
|
|
return nargs[0]
|
|
|
|
|
+ if len(nargs) == 0:
|
|
|
|
|
+ return 0
|
|
|
elif name == '*':
|
|
elif name == '*':
|
|
|
val = 1
|
|
val = 1
|
|
|
occ = {}
|
|
occ = {}
|
|
@@ -443,9 +519,12 @@ class Fnc:
|
|
|
"""
|
|
"""
|
|
|
return self.name in ["+", "-", "*", "~", "^", "root", "%", "or", "and", "==", "<=", "<"]
|
|
return self.name in ["+", "-", "*", "~", "^", "root", "%", "or", "and", "==", "<=", "<"]
|
|
|
|
|
|
|
|
- def latex(self):
|
|
|
|
|
|
|
+ def latex(self, latex=True):
|
|
|
"""
|
|
"""
|
|
|
Returns a LaTeX-formatted string of this function.
|
|
Returns a LaTeX-formatted string of this function.
|
|
|
|
|
+
|
|
|
|
|
+ Args:
|
|
|
|
|
+ latex (bool): Whether or not to use LaTeX-based strings.
|
|
|
"""
|
|
"""
|
|
|
largs = deepcopy(self.args)
|
|
largs = deepcopy(self.args)
|
|
|
for i, a in enumerate(self.args):
|
|
for i, a in enumerate(self.args):
|
|
@@ -460,34 +539,38 @@ class Fnc:
|
|
|
else:
|
|
else:
|
|
|
largs[i] = str(a)
|
|
largs[i] = str(a)
|
|
|
|
|
|
|
|
- if self.name in ['+', '*', 'or', 'and']:
|
|
|
|
|
|
|
+ opers = {}
|
|
|
|
|
+ if latex:
|
|
|
op = {
|
|
op = {
|
|
|
'*': r"\cdot ",
|
|
'*': r"\cdot ",
|
|
|
'or': r"\wedge ",
|
|
'or': r"\wedge ",
|
|
|
'and': r"\vee ",
|
|
'and': r"\vee ",
|
|
|
- }.get(self.name, self.name)
|
|
|
|
|
- return (" %s " % op).join(largs)
|
|
|
|
|
- elif self.name in '-!~':
|
|
|
|
|
- op = {
|
|
|
|
|
'!': r"\neg ",
|
|
'!': r"\neg ",
|
|
|
'~': "1/",
|
|
'~': "1/",
|
|
|
- }.get(self.name, self.name)
|
|
|
|
|
|
|
+ "%": r"\mod ",
|
|
|
|
|
+ "<=": r"\leq ",
|
|
|
|
|
+ "==": r"\leftrightarrow ",
|
|
|
|
|
+ }
|
|
|
|
|
+ if self.name in ['+', '*', 'or', 'and']:
|
|
|
|
|
+ op = opers.get(self.name, self.name)
|
|
|
|
|
+ return (" %s " % op).join(largs)
|
|
|
|
|
+ elif self.name in '-!~':
|
|
|
|
|
+ op = opers.get(self.name, self.name)
|
|
|
return "{}{}".format(op, largs[0])
|
|
return "{}{}".format(op, largs[0])
|
|
|
elif self.name == '^':
|
|
elif self.name == '^':
|
|
|
- return "%s^{%s}" % (largs[0], largs[1])
|
|
|
|
|
|
|
+ if latex:
|
|
|
|
|
+ return "%s^{%s}" % (largs[0], largs[1])
|
|
|
|
|
+ return "%s^(%s)" % (largs[0], largs[1])
|
|
|
elif self.name == 'root':
|
|
elif self.name == 'root':
|
|
|
- return "%s^{1/%s}" % (largs[1], largs[0])
|
|
|
|
|
|
|
+ if latex:
|
|
|
|
|
+ return "%s^{1/%s}" % (largs[0], largs[1])
|
|
|
|
|
+ if largs[1] == 2:
|
|
|
|
|
+ return "sqrt(%s)" % largs[0]
|
|
|
|
|
+ return "root(%s, %s)" % (largs[0], largs[1])
|
|
|
elif self.name in ['%', '<', '<=', '==']:
|
|
elif self.name in ['%', '<', '<=', '==']:
|
|
|
- op = {
|
|
|
|
|
- "%": r"\mod ",
|
|
|
|
|
- "<=": r"\leq ",
|
|
|
|
|
- "==": r"\leftrightarrow ",
|
|
|
|
|
- }.get(self.name, self.name)
|
|
|
|
|
|
|
+ op = opers.get(self.name, self.name)
|
|
|
return "%s %s %s" % (largs[0], op, largs[1])
|
|
return "%s %s %s" % (largs[0], op, largs[1])
|
|
|
elif self.name == 'D':
|
|
elif self.name == 'D':
|
|
|
- # return r"\left\{{\begin{{array}}{{lcr}}{ic}&\textrm{{if }}t + 1 = 0\\" \
|
|
|
|
|
- # r"{n}&\textrm{{otherwise}}\end{{array}}\right.".format(ic=largs[1], n=largs[0])
|
|
|
|
|
- # return "delay(%s, %s)" % (largs[0], largs[1])
|
|
|
|
|
return largs[0]
|
|
return largs[0]
|
|
|
return "{}({})".format(self.name, ", ".join(largs))
|
|
return "{}({})".format(self.name, ", ".join(largs))
|
|
|
|
|
|
|
@@ -523,7 +606,10 @@ class Fnc:
|
|
|
t -= time
|
|
t -= time
|
|
|
for i, a in enumerate(self.args):
|
|
for i, a in enumerate(self.args):
|
|
|
if isinstance(a, str):
|
|
if isinstance(a, str):
|
|
|
- self.args[i] = "%s(%s)" % (a, str(t))
|
|
|
|
|
|
|
+ if not isinstance(t, str) and t < 0:
|
|
|
|
|
+ self.args[i] = "%s(0)" % a
|
|
|
|
|
+ else:
|
|
|
|
|
+ self.args[i] = "%s(%s)" % (a, str(t))
|
|
|
elif isinstance(a, Fnc):
|
|
elif isinstance(a, Fnc):
|
|
|
if self.name == 'D' and i == 1:
|
|
if self.name == 'D' and i == 1:
|
|
|
a.apply_time(None, to)
|
|
a.apply_time(None, to)
|
|
@@ -560,30 +646,30 @@ def _clamp_block(block, p):
|
|
|
# lambda b, p, f=func: (p + ".OUT1", Fnc(f, [p + ".%s" % x for x in block.getInputPortNames()]))
|
|
# lambda b, p, f=func: (p + ".OUT1", Fnc(f, [p + ".%s" % x for x in block.getInputPortNames()]))
|
|
|
# Note: the LHS is required to be a single value!
|
|
# Note: the LHS is required to be a single value!
|
|
|
_BLOCK_MAP = {
|
|
_BLOCK_MAP = {
|
|
|
- "ConstantBlock": lambda block, p: (p + ".OUT1", block.getValue()),
|
|
|
|
|
- "NegatorBlock": lambda block, p: (p + ".OUT1", Fnc('-', [p + ".IN1"])),
|
|
|
|
|
- "InverterBlock": lambda block, p: (p + ".OUT1", Fnc('~', [p + ".IN1"])),
|
|
|
|
|
|
|
+ "ConstantBlock": lambda block, p: (p("OUT1"), block.getValue()),
|
|
|
|
|
+ "NegatorBlock": lambda block, p: (p("OUT1"), Fnc('-', [p("IN1")])),
|
|
|
|
|
+ "InverterBlock": lambda block, p: (p("OUT1"), Fnc('~', [p("IN1")])),
|
|
|
"AdderBlock": '+',
|
|
"AdderBlock": '+',
|
|
|
"ProductBlock": '*',
|
|
"ProductBlock": '*',
|
|
|
- "ModuloBlock": lambda block, p: (p + ".OUT1", Fnc('%', [p + ".IN1", p + ".IN2"])),
|
|
|
|
|
- "RootBlock": lambda block, p: (p + ".OUT1", Fnc('root', [p + ".IN1", p + ".IN2"])),
|
|
|
|
|
- "PowerBlock": lambda block, p: (p + ".OUT1", Fnc('^', [p + ".IN1", p + ".IN2"])),
|
|
|
|
|
- "AbsBlock": lambda block, p: (p + ".OUT1", Fnc('abs', [p + ".IN1"])),
|
|
|
|
|
- "IntBlock": lambda block, p: (p + ".OUT1", Fnc('int', [p + ".IN1"])),
|
|
|
|
|
|
|
+ "ModuloBlock": lambda block, p: (p("OUT1"), Fnc('%', [p("IN1"), p("IN2")])),
|
|
|
|
|
+ "RootBlock": lambda block, p: (p("OUT1"), Fnc('root', [p("IN1"), p("IN2")])),
|
|
|
|
|
+ "PowerBlock": lambda block, p: (p("OUT1"), Fnc('^', [p("IN1"), p("IN2")])),
|
|
|
|
|
+ "AbsBlock": lambda block, p: (p("OUT1"), Fnc('abs', [p("IN1")])),
|
|
|
|
|
+ "IntBlock": lambda block, p: (p("OUT1"), Fnc('int', [p("IN1")])),
|
|
|
"ClampBlock": _clamp_block,
|
|
"ClampBlock": _clamp_block,
|
|
|
- "GenericBlock": lambda block, p: (p + ".OUT1", Fnc(block.getBlockOperator(), [p + ".IN1"])),
|
|
|
|
|
|
|
+ "GenericBlock": lambda block, p: (p("OUT1"), Fnc(block.getBlockOperator(), [p("IN1")])),
|
|
|
"MultiplexerBlock": 'MUX',
|
|
"MultiplexerBlock": 'MUX',
|
|
|
"MaxBlock": 'max',
|
|
"MaxBlock": 'max',
|
|
|
"MinBlock": 'min',
|
|
"MinBlock": 'min',
|
|
|
- "LessThanBlock": lambda block, p: (p + ".OUT1", Fnc('<', [p + ".IN1", p + ".IN2"])),
|
|
|
|
|
- "LessThanOrEqualsBlock": lambda block, p: (p + ".OUT1", Fnc('<=', [p + ".IN1", p + ".IN2"])),
|
|
|
|
|
- "EqualsBlock": lambda block, p: (p + ".OUT1", Fnc('==', [p + ".IN1", p + ".IN2"])),
|
|
|
|
|
- "NotBlock": lambda block, p: (p + ".OUT1", Fnc('!', [p + ".IN1"])),
|
|
|
|
|
|
|
+ "LessThanBlock": lambda block, p: (p("OUT1"), Fnc('<', [p("IN1"), p("IN2")])),
|
|
|
|
|
+ "LessThanOrEqualsBlock": lambda block, p: (p("OUT1"), Fnc('<=', [p("IN1"), p("IN2")])),
|
|
|
|
|
+ "EqualsBlock": lambda block, p: (p("OUT1"), Fnc('==', [p("IN1"), p("IN2")])),
|
|
|
|
|
+ "NotBlock": lambda block, p: (p("OUT1"), Fnc('!', [p("IN1")])),
|
|
|
"OrBlock": 'or',
|
|
"OrBlock": 'or',
|
|
|
"AndBlock": 'and',
|
|
"AndBlock": 'and',
|
|
|
"DelayBlock": 'D',
|
|
"DelayBlock": 'D',
|
|
|
- # "DelayBlock": lambda block, p: [(p + ".OUT1", Fnc('D', [p + ".IN1"])), (p + ".OUT1(0)", Fnc('S', [p + ".IC"]))],
|
|
|
|
|
- "TimeBlock": lambda block, p: (p + ".OUT1", 't')
|
|
|
|
|
|
|
+ # "DelayBlock": lambda block, p: [(p(.UT1"), Fnc('D', [p(.N1")])), (p(.UT1()0)", Fnc('S', [p(.C")]))],
|
|
|
|
|
+ "TimeBlock": lambda block, p: (p("OUT1"), 't')
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -628,7 +714,7 @@ if __name__ == '__main__':
|
|
|
self.addConnection("delay3", "OUT1", output_port_name='OUT1')
|
|
self.addConnection("delay3", "OUT1", output_port_name='OUT1')
|
|
|
|
|
|
|
|
|
|
|
|
|
- ltx = CBD2Latex(FibonacciGen("fib"))
|
|
|
|
|
|
|
+ ltx = CBD2Latex(FibonacciGen("fib"), render_latex=False, show_steps=True)
|
|
|
# ltx.render()
|
|
# ltx.render()
|
|
|
ltx.simplify()
|
|
ltx.simplify()
|
|
|
print(ltx.render())
|
|
print(ltx.render())
|