Example #1
0
class ProveItMagic(Magics):
    "Magics that hold additional state"

    def __init__(self, shell, assignmentBehaviorModifier):
        # You must call the parent constructor
        super(ProveItMagic, self).__init__(shell)
        self.kind = None
        self.definitions = dict()
        self.keys = []  # the keys of the definitions in the order they appear
        self.lowerCaseNames = set()
        self.context = None
        self.ranFinish = False
        self.assignmentBehaviorModifier = assignmentBehaviorModifier
        assignmentBehaviorModifier.displayAssignments(ip)

    @line_magic
    def display_assignments(self, line):
        if line.strip() == 'off':
            self.assignmentBehaviorModifier.resetBehavior()
        else:
            self.assignmentBehaviorModifier.displayAssignments(self.shell)

    @line_magic
    def context(self, line):
        '''
        Create the _common_, _axioms_ and _theorems_ notebooks for the current
        context (if they do not already exist).  Show the table of contents
        for sub-contexts which may be edited.
        '''
        import proveit
        import ipywidgets as widgets
        # create an '_init_.py' in the directory if there is not an existing one.
        if not os.path.isfile('__init__.py'):
            open('__init__.py', 'w').close()  # create an empty __init__.py
        context = Context()
        proveit_path = os.path.split(proveit.__file__)[0]
        special_notebook_types = ('common', 'axioms', 'theorems',
                                  'demonstrations')
        special_notebook_texts = ('common expressions', 'axioms', 'theorems',
                                  'demonstrations')
        for special_notebook_type in special_notebook_types:
            notebook_name = '_%s_.ipynb' % special_notebook_type
            if not os.path.isfile(notebook_name):
                # notebook does not yet exist, create it from the template
                template_name = '_%s_template_.ipynb' % special_notebook_type
                with open(os.path.join(proveit_path, '..', template_name),
                          'r') as template:
                    nb = template.read()
                    nb = nb.replace('#CONTEXT#', context.name)
                # write the notebook file
                with open(notebook_name, 'w') as notebook_file:
                    notebook_file.write(nb)

        context_interface = ContextInterface()

        if context_interface.mode == 'static':
            special_notebooks_html = '<table>\n'
            for special_notebook_type, special_notebook_text in zip(
                    special_notebook_types, special_notebook_texts):
                special_notebooks_html += '<th><a class="ProveItLink" href="_%s_.ipynb">%s</a></th>\n' % (
                    special_notebook_type, special_notebook_text)
            special_notebooks_html += '</table>\n'
            if len(context_interface.subContextNames) > 0:
                special_notebooks_html += '<table>\n'
                for name in context_interface.subContextNames:
                    description = context_interface.subContextDescriptions[
                        name]
                    href = context_interface.subContextNotebook(name)
                    special_notebooks_html += '<tr><th><a class="ProveItLink" href="%s">%s</a></th><td>%s</td></tr>\n' % (
                        href, name, description)
                special_notebooks_html += '</table>\n'
            display(HTML(special_notebooks_html))
        else:
            special_notebook_links = []
            full_width_layout = widgets.Layout(width='100%', padding='5px')
            for special_notebook_type, special_notebook_text in zip(
                    special_notebook_types, special_notebook_texts):
                special_notebook_links.append(
                    widgets.HTML(
                        '<a class="ProveItLink" href="_%s_.ipynb">%s</a>' %
                        (special_notebook_type, special_notebook_text),
                        layout=full_width_layout))
            special_notebook_links = widgets.HBox(special_notebook_links)

            sub_contexts_label = widgets.Label(
                'List of sub-contexts:', layout=widgets.Layout(width='100%'))
            #sub_context_widgets = widgets.VBox(sub_context_widgets)
            add_context_widget = widgets.Text(value='',
                                              placeholder='Add sub-context...')

            def addSubContext(sender):
                context_interface.addSubContext(add_context_widget.value)
                add_context_widget.value = ''

            add_context_widget.on_submit(addSubContext)
            #layout = widgets.Layout(display='flex', flex_flow='column-reverse')
            #display(widgets.Button(description='Edit...', disabled=False, button_style='', tooltip='Edit the sub-contents list', layout=layout))
            #layout = widgets.Layout(float='bottom')
            display(
                widgets.VBox([
                    special_notebook_links, sub_contexts_label,
                    context_interface.widget, add_context_widget
                ]))

    def begin_axioms(self):
        # context based upon current working directory
        self.context = Context()
        if len(self.definitions) > 0 or self.kind is not None:
            if self.kind != 'axioms':
                raise ProveItMagicFailure(
                    "Run %%begin_axioms in a separate notebook from %%begin_%s."
                    % self.kind)
            print "WARNING: Re-running %begin_axioms does not reset previously defined axioms."
            print "         It is suggested that you restart and run all cells after editing axioms."
        print "Defining axioms for context '" + self.context.name + "'"
        print "Subsequent end-of-cell assignments will define axioms"
        print "%end_axioms will finalize the definitions"

    def end_axioms(self):
        self._finish('axioms')

    def begin_theorems(self):
        # context based upon current working directory
        if len(self.definitions) > 0 or self.kind is not None:
            if self.kind != 'theorems':
                raise ProveItMagicFailure(
                    "Run %%begin_theorems in a separate notebook from %%begin_%s."
                    % self.kind)
            print "WARNING: Re-running %begin_theorems does not reset previously defined theorems."
            print "         It is suggested that you restart and run all cells after editing theorems."
        print "Defining theorems for context '" + self.context.name + "'"
        print "Subsequent end-of-cell assignments will define theorems"
        print "'%end theorems' will finalize the definitions"

    def end_theorems(self):
        self._finish('theorems')
        # stash proof notebooks that are not active theorems.
        self.context.stashExtraneousProofNotebooks()

    def begin_common(self):
        if len(self.definitions) > 0 or self.kind is not None:
            if self.kind != 'common':
                raise ProveItMagicFailure(
                    "Run '%%begin common' in a separate notebook from %%begin_%s."
                    % self.kind)
            print "WARNING: Re-running '%begin common' does not reset previously defined common expressions."
            print "         It is suggested that you restart and run all cells after editing the expressions."
        print "Defining common sub-expressions for context '" + self.context.name + "'"
        print "Subsequent end-of-cell assignments will define common sub-expressions"
        print "%end_common will finalize the definitions"

    def end_common(self):
        # Record the context names of common expressions referenced
        # by this context's common expressions notebook...
        self.context.recordCommonExprDependencies()
        # and check for illegal mutual references.
        cyclically_referenced_common_expr_context = self.context.cyclicallyReferencedCommonExprContext(
        )
        if cyclically_referenced_common_expr_context is not None:
            raise ProveItMagicFailure(
                "Not allowed to have cyclically dependent 'common expression' notebooks: %s._common_"
                % cyclically_referenced_common_expr_context)
        self._finish('common')

    @line_magic
    def begin(self, line):
        kind = line.strip()
        # context based upon current working directory
        self.context = Context()
        if kind == 'axioms':
            self.begin_axioms()
        elif kind == 'theorems':
            self.begin_theorems()
        elif kind == 'common':
            self.begin_common()
        self.kind = kind

    @line_magic
    def end(self, line):
        kind = line.strip()
        if kind == 'axioms':
            self.end_axioms()
        elif kind == 'theorems':
            self.end_theorems()
        elif kind == 'common':
            self.end_common()
        # reference any expressions that were displayed:
        self.context.referenceDisplayedExpressions(kind)
        # clean unreferenced expressions:
        self.context.clean()
        self.kind = None

    @line_magic
    def clear(self, line):
        kind = line.strip()
        # context based upon current working directory
        self.context = Context()
        if kind == 'axioms':
            self.context._clearAxioms()
        elif kind == 'theorems':
            self.context._clearTheorems()
        elif kind == 'common':
            self.context._clearCommonExressions()
        elif KnownTruth.theoremBeingProven is not None:
            kind = '_proof_' + KnownTruth.theoremBeingProven.name
        # clean unreferenced expressions:
        self.context.referenceDisplayedExpressions(kind, clear=True)
        self.context.clean()
        self.kind = None

    @line_magic
    def check_expr(self, line):
        _, hash_id = os.path.split(os.path.abspath('.'))
        context = Context()
        expr_name = line.strip()
        if expr_name == '':
            expr_name = 'expr'
            expr = self.shell.user_ns[expr_name]
        else:
            expr = self.shell.user_ns[expr_name]
            if isinstance(expr, KnownTruth):
                # actually a KnownTruth; convert to an Expression
                expr = expr.expr
        stored_expr = context.getStoredExpr(hash_id)
        if expr != stored_expr:
            raise ProveItMagicFailure(
                "The built '%s' does not match the stored Expression" %
                expr_name)
        if expr._style_id != stored_expr._style_id:
            raise ProveItMagicFailure(
                "The built '%s' style does not match that of the stored Expression"
                % expr_name)
        print "Passed sanity check: built '%s' is the same as the stored Expression." % expr_name

    @line_magic
    def proving(self, line):
        from proveit._core_.proof import Theorem
        self.context = Context(
            '..'
        )  # the context should be up a directory from the _proofs_ directory
        sys.path.append('..')
        theorem_name, presuming_str = str(line.strip()).split(' ', 1)
        if not presuming_str.find('presuming ') == 0:
            print "Format: %begin_proof <theorem_name> presuming [<list of theorems / context-names>]"
            return
        args = presuming_str.split(' ', 1)[-1].strip('[]').split(',')
        theorem_truth = Context('..').getTheorem(theorem_name).provenTruth
        print "Beginning proof of", theorem_name
        presuming = [arg.strip() for arg in args if arg.strip() != '']
        # The list of theorems/context-names may be composed of full-path strings containing '.'s
        # or may be actual theorem variables defined in the IPython sesson.  The latter
        # instances will be converted to strings.
        for k, arg in enumerate(list(presuming)):
            if '.' not in arg:
                knownTruth = self.shell.user_ns[arg]
                if not isinstance(knownTruth, KnownTruth) or not isinstance(
                        knownTruth.proof(), Theorem):
                    raise ValueError(
                        "Presuming list must be composed of full-path theorem/context-name containing '.'s or be KnownTruth variable representing a Theorem"
                    )
                theorem = knownTruth.proof()
                presuming[k] = str(theorem)  # full path of theorem
        begin_proof_result = theorem_truth.beginProof(presuming)
        if isinstance(begin_proof_result, Expression):
            # assign the theorem name to the theorem expression
            # and display this assignment
            theorem_expr = theorem_truth.expr
            self.shell.user_ns[theorem_name] = theorem_expr
            return Assignments([theorem_name], [theorem_expr],
                               beginningProof=True)

    @line_magic
    def qed(self, line):
        proof = KnownTruth.theoremBeingProven.provenTruth._qed()
        proof._repr_html_()  # generate expressions that should be referenced
        self.context.referenceDisplayedExpressions(
            '_proof_' + KnownTruth.theoremBeingProven.name)
        # clean unreferenced expressions:
        self.context.clean()
        return proof

    def _finish(self, kind):
        '''
        Finish 'axioms', 'theorems', or 'common' for the Context
        associated with the current working directory.
        '''
        if self.kind != kind:
            raise ProveItMagicFailure(r"Must run %begin " + kind +
                                      r" before %end " + kind)
        # Add the special statements / expressions to the context
        context = self.context
        if kind == 'axioms':
            context._setAxioms(self.keys, self.definitions)
        elif kind == 'theorems':
            context._setTheorems(self.keys, self.definitions)
        elif kind == 'common':
            context._setCommonExpressions(self.keys, self.definitions)

        # Make a _common_.py, _axioms_.py or _theorems_.py for importing
        # expressions from the certified database.
        context.makeSpecialExprModule(kind)

        # Update the expression notebooks now that these have been registered
        # as special expressions.
        for name, expr in self.definitions.iteritems():
            # remake the expression notebooks using the special expressions of the context
            context.expressionNotebook(expr)

        if len(self.definitions) == 0:
            print "Context %s has no %s" % (context.name, kind if kind !=
                                            'common' else 'common expressions')
        elif kind == 'common':
            print "Common expressions may be imported from autogenerated _%s_.py" % kind
        else:
            print "%s may be imported from autogenerated _%s_.py" % (
                (kind[0].upper() + kind[1:]), kind)
        self.ranFinish = True

    @line_magic
    def dependencies(self, line):
        '''
        Show the dependencies of an axiom or theorem.
        '''
        from .proof import Theorem
        name = line.strip()
        known_truth = self.shell.user_ns[line.strip()]
        proof = known_truth.proof()  # Axiom or Theorem

        def displaySpecialStmt(stmt):
            '''
            Given an Axiom or Theorem, display HTML with a link
            to the definition.
            '''
            expr = stmt.provenTruth.expr
            display(
                HTML(
                    '<dt><a class="ProveItLink" href="%s">%s</a></dt><dd>%s</dd>'
                    % (stmt.getLink(), str(stmt), expr._repr_html_())))

        def stmt_sort(stmt):
            return str(stmt)

        if isinstance(proof, Theorem):
            try:
                required_axioms, required_unproven_theorems = proof.allRequirements(
                )
            except:
                display(HTML('<h3>This theorem has not been proven yet.</h3>'))
                required_axioms, required_unproven_theorems = tuple(), tuple()

            if len(required_unproven_theorems) > 0:
                display(
                    HTML(
                        '<h3>Unproven theorems required (directly or indirectly) to prove %s</h3>'
                        % name))
                display(HTML('<dl>'))
                for required_unproven_theorem in sorted(
                        required_unproven_theorems, key=stmt_sort):
                    displaySpecialStmt(
                        Context.findTheorem(required_unproven_theorem))
                display(HTML('</dl>'))
            if len(required_axioms) > 0:
                display(
                    HTML(
                        '<h3>Axioms required (directly or indirectly) to prove %s</h3>'
                        % name))
                display(HTML('<dl>'))
                for required_axiom in sorted(required_axioms, key=stmt_sort):
                    displaySpecialStmt(Context.findAxiom(required_axiom))
                display(HTML('</dl>'))

        dependents = proof.directDependents()
        if len(dependents) == 0:
            display(HTML('<h3>No theorems depend upon %s</h3>' % name))
        else:
            display(HTML('<h3>Theorems that depend directly on %s</h3>' %
                         name))
            display(HTML('<dl>'))
            for dependent in sorted(proof.directDependents(), key=stmt_sort):
                displaySpecialStmt(Context.findTheorem(dependent))
            display(HTML('</dl>'))
Example #2
0
class ProveItMagicCommands:
    def __init__(self):
        self.reset()

    def reset(self):
        # You must call the parent constructor
        self.kind = None
        self.definitions = dict()  # map name to expression
        self.expr_names = dict()  # map expression to names
        self.keys = []  # the keys of the definitions in the order they appear
        self.lowerCaseNames = set()
        self.context = None
        self.ranFinish = False

    def display_contents(self, context_names):
        '''
        Generates a "table of contents" hierarchy of contexts for the contexts
        listed in the line.
        '''
        def generateContents(contexts):
            if len(contexts) == 0: return ''
            html = '<ul>\n'
            for context in contexts:
                href = relurl(
                    os.path.join(context.getPath(), '_context_.ipynb'))
                html += '<li><a class="ProveItLink" href="%s">%s</a></li>\n' % (
                    href, context.name)
                html += generateContents(list(context.getSubContexts()))
            return html + '</ul>\n'

        display(
            HTML(
                generateContents([
                    Context(context_name) for context_name in context_names
                ])))

    def display_context(self):
        '''
        Create the _common_, _axioms_ and _theorems_ notebooks for the current
        context (if they do not already exist).  Show the table of contents
        for sub-contexts which may be edited.
        '''
        import proveit
        # create an '__init__.py' in the directory if there is not an existing one.
        if not os.path.isfile('__init__.py'):
            open('__init__.py', 'w').close()  # create an empty __init__.py
        context = Context()
        proveit_path = os.path.split(proveit.__file__)[0]
        special_notebook_types = ('common', 'axioms', 'theorems',
                                  'demonstrations')
        special_notebook_texts = ('common expressions', 'axioms', 'theorems',
                                  'demonstrations')
        for special_notebook_type in special_notebook_types:
            notebook_name = '_%s_.ipynb' % special_notebook_type
            if not os.path.isfile(notebook_name):
                # notebook does not yet exist, create it from the template
                template_name = '_%s_template_.ipynb' % special_notebook_type
                with open(os.path.join(proveit_path, '..', template_name),
                          'r') as template:
                    nb = template.read()
                    nb = nb.replace('#CONTEXT#', context.name)
                # write the notebook file
                with open(notebook_name, 'w') as notebook_file:
                    notebook_file.write(nb)

        context_interface = ContextInterface()

        if context_interface.mode == 'static':
            special_notebooks_html = '<table><tr>\n'
            for special_notebook_type, special_notebook_text in zip(
                    special_notebook_types, special_notebook_texts):
                special_notebooks_html += '<th><a class="ProveItLink" href="_%s_.ipynb">%s</a></th>\n' % (
                    special_notebook_type, special_notebook_text)
            special_notebooks_html += '</tr></table>\n'
            if len(context_interface.subContextNames) > 0:
                special_notebooks_html += '<table>\n'
                for name in context_interface.subContextNames:
                    description = context_interface.subContextDescriptions[
                        name]
                    href = context_interface.subContextNotebook(name)
                    special_notebooks_html += '<tr><th><a class="ProveItLink" href="%s">%s</a></th><td>%s</td></tr>\n' % (
                        href, name, description)
                special_notebooks_html += '</table>\n'
            display(HTML(special_notebooks_html))
        else:
            special_notebook_links = []
            full_width_layout = widgets.Layout(width='100%', padding='5px')
            for special_notebook_type, special_notebook_text in zip(
                    special_notebook_types, special_notebook_texts):
                special_notebook_links.append(
                    widgets.HTML(
                        '<a class="ProveItLink" href="_%s_.ipynb">%s</a>' %
                        (special_notebook_type, special_notebook_text),
                        layout=full_width_layout))
            special_notebook_links = widgets.HBox(special_notebook_links)

            sub_contexts_label = widgets.Label(
                'List of sub-contexts:', layout=widgets.Layout(width='100%'))
            #sub_context_widgets = widgets.VBox(sub_context_widgets)
            add_context_widget = widgets.Text(value='',
                                              placeholder='Add sub-context...')

            def addSubContext(sender):
                context_interface.addSubContext(add_context_widget.value)
                add_context_widget.value = ''

            add_context_widget.on_submit(addSubContext)
            #layout = widgets.Layout(display='flex', flex_flow='column-reverse')
            #display(widgets.Button(description='Edit...', disabled=False, button_style='', tooltip='Edit the sub-contents list', layout=layout))
            #layout = widgets.Layout(float='bottom')
            display(
                widgets.VBox([
                    special_notebook_links, sub_contexts_label,
                    context_interface.widget, add_context_widget
                ]))

    def begin_axioms(self):
        # context based upon current working directory
        self.context = Context()
        if len(self.definitions) > 0 or self.kind is not None:
            if self.kind != 'axioms':
                raise ProveItMagicFailure(
                    "Run %%begin_axioms in a separate notebook from %%begin_%s."
                    % self.kind)
            print(
                "WARNING: Re-running %begin_axioms does not reset previously defined axioms."
            )
            print(
                "         It is suggested that you restart and run all cells after editing axioms."
            )
        print("Defining axioms for context '" + self.context.name + "'")
        print("Subsequent end-of-cell assignments will define axioms")
        print("%end_axioms will finalize the definitions")

    def begin_theorems(self):
        # context based upon current working directory
        if len(self.definitions) > 0 or self.kind is not None:
            if self.kind != 'theorems':
                raise ProveItMagicFailure(
                    "Run %%begin_theorems in a separate notebook from %%begin_%s."
                    % self.kind)
            print(
                "WARNING: Re-running %begin_theorems does not reset previously defined theorems."
            )
            print(
                "         It is suggested that you restart and run all cells after editing theorems."
            )
        print("Defining theorems for context '" + self.context.name + "'")
        print("Subsequent end-of-cell assignments will define theorems")
        print("'%end theorems' will finalize the definitions")

    def begin_common(self):
        if len(self.definitions) > 0 or self.kind is not None:
            if self.kind != 'common':
                raise ProveItMagicFailure(
                    "Run '%%begin common' in a separate notebook from %%begin_%s."
                    % self.kind)
            print(
                "WARNING: Re-running '%begin common' does not reset previously defined common expressions."
            )
            print(
                "         It is suggested that you restart and run all cells after editing the expressions."
            )
        print("Defining common sub-expressions for context '" +
              self.context.name + "'")
        print(
            "Subsequent end-of-cell assignments will define common sub-expressions"
        )
        print("%end_common will finalize the definitions")

    def clear(self, kind):
        # context based upon current working directory
        self.context = Context()
        if kind == 'axioms':
            self.context._clearAxioms()
        elif kind == 'theorems':
            self.context._clearTheorems()
        elif kind == 'common':
            self.context._clearCommonExressions()
        elif KnownTruth.theoremBeingProven is not None:
            kind = '_proof_' + KnownTruth.theoremBeingProven.name
        # clean unreferenced expressions:
        self.context.referenceDisplayedExpressions(kind, clear=True)
        self.context.clean()
        self.kind = None

    def check_expr(self, expr_name, expr):
        _, hash_id = os.path.split(os.path.abspath('.'))
        context = Context()
        stored_expr = context.getStoredExpr(hash_id)
        if expr != stored_expr:
            raise ProveItMagicFailure(
                "The built '%s' does not match the stored Expression" %
                expr_name)
        if expr._style_id != stored_expr._style_id:
            raise ProveItMagicFailure(
                "The built '%s' style does not match that of the stored Expression"
                % expr_name)
        print(
            "Passed sanity check: built '%s' is the same as the stored Expression."
            % expr_name)

    def proving(self,
                theorem_name,
                presumptions,
                justRecordPresumingInfo=False):
        self.context = Context(
            '..'
        )  # the context should be up a directory from the _proofs_ directory
        sys.path.append('..')
        proving_theorem = self.context.getTheorem(theorem_name)
        proving_theorem_truth = proving_theorem.provenTruth
        print("Beginning proof of", theorem_name)
        return proving_theorem_truth.beginProof(
            proving_theorem,
            presumptions,
            justRecordPresumingInfo=justRecordPresumingInfo)

    def qed(self):
        proof = KnownTruth.theoremBeingProven.provenTruth._qed()
        proof._repr_html_()  # generate expressions that should be referenced
        self.context.referenceDisplayedExpressions(
            '_proof_' + KnownTruth.theoremBeingProven.name)
        # clean unreferenced expressions:
        self.context.clean()
        return proof

    def end(self, kind):
        '''
        Finish 'axioms', 'theorems', 'common', or other (e.g., 'demonstrations')
        for the Context associated with the current working directory.
        '''
        if self.kind != kind:
            raise ProveItMagicFailure(r"Must run %begin " + kind +
                                      r" before %end " + kind)
        # Add the special statements / expressions to the context
        context = self.context
        if kind == 'axioms':
            context._setAxioms(self.keys, self.definitions)
        elif kind == 'theorems':
            context._setTheorems(self.keys, self.definitions)
        elif kind == 'common':
            # Record the context names of common expressions referenced
            # by this context's common expressions notebook...
            context.recordCommonExprDependencies()
            # and check for illegal mutual references.
            cyclically_referenced_common_expr_context = self.context.cyclicallyReferencedCommonExprContext(
            )
            if cyclically_referenced_common_expr_context is not None:
                raise ProveItMagicFailure(
                    "Not allowed to have cyclically dependent 'common expression' notebooks: %s._common_"
                    % cyclically_referenced_common_expr_context)
            context._setCommonExpressions(self.keys, self.definitions)

        if kind in ('axioms', 'theorems', 'common'):
            # Make a _common_.py, _axioms_.py or _theorems_.py for importing
            # expressions from the certified database.
            context.makeSpecialExprModule(kind)

            # Update the expression notebooks now that these have been registered
            # as special expressions.
            for name, expr in self.definitions.items():
                # remake the expression notebooks using the special expressions of the context
                context.expressionNotebook(expr)

            if len(self.definitions) == 0:
                print("Context %s has no %s" %
                      (context.name,
                       kind if kind != 'common' else 'common expressions'))
            elif kind == 'common':
                print(
                    "Common expressions may be imported from autogenerated _%s_.py"
                    % kind)
            else:
                print("%s may be imported from autogenerated _%s_.py" %
                      ((kind[0].upper() + kind[1:]), kind))
        self.ranFinish = True

        # reference any expressions that were displayed:
        self.context.referenceDisplayedExpressions(kind)
        # clean unreferenced expressions:
        self.context.clean()
        if kind == 'theorems':
            # stash proof notebooks that are not active theorems.
            self.context.stashExtraneousProofNotebooks()
        self.kind = None

    def display_dependencies(self, name, known_truth):
        '''
        Show the dependencies of an axiom or theorem.
        '''
        proof = known_truth.proof()  # Axiom or Theorem

        def displaySpecialStmt(stmt):
            '''
            Given an Axiom or Theorem, display HTML with a link
            to the definition.
            '''
            expr = stmt.provenTruth.expr
            display(
                HTML(
                    '<dt><a class="ProveItLink" href="%s">%s</a></dt><dd>%s</dd>'
                    % (stmt.getLink(), str(stmt), expr._repr_html_())))

        def stmt_sort(stmt):
            return str(stmt)

        if isinstance(proof, Theorem):
            try:
                required_axioms, required_unproven_theorems = proof.allRequirements(
                )
            except:
                display(HTML('<h3>This theorem has not been proven yet.</h3>'))
                required_axioms, required_unproven_theorems = tuple(), tuple()

            if len(required_unproven_theorems) > 0:
                display(
                    HTML(
                        '<h3>Unproven theorems required (directly or indirectly) to prove %s</h3>'
                        % name))
                display(HTML('<dl>'))
                for required_unproven_theorem in sorted(
                        required_unproven_theorems, key=stmt_sort):
                    displaySpecialStmt(
                        Context.findTheorem(required_unproven_theorem))
                display(HTML('</dl>'))
            if len(required_axioms) > 0:
                display(
                    HTML(
                        '<h3>Axioms required (directly or indirectly) to prove %s</h3>'
                        % name))
                display(HTML('<dl>'))
                for required_axiom in sorted(required_axioms, key=stmt_sort):
                    displaySpecialStmt(Context.findAxiom(required_axiom))
                display(HTML('</dl>'))

        dependents = proof.directDependents()
        if len(dependents) == 0:
            display(HTML('<h3>No theorems depend upon %s</h3>' % name))
        else:
            display(HTML('<h3>Theorems that depend directly on %s</h3>' %
                         name))
            display(HTML('<dl>'))
            for dependent in sorted(proof.directDependents(), key=stmt_sort):
                displaySpecialStmt(Context.findTheorem(dependent))
            display(HTML('</dl>'))