"""ASCII Printer"""
from ..utils.singleton import Singleton
from ..algebra.core.exceptions import BasisNotSetError
from .base import QnetBasePrinter
from .sympy import SympyStrPrinter
from ._precedence import precedence, PRECEDENCE
__all__ = []
__private__ = ['QnetAsciiPrinter', 'QnetAsciiDefaultPrinter']
[docs]class QnetAsciiPrinter(QnetBasePrinter):
"""Printer for a string (ASCII) representation.
Attributes:
_parenth_left (str): String to use for a left parenthesis
(e.g. '\left(' in LaTeX). Used by :meth:`_split_op`
_parenth_left (str): String to use for a right parenthesis
_dagger_sym (str): Symbol that indicates the complex conjugate of an
operator. Used by :meth:`_split_op`
_tensor_sym (str): Symbol to use for tensor products. Used by
:meth:`_render_hs_label`.
"""
sympy_printer_cls = SympyStrPrinter
printmethod = '_ascii'
_default_settings = {
'show_hs_label': True, # alternatively: False, 'subscript'
'sig_as_ketbra': True,
}
_parenth_left = '('
_parenth_right = ')'
_bracket_left = '['
_bracket_right = ']'
_dagger_sym = 'H'
_tensor_sym = '*'
_product_sym = '*'
_circuit_series_sym = "<<"
_circuit_concat_sym = "+"
_cid = 'cid(%d)'
_sum_sym = 'Sum'
_element_sym = 'in'
_ellipsis = '...'
_set_delim_left = '{'
_set_delim_right = '}'
@property
def _spaced_product_sym(self):
if len(self._product_sym.strip()) == 0:
return self._product_sym
else:
return " %s " % self._product_sym
def _split_identifier(self, identifier):
"""Split the given identifier at the first underscore into (rendered)
name and subscript. Both `name` and `subscript` are rendered as
strings"""
try:
name, subscript = identifier.split("_", 1)
except (TypeError, ValueError, AttributeError):
name = identifier
subscript = ''
return self._render_str(name), self._render_str(subscript)
def _split_op(
self, identifier, hs_label=None, dagger=False, args=None):
"""Return `name`, total `subscript`, total `superscript` and
`arguments` str. All of the returned strings are fully rendered.
Args:
identifier (str or SymbolicLabelBase): A (non-rendered/ascii)
identifier that may include a subscript. The output `name` will
be the `identifier` without any subscript
hs_label (str): The rendered label for the Hilbert space of the
operator, or None. Returned unchanged.
dagger (bool): Flag to indicate whether the operator is daggered.
If True, :attr:`dagger_sym` will be included in the
`superscript` (or `subscript`, depending on the settings)
args (list or None): List of arguments (expressions). Each element
will be rendered with :meth:`doprint`. The total list of args
will then be joined with commas, enclosed
with :attr:`_parenth_left` and :attr:`parenth_right`, and
returnd as the `arguments` string
"""
if self._isinstance(identifier, 'SymbolicLabelBase'):
identifier = QnetAsciiDefaultPrinter()._print_SCALAR_TYPES(
identifier.expr)
name, total_subscript = self._split_identifier(identifier)
total_superscript = ''
if (hs_label not in [None, '']):
if self._settings['show_hs_label'] == 'subscript':
if len(total_subscript) == 0:
total_subscript = '(' + hs_label + ')'
else:
total_subscript += ',(' + hs_label + ')'
else:
total_superscript += '(' + hs_label + ')'
if dagger:
total_superscript += self._dagger_sym
args_str = ''
if (args is not None) and (len(args) > 0):
args_str = (self._parenth_left +
",".join([self.doprint(arg) for arg in args]) +
self._parenth_right)
return name, total_subscript, total_superscript, args_str
@classmethod
def _is_single_letter(cls, label):
return len(label) == 1
def _render_hs_label(self, hs):
"""Return the label of the given Hilbert space as a string"""
if isinstance(hs.__class__, Singleton):
return self._render_str(hs.label)
else:
return self._tensor_sym.join(
[self._render_str(ls.label) for ls in hs.local_factors])
def _render_state_label(self, label):
if self._isinstance(label, 'SymbolicLabelBase'):
return self._print_SCALAR_TYPES(label.expr)
else:
return self._render_str(label)
def _braket_fmt(self, expr_type):
"""Return a format string for printing an `expr_type`
ket/bra/ketbra/braket"""
mapping = {
'bra': {
True: '<{label}|^({space})',
'subscript': '<{label}|_({space})',
False: '<{label}|'},
'ket': {
True: '|{label}>^({space})',
'subscript': '|{label}>_({space})',
False: '|{label}>'},
'ketbra': {
True: '|{label_i}><{label_j}|^({space})',
'subscript': '|{label_i}><{label_j}|_({space})',
False: '|{label_i}><{label_j}|'},
'braket': {
True: '<{label_i}|{label_j}>^({space})',
'subscript': '<{label_i}|{label_j}>_({space})',
False: '<{label_i}|{label_j}>'},
}
hs_setting = bool(self._settings['show_hs_label'])
if self._settings['show_hs_label'] == 'subscript':
hs_setting = 'subscript'
return mapping[expr_type][hs_setting]
def _render_op(
self, identifier, hs=None, dagger=False, args=None, superop=False):
"""Render an operator
Args:
identifier (str or SymbolicLabelBase): The identifier (name/symbol)
of the operator. May include a subscript, denoted by '_'.
hs (qnet.algebra.hilbert_space_algebra.HilbertSpace): The Hilbert
space in which the operator is defined
dagger (bool): Whether the operator should be daggered
args (list): A list of expressions that will be rendered with
:meth:`doprint`, joined with commas, enclosed in parenthesis
superop (bool): Whether the operator is a super-operator
"""
hs_label = None
if hs is not None and self._settings['show_hs_label']:
hs_label = self._render_hs_label(hs)
name, total_subscript, total_superscript, args_str \
= self._split_op(identifier, hs_label, dagger, args)
res = name
if len(total_subscript) > 0:
res += "_" + total_subscript
if len(total_superscript) > 0:
res += "^" + total_superscript
if len(args_str) > 0:
res += args_str
return res
[docs] def parenthesize(self, expr, level, *args, strict=False, **kwargs):
"""Render `expr` and wrap the result in parentheses if the precedence
of `expr` is below the given `level` (or at the given `level` if
`strict` is True. Extra `args` and `kwargs` are passed to the internal
`doit` renderer"""
needs_parenths = (
(precedence(expr) < level) or
(strict and precedence(expr) == level))
if needs_parenths:
return (
self._parenth_left + self.doprint(expr, *args, **kwargs) +
self._parenth_right)
else:
return self.doprint(expr, *args, **kwargs)
def _print_tuple(self, expr):
return (
self._parenth_left + ", ".join([self.doprint(c) for c in expr])
+ self._parenth_right)
def _print_list(self, expr):
return (
self._bracket_left + ", ".join([self.doprint(c) for c in expr])
+ self._bracket_right)
def _print_CircuitSymbol(self, expr):
res = self._render_str(expr.label)
if len(expr.sym_args) > 0:
res += (
self._parenth_left +
", ".join([self.doprint(arg) for arg in expr.sym_args]) +
self._parenth_right)
return res
def _print_CPermutation(self, expr):
return r'Perm(%s)' % (
", ".join(map(self._render_str, expr.permutation)))
def _print_SeriesProduct(self, expr):
prec = precedence(expr)
circuit_series_sym = " " + self._circuit_series_sym + " "
return circuit_series_sym.join(
[self.parenthesize(op, prec) for op in expr.operands])
def _print_Concatenation(self, expr):
prec = precedence(expr)
reduced_operands = [] # reduce consecutive identities to a str
id_count = 0
for o in expr.operands:
if self._isinstance(o, 'CIdentity'):
id_count += 1
else:
if id_count > 0:
reduced_operands.append(self._cid % id_count)
id_count = 0
reduced_operands.append(o)
if id_count > 0:
reduced_operands.append(self._cid % id_count)
circuit_concat_sym = " " + self._circuit_concat_sym + " "
parts = []
for op in reduced_operands:
if self._isinstance(op, 'SeriesProduct'):
# while a SeriesProduct has a higher precedence than a
# Concatenation, for most readers, extra parentheses will be
# helpful
# TODO: make this an option
parts.append(
self._parenth_left + self.doprint(op) +
self._parenth_right)
else:
parts.append(self.parenthesize(op, prec))
return circuit_concat_sym.join(parts)
def _print_Feedback(self, expr):
o, i = expr.out_in_pair
return '[{operand}]_{{{output}->{input}}}'.format(
operand=self.doprint(expr.operand), output=o, input=i)
def _print_SeriesInverse(self, expr):
return r'[{operand}]^{{-1}}'.format(
operand=self.doprint(expr.operand))
def _print_HilbertSpace(self, expr):
return r'H_{label}'.format(
label=self._render_hs_label(expr))
def _print_ProductSpace(self, expr):
tensor_sym = " " + self._tensor_sym + " "
return tensor_sym.join(
[self.doprint(op) for op in expr.operands])
def _print_OperatorSymbol(self, expr, adjoint=False):
res = self._render_op(expr.label, expr._hs, dagger=adjoint)
if len(expr.sym_args) > 0:
res += (
self._parenth_left +
", ".join([self.doprint(arg) for arg in expr.sym_args]) +
self._parenth_right)
return res
def _print_LocalOperator(self, expr, adjoint=False):
if adjoint:
dagger = not expr._dagger
else:
dagger = expr._dagger
return self._render_op(
expr.identifier, expr._hs, dagger=dagger, args=expr.args)
def _print_LocalSigma(self, expr, adjoint=False):
if self._settings['sig_as_ketbra']:
fmt = self._braket_fmt('ketbra')
if adjoint:
return fmt.format(
label_i=self._render_state_label(expr.k),
label_j=self._render_state_label(expr.j),
space=self._render_hs_label(expr.space))
else:
return fmt.format(
label_i=self._render_state_label(expr.j),
label_j=self._render_state_label(expr.k),
space=self._render_hs_label(expr.space))
else:
if expr.j == expr.k:
identifier = "%s_%s" % (expr._identifier_projector, expr.j)
else:
if adjoint:
identifier = "%s_%s,%s" % (expr.identifier, expr.k, expr.j)
else:
identifier = "%s_%s,%s" % (expr.identifier, expr.j, expr.k)
return self._render_op(identifier, expr._hs, dagger=adjoint)
def _print_IdentityOperator(self, expr):
return "1"
def _print_ZeroOperator(self, expr):
return "0"
def _print_ScalarValue(self, expr, **kwargs):
return self.doprint(expr.val, **kwargs)
def _print_Zero(self, expr, **kwargs):
return "0"
def _print_One(self, expr, **kwargs):
return "1"
def _print_ScalarTimesQuantumExpression(self, expr, **kwargs):
prec = PRECEDENCE['Mul']
coeff, term = expr.coeff, expr.term
term_str = self.doprint(term, **kwargs)
if precedence(term) < prec:
term_str = self._parenth_left + term_str + self._parenth_right
if coeff == -1:
if term_str.startswith(self._parenth_left):
return "- " + term_str
else:
return "-" + term_str
if 'adjoint' in kwargs:
coeff_str = self.doprint(coeff, adjoint=kwargs['adjoint'])
else:
coeff_str = self.doprint(coeff)
if term_str in [
'1', self._print_IdentityOperator(expr),
self._print_IdentitySuperOperator]:
return coeff_str
else:
coeff_str = coeff_str.strip()
if precedence(coeff) < prec and precedence(-coeff) < prec:
# the above precedence check catches on only for true sums
coeff_str = (
self._parenth_left + coeff_str + self._parenth_right)
return coeff_str + self._spaced_product_sym + term_str.strip()
def _print_QuantumPlus(self, expr, adjoint=False, superop=False):
prec = precedence(expr)
l = []
kwargs = {}
if adjoint:
kwargs['adjoint'] = adjoint
if superop:
kwargs['superop'] = superop
for term in expr.args:
t = self.doprint(term, **kwargs)
if t.startswith('-'):
sign = "-"
t = t[1:].strip()
else:
sign = "+"
if precedence(term) < prec:
l.extend([sign, self._parenth_left + t + self._parenth_right])
else:
l.extend([sign, t])
try:
sign = l.pop(0)
if sign == '+':
sign = ""
except IndexError:
sign = ""
return sign + ' '.join(l)
def _print_QuantumTimes(self, expr, **kwargs):
prec = precedence(expr)
return self._spaced_product_sym.join(
[self.parenthesize(op, prec, **kwargs) for op in expr.operands])
def _print_Commutator(self, expr, adjoint=False):
res = "[" + self.doprint(expr.A) + ", " + self.doprint(expr.B) + "]"
if adjoint:
res += "^" + self._dagger_sym
return res
def _print_OperatorTrace(self, expr, adjoint=False):
s = self._render_hs_label(expr._over_space)
kwargs = {}
if adjoint:
kwargs['adjoint'] = adjoint
o = self.doprint(expr.operand, **kwargs)
return r'tr_({space})[{operand}]'.format(space=s, operand=o)
def _print_Adjoint(self, expr, adjoint=False):
o = expr.operand
if self._isinstance(o, 'LocalOperator'):
if adjoint:
dagger = o._dagger
else:
dagger = not o._dagger
return self._render_op(
o.identifier, hs=o.space, dagger=dagger, args=o.args[1:])
elif self._isinstance(o, 'OperatorSymbol'):
return self._render_op(
o.label, hs=o.space, dagger=(not adjoint))
else:
if adjoint:
return self.doprint(o)
else:
return (
self._parenth_left + self.doprint(o) +
self._parenth_right + "^" + self._dagger_sym)
def _print_OperatorPlusMinusCC(self, expr):
prec = precedence(expr)
o = expr.operand
sign_str = ' + '
if expr._sign < 0:
sign_str = ' - '
return self.parenthesize(o, prec) + sign_str + "c.c."
def _print_PseudoInverse(self, expr):
prec = precedence(expr)
return self.parenthesize(expr.operand, prec) + "^+"
def _print_NullSpaceProjector(self, expr, adjoint=False):
null_space_proj_sym = 'P_Ker'
return self._render_op(
null_space_proj_sym, hs=None, args=expr.operands, dagger=adjoint)
def _print_KetSymbol(self, expr, adjoint=False):
if adjoint:
fmt = self._braket_fmt('bra')
else:
fmt = self._braket_fmt('ket')
label = self._render_state_label(expr.label)
if len(expr.sym_args) > 0:
label += (
self._parenth_left +
", ".join([self.doprint(arg) for arg in expr.sym_args]) +
self._parenth_right)
return fmt.format(
label=label, space=self._render_hs_label(expr.space))
def _print_ZeroKet(self, expr, adjoint=False):
return "0"
def _print_TrivialKet(self, expr, adjoint=False):
return "1"
def _print_CoherentStateKet(self, expr, adjoint=False):
if adjoint:
fmt = self._braket_fmt('bra')
else:
fmt = self._braket_fmt('ket')
label = self._render_state_label('alpha=') + self.doprint(expr._ampl)
space = self._render_hs_label(expr.space)
return fmt.format(label=label, space=space)
def _print_TensorKet(self, expr, adjoint=False):
if all(self._isinstance(o, 'BasisKet') for o in expr.operands):
labels = [self._render_state_label(o.label) for o in expr.operands]
single_letters = all([self._is_single_letter(l) for l in labels])
try:
small_hs = all(
[(o.space.dimension < 10) for o in expr.operands])
except BasisNotSetError:
small_hs = False
if small_hs and single_letters:
joiner = ""
else:
joiner = ","
label = joiner.join(labels)
fmt = self._braket_fmt('ket')
if adjoint:
fmt = self._braket_fmt('bra')
space = self._render_hs_label(expr.space)
return fmt.format(label=label, space=space)
else:
prec = precedence(expr)
kwargs = {}
if adjoint:
kwargs['adjoint'] = adjoint
tensor_sym = " %s " % self._tensor_sym
return tensor_sym.join([
self.parenthesize(op, prec, **kwargs)
for op in expr.operands])
def _print_OperatorTimesKet(self, expr, adjoint=False):
prec = precedence(expr)
op, ket = expr.operator, expr.ket
kwargs = {}
if adjoint:
kwargs['adjoint'] = adjoint
rendered_op = self.parenthesize(op, prec, **kwargs)
rendered_ket = self.parenthesize(ket, prec, **kwargs)
if adjoint:
return rendered_ket + " " + rendered_op
else:
return rendered_op + " " + rendered_ket
def _print_IndexedSum(self, expr, adjoint=False):
prec = precedence(expr)
kwargs = {}
if adjoint:
kwargs['adjoint'] = adjoint
indices = []
bottom_rhs = None
top = None
res = ''
# ranges with the same limits are grouped into the same sum symbol
for index_range in expr.ranges:
current_index = self.doprint(index_range, which='bottom_index')
current_bottom_rhs = self.doprint(index_range, which='bottom_rhs')
current_top = self.doprint(index_range, which='top')
if top is not None: # index_ranges after the first one
if current_top != top or current_bottom_rhs != bottom_rhs:
res += self._sum_sym
bottom = ",".join(indices) + bottom_rhs
if len(bottom) > 0:
res += '_{%s}' % bottom
if len(top) > 0:
res += '^{%s}' % top
res += " "
indices = [current_index, ]
top = current_top
bottom_rhs = current_bottom_rhs
else:
indices.append(current_index)
else: # first range
indices.append(current_index)
top = current_top
bottom_rhs = current_bottom_rhs
# add the final accumulated sum symbol
res += self._sum_sym
bottom = ",".join(indices) + bottom_rhs
if len(bottom) > 0:
res += '_{%s}' % bottom
if len(top) > 0:
res += '^{%s}' % top
res += " " + self.parenthesize(expr.term, prec, strict=True, **kwargs)
return res
def _print_IndexRangeBase(self, expr, which='bottom'):
assert which in ['bottom', 'bottom_index', 'bottom_rhs', 'top']
if which in ['bottom', 'bottom_index']:
return self.doprint(expr.index_symbol)
else:
return ''
def _print_IndexOverFockSpace(self, expr, which='bottom'):
assert which in ['bottom', 'bottom_index', 'bottom_rhs', 'top']
if 'bottom' in which:
bottom_index = self.doprint(expr.index_symbol)
bottom_rhs = " " + self._element_sym + " " + self.doprint(expr.hs)
if which == 'bottom_index':
return bottom_index
elif which == 'bottom_rhs':
return bottom_rhs
else:
return bottom_index + bottom_rhs
elif which == 'top':
return ''
else:
raise ValueError("invalid `which`: %s" % which)
def _print_IndexOverList(self, expr, which='bottom'):
assert which in ['bottom', 'bottom_index', 'bottom_rhs', 'top']
if 'bottom' in which:
bottom_index = self.doprint(expr.index_symbol)
bottom_rhs = (
" " + self._element_sym + " " + self._set_delim_left +
",".join([self.doprint(val) for val in expr.values]) +
self._set_delim_right)
if which == 'bottom_index':
return bottom_index
elif which == 'bottom_rhs':
return bottom_rhs
else:
return bottom_index + bottom_rhs
elif which == 'top':
return ''
else:
raise ValueError("invalid `which`: %s" % which)
def _print_IndexOverRange(self, expr, which='bottom'):
assert which in ['bottom', 'bottom_index', 'bottom_rhs', 'top']
if 'bottom' in which:
bottom_index = self.doprint(expr.index_symbol)
bottom_rhs = "=%s" % expr.start_from
if abs(expr.step) > 1:
bottom_rhs += ", %s" % expr.start_from + expr.step
bottom_rhs += ", " + self._ellipsis
if which == 'bottom_index':
return bottom_index
elif which == 'bottom_rhs':
return bottom_rhs
else:
return bottom_index + bottom_rhs
elif which == 'top':
return str(expr.to)
else:
raise ValueError("invalid `which`: %s" % which)
def _print_BaseLabel(self, expr):
return self.doprint(expr.expr)
def _print_Bra(self, expr, adjoint=False):
return self.doprint(expr.ket, adjoint=(not adjoint))
def _print_BraKet(self, expr, adjoint=False):
trivial = True
try:
bra_label = self._render_state_label(expr.bra.label)
bra = expr.bra.ket
if hasattr(bra, 'sym_args') and len(bra.sym_args) > 0:
bra_label += (
self._parenth_left +
", ".join([self.doprint(arg) for arg in bra.sym_args]) +
self._parenth_right)
except AttributeError:
trivial = False
try:
ket_label = self._render_state_label(expr.ket.label)
if hasattr(expr.ket, 'sym_args') and len(expr.ket.sym_args) > 0:
ket_label += (
self._parenth_left +
", ".join(
[self.doprint(arg) for arg in expr.ket.sym_args]) +
self._parenth_right)
except AttributeError:
trivial = False
if trivial:
fmt = self._braket_fmt('braket')
if adjoint:
return fmt.format(
label_i=ket_label, label_j=bra_label,
space=self._render_hs_label(expr.ket.space))
else:
return fmt.format(
label_i=bra_label, label_j=ket_label,
space=self._render_hs_label(expr.ket.space))
else:
prec = precedence(expr)
rendered_bra = self.parenthesize(expr.bra, prec, adjoint=adjoint)
rendered_ket = self.parenthesize(expr.ket, prec, adjoint=adjoint)
if adjoint:
return rendered_ket + self._spaced_product_sym + rendered_bra
else:
return rendered_bra + self._spaced_product_sym + rendered_ket
def _print_KetBra(self, expr, adjoint=False):
trivial = True
try:
bra_label = self._render_state_label(expr.bra.label)
bra = expr.bra.ket
if hasattr(bra, 'sym_args') and len(bra.sym_args) > 0:
bra_label += (
self._parenth_left +
", ".join([self.doprint(arg) for arg in bra.sym_args]) +
self._parenth_right)
except AttributeError:
trivial = False
try:
ket_label = self._render_state_label(expr.ket.label)
if hasattr(expr.ket, 'sym_args') and len(expr.ket.sym_args) > 0:
ket_label += (
self._parenth_left +
", ".join(
[self.doprint(arg) for arg in expr.ket.sym_args]) +
self._parenth_right)
except AttributeError:
trivial = False
if trivial:
fmt = self._braket_fmt('ketbra')
if adjoint:
return fmt.format(
label_i=bra_label, label_j=ket_label,
space=self._render_hs_label(expr.ket.space))
else:
return fmt.format(
label_i=ket_label, label_j=bra_label,
space=self._render_hs_label(expr.ket.space))
else:
prec = precedence(expr)
rendered_bra = self.parenthesize(expr.bra, prec, adjoint=adjoint)
rendered_ket = self.parenthesize(expr.ket, prec, adjoint=adjoint)
if adjoint:
return rendered_bra + rendered_ket
else:
return rendered_ket + rendered_bra
def _print_SuperOperatorSymbol(self, expr, adjoint=False, superop=True):
res = self._render_op(
expr.label, expr._hs, dagger=adjoint, superop=True)
if len(expr.sym_args) > 0:
res += (
self._parenth_left +
", ".join([self.doprint(arg) for arg in expr.sym_args]) +
self._parenth_right)
return res
def _print_IdentitySuperOperator(self, expr, superop=True):
return "1"
def _print_ZeroSuperOperator(self, expr, superop=True):
return "0"
def _print_SuperOperatorPlus(self, expr, adjoint=False, superop=True):
return self._print_QuantumPlus(expr, adjoint=adjoint, superop=True)
def _print_SuperOperatorTimes(self, expr, adjoint=False, superop=True):
kwargs = {}
if adjoint:
kwargs['adjoint'] = True
return self._print_QuantumTimes(expr, superop=True, **kwargs)
def _print_SuperAdjoint(self, expr, adjoint=False, superop=True):
o = expr.operand
if self._isinstance(o, 'SuperOperatorSymbol'):
return self._render_op(
o.label, hs=o.space, dagger=(not adjoint), superop=True)
else:
if adjoint:
return self.doprint(o)
else:
return (
self._parenth_left + self.doprint(o) +
self._parenth_right + "^" + self._dagger_sym)
def _print_SPre(self, expr, superop=True):
return (
"SPre" + self._parenth_left + self.doprint(expr.operands[0]) +
self._parenth_right)
def _print_SPost(self, expr, superop=True):
return (
"SPost" + self._parenth_left + self.doprint(expr.operands[0]) +
self._parenth_right)
def _print_SuperOperatorTimesOperator(self, expr):
prec = precedence(expr)
sop, op = expr.sop, expr.op
cs = self.parenthesize(sop, prec)
ct = self.doprint(op)
return "%s[%s]" % (cs, ct)
def _print_QuantumDerivative(self, expr):
res = ""
for sym, n in expr.derivs.items():
sym_str = self.doprint(sym)
if " " in sym_str:
sym_str = "(%s)" % sym_str
if n == 1:
res += "D_%s " % sym_str
else:
res += "D_%s^%s " % (sym_str, n)
res += self.parenthesize(expr.operand, PRECEDENCE['Mul'], strict=True)
if expr.vals:
evaluation_strs = []
for sym, val in expr.vals.items():
evaluation_strs.append(
"%s=%s" % (self.doprint(sym), self.doprint(val)))
res += " |_(%s)" % ", ".join(evaluation_strs)
return res
def _print_Matrix(self, expr):
matrix_left_sym = '['
matrix_right_sym = ']'
matrix_row_left_sym = '['
matrix_row_right_sym = ']'
matrix_col_sep_sym = ', '
matrix_row_sep_sym = ', '
row_strs = []
if len(expr.matrix) == 0:
row_strs.append(matrix_row_left_sym + matrix_row_right_sym)
row_strs.append(matrix_row_left_sym + matrix_row_right_sym)
else:
for row in expr.matrix:
row_strs.append(
matrix_row_left_sym +
matrix_col_sep_sym.join(
[self.doprint(entry) for entry in row]) +
matrix_row_right_sym)
return (
matrix_left_sym + matrix_row_sep_sym.join(row_strs) +
matrix_right_sym)
def _print_Eq(self, expr):
# print for qnet.algebra.toolbox.equality.Eq, but also works for any
# Eq class that has the minimum requirement to have an `lhs` and `rhs`
# attribute
try:
return expr._render_str(renderer=self.doprint)
except AttributeError:
return (self.doprint(expr.lhs) + ' = ' + self.doprint(expr.rhs))
[docs]class QnetAsciiDefaultPrinter(QnetAsciiPrinter):
"""Printer for an ASCII representation that accepts no settings. This can
be used internally when a well-defined, static representation is needed
(e.g. as a sort key)"""
_default_settings = {}
def __init__(self):
super().__init__(cache=None, settings=None)
self._settings = {
'show_hs_label': True,
'sig_as_ketbra': True}