예제 #1
0
 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
예제 #2
0
 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)
예제 #3
0
    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)
예제 #4
0
 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
예제 #5
0
 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)
예제 #6
0
파일: label.py 프로젝트: PyProveIt/Prove-It
 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)
예제 #7
0
 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)
예제 #8
0
    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
예제 #9
0
 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)
예제 #10
0
 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)
예제 #11
0
 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)
예제 #12
0
 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'
예제 #13
0
    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
예제 #14
0
 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)
예제 #15
0
 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)
예제 #16
0
 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)
예제 #17
0
    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)
예제 #18
0
 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)
예제 #19
0
 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)
예제 #20
0
    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])
예제 #21
0
    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)
예제 #22
0
    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)
예제 #23
0
 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)
예제 #24
0
    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)