def __init__(self, var, index_or_indices, base=1, styles=None, requirements=tuple()): from .composite import compositeExpression if not isinstance(var, Variable): raise TypeError( "'var' being indexed should be a Variable, got %s" % str(var)) self.indices = compositeExpression(index_or_indices) if len(self.indices) == 1: # has a single parameter self.index = self.indices[0] self.index_or_indices = self.index else: self.index_or_indices = self.indices if not isinstance(base, int): raise TypeError("'base' should be an integer") Expression.__init__(self, ['Indexed', str(base)], [var, self.index_or_indices], styles=styles, requirements=requirements) self.var = var self.base = base
def __init__(self, items, styles=None): ''' Create a NamedExprs Expression object from a list (iterable) of (keyword, Expression) pairs, where each keyword is a string. ''' from proveit._core_ import Judgment keywords = [] elems = dict() for key, val in items: keywords.append(key) if ':' in key: raise ValueError("':' not allowed in NamedExprs string") if not isinstance(key, str): raise TypeError( "Keywords of an expression dictionary may only be strings") # if not re.match('[A-Za-z0-9_]+', key): # raise ValueError('A NamedExprs key may only include alphanumeric or underscore chararcters.') if isinstance(val, Judgment): val = val.expr # extract the Expression from the Judgment try: val = single_or_composite_expression(val) except TypeError: raise TypeError("Values of NamedExprs must be Expressions") assert isinstance(val, Expression) elems[key] = val self.keywords, self.elems = keywords, elems # ',' isn't allowed in the core info and ':' is not allowed # in NamedExprs keys, so swap one with the other to encode. core_info_enc_keywords = [key.replace(',', ':') for key in keywords] Expression.__init__(self, ['NamedExprs'] + core_info_enc_keywords, [self[key] for key in list(self.keys())], styles=styles)
def __init__(self, *expressions, styles=None): ''' Initialize an ExprTuple from an iterable over Expression objects. ''' from proveit._core_ import KnownTruth from .composite import singleOrCompositeExpression entries = [] for entry in expressions: if isinstance(entry, KnownTruth): # Extract the Expression from the KnownTruth: entry = entry.expr if not isinstance(entry, Expression): entry = singleOrCompositeExpression(entry) assert isinstance(entry, Expression) entries.append(entry) self.entries = tuple(entries) self._lastEntryCoordInfo = None self._lastQueriedEntryIndex = 0 if styles is None: styles = dict() if 'wrapPositions' not in styles: styles['wrapPositions'] = '()' # no wrapping by default if 'justification' not in styles: styles['justification'] = 'left' Expression.__init__(self, ['ExprTuple'], self.entries, styles=styles)
def __init__(self, var, index_or_indices, base=1, styles=dict(), requirements=tuple()): from composite import Composite, singleOrCompositeExpression, compositeExpression if not isinstance(var, Variable): raise TypeError("'var' being indexed should be a Variable") self.index_or_indices = singleOrCompositeExpression(index_or_indices) if isinstance(index_or_indices, Composite): # a composite of multiple indices self.indices = index_or_indices else: # a single index self.index = index_or_indices # wrap a single index in a composite for convenience self.indices = compositeExpression(self.index) if not isinstance(base, int): raise TypeError("'base' should be an integer") Expression.__init__(self, ['Indexed', str(base)], [var, index_or_indices], styles=styles, requirements=requirements) self.var = var self.base = base
def __init__(self, items, styles=None, requirements=tuple()): ''' Create a NamedExprs Expression object from a list (iterable) of (keyword, Expression) pairs, where each keyword is a string. ''' from proveit._core_ import KnownTruth keywords = [] elems = dict() for key, val in items: keywords.append(key) elems[key] = val if not isinstance(key, str): raise TypeError( "Keywords of an expression dictionary may only be strings") if not re.match('[A-Za-z0-9_]+', key): raise ValueError( 'A NamedExprs key may only include alphanumeric or underscore chararcters.' ) if isinstance(val, KnownTruth): val = val.expr # extract the Expression from the KnownTruth if not isinstance(val, Expression): raise TypeError( "Values of an expression dictionary must be Expressions") self.keywords, self.elems = keywords, elems Expression.__init__(self, ['NamedExprs'] + list(self.keys()), [self[key] for key in list(self.keys())], styles=styles, requirements=requirements)
def __init__(self, string_format, latex_format=None, label_type='Label', extra_core_info=tuple(), *, fence_when_forced=False, styles=None): ''' Create a Label with the given string and latex formatting. By default, the latex formatting is the same as the string formatting. ''' self.string_format = string_format if latex_format is None: latex_format = string_format self.latex_format = latex_format.strip( ) if latex_format is not None else string_format assert re.match( '[!-~]+', self.string_format), 'Label string_format may include only printable ascii characters and no space' assert re.match( '[ -~]+', self.latex_format), 'Label latex_format may include only printable ascii characters' if not isinstance(self.string_format, str): raise TypeError("'string_format' must be a str") if not isinstance(self.latex_format, str): raise TypeError("'latex_format' must be a str") if ',' in self.string_format or ',' in self.latex_format: raise ValueError("Comma not allowed within a label's formatting") if fence_when_forced: extra_core_info = ('fence_when_forced',) + extra_core_info core_info = ((label_type, self.string_format, self.latex_format) + extra_core_info) self.fence_when_forced = fence_when_forced Expression.__init__(self, core_info, sub_expressions=tuple(), styles=styles)
def __init__(self, *expressions, styles=None): ''' Initialize an ExprTuple from an iterable over Expression objects. ''' from proveit._core_ import Judgment from .composite import single_or_composite_expression entries = [] if isinstance(expressions, str): # We should check for strings in particular because this # will otherwise lead to an infinite recursion. raise TypeError("ExprTuple accepts Expressions, not a str: %s" %expressions) for entry in expressions: if isinstance(entry, Judgment): # Extract the Expression from the Judgment: entry = entry.expr if not isinstance(entry, Expression): entry = single_or_composite_expression(entry) assert isinstance(entry, Expression) entries.append(entry) self.entries = tuple(entries) Expression.__init__(self, ['ExprTuple'], self.entries, styles=styles)
def __init__(self, value, condition_or_conditions): ''' Create a Conditional with the given particular value and the given condition. If multiple conditions are provided, these will be wrapped in a conjunction internally. However, if the 'condition_delimiter' style is set to 'comma', the conditions will be displayed in a comma delimited fashion if it is within a conjunction. ''' from proveit._core_.expression.composite import \ single_or_composite_expression, Composite, ExprTuple, ExprRange value = single_or_composite_expression(value) assert (isinstance(value, Expression) and not isinstance(value, ExprRange)) condition_or_conditions = \ single_or_composite_expression(condition_or_conditions) if isinstance(condition_or_conditions, ExprTuple): if is_single(condition_or_conditions): condition = condition_or_conditions[0] else: # Must wrap a tuple of conditions in a conjunction. from proveit.logic import And condition = And(*condition_or_conditions.entries) else: condition = condition_or_conditions assert (isinstance(condition, Expression) and not isinstance(condition, Composite)) Expression.__init__(self, ['Conditional'], (value, condition)) self.value = value self.condition = condition
def __init__(self, stringFormat, latexFormat=None, labelType='Label', extraCoreInfo=tuple(), subExpressions=tuple()): ''' Create a Label with the given string and latex formatting. By default, the latex formatting is the same as the string formatting. ''' self.stringFormat = stringFormat if latexFormat is None: latexFormat = stringFormat self.latexFormat = latexFormat.strip( ) if latexFormat is not None else stringFormat assert re.match( '[!-~]+', self.stringFormat ), 'Label stringFormat may include only printable ascii characters and no space' assert re.match( '[ -~]+', self.latexFormat ), 'Label latexFormat may include only printable ascii characters' if not isinstance(self.stringFormat, str): raise TypeError("'stringFormat' must be a str") if not isinstance(self.latexFormat, str): raise TypeError("'latexFormat' must be a str") if ',' in self.stringFormat or ',' in self.latexFormat: raise ValueError("Comma not allowed within a label's formatting") coreInfo = [labelType] + self._labelInfo() + list(extraCoreInfo) Expression.__init__(self, coreInfo, subExpressions=subExpressions)
def _replaced(self, repl_map, allow_relabeling, assumptions, requirements, equality_repl_requirements): ''' Returns this expression with sub-expressions substituted according to the replacement map (repl_map) dictionary. ''' if len(repl_map) > 0 and (self in repl_map): return repl_map[self] # First do a replacement after temporarily removing the base # variable from the repl_map so we can see if the result of # that is in the repl_map. base_var = self.var base_var_sub = repl_map.pop(base_var, None) replaced_sans_base_var_sub = \ Expression._replaced(self, repl_map, allow_relabeling, assumptions, requirements, equality_repl_requirements) if base_var_sub is None: # base_var wasn't in repl_map in the first place, so # attempting to remove it had no effect. return replaced_sans_base_var_sub try: if replaced_sans_base_var_sub in repl_map: return repl_map[replaced_sans_base_var_sub] finally: repl_map[base_var] = base_var_sub # As the last resort, do the replacement with the # base_var in the repl_map. return Expression._replaced(self, repl_map, allow_relabeling, assumptions, requirements, equality_repl_requirements)
def __init__(self, parameter_or_parameters, body, conditions=tuple(), styles=None, requirements=tuple()): ''' Initialize a Lambda function expression given parameter(s) and a body. Each parameter must be a Variable. When there is a single parameter, there will be a 'parameter' attribute. Either way, there will be a 'parameters' attribute that bundles the one or more Variables into an ExprList. The 'body' attribute will be the lambda function body Expression (that may or may not be a Composite). Zero or more expressions may be provided. ''' from proveit._core_.expression.composite import compositeExpression, singleOrCompositeExpression, Iter if styles is None: styles = dict() self.parameters = compositeExpression(parameter_or_parameters) parameterVars = [getParamVar(parameter) for parameter in self.parameters] if len(self.parameters) == 1: # has a single parameter self.parameter = self.parameters[0] self.parameter_or_parameters = self.parameter else: self.parameter_or_parameters = self.parameters self.parameterVars = tuple(parameterVars) self.parameterVarSet = frozenset(parameterVars) if len(self.parameterVarSet) != len(self.parameters): raise ValueError('Lambda parameters Variables must be unique with respect to each other.') body = singleOrCompositeExpression(body) if not isinstance(body, Expression): raise TypeError('A Lambda body must be of type Expression') if isinstance(body, Iter): raise TypeError('An Iter must be within an ExprList or ExprTensor, not directly as a Lambda body') self.body = body self.conditions = compositeExpression(conditions) for requirement in self.body.getRequirements(): if not self.parameterVarSet.isdisjoint(requirement.freeVars()): raise LambdaError("Cannot generate a Lambda expression with parameter variables involved in Lambda body requirements: " + str(requirement)) sub_exprs = [self.parameter_or_parameters, self.body] if len(self.conditions)>0: sub_exprs.append(self.conditions) # Create a "generic" version (if not already) of the Lambda expression since the # choice of parameter labeling is irrelevant. generic_body_vars = self.body._genericExpr.usedVars() generic_condition_vars = self.conditions._genericExpr.usedVars() used_generic_vars = generic_body_vars.union(generic_condition_vars) generic_params = tuple(safeDummyVars(len(self.parameterVars), *(used_generic_vars-self.parameterVarSet))) if generic_params != self.parameterVars: relabel_map = {param:generic_param for param, generic_param in zip(self.parameterVars, generic_params)} # temporarily disable automation during the relabeling process prev_automation = defaults.automation defaults.automation = False generic_parameters = self.parameters._genericExpr.relabeled(relabel_map) generic_body = self.body._genericExpr.relabeled(relabel_map) generic_conditions = self.conditions._genericExpr.relabeled(relabel_map) self._genericExpr = Lambda(generic_parameters, generic_body, generic_conditions, styles=dict(styles), requirements=requirements) defaults.automation = prev_automation # restore to previous value Expression.__init__(self, ['Lambda'], sub_exprs, styles=styles, requirements=requirements)
def _config_latex_tool(self, lt): Expression._config_latex_tool(self, lt) if not 'xy' in lt.packages: lt.packages.append('xy') if r'\newcommand{\exprtensorelem}' not in lt.preamble: lt.preamble += r'\newcommand{\exprtensorelem}[1]{*+<1em,.9em>{\hphantom{#1}} \POS [0,0]="i",[0,0].[0,0]="e",!C *{#1},"e"+UR;"e"+UL **\dir{-};"e"+DL **\dir{-};"e"+DR **\dir{-};"e"+UR **\dir{-}, "i"}' + '\n' if r'\newcommand{\exprtensorblock}' not in lt.preamble: lt.preamble += r'\newcommand{\exprtensorblock}[3]{\POS [0,0]="i",[0,0].[#1,#2]="e",!C *{#3},"e"+UR;"e"+UL **\dir{-};"e"+DL **\dir{-};"e"+DR **\dir{-};"e"+UR **\dir{-}, "i"}' + '\n' if r'\newcommand{\exprtensorghost}' not in lt.preamble: lt.preamble += r'\newcommand{\exprtensorghost}[1]{*+<1em,.9em>{\hphantom{#1}}}' + '\n'
def __init__(self, lambda_map, start_index_or_indices, end_index_or_indices, styles=dict(), requirements=tuple()): if not isinstance(lambda_map, Lambda): raise TypeError( 'When creating an Iter Expression, the lambda_map argument must be a Lambda expression' ) if isinstance(start_index_or_indices, ExprList) and len(start_index_or_indices) == 1: start_index_or_indices = start_index_or_indices[0] self.start_index_or_indices = singleOrCompositeExpression( start_index_or_indices) if isinstance(self.start_index_or_indices, Composite): # a composite of multiple indices self.start_indices = self.start_index_or_indices else: # a single index self.start_index = self.start_index_or_indices # wrap a single index in a composite for convenience self.start_indices = compositeExpression( self.start_index_or_indices) if isinstance(end_index_or_indices, ExprList) and len(end_index_or_indices) == 1: end_index_or_indices = end_index_or_indices[0] self.end_index_or_indices = singleOrCompositeExpression( end_index_or_indices) if isinstance(self.end_index_or_indices, Composite): # a composite of multiple indices self.end_indices = self.end_index_or_indices else: # a single index self.end_index = self.end_index_or_indices # wrap a single index in a composite for convenience self.end_indices = compositeExpression(self.end_index_or_indices) self.ndims = len(self.start_indices) if self.ndims != len(self.end_indices): raise ValueError( "Inconsistent number of 'start' and 'end' indices") if len(lambda_map.parameters) != len(self.start_indices): raise ValueError( "Inconsistent number of indices and lambda map parameters") Expression.__init__(self, ['Iter'], [ lambda_map, self.start_index_or_indices, self.end_index_or_indices ], styles=styles, requirements=requirements) self.lambda_map = lambda_map
def __init__(self, operator_or_operators, operand_or_operands, styles=dict(), requirements=tuple()): ''' Create an operation with the given operator(s) and operand(s). The operator(s) must be Label(s) (a Variable or a Literal). When there is a single operator, there will be an 'operator' attribute. When there is a single operand, there will be an 'operand' attribute. In any case, there will be 'operators' and 'operands' attributes that bundle the one or more Expressions into a composite Expression. ''' from proveit._core_.expression.composite import Composite, compositeExpression, singleOrCompositeExpression, Iter, Indexed from proveit._core_.expression.label.label import Label from proveit import Context if hasattr(self.__class__, '_operator_') and operator_or_operators==self.__class__._operator_: operator = operator_or_operators context = Context(inspect.getfile(self.__class__)) if Expression.contexts[operator] != context: raise OperationError("Expecting '_operator_' Context to match the Context of the Operation sub-class. Use 'context=__file__'.") self.operator_or_operators = singleOrCompositeExpression(operator_or_operators) self.operand_or_operands = singleOrCompositeExpression(operand_or_operands) if isinstance(self.operator_or_operators, Composite): # a composite of multiple operators: self.operators = self.operator_or_operators for operator in self.operators: if isinstance(operator, Iter): if not isinstance(operator.lambda_map.body, Indexed): raise TypeError('operators must be Labels, Indexed variables, or iteration (Iter) over Indexed variables.') elif not isinstance(operator, Label) and not isinstance(operator, Indexed): raise TypeError('operator must be a Label, Indexed variable, or iteration (Iter) over Indexed variables.') else: # a single operator self.operator = self.operator_or_operators if not isinstance(self.operator, Label) and not isinstance(self.operator, Indexed): raise TypeError('operator must be a Label, Indexed variable, or iteration (Iter) over Indexed variables.') # wrap a single operator in a composite for convenience self.operators = compositeExpression(self.operator) if isinstance(self.operand_or_operands, Composite): # a composite of multiple operands self.operands = self.operand_or_operands else: # a single operand self.operand = self.operand_or_operands # wrap a single operand in a composite for convenience self.operands = compositeExpression(self.operand) if 'operation' not in styles: styles['operation'] = 'normal' # vs 'function if 'wrapPositions' not in styles: styles['wrapPositions'] = '()' # no wrapping by default if 'justification' not in styles: styles['justification'] = 'center' Expression.__init__(self, ['Operation'], [self.operator_or_operators, self.operand_or_operands], styles=styles, requirements=requirements)
def _iterSubParamVals(self, axis, iterParam, startArg, endArg, exprMap, relabelMap=None, reservedVars=None, assumptions=USE_DEFAULTS, requirements=None): ''' Consider a substitution over a containing iteration (Iter) defined via exprMap, relabelMap, etc, and expand the iteration by substituting the "iteration parameter" over the range from the "starting argument" (inclusive) to the "ending argument" (exclusive). This deviates from the default it its need to impose scoping limitations -- lambda parameters are in a new scope. ''' new_params, inner_expr_map, inner_assumptions, inner_reservations \ = self._innerScopeSub(exprMap, relabelMap, reservedVars, assumptions, requirements) # Use the default version but with arguments adapted for # the inner scope: # (Is this doing the right thing w.r.t. the parameters sub-expression???) return Expression._iterSubParamVals(self, axis, iterParam, startArg, endArg, inner_expr_map, relabelMap, inner_reservations, inner_assumptions, requirements)
def __init__(self, *expressions): ''' Initialize an ExprTuple from an iterable over Expression objects. ''' from proveit._core_ import Judgment from .composite import single_or_composite_expression entries = [] for entry in expressions: if isinstance(entry, Judgment): # Extract the Expression from the Judgment: entry = entry.expr if not isinstance(entry, Expression): entry = single_or_composite_expression(entry) assert isinstance(entry, Expression) entries.append(entry) self.entries = tuple(entries) Expression.__init__(self, ['ExprTuple'], self.entries)
def __init__(self, operator, operand_or_operands, styles=None): ''' Create an operation with the given operator and operands. The operator must be a Label (a Variable or a Literal). If a composite expression is provided as the 'operand_or_operands' it is taken to be the 'operands' of the Operation; otherwise the 'operands' will be the the provided Expression wrapped as a single entry in an ExprTuple. When there is a single operand that is not an ExprRange, there will be an 'operand' attribute as well as 'operands' as an ExprTuple containing the one operand. ''' from proveit._core_.expression.composite import ( single_or_composite_expression, Composite, ExprTuple) from proveit._core_.expression.label.label import Label from .indexed_var import IndexedVar self.operator = operator operand_or_operands = single_or_composite_expression( operand_or_operands, do_singular_reduction=True) if isinstance(operand_or_operands, Composite): # a composite of multiple operands self.operands = operand_or_operands else: self.operands = ExprTuple(operand_or_operands) def raise_bad_operator_type(operator): raise TypeError('operator must be a Label or an indexed variable ' '(IndexedVar). %s is none of those.' % str(operator)) if (not isinstance(self.operator, Label) and not isinstance(self.operator, IndexedVar)): raise_bad_operator_type(self.operator) if (isinstance(self.operands, ExprTuple) and self.operands.is_single()): # This is a single operand. self.operand = self.operands[0] sub_exprs = (self.operator, self.operands) if isinstance(self, IndexedVar): core_type = 'IndexedVar' else: core_type = 'Operation' Expression.__init__(self, [core_type], sub_exprs, styles=styles)
def __init__(self, *expressions): ''' Initialize an ExprList from an iterable over Expression objects. ''' from proveit._core_ import KnownTruth from .composite import singleOrCompositeExpression entries = [] for entry in expressions: if isinstance(entry, KnownTruth): entry = entry.expr # extract the Expression from the KnownTruth try: entry = singleOrCompositeExpression(entry) assert isinstance(entry, Expression) except: raise TypeError('ExprList must be created out of Expressions)') entries.append(entry) self.entries = entries self._sortedCoords = [] Expression.__init__(self, ['ExprList'], self.entries)
def __init__(self, parameter_or_parameters, body, conditions=tuple(), styles=dict(), requirements=tuple()): ''' Initialize a Lambda function expression given parameter(s) and a body. Each parameter must be a Variable. When there is a single parameter, there will be a 'parameter' attribute. Either way, there will be a 'parameters' attribute that bundles the one or more Variables into an ExprList. The 'body' attribute will be the lambda function body Expression (that may or may not be a Composite). Zero or more expressions may be provided. ''' from proveit._core_.expression.composite import compositeExpression, singleOrCompositeExpression, Iter, Indexed from proveit._core_.expression.label import Variable self.parameters = compositeExpression(parameter_or_parameters) parameterVars = list() for parameter in self.parameters: if isinstance(parameter, Iter) and isinstance( parameter.lambda_map.body, Indexed): parameterVars.append(parameter.lambda_map.body.var) elif isinstance(parameter, Indexed): parameterVars.append(parameter.var) elif isinstance(parameter, Variable): parameterVars.append(parameter) else: raise TypeError( 'parameters must be a Variables, Indexed variable, or iteration (Iter) over Indexed variables.' ) if len(self.parameters) == 1: # has a single parameter self.parameter = self.parameters[0] self.parameter_or_parameters = self.parameter else: self.parameter_or_parameters = self.parameters self.parameterVars = tuple(parameterVars) self.parameterVarSet = frozenset(parameterVars) if len(self.parameterVarSet) != len(self.parameters): raise ValueError( 'Lambda parameters Variables must be unique with respect to each other.' ) body = singleOrCompositeExpression(body) if not isinstance(body, Expression): raise TypeError('A Lambda body must be of type Expression') if isinstance(body, Iter): raise TypeError( 'An Iter must be within an ExprList or ExprTensor, not directly as a Lambda body' ) self.body = body self.conditions = compositeExpression(conditions) for requirement in self.body.requirements: if not self.parameterVarSet.isdisjoint(requirement.freeVars()): raise LambdaError( "Cannot generate a Lambda expression with parameter variables involved in Lambda body requirements: " + str(requirement)) Expression.__init__( self, ['Lambda'], [self.parameter_or_parameters, self.body, self.conditions], styles=styles, requirements=requirements)
def __init__(self, tensor, shape=None, styles=None, assumptions=USE_DEFAULTS, requirements=tuple()): ''' Create an ExprTensor either with a simple, dense tensor (list of lists ... of lists) or with a dictionary mapping coordinates (as tuples of expressions that represent integers) to expr elements or Blocks. Providing starting and/or ending location(s) can extend the bounds of the tensor beyond the elements that are supplied. ''' from .composite import _simplifiedCoord from proveit._core_ import KnownTruth from proveit.number import Less, Greater, zero, one, num, Add, Subtract assumptions = defaults.checkedAssumptions(assumptions) requirements = [] if not isinstance(tensor, dict): tensor = { loc: element for loc, element in ExprTensor._tensorDictFromIterables( tensor, assumptions, requirements) } # Map direct compositions for the end-coordinate of Iter elements # to their simplified forms. self.endCoordSimplifications = dict() # generate the set of distinct coordinates for each dimension coord_sets = None # simplified versions full_tensor = dict() ndims = None if shape is not None: shape = ExprTensor.locAsExprs(shape) ndims = len(shape) for loc, element in tensor.items(): if isinstance(element, KnownTruth): element = element.expr # extract the Expression from the KnownTruth ndims = len(loc) if coord_sets is None: coord_sets = [set() for _ in range(ndims)] elif len(coord_sets) != ndims: if shape is not None: raise ValueError( "length of 'shape' is inconsistent with number of dimensions for ExprTensor locations" ) else: raise ValueError( "inconsistent number of dimensions for locations of the ExprTensor" ) for axis, coord in enumerate(list(loc)): if isinstance(coord, int): coord = num( coord) # convert from Python int to an Expression loc[axis] = coord coord_sets[axis].add(coord) if isinstance(element, Iter): # Add (end-start)+1 of the Iter to get to the end # location of the entry along this axis. orig_end_coord = Add( coord, Subtract(element.end_indices[axis], element.start_indices[axis]), one) end_coord = _simplifiedCoord(orig_end_coord, assumptions, requirements) self.endCoordSimplifications[orig_end_coord] = end_coord coord_sets[axis].add(end_coord) full_tensor[tuple(loc)] = element if ndims is None: raise ExprTensorError("Empty ExprTensor is not allowed") if ndims <= 1: raise ExprTensorError( "ExprTensor must be 2 or more dimensions (use an ExprList for something 1-dimensional" ) # in each dimension, coord_indices will be a dictionary # that maps each tensor location coordinate to its relative entry index. coord_rel_indices = [] self.sortedCoordLists = [] self.coordDiffRelationLists = [] for axis in range(ndims): # for each axis # KnownTruth sorting relation for the simplified coordinates used along this axis # (something with a form like a < b <= c = d <= e, that sorts the tensor location coordinates): coord_sorting_relation = Less.sort(coord_sets[axis], assumptions=assumptions) sorted_coords = list(coord_sorting_relation.operands) if shape is None: # Since nothing was explicitly specified, the shape is dictacted by extending # one beyond the last coordinate entry. sorted_coords.append(Add(sorted_coords[-1], one)) else: sorted_coords.append( shape[axis] ) # append the coordinate for the explicitly specified shape if sorted_coords[0] != zero: sorted_coords.insert( 0, zero ) # make sure the first of the sorted coordinates is zero. self.sortedCoordLists.append(ExprList(sorted_coords)) # Add in coordinate expressions that explicitly indicate the difference between coordinates. # These may be used in generating the latex form of the ExprTensor. diff_relations = [] for c1, c2 in zip(sorted_coords[:-1], sorted_coords[1:]): diff = _simplifiedCoord(Subtract(c2, c1), assumptions, requirements) # get the relationship between the difference of successive coordinate and zero. diff_relation = Greater.sort([zero, diff], assumptions=assumptions) if isinstance(diff_relation, Greater): if c2 == sorted_coords[-1] and shape is not None: raise ExprTensorError( "Coordinates extend beyond the specified shape in axis %d: %s after %s" % (axis, str(coord_sorting_relation.operands[-1]), str(shape[axis]))) assert tuple(diff_relation.operands) == ( diff, zero), 'Inconsistent Less.sort results' # diff > 0, let's compare it with one now diff_relation = Greater.sort([one, diff], assumptions=assumptions) requirements.append(diff_relation) diff_relations.append(diff_relation) self.coordDiffRelationLists.append(ExprList(diff_relations)) # map each coordinate expression to its index into the sorting_relation operands coord_rel_indices.append( {coord: k for k, coord in enumerate(sorted_coords)}) # convert from the full tensor with arbitrary expression coordinates to coordinates that are # mapped according to sorted relation enumerations. rel_index_tensor = dict() for loc, element in full_tensor.items(): rel_index_loc = ( rel_index_map[coord] for coord, rel_index_map in zip(loc, coord_rel_indices)) rel_index_tensor[rel_index_loc] = element sorted_keys = sorted(rel_index_tensor.keys()) Expression.__init__(self, [ 'ExprTensor', str(ndims), ';'.join(str(key) for key in sorted_keys) ], self.sortedCoordLists + self.coordDiffRelationLists + [rel_index_tensor[key] for key in sorted_keys], styles=styles, requirements=requirements) self.ndims = ndims self.relIndexTensor = rel_index_tensor # entryOrigins maps relative indices that contain tensor elements to # the relative indices of the origin for the corresponding entry. # Specifically, single-element entries map indices to themselves, but # multi-element Iter entries map each of the encompassed # relative index location to the origin relative index location where # that Iter entry is stored. self.relEntryOrigins = self._makeEntryOrigins() # the last coordinates of the sorted coordinates along each eaxis define the shape: self.shape = ExprList( [sorted_coords[-1] for sorted_coords in self.sortedCoordLists])
def __init__(self, parameter_or_parameters, body, start_index_or_indices, end_index_or_indices, styles=None, requirements=tuple(), _lambda_map=None): ''' Create an Iter that represents an iteration of the body for the parameter(s) ranging from the start index/indices to the end index/indices. A Lambda expression will be created as its sub-expression that maps the parameter(s) to the body with conditions that restrict the parameter(s) to the appropriate interval. _lambda_map is used internally for efficiently rebuilding an Iter. ''' from proveit.logic import InSet from proveit.number import Interval if _lambda_map is not None: # Use the provided 'lambda_map' instead of creating one. lambda_map = _lambda_map pos_args = (parameter_or_parameters, body, start_index_or_indices, end_index_or_indices) if pos_args != (None, None, None, None): raise ValueError( "Positional arguments of the Init constructor " "should be None if lambda_map is provided.") parameters = lambda_map.parameters body = lambda_map.body conditions = lambda_map.conditions if len(conditions) != len(parameters): raise ValueError( "Inconsistent number of conditions and lambda " "map parameters") start_indices, end_indices = [], [] for param, condition in zip(parameters, conditions): invalid_condition_msg = ( "Not the right kind of lambda_map condition " "for an iteration") if not isinstance(condition, InSet) or condition.element != param: raise ValueError(invalid_condition_msg) domain = condition.domain if not isinstance(domain, Interval): raise ValueError(invalid_condition_msg) start_index, end_index = domain.lowerBound, domain.upperBound start_indices.append(start_index) end_indices.append(end_index) self.start_indices = ExprTuple(*start_indices) self.end_indices = ExprTuple(*end_indices) if len(parameters) == 1: self.start_index = self.start_indices[0] self.end_index = self.end_indices[0] self.start_index_or_indices = self.start_index self.end_index_or_indices = self.end_index else: self.start_index_or_indices = self.start_indices self.end_index_or_indices = self.end_indices else: parameters = compositeExpression(parameter_or_parameters) start_index_or_indices = singleOrCompositeExpression( start_index_or_indices) if isinstance(start_index_or_indices, ExprTuple) and len(start_index_or_indices) == 1: start_index_or_indices = start_index_or_indices[0] self.start_index_or_indices = start_index_or_indices if isinstance(start_index_or_indices, Composite): # a composite of multiple indices self.start_indices = self.start_index_or_indices else: # a single index self.start_index = self.start_index_or_indices # wrap a single index in a composite for convenience self.start_indices = compositeExpression( self.start_index_or_indices) end_index_or_indices = singleOrCompositeExpression( end_index_or_indices) if isinstance(end_index_or_indices, ExprTuple) and len(end_index_or_indices) == 1: end_index_or_indices = end_index_or_indices[0] self.end_index_or_indices = end_index_or_indices if isinstance(self.end_index_or_indices, Composite): # a composite of multiple indices self.end_indices = self.end_index_or_indices else: # a single index self.end_index = self.end_index_or_indices # wrap a single index in a composite for convenience self.end_indices = compositeExpression( self.end_index_or_indices) conditions = [] for param, start_index, end_index in zip(parameters, self.start_indices, self.end_indices): conditions.append( InSet(param, Interval(start_index, end_index))) lambda_map = Lambda(parameters, body, conditions=conditions) self.ndims = len(self.start_indices) if self.ndims != len(self.end_indices): raise ValueError( "Inconsistent number of 'start' and 'end' indices") if len(parameters) != len(self.start_indices): raise ValueError( "Inconsistent number of indices and lambda map parameters") Expression.__init__(self, ['Iter'], [lambda_map], styles=styles, requirements=requirements) self.lambda_map = lambda_map self._checkIndexedRestriction(body)
def __init__(self, operator, operand_or_operands=None, *, operands=None, styles): ''' Create an operation with the given operator and operands. The operator must be a Label (a Variable or a Literal). If a composite expression is provided as the 'operand_or_operands' it is taken to be the 'operands' of the Operation; otherwise the 'operands' will be the the provided Expression wrapped as a single entry in an ExprTuple. When there is a single operand that is not an ExprRange, there will be an 'operand' attribute as well as 'operands' as an ExprTuple containing the one operand. ''' from proveit._core_.expression.composite import ( composite_expression, single_or_composite_expression, Composite, ExprTuple, NamedExprs) from proveit._core_.expression.lambda_expr import Lambda from .indexed_var import IndexedVar if self.__class__ == Operation: raise TypeError("Do not create an object of type Operation; " "use a derived class (e.g., Function) instead.") self.operator = operator if (operand_or_operands == None) == (operands == None): if operands == None: raise ValueError( "Must supply either 'operand_or_operands' or 'operands' " "when constructing an Operation") else: raise ValueError( "Must supply 'operand_or_operands' or 'operands' but not " "both when constructing an Operation") if operands is not None: if not isinstance(operands, Expression): operands = composite_expression(operands) self.operands = operands else: orig_operand_or_operands = operand_or_operands operand_or_operands = single_or_composite_expression( operand_or_operands, do_singular_reduction=True) if isinstance(operand_or_operands, Composite): # a composite of multiple operands self.operands = operand_or_operands else: if isinstance(orig_operand_or_operands, Composite): self.operands = orig_operand_or_operands else: self.operands = ExprTuple(operand_or_operands) def raise_bad_operator_type(operator): raise TypeError("An operator may not be an explicit Lambda map " "like %s; this is necessary to avoid a Curry's " "paradox." % str(operator)) if isinstance(self.operator, Lambda): raise_bad_operator_type(self.operator) if (isinstance(self.operands, ExprTuple) and self.operands.is_single()): # This is a single operand. self.operand = self.operands[0] sub_exprs = (self.operator, self.operands) if isinstance(self, IndexedVar): core_type = 'IndexedVar' else: core_type = 'Operation' if isinstance(self.operands, NamedExprs): # Make attributes to make the keys of the NamedExprs # operands. for key in self.operands.keys(): setattr(self, key, self.operands[key]) Expression.__init__(self, [core_type], sub_exprs, styles=styles)
def __init__(self, *expressions): ''' Initialize an ExprTuple from an iterable over Expression objects. When subsequent iterations in the tuple form a self-evident continuation, these iterations will be joined. For example, (a_1, ..., a_n, a_{n+1}, ..., a_m) will join to form (a_1, ..., a_m). "Self-evident" falls under two categories: the start of the second iteration is the successor to the end of the first iteration (e.g., n and n+1) or the end of the first iteration is the predecessor of the start of the second iteration (e.g., n-1 and n). To be a valid ExprTuple, all iterations must span a range whose extent is a natural number. In the above example with the tuple of "a"-indexed iterations, n must be a natural number and m-n must be a natural number for the ExprTuple to be valid (note that iterations may have an extent of zero). When an ExprTuple is created, there is not a general check that it is valid. However, when deriving new known truths from valid existing known truths, validity is guaranteed to be maintained (in particular, specializations that transform ExprTuples ensure that validity is maintained). The joining of iterations is valid as long as the original iterations are valid, so this process is also one that maintains validity which is the thing that is important. ''' from proveit._core_ import KnownTruth from .composite import singleOrCompositeExpression from .iteration import Iter prev_entry = None entries = [] for entry in expressions: if isinstance(entry, KnownTruth): # Extract the Expression from the KnownTruth: entry = entry.expr try: entry = singleOrCompositeExpression(entry) assert isinstance(entry, Expression) except: raise TypeError("ExprTuple must be created out of " "Expressions.") # See if this entry should be joined with the previous # entry. if isinstance(prev_entry, Iter) and isinstance(entry, Iter): from proveit.number import dist_add, dist_subtract, one if prev_entry.lambda_map == entry.lambda_map: prev_end_successor = dist_add(prev_entry.end_index, one) next_start_predecessor = dist_subtract( entry.start_index, one) if entry.start_index == prev_end_successor: # Join the entries of the form # (a_i, ..., a_n, a_{n+1}, ..., a_m). prev_entry.end_index = entry.end_index entry = None elif prev_entry.end_index == next_start_predecessor: # Join the entries of the form # (a_i, ..., a_{n-1}, a_{n}, ..., a_m). prev_entry.end_index = entry.end_index entry = None if entry is not None: # Safe to append the previous entry since it does # not join with the new entry. if prev_entry is not None: entries.append(prev_entry) prev_entry = entry if prev_entry is not None: # One last entry to append. entries.append(prev_entry) self.entries = tuple(entries) self._lastEntryCoordInfo = None self._lastQueriedEntryIndex = 0 Expression.__init__(self, ['ExprTuple'], self.entries)
def __init__(self, operator_or_operators, operand_or_operands, styles=None): ''' Create an operation with the given operator(s) and operand(s). The operator(s) must be Label(s) (a Variable or a Literal). When there is a single operator, there will be an 'operator' attribute. When there is a single operand, there will be an 'operand' attribute. In any case, there will be 'operators' and 'operands' attributes that bundle the one or more Expressions into a composite Expression. ''' from proveit._core_.expression.composite import ( Composite, compositeExpression, singleOrCompositeExpression, ExprTuple, ExprRange) from proveit._core_.expression.label.label import Label from .indexed_var import IndexedVar if styles is None: styles = dict() if hasattr(self.__class__, '_operator_' ) and operator_or_operators == self.__class__._operator_: operator = operator_or_operators #if Expression.contexts[operator._style_id] != operator.context: # raise OperationError("Expecting '_operator_' Context to match the Context of the Operation sub-class. Use 'context=__file__'.") if isinstance(operator_or_operators, ExprRange): operator_or_operators = [operator_or_operators] if isinstance(operand_or_operands, ExprRange): operand_or_operands = [operand_or_operands] self.operator_or_operators = singleOrCompositeExpression( operator_or_operators) # Reduce to a single operand if it is just a tuple with # one non-ExprRange and non-ExprTuple element. self.operand_or_operands = singleOrCompositeExpression( operand_or_operands, do_singular_reduction=True) def raiseBadOperatorType(operator): raise TypeError('operator(s) must be a Label, an indexed variable ' '(IndexedVar), or iteration (Iter) over indexed' 'variables (IndexedVar). %s is none of those.' % str(operator)) if isinstance(self.operator_or_operators, Composite): # a composite of multiple operators: self.operators = self.operator_or_operators for operator in self.operators: if isinstance(operator, ExprRange): if not isinstance(operator.body, IndexedVar): raiseBadOperatorType(operator) elif not isinstance(operator, Label) and not isinstance( operator, IndexedVar): raiseBadOperatorType(operator) else: # a single operator self.operator = self.operator_or_operators if not isinstance(self.operator, Label) and not isinstance( self.operator, IndexedVar): raiseBadOperatorType(self.operator) # wrap a single operator in a composite for convenience self.operators = compositeExpression(self.operator) if isinstance(self.operand_or_operands, Composite): # a composite of multiple operands self.operands = self.operand_or_operands if (isinstance(self.operands, ExprTuple) and len(self.operands) == 1 and isinstance(self.operands[0], ExprTuple)): # This is a single operand that is an ExprTuple. self.operand = self.operands[0] else: # a single operand self.operand = self.operand_or_operands # wrap a single operand in a composite for convenience self.operands = compositeExpression(self.operand) if 'operation' not in styles: styles['operation'] = 'infix' # vs 'function' if 'wrapPositions' not in styles: styles['wrapPositions'] = '()' # no wrapping by default if 'justification' not in styles: styles['justification'] = 'center' sub_exprs = (self.operator_or_operators, self.operand_or_operands) if isinstance(self, IndexedVar): core_type = 'IndexedVar' else: core_type = 'Operation' Expression.__init__(self, [core_type], sub_exprs, styles=styles)