From f02660688c90560db7922d6e153fccc0af08c833 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 15 Apr 2025 20:18:49 -0500
Subject: [PATCH 001/159] Establish graphs theory package (and union sub-theory
 package)

Establish a graphs theory package, along with a union sub-theory package. No content yet.
---
 packages/proveit/_sub_theories_.txt           |  1 +
 packages/proveit/graphs/__init__.py           |  9 +++
 .../proveit/graphs/_brief_description_.txt    |  1 +
 packages/proveit/graphs/_sub_theories_.txt    |  1 +
 .../proveit/graphs/_theory_nbs_/__init__.py   |  0
 .../proveit/graphs/_theory_nbs_/axioms.ipynb  | 59 +++++++++++++++++++
 .../proveit/graphs/_theory_nbs_/common.ipynb  | 59 +++++++++++++++++++
 .../graphs/_theory_nbs_/demonstrations.ipynb  | 47 +++++++++++++++
 .../graphs/_theory_nbs_/theorems.ipynb        | 59 +++++++++++++++++++
 .../proveit/graphs/_theory_nbs_/theory.ipynb  | 33 +++++++++++
 packages/proveit/graphs/union/__init__.py     |  9 +++
 .../graphs/union/_brief_description_.txt      |  1 +
 .../proveit/graphs/union/_sub_theories_.txt   |  0
 .../graphs/union/_theory_nbs_/__init__.py     |  0
 .../graphs/union/_theory_nbs_/axioms.ipynb    | 59 +++++++++++++++++++
 .../graphs/union/_theory_nbs_/common.ipynb    | 59 +++++++++++++++++++
 .../union/_theory_nbs_/demonstrations.ipynb   | 47 +++++++++++++++
 .../graphs/union/_theory_nbs_/theorems.ipynb  | 59 +++++++++++++++++++
 .../graphs/union/_theory_nbs_/theory.ipynb    | 33 +++++++++++
 19 files changed, 536 insertions(+)
 create mode 100644 packages/proveit/graphs/__init__.py
 create mode 100644 packages/proveit/graphs/_brief_description_.txt
 create mode 100644 packages/proveit/graphs/_sub_theories_.txt
 create mode 100644 packages/proveit/graphs/_theory_nbs_/__init__.py
 create mode 100644 packages/proveit/graphs/_theory_nbs_/axioms.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/common.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/theorems.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/theory.ipynb
 create mode 100644 packages/proveit/graphs/union/__init__.py
 create mode 100644 packages/proveit/graphs/union/_brief_description_.txt
 create mode 100644 packages/proveit/graphs/union/_sub_theories_.txt
 create mode 100644 packages/proveit/graphs/union/_theory_nbs_/__init__.py
 create mode 100644 packages/proveit/graphs/union/_theory_nbs_/axioms.ipynb
 create mode 100644 packages/proveit/graphs/union/_theory_nbs_/common.ipynb
 create mode 100644 packages/proveit/graphs/union/_theory_nbs_/demonstrations.ipynb
 create mode 100644 packages/proveit/graphs/union/_theory_nbs_/theorems.ipynb
 create mode 100644 packages/proveit/graphs/union/_theory_nbs_/theory.ipynb

diff --git a/packages/proveit/_sub_theories_.txt b/packages/proveit/_sub_theories_.txt
index 37abe2ca19c6..29f2a16b4cbe 100644
--- a/packages/proveit/_sub_theories_.txt
+++ b/packages/proveit/_sub_theories_.txt
@@ -4,5 +4,6 @@ numbers
 trigonometry
 abstract_algebra
 linear_algebra
+graphs
 statistics
 physics
diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
new file mode 100644
index 000000000000..dba3de849ed8
--- /dev/null
+++ b/packages/proveit/graphs/__init__.py
@@ -0,0 +1,9 @@
+
+
+# KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
+#  Make additions above, or add to sys.modules[__name__].__dict__ below.
+# This allows us to import common expression, axioms, and theorems of
+# the theory package directly from the package.
+import sys
+from proveit._core_.theory import TheoryPackage
+sys.modules[__name__] = TheoryPackage(__name__, __file__, locals())
diff --git a/packages/proveit/graphs/_brief_description_.txt b/packages/proveit/graphs/_brief_description_.txt
new file mode 100644
index 000000000000..3209d67f8161
--- /dev/null
+++ b/packages/proveit/graphs/_brief_description_.txt
@@ -0,0 +1 @@
+basic graph theory concepts
diff --git a/packages/proveit/graphs/_sub_theories_.txt b/packages/proveit/graphs/_sub_theories_.txt
new file mode 100644
index 000000000000..abdc440350b8
--- /dev/null
+++ b/packages/proveit/graphs/_sub_theories_.txt
@@ -0,0 +1 @@
+union
diff --git a/packages/proveit/graphs/_theory_nbs_/__init__.py b/packages/proveit/graphs/_theory_nbs_/__init__.py
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
new file mode 100644
index 000000000000..cabae40de7a2
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Axioms for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the axioms of a theory:\n",
+    "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin axioms"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end axioms"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/common.ipynb b/packages/proveit/graphs/_theory_nbs_/common.ipynb
new file mode 100644
index 000000000000..60c5fd124491
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/common.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Common expressions for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the common expressions of a theory:\n",
+    "%common_expressions_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin common"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end common"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
new file mode 100644
index 000000000000..4c113ca42ef3
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Demonstrations for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%begin demonstrations"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end demonstrations"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
new file mode 100644
index 000000000000..21d1714cea56
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theorems (or conjectures) for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the theorems of a theory:\n",
+    "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin theorems"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end theorems"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/theory.ipynb b/packages/proveit/graphs/_theory_nbs_/theory.ipynb
new file mode 100644
index 000000000000..c73a8d0d9dc3
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/theory.ipynb
@@ -0,0 +1,33 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theory of <a class=\"ProveItLink\" href=\"../../_theory_nbs_/theory.ipynb\">proveit</a>.graphs\n",
+    "========\n",
+    "\n",
+    "Provide description here."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%theory # toggles between interactive and static modes"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/union/__init__.py b/packages/proveit/graphs/union/__init__.py
new file mode 100644
index 000000000000..dba3de849ed8
--- /dev/null
+++ b/packages/proveit/graphs/union/__init__.py
@@ -0,0 +1,9 @@
+
+
+# KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
+#  Make additions above, or add to sys.modules[__name__].__dict__ below.
+# This allows us to import common expression, axioms, and theorems of
+# the theory package directly from the package.
+import sys
+from proveit._core_.theory import TheoryPackage
+sys.modules[__name__] = TheoryPackage(__name__, __file__, locals())
diff --git a/packages/proveit/graphs/union/_brief_description_.txt b/packages/proveit/graphs/union/_brief_description_.txt
new file mode 100644
index 000000000000..1939b57f4269
--- /dev/null
+++ b/packages/proveit/graphs/union/_brief_description_.txt
@@ -0,0 +1 @@
+basic concepts involving the union of graphs
diff --git a/packages/proveit/graphs/union/_sub_theories_.txt b/packages/proveit/graphs/union/_sub_theories_.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/union/_theory_nbs_/__init__.py b/packages/proveit/graphs/union/_theory_nbs_/__init__.py
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/union/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/union/_theory_nbs_/axioms.ipynb
new file mode 100644
index 000000000000..5e90b1a3a736
--- /dev/null
+++ b/packages/proveit/graphs/union/_theory_nbs_/axioms.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Axioms for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.union</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the axioms of a theory:\n",
+    "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin axioms"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end axioms"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/union/_theory_nbs_/common.ipynb b/packages/proveit/graphs/union/_theory_nbs_/common.ipynb
new file mode 100644
index 000000000000..78cdd0accb17
--- /dev/null
+++ b/packages/proveit/graphs/union/_theory_nbs_/common.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Common expressions for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.union</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the common expressions of a theory:\n",
+    "%common_expressions_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin common"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end common"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/union/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/union/_theory_nbs_/demonstrations.ipynb
new file mode 100644
index 000000000000..cea403a37716
--- /dev/null
+++ b/packages/proveit/graphs/union/_theory_nbs_/demonstrations.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Demonstrations for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.union</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%begin demonstrations"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end demonstrations"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/union/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/union/_theory_nbs_/theorems.ipynb
new file mode 100644
index 000000000000..9e96036394e9
--- /dev/null
+++ b/packages/proveit/graphs/union/_theory_nbs_/theorems.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theorems (or conjectures) for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.union</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the theorems of a theory:\n",
+    "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin theorems"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end theorems"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/union/_theory_nbs_/theory.ipynb b/packages/proveit/graphs/union/_theory_nbs_/theory.ipynb
new file mode 100644
index 000000000000..906066dfefff
--- /dev/null
+++ b/packages/proveit/graphs/union/_theory_nbs_/theory.ipynb
@@ -0,0 +1,33 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theory of <a class=\"ProveItLink\" href=\"../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../_theory_nbs_/theory.ipynb\">graphs</a>.union\n",
+    "========\n",
+    "\n",
+    "Provide description here."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%theory # toggles between interactive and static modes"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}

From dd1944b699759689cfca4800bf7909dac368b1eb Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 16 Apr 2025 19:48:34 -0500
Subject: [PATCH 002/159] Establish graphs.py with Graphs and Graph(V,E)
 classes

Establish proveit/graphs/graphs.py with initial classes (Graphs, GraphsMembership, Graph(V,E), Path(V, E), and EndPoints(P)) and update the graphs/__init__.py. Path and Endpoints classes will likely eventually move to their own sub-theory packages.
---
 packages/proveit/graphs/__init__.py |   5 +-
 packages/proveit/graphs/graph.py    | 115 ++++++++++++++++++++++++++++
 2 files changed, 119 insertions(+), 1 deletion(-)
 create mode 100644 packages/proveit/graphs/graph.py

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index dba3de849ed8..dfb3f1896134 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -1,4 +1,7 @@
-
+from .graph import EndPoints, Graph, Graphs, Path
+from .membership import (
+      GraphMembership, GraphNonmembership, InGraph, NotInGraph)
+from .union import GraphUnion
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
 #  Make additions above, or add to sys.modules[__name__].__dict__ below.
diff --git a/packages/proveit/graphs/graph.py b/packages/proveit/graphs/graph.py
new file mode 100644
index 000000000000..931dca2691c4
--- /dev/null
+++ b/packages/proveit/graphs/graph.py
@@ -0,0 +1,115 @@
+from proveit import Function, Literal
+from proveit import E, V
+from proveit.logic import ClassMembership
+
+class Graphs(Literal):
+    '''
+    Graphs represents the (mathematical) class of graphs, to which
+    any specific graph G = (V, E) of vertices and edges belongs.
+    This class might not be necessary, but is modeled on the
+    HilbertSpacesLiteral class in the linear_algebra/inner_products
+    theory package.
+    '''
+
+    # the literal string for representing the class of Graphs
+    def __init__(self, *, styles=None):
+        Literal.__init__(self, string_format='Graphs', 
+                         latex_format=r'\textrm{Graphs}',
+                         styles=styles)
+
+    def membership_object(self, element):
+        return GraphsMembership(element, self)
+
+    @property
+    def is_proper_class(self):
+        '''
+        Graphs consitute a proper class (i.e. instead of a set).
+        This indicates that InClass() should be used instead of
+        InSet() when this is a domain.
+        '''
+        return True
+
+class GraphsMembership(ClassMembership):
+
+    def __init__(self, element, domain):
+        from . import Graphs
+        ClassMembership.__init__(self, element, domain)
+        if domain != Graphs:
+            raise TypeError("domain expected to be Graphs, not %s"
+                            %domain.__class__)
+
+class Graph(Function):
+    '''
+    Graph(V, E) represents a graph with vertex set V and edge set E.
+    The vertex set V is conceptualized as a set of vertices such as
+    {x_1, ..., x_n} but might appear or be interpreted as a set of
+    geometric points such as {(x1, y1), (x2, y2), ..., (xn, yn)}.
+    The edge set E is conceptualized as a set of pairs of vertices,
+    such as {x1 x2, x2 x3, ..., xn x1}, which might eventually take
+    the form of a set of 2-element sets or a set of ordered pairs.
+    '''
+
+    # the literal operator of the Graph operation
+    _operator_ = Literal(string_format='Graph',
+                         latex_format=r'\textrm{Graph}',
+                         theory=__file__)
+
+    def __init__(self, V, E, *, styles=None):
+        '''
+        Create a graph G(V,E) with vertex set V and edge set E.
+        '''
+        self.vertex_set = V
+        self.edge_set   = E
+        Function.__init__(
+                self, Graph._operator_, (V, E), styles=styles)
+
+
+class Path(Graph):
+    '''
+    A Path is a non-empty graph P = (V,E) with vertex set V and edge
+    set E such that:
+
+        V = {x0, x1, ..., xk}, E = {x0x1, x1x2, ..., x_{k-1}x_{k}},
+
+    where the x_{i} are all distinct. The vertices x0 and xk are said
+    to be linked by the path P and are called its endvertices, or
+    endpoints, or simply its ends. The vertices x1, ..., x_{k-1} are
+    the inner vertices of P. The number of edges in the path P,
+    denoted ||P||, is its length (in this example, ||P|| = k).
+    '''
+
+    # the literal operator of the Path operator
+    _operator_ = Literal(string_format='Path',
+                         latex_format=r'\text{Path}',
+                         theory=__file__)
+
+    def __init__(self, V, E, *, styles=None):
+        '''
+        Create or represent a Path, Path(V,E), with vertex set V
+        and edge set E.
+        '''
+        self.vertex_set = V
+        self.edge_set   = E
+        Function.__init__(
+                self, Path._operator_, (V, E), styles=styles)
+
+
+class EndPoints(Function):
+    '''
+    EndPoints(P) denotes the set of two endpoints of a Path P = (V, E),
+    where Path P has vertex set V and edge set E. EndPoints(P) will be
+    a subset of the Path P's vertex set V.
+    EndPoints(P) will not "know" the original path P whence it came.
+    '''
+
+    # the literal operator of the EndPoints operator
+    _operator_ = Literal(
+            string_format='EndPts', latex_format=r'\text{EndPts}',
+            theory=__file__)
+
+    def __init__(self, P, *, styles=None):
+        '''
+        Create the endpoints set EndPts(P) for Path P.
+        '''
+        Function.__init__(
+                self, EndPoints._operator_, P, styles=styles)

From 60f4eb89894c822e21f2904caa2df71246417af0 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 17 Apr 2025 09:25:12 -0500
Subject: [PATCH 003/159] Establish graphs/membership sub-theory package

Establish graphs/membership sub-theory package with initial InGraph, NotInGraph, GraphMembership, and GraphNonmembership classes, along with some preliminary axioms and theorems (modeled on the sets/unification package) and some basic testing in the membership demonstrations ipynb. Some basic methods await the establishment and development of the subgraph concept.
---
 packages/proveit/graphs/_sub_theories_.txt    |   1 +
 .../proveit/graphs/_theory_nbs_/common.ipynb  |  28 ++-
 .../proveit/graphs/membership/__init__.py     |  10 +
 .../graphs/membership/_brief_description_.txt |   1 +
 .../graphs/membership/_sub_theories_.txt      |   0
 .../membership/_theory_nbs_/__init__.py       |   0
 .../membership/_theory_nbs_/axioms.ipynb      |  84 ++++++++
 .../membership/_theory_nbs_/common.ipynb      |  59 ++++++
 .../_theory_nbs_/demonstrations.ipynb         | 143 +++++++++++++
 .../double_negated_membership/thm_proof.ipynb |  47 ++++
 .../proofs/fold_not_in_graph/thm_proof.ipynb  |  47 ++++
 .../thm_proof.ipynb                           |  47 ++++
 .../not_in_graph_is_bool/thm_proof.ipynb      |  47 ++++
 .../unfold_not_in_graph/thm_proof.ipynb       |  47 ++++
 .../membership/_theory_nbs_/theorems.ipynb    |  99 +++++++++
 .../membership/_theory_nbs_/theory.ipynb      |  33 +++
 .../proveit/graphs/membership/in_graph.py     | 180 ++++++++++++++++
 .../proveit/graphs/membership/not_in_graph.py | 200 ++++++++++++++++++
 18 files changed, 1071 insertions(+), 2 deletions(-)
 create mode 100644 packages/proveit/graphs/membership/__init__.py
 create mode 100644 packages/proveit/graphs/membership/_brief_description_.txt
 create mode 100644 packages/proveit/graphs/membership/_sub_theories_.txt
 create mode 100644 packages/proveit/graphs/membership/_theory_nbs_/__init__.py
 create mode 100644 packages/proveit/graphs/membership/_theory_nbs_/axioms.ipynb
 create mode 100644 packages/proveit/graphs/membership/_theory_nbs_/common.ipynb
 create mode 100644 packages/proveit/graphs/membership/_theory_nbs_/demonstrations.ipynb
 create mode 100644 packages/proveit/graphs/membership/_theory_nbs_/proofs/double_negated_membership/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/membership/_theory_nbs_/proofs/fold_not_in_graph/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/membership/_theory_nbs_/proofs/membership_denied_via_contradiction/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/membership/_theory_nbs_/proofs/not_in_graph_is_bool/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/membership/_theory_nbs_/proofs/unfold_not_in_graph/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/membership/_theory_nbs_/theorems.ipynb
 create mode 100644 packages/proveit/graphs/membership/_theory_nbs_/theory.ipynb
 create mode 100644 packages/proveit/graphs/membership/in_graph.py
 create mode 100644 packages/proveit/graphs/membership/not_in_graph.py

diff --git a/packages/proveit/graphs/_sub_theories_.txt b/packages/proveit/graphs/_sub_theories_.txt
index abdc440350b8..82d9f7cf2873 100644
--- a/packages/proveit/graphs/_sub_theories_.txt
+++ b/packages/proveit/graphs/_sub_theories_.txt
@@ -1 +1,2 @@
 union
+membership
diff --git a/packages/proveit/graphs/_theory_nbs_/common.ipynb b/packages/proveit/graphs/_theory_nbs_/common.ipynb
index 60c5fd124491..7741dcafa169 100644
--- a/packages/proveit/graphs/_theory_nbs_/common.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/common.ipynb
@@ -18,7 +18,11 @@
     "# Prepare this notebook for defining the common expressions of a theory:\n",
     "%common_expressions_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "# from ... import ..."
+    "from proveit import i, n, x, G, ExprRange, IndexedVar, var_range\n",
+    "from proveit.logic import And, Or\n",
+    "from proveit.logic.sets import InSet\n",
+    "from proveit.numbers import one\n",
+    "from proveit.graphs import InGraph, NotInGraph"
    ]
   },
   {
@@ -35,7 +39,27 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "G_1_to_n = var_range(G, one, n)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "x_in_any_G_1_to_n = Or(ExprRange(i, InGraph(x, IndexedVar(G, i)), one, n))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "x_not_in_any_G_1_to_n = And(ExprRange(i, NotInGraph(x, IndexedVar(G, i)), one, n))"
+   ]
   },
   {
    "cell_type": "code",
diff --git a/packages/proveit/graphs/membership/__init__.py b/packages/proveit/graphs/membership/__init__.py
new file mode 100644
index 000000000000..2beead7e73da
--- /dev/null
+++ b/packages/proveit/graphs/membership/__init__.py
@@ -0,0 +1,10 @@
+from .in_graph import InGraph, GraphMembership
+from .not_in_graph import NotInGraph, GraphNonmembership
+
+# KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
+#  Make additions above, or add to sys.modules[__name__].__dict__ below.
+# This allows us to import common expression, axioms, and theorems of
+# the theory package directly from the package.
+import sys
+from proveit._core_.theory import TheoryPackage
+sys.modules[__name__] = TheoryPackage(__name__, __file__, locals())
diff --git a/packages/proveit/graphs/membership/_brief_description_.txt b/packages/proveit/graphs/membership/_brief_description_.txt
new file mode 100644
index 000000000000..23d32e8e7bb9
--- /dev/null
+++ b/packages/proveit/graphs/membership/_brief_description_.txt
@@ -0,0 +1 @@
+basic concepts involving membership in a graph
diff --git a/packages/proveit/graphs/membership/_sub_theories_.txt b/packages/proveit/graphs/membership/_sub_theories_.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/membership/_theory_nbs_/__init__.py b/packages/proveit/graphs/membership/_theory_nbs_/__init__.py
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/membership/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/membership/_theory_nbs_/axioms.ipynb
new file mode 100644
index 000000000000..49ce6ead356a
--- /dev/null
+++ b/packages/proveit/graphs/membership/_theory_nbs_/axioms.ipynb
@@ -0,0 +1,84 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Axioms for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.membership</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the axioms of a theory:\n",
+    "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "from proveit import x, E, G, V\n",
+    "from proveit.logic import Equals, Forall, InSet, Not, Or\n",
+    "from proveit.graphs import InGraph, NotInGraph"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin axioms"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "An element of a graph is either a point or an edge (but not both)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# this should eventually use an exclusive or (XOR) instead of simple disjunction (OR)\n",
+    "in_graph_def = (\n",
+    "    Forall((E, V),\n",
+    "    Forall((x, G),\n",
+    "           Equals(InGraph(x, G), Or(InSet(x, V), InSet(x, E))))\n",
+    "    ))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_in_graph_def = Forall((x, G), Equals(NotInGraph(x, G), Not(InGraph(x, G))))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end axioms"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/membership/_theory_nbs_/common.ipynb b/packages/proveit/graphs/membership/_theory_nbs_/common.ipynb
new file mode 100644
index 000000000000..95a47ce628bc
--- /dev/null
+++ b/packages/proveit/graphs/membership/_theory_nbs_/common.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Common expressions for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.membership</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the common expressions of a theory:\n",
+    "%common_expressions_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin common"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end common"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/membership/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/membership/_theory_nbs_/demonstrations.ipynb
new file mode 100644
index 000000000000..9e57290e559b
--- /dev/null
+++ b/packages/proveit/graphs/membership/_theory_nbs_/demonstrations.ipynb
@@ -0,0 +1,143 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Demonstrations for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.membership</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "from proveit import x, G\n",
+    "from proveit.logic import in_bool, Not\n",
+    "from proveit.graphs import InGraph, NotInGraph\n",
+    "\n",
+    "%begin demonstrations"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Graph Membership & Non-Membership: $x \\in G$, $x \\notin G$"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Miscellaneous Testing\n",
+    "Testing various classes and methods related to graph membership. Some of this material could eventually be integrated into the `_demonstrations_` page and/or deleted as development continues."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Basic Constructions"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InGraph(x, G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInGraph(x, G)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Basic Testing of `InGraph()` methods"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InGraph(x, G).negated()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Basic Testing of `NotInGraph()` methods"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInGraph(x, G).deduce_in_bool(assumptions=[in_bool(InGraph(x, G))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInGraph(x, G).unfold(assumptions=[NotInGraph(x, G)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInGraph(x, G).conclude_as_folded(assumptions=[Not(InGraph(x, G))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInGraph(x, G).conclude_negation(assumptions=[InGraph(x, G)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end demonstrations"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/membership/_theory_nbs_/proofs/double_negated_membership/thm_proof.ipynb b/packages/proveit/graphs/membership/_theory_nbs_/proofs/double_negated_membership/thm_proof.ipynb
new file mode 100644
index 000000000000..e280b62c0b14
--- /dev/null
+++ b/packages/proveit/graphs/membership/_theory_nbs_/proofs/double_negated_membership/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">membership</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#double_negated_membership\">double_negated_membership</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving double_negated_membership"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/membership/_theory_nbs_/proofs/fold_not_in_graph/thm_proof.ipynb b/packages/proveit/graphs/membership/_theory_nbs_/proofs/fold_not_in_graph/thm_proof.ipynb
new file mode 100644
index 000000000000..c0e9ea2b1dc5
--- /dev/null
+++ b/packages/proveit/graphs/membership/_theory_nbs_/proofs/fold_not_in_graph/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">membership</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#fold_not_in_graph\">fold_not_in_graph</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving fold_not_in_graph"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/membership/_theory_nbs_/proofs/membership_denied_via_contradiction/thm_proof.ipynb b/packages/proveit/graphs/membership/_theory_nbs_/proofs/membership_denied_via_contradiction/thm_proof.ipynb
new file mode 100644
index 000000000000..d1b31da1735f
--- /dev/null
+++ b/packages/proveit/graphs/membership/_theory_nbs_/proofs/membership_denied_via_contradiction/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">membership</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_denied_via_contradiction\">membership_denied_via_contradiction</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving membership_denied_via_contradiction"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/membership/_theory_nbs_/proofs/not_in_graph_is_bool/thm_proof.ipynb b/packages/proveit/graphs/membership/_theory_nbs_/proofs/not_in_graph_is_bool/thm_proof.ipynb
new file mode 100644
index 000000000000..203fa7780075
--- /dev/null
+++ b/packages/proveit/graphs/membership/_theory_nbs_/proofs/not_in_graph_is_bool/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">membership</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#not_in_graph_is_bool\">not_in_graph_is_bool</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving not_in_graph_is_bool"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/membership/_theory_nbs_/proofs/unfold_not_in_graph/thm_proof.ipynb b/packages/proveit/graphs/membership/_theory_nbs_/proofs/unfold_not_in_graph/thm_proof.ipynb
new file mode 100644
index 000000000000..db63b80c9b2e
--- /dev/null
+++ b/packages/proveit/graphs/membership/_theory_nbs_/proofs/unfold_not_in_graph/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">membership</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#unfold_not_in_graph\">unfold_not_in_graph</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving unfold_not_in_graph"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/membership/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/membership/_theory_nbs_/theorems.ipynb
new file mode 100644
index 000000000000..d6ab32b30716
--- /dev/null
+++ b/packages/proveit/graphs/membership/_theory_nbs_/theorems.ipynb
@@ -0,0 +1,99 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theorems (or conjectures) for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.membership</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the theorems of a theory:\n",
+    "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "from proveit import x, G\n",
+    "from proveit.logic import FALSE, Forall, Implies, in_bool, Not\n",
+    "from proveit.graphs import InGraph, NotInGraph"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin theorems"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_in_graph_is_bool = Forall((x, G), in_bool(NotInGraph(x, G)), conditions=[in_bool(InGraph(x, G))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "unfold_not_in_graph = Forall((x, G), Not(InGraph(x, G)), conditions=[NotInGraph(x, G)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "fold_not_in_graph = Forall((x, G), NotInGraph(x, G), conditions=[Not(InGraph(x, G))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "double_negated_membership = Forall((x, G), Not(NotInGraph(x, G)), conditions=[InGraph(x, G)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_denied_via_contradiction = Forall((x, G), Implies(Implies(InGraph(x, G), FALSE), NotInGraph(x, G)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end theorems"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/membership/_theory_nbs_/theory.ipynb b/packages/proveit/graphs/membership/_theory_nbs_/theory.ipynb
new file mode 100644
index 000000000000..0b900892b1db
--- /dev/null
+++ b/packages/proveit/graphs/membership/_theory_nbs_/theory.ipynb
@@ -0,0 +1,33 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theory of <a class=\"ProveItLink\" href=\"../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../_theory_nbs_/theory.ipynb\">graphs</a>.membership\n",
+    "========\n",
+    "\n",
+    "Provide description here."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%theory # toggles between interactive and static modes"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/membership/in_graph.py b/packages/proveit/graphs/membership/in_graph.py
new file mode 100644
index 000000000000..92cf8ccfd125
--- /dev/null
+++ b/packages/proveit/graphs/membership/in_graph.py
@@ -0,0 +1,180 @@
+from proveit import (Literal, defaults, USE_DEFAULTS, ProofFailure,
+                     UnusableProof, single_or_composite_expression,
+                     prover, equality_prover, relation_prover)
+from proveit.relation import Relation
+from proveit.logic.classes import InClass, ClassMembership
+
+# UNDER CONSTRUCTION, ADAPTING FROM InSet beginning 4/16/2025
+
+class InGraph(InClass):
+    '''
+    Graph membership (applicable to vertices and edges) is a
+    special case of class membership, so we'll derive from InClass
+    for possible code re-use. The operators are distinct (though
+    the formatting is the same).
+    '''
+
+    # operator of the InGraph operation
+    _operator_ = Literal(string_format='in',
+                         latex_format=r'\in',
+                         theory=__file__)
+
+    # map (element, domain) pairs to corresponding InGraph expressions
+    ingraph_expressions = dict()
+
+    def __init__(self, element, domain, *, styles=None):
+        element = single_or_composite_expression(element)
+        domain = single_or_composite_expression(domain)
+        InGraph.ingraph_expressions[(element, domain)] = self
+        InClass.__init__(self, element, domain, operator=InGraph._operator_,
+                         styles=styles)
+
+    def negated(self):
+        '''
+        Return the negated membership expression (not a judgment):
+        element not in (graph) domain.
+        '''
+        from .not_in_graph import NotInGraph
+        return NotInGraph(self.element, self.domain)
+
+    # A placeholder from the InSet class; delaying for now
+    # come back to this after subgraphs are defined
+    # def _readily_provable(self, check_directly_known_elem_equality=True):
+    #     '''
+    #     This membership is readily provable if the membership
+    #     object indicates that it is readily provable or there is a 
+    #     known as-strong membership (with known equal elements and the
+    #     domain a subset of the desired domain).
+    #     '''
+    #     if InClass._readily_provable(
+    #             self, check_directly_known_elem_equality=(
+    #                     check_directly_known_elem_equality)):
+    #         return True
+    #     if self.as_strong_known_membership() is not None:
+    #         return True
+    #     return False
+
+    # A placeholder from the InSet class; delaying for now
+    # @prover
+    # def conclude(self, **defaults_config):
+    #     '''
+    #     Attempt to conclude that the element is in the domain.  First
+    #     see if there is an equivalent known membership to use
+    #     (same domain).  If not, see if there is a membership object
+    #     that is readily provable and conclude via that object if so.
+    #     Then check for a membership that is at least as strong with
+    #     a possibly different domain to use.  Finally, defer to
+    #     InClass.conclude which defers to InRelation.conclude and
+    #     attempts simplifications.
+    #     '''
+    #     # See if the element, or something known to be equal to
+    #     # the element, is known to be a member of the domain or a subset
+    #     # of the domain.
+    #     as_strong_membership = self.as_strong_known_membership(
+    #             include_canonical_forms=False)
+    #     if as_strong_membership is not None:
+    #         if as_strong_membership.domain == self.domain:
+    #             try:
+    #                 # Use an equivalent known membership.
+    #                 return self.conclude_from_as_strong_membership(
+    #                         as_strong_membership)
+    #             except UnusableProof:
+    #                 pass
+        
+    #     if hasattr(self, 'membership_object') and (
+    #             self.membership_object._readily_provable()):
+    #         # Don't bother with a fancy, indirect approach if
+    #         # we can readily conclude membership via the membership
+    #         # object.
+    #         return self.membership_object.conclude()
+
+    #     as_strong_membership = self.as_strong_known_membership(
+    #             include_canonical_forms=True)
+    #     if as_strong_membership is not None:
+    #         # Use a known membership that is at least as strong.
+    #         return self.conclude_from_as_strong_membership(
+    #                 as_strong_membership)
+
+    #     return InClass.conclude(self)
+    
+    # A placeholder from the InSet class; delaying for now
+    # come back to this after subgraphs are defined
+    # @prover
+    # def conclude_from_as_strong_membership(self, as_strong_membership,
+    #                                        **defaults_config):
+    #     '''
+    #     Conclude from a membership with an equal element and a domain
+    #     that is a subset of the desired domain.
+    #     '''
+    #     from proveit.logic import Equals, SubsetEq
+    #     elem_sub = as_strong_membership.element
+    #     if as_strong_membership.domain == self.domain:
+    #         elem_sub_in_domain = as_strong_membership
+    #     else:
+    #         eq_rel = Equals(as_strong_membership.domain, self.domain)
+    #         if eq_rel.readily_provable():
+    #             # domains are equal -- just substitute the domain.
+    #             elem_sub_in_domain = eq_rel.sub_right_side_into(
+    #                     as_strong_membership.inner_expr().domain)
+    #         else:
+    #             # S is a superset of R, so now we can prove x in S.
+    #             sub_rel = SubsetEq(as_strong_membership.domain, self.domain)
+    #             try:
+    #                 sub_rel.prove()
+    #             except ProofFailure:
+    #                 # May have been blocked to avoid infinite
+    #                 # recursion.
+    #                 return InClass.conclude(self)
+    #             elem_sub_in_domain = sub_rel.derive_superset_membership(
+    #                     elem_sub)
+    #     if elem_sub == self.element:
+    #         return elem_sub_in_domain # done
+    #     # Just need to sub in the element for _elem_sub.
+    #     return elem_sub_in_domain.inner_expr().element.substitute(
+    #             self.element)        
+
+    # A placeholder from the InSet class; delaying for now
+    # come back to this after subgraphs are defined
+    # def as_strong_known_membership(self, include_canonical_forms=True):
+    #     '''
+    #     If there is a known membership that is as strong as this one,
+    #     where the element is known to be equal this one's element
+    #     and the domain is a subset of this one's domain, return this
+    #     as-strong known membership.  Otherwise, return None.
+    #     '''
+    #     from proveit.logic import Equals, SubsetEq
+    #     known_memberships = list(
+    #             InClass.yield_known_memberships(
+    #                     self.element, 
+    #                     include_canonical_forms=include_canonical_forms))
+    #     # First see of there is a known membership with the same domain.
+    #     for known_membership in known_memberships:
+    #         if known_membership.domain == self.domain:
+    #             # this is the best to use; we are done
+    #             return known_membership
+    #     # Next see of there is a known membership with a domain
+    #     # readily provable to be equal to this domain.
+    #     for known_membership in known_memberships:
+    #         eq_rel = Equals(known_membership.domain, self.domain)
+    #         if eq_rel.readily_provable():
+    #             return known_membership
+    #     # Finaly see of there is a known membership with a domain
+    #     # readily provable to be a subset of to this domain.
+    #     for known_membership in known_memberships:
+    #         sub_rel = SubsetEq(known_membership.domain, self.domain)
+    #         if sub_rel.readily_provable():
+    #             return known_membership
+    #     return None # No match found.
+
+class GraphMembership(ClassMembership):
+    def __init__(self, element, domain):
+        '''
+        Base class for any 'membership object' returned by a domain's
+        'membership_object' method.
+        '''
+        # The expression represented by this Membership.
+        if (element, domain) in InGraph.ingraph_expressions:
+            expr = InGraph.ingraph_expressions[(element, domain)]
+        else:
+            expr = InGraph(element, domain)
+        ClassMembership.__init__(self, element, domain, expr=expr)
diff --git a/packages/proveit/graphs/membership/not_in_graph.py b/packages/proveit/graphs/membership/not_in_graph.py
new file mode 100644
index 000000000000..b3e72419150e
--- /dev/null
+++ b/packages/proveit/graphs/membership/not_in_graph.py
@@ -0,0 +1,200 @@
+from proveit import (Literal, defaults, USE_DEFAULTS, equality_prover, 
+                     ProofFailure, prover, relation_prover)
+from proveit import x, G
+from proveit.relation import Relation
+from proveit.logic.classes import NotInClass, ClassNonmembership
+
+# UNDER CONSTRUCTION, ADAPTING FROM InSet beginning 4/16/2025
+
+
+class NotInGraph(NotInClass):
+    '''
+    Graph non-membership is a special case of class nonmembership,
+    so we derive from NotInClass for code re-use.  The operators are
+    distinct (though the formatting is the same).
+    '''
+    # operator of the NotInSet operation
+    _operator_ = Literal(string_format='not-in', latex_format=r'\notin',
+                         theory=__file__)
+
+    # map (element, domain) pairs to corresponding NotInGraph exprs
+    notingraph_expressions = dict()
+
+    def __init__(self, element, domain, *, styles=None):
+        NotInGraph.notingraph_expressions[(element, domain)] = self
+        NotInClass.__init__(
+                self, element, domain, operator=NotInGraph._operator_,
+                styles=styles)
+
+    @relation_prover
+    def deduce_in_bool(self, **defaults_config):
+        '''
+        Deduce and return that this 'not in' statement is in the set
+        of BOOLEANS. For example, NotInGraph(x, G(V,E)).deduce_in_bool()
+        returns:
+                   |- NotInGraph(x, G(V,E)) in Bool.
+
+        '''
+        from . import not_in_graph_is_bool
+        return not_in_graph_is_bool.instantiate(
+                {x: self.element, G: self.domain})
+
+    @prover
+    def unfold(self, **defaults_config):
+        r'''
+        From NotInGraph(x, G), derive and return Not(InGraph(x, G)).
+        For example,
+
+            NotInGraph(a, G(V, E)).unfold_not_in(
+                assumptions=[NotInGraph(a, G(V, E))])
+        returns
+
+            NotInGraph(a, G(V, E)) |- Not (a in G(V, E)).
+
+        We include the auto_simplify=False to keep the membership
+        result inside the Not() from being reduced to False.
+        '''
+        from . import unfold_not_in_graph
+        return unfold_not_in_graph.instantiate(
+            {x: self.element, G: self.domain}, auto_simplify=False)
+
+    # A placeholder from the NotInSet class; delaying for now
+    # come back to this after subgraphs are defined
+    # def _readily_provable(self):
+    #     '''
+    #     This membership is readily provable if the membership
+    #     object indicates that it is readily provable or there is a 
+    #     known as-strong membership (with known equal elements and the
+    #     domain a subset of the desired domain).
+    #     '''
+    #     if NotInClass._readily_provable(self):
+    #         return True
+    #     if self.as_strong_known_nonmembership() is not None:
+    #         return True
+    #     return False
+
+    # A placeholder from the NotInSet class; delaying for now
+    # @prover
+    # def conclude(self, **defaults_config):
+    #     '''
+    #     Attempt to conclude that the element is not in the domain. 
+    #     First see if the corresponding membership has been disproven. 
+    #     Then see if there is a as-strong known nonmembership to use.  
+    #     If not, use the NotInClass conclude strategies (which uses the
+    #     Relation conclude strategies that simplify both sides and then 
+    #     uses the domain-specific conclude method of the membership
+    #     object as a last resort).
+    #     '''
+    #     # Has the membership been disproven?
+    #     if self.negated().disproven(): # don't use readily_disprovable
+    #         return self.conclude_as_folded()
+        
+    #     # See if the element, or something known to be equal to
+    #     # the element, is known to be a nonmember of the domain or a 
+    #     # superset of the domain.
+    #     as_strong_nonmembership = self.as_strong_known_nonmembership()
+    #     if as_strong_nonmembership is not None:
+    #         return self.conclude_from_as_strong_nonmembership(
+    #                 as_strong_nonmembership)
+    #     return NotInClass.conclude(self)
+
+    @prover
+    def conclude_as_folded(self, **defaults_config):
+        '''
+        Attempt to conclude x not in G via Not(x in G).
+        '''
+        from . import fold_not_in_graph
+        return fold_not_in_graph.instantiate(
+            {x: self.element, G: self.domain})
+
+    @prover
+    def conclude_negation(self, **defaults_config):
+        '''
+        Attempt to conclude the negation of nonmembership via
+        proving membership.
+        '''
+        from . import double_negated_membership
+        return double_negated_membership.instantiate(
+                {x:self.element, G:self.domain})
+
+    # A placeholder from the NotInSet class; delaying for now
+    # come back to this after subgraphs are defined
+    # @prover
+    # def conclude_from_as_strong_nonmembership(
+    #         self, as_strong_nonmembership, **defaults_config):
+    #     '''
+    #     Conclude from a nonmembership with an equal element and a 
+    #     domain that is a superset of the desired domain.
+    #     '''
+    #     from proveit.logic import Equals, SubsetEq
+    #     elem_sub = as_strong_nonmembership.element
+    #     if as_strong_nonmembership.domain == self.domain:
+    #         elem_sub_notin_domain = as_strong_nonmembership
+    #     else:
+    #         eq_rel = Equals(as_strong_nonmembership.domain, self.domain)
+    #         if eq_rel.readily_provable():
+    #             # domains are equal -- just substitute the domain.
+    #             elem_sub_notin_domain = eq_rel.sub_right_side_into(
+    #                     as_strong_nonmembership.inner_expr().domain)
+    #         else:
+    #             # S is a subset of R, so now we can prove 
+    #             # x not in S.
+    #             sub_rel = SubsetEq(self.domain, as_strong_nonmembership.domain)
+    #             try:
+    #                 sub_rel.prove()
+    #             except ProofFailure:
+    #                 # May have been blocked to avoid infinite
+    #                 # recursion.
+    #                 return NotInClass.conclude(self)
+    #             elem_sub_notin_domain = sub_rel.derive_subset_nonmembership(
+    #                     elem_sub)
+    #     if elem_sub == self.element:
+    #         return elem_sub_notin_domain # done
+    #     # Just need to sub in the element for _elem_sub.
+    #     Equals(elem_sub, self.element).conclude_via_transitivity()
+    #     return elem_sub_notin_domain.inner_expr().element.substitute(
+    #             self.element)
+
+    # A placeholder from the NotInSet class; delaying for now
+    # come back to this after subgraphs are defined
+    # def as_strong_known_nonmembership(self):
+    #     '''
+    #     If there is a known nonmembership that is as strong as this 
+    #     one, where the element is equal to this one's element and the 
+    #     domain is a subset of this one's domain, return this
+    #     as-strong known membership.  Otherwise, return None.
+    #     '''
+    #     from proveit.logic import Equals, SubsetEq
+    #     known_nonmemberships = list(
+    #             NotInClass.yield_known_nonmemberships(self.element))
+    #     # First see of there is a known nonmembership with the same domain.
+    #     for known_nonmembership in known_nonmemberships:
+    #         if known_nonmembership.domain == self.domain:
+    #             # this is the best to use; we are done
+    #             return known_nonmembership
+    #     # Next see of there is a known nonmembership with a domain
+    #     # readily provable to be equal to this domain.
+    #     for known_nonmembership in known_nonmemberships:
+    #         eq_rel = Equals(known_nonmembership.domain, self.domain)
+    #         if eq_rel.readily_provable():
+    #             return known_nonmembership
+    #     # Finaly see of there is a known nonmembership with a domain
+    #     # readily provable to be a superset of to this domain.
+    #     for known_nonmembership in known_nonmemberships:
+    #         sub_rel = SubsetEq(self.domain, known_nonmembership.domain)
+    #         if sub_rel.readily_provable():
+    #             return known_nonmembership
+    #     return None # No match found.
+
+class GraphNonmembership(ClassNonmembership):
+    def __init__(self, element, domain):
+        '''
+        Base class for any 'non-membership object' returned by a
+        domain's 'non-membership_object' method.
+        '''
+        # The expression represented by this Non-Membership.
+        if (element, domain) in NotInGraph.notingraph_expressions:
+            expr = NotInGraph.notingraph_expressions[(element, domain)]
+        else:
+            expr = NotInGraph(element, domain)
+        ClassNonmembership.__init__(self, element, domain, expr=expr)

From 1530bcfc60e01cb6c492fdf889fc5643a4d89081 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 17 Apr 2025 13:16:16 -0500
Subject: [PATCH 004/159] Establish graphs/union sub-theory package

Establish graphs/union sub-theory package with initial GraphUnion, GraphUnionMembership, and GraphUnionNonmembership classes, along with some preliminary axioms and theorems (modeled on the sets/unification package). GraphUnionNonmembership.conclude() raises an error, seemingly related to the distinction between set membership and class membership, despite GraphUnionMembership having no such problem. For now, the demonstrations nb tests the GraphUnionNonmembership.conclude() inside a try-except block.
---
 packages/proveit/graphs/union/__init__.py     |   3 +-
 .../graphs/union/_theory_nbs_/axioms.ipynb    |  24 +-
 .../union/_theory_nbs_/demonstrations.ipynb   | 251 +++++++++++++++++-
 .../proofs/membership_folding/thm_proof.ipynb |  47 ++++
 .../membership_unfolding/thm_proof.ipynb      |  47 ++++
 .../nonmembership_equiv/thm_proof.ipynb       |  47 ++++
 .../nonmembership_folding/thm_proof.ipynb     |  47 ++++
 .../union_membership_is_bool/thm_proof.ipynb  |  47 ++++
 .../thm_proof.ipynb                           |  47 ++++
 .../graphs/union/_theory_nbs_/theorems.ipynb  |  79 +++++-
 packages/proveit/graphs/union/graph_union.py  |  53 ++++
 .../graphs/union/graph_union_membership.py    | 170 ++++++++++++
 12 files changed, 856 insertions(+), 6 deletions(-)
 create mode 100644 packages/proveit/graphs/union/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/union/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/union/_theory_nbs_/proofs/nonmembership_equiv/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/union/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/union/_theory_nbs_/proofs/union_membership_is_bool/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/union/_theory_nbs_/proofs/union_nonmembership_is_bool/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/union/graph_union.py
 create mode 100644 packages/proveit/graphs/union/graph_union_membership.py

diff --git a/packages/proveit/graphs/union/__init__.py b/packages/proveit/graphs/union/__init__.py
index dba3de849ed8..611fe3f30a42 100644
--- a/packages/proveit/graphs/union/__init__.py
+++ b/packages/proveit/graphs/union/__init__.py
@@ -1,4 +1,5 @@
-
+from .graph_union import GraphUnion
+from .graph_union_membership import GraphUnionMembership
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
 #  Make additions above, or add to sys.modules[__name__].__dict__ below.
diff --git a/packages/proveit/graphs/union/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/union/_theory_nbs_/axioms.ipynb
index 5e90b1a3a736..f14d75785541 100644
--- a/packages/proveit/graphs/union/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/union/_theory_nbs_/axioms.ipynb
@@ -18,7 +18,11 @@
     "# Prepare this notebook for defining the axioms of a theory:\n",
     "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "# from ... import ..."
+    "from proveit import n, x, E, G, V\n",
+    "from proveit.logic import Equals, Forall, Or\n",
+    "from proveit.logic.sets import InSet\n",
+    "from proveit.numbers import NaturalPos\n",
+    "from proveit.graphs import G_1_to_n, Graph, GraphUnion, InGraph, x_in_any_G_1_to_n"
    ]
   },
   {
@@ -30,12 +34,28 @@
     "%begin axioms"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Graph Union Membership\n",
+    "\n",
+    "An element (i.e., a vertex or edge) of the union of a collection of graphs is an element of at least one of those graphs."
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "graph_union_membership_def = Forall(n,\n",
+    "       Forall((x, G_1_to_n),\n",
+    "              Equals(InGraph(x, GraphUnion(G_1_to_n)),\n",
+    "                     x_in_any_G_1_to_n)),\n",
+    "       domain=NaturalPos\n",
+    ")"
+   ]
   },
   {
    "cell_type": "code",
diff --git a/packages/proveit/graphs/union/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/union/_theory_nbs_/demonstrations.ipynb
index cea403a37716..b66d300170be 100644
--- a/packages/proveit/graphs/union/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/union/_theory_nbs_/demonstrations.ipynb
@@ -15,15 +15,264 @@
    "outputs": [],
    "source": [
     "import proveit\n",
+    "from proveit import g, i, n, x, G, ExprRange, IndexedVar\n",
+    "from proveit.logic import And, InSet, Or\n",
+    "from proveit.numbers import one, two, NaturalPos\n",
+    "from proveit.graphs import GraphUnion, InGraph, NotInGraph\n",
     "%begin demonstrations"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Graph Union, Graph Union Membership, & Related Concepts and Methods: $G_{1} \\cup G_{2} \\cup \\cdots \\cup G_{n}$"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Miscellaneous Testing\n",
+    "Testing various classes and methods related to unions of graphs and membership (or non-membership) in such unions. Some of this material could eventually be integrated into the `_demonstrations_` page and/or deleted as development continues."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Basic Constructions: Graph Unions and Union Membership\n",
+    "\n",
+    "A graph $G = (V, E)$ consists of an ordered pair of sets $V$ and $E$, where $V$ is the set of vertices and $E$ is the set of edges. The union $G = G_{1} \\cup G_{2} \\cup \\cdots \\cup G_{n}$ of graphs $G_{1}, G_{2}, \\ldots G_{n}$ is a graph $G = (V, E)$ with vertex $V = V_{1} \\cup \\cdots \\cup V_{n}$ and edge set $E = E_{1} \\cup \\cdots \\cup E_{n}$."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G1, G2 = (IndexedVar(G, one), IndexedVar(G, two))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "GraphUnion(G1, G2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G_1_to_n = ExprRange(i, IndexedVar(G, i), one, n)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "GraphUnion(G_1_to_n)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InGraph(G, GraphUnion(G1, G2))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInGraph(G, GraphUnion(G_1_to_n))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Basic Testing of `GraphUnion()` methods\n",
+    "\n",
+    "TBA"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Basic Testing of `GraphUnionMembership()` methods"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G_in_union_G1_G2 = InGraph(G, GraphUnion(G1, G2))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G_in_union_G1_G2.definition()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G_in_union_G1_G2.as_defined()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G_in_union_G1_G2.unfold(assumptions = [G_in_union_G1_G2])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G_in_union_G1_G2.conclude(assumptions = [Or(InGraph(G, G1), InGraph(G, G2))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G_in_union_G1_G2.deduce_in_bool()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Basic Testing of `GraphUnionNonmembership()` methods"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G_not_in_union_G1_to_Gn = NotInGraph(G, GraphUnion(G_1_to_n))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G_not_in_union_G1_G2 = NotInGraph(G, GraphUnion(G1, G2))"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "G_not_in_union_G1_to_Gn.definition(assumptions=[InSet(n, NaturalPos)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G_not_in_union_G1_G2.definition()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G_not_in_union_G1_to_Gn.as_defined()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G_not_in_union_G1_G2.as_defined()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "try:\n",
+    "    G_not_in_union_G1_G2.conclude(assumptions = [And(NotInGraph(G, G1), NotInGraph(G, G2))])\n",
+    "except Exception as the_exception:\n",
+    "    print(f\"Exception: {the_exception}\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "try:\n",
+    "    G_not_in_union_G1_to_Gn.conclude(\n",
+    "        assumptions = [InSet(n, NaturalPos), And(ExprRange(i, NotInGraph(G, IndexedVar(G, i)), one, n))])\n",
+    "except Exception as the_exception:\n",
+    "    print(f\"Exception: {the_exception}\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G_not_in_union_G1_G2.deduce_in_bool()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G_not_in_union_G1_to_Gn.deduce_in_bool(assumptions = [InSet(n, NaturalPos)])"
+   ]
   },
   {
    "cell_type": "code",
diff --git a/packages/proveit/graphs/union/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb b/packages/proveit/graphs/union/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..fb55221aacf8
--- /dev/null
+++ b/packages/proveit/graphs/union/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">union</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_folding\">membership_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving membership_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/union/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/union/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
new file mode 100644
index 000000000000..4fc7a5fecfa6
--- /dev/null
+++ b/packages/proveit/graphs/union/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">union</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_unfolding\">membership_unfolding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving membership_unfolding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/union/_theory_nbs_/proofs/nonmembership_equiv/thm_proof.ipynb b/packages/proveit/graphs/union/_theory_nbs_/proofs/nonmembership_equiv/thm_proof.ipynb
new file mode 100644
index 000000000000..2ecd4e40f65a
--- /dev/null
+++ b/packages/proveit/graphs/union/_theory_nbs_/proofs/nonmembership_equiv/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">union</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_equiv\">nonmembership_equiv</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving nonmembership_equiv"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/union/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb b/packages/proveit/graphs/union/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..cbb9f70e6cae
--- /dev/null
+++ b/packages/proveit/graphs/union/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">union</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_folding\">nonmembership_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving nonmembership_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/union/_theory_nbs_/proofs/union_membership_is_bool/thm_proof.ipynb b/packages/proveit/graphs/union/_theory_nbs_/proofs/union_membership_is_bool/thm_proof.ipynb
new file mode 100644
index 000000000000..e89f49c703b6
--- /dev/null
+++ b/packages/proveit/graphs/union/_theory_nbs_/proofs/union_membership_is_bool/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">union</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#union_membership_is_bool\">union_membership_is_bool</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving union_membership_is_bool"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/union/_theory_nbs_/proofs/union_nonmembership_is_bool/thm_proof.ipynb b/packages/proveit/graphs/union/_theory_nbs_/proofs/union_nonmembership_is_bool/thm_proof.ipynb
new file mode 100644
index 000000000000..7a6b6fd807ff
--- /dev/null
+++ b/packages/proveit/graphs/union/_theory_nbs_/proofs/union_nonmembership_is_bool/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">union</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#union_nonmembership_is_bool\">union_nonmembership_is_bool</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving union_nonmembership_is_bool"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/union/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/union/_theory_nbs_/theorems.ipynb
index 9e96036394e9..1d0ab199ad71 100644
--- a/packages/proveit/graphs/union/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/union/_theory_nbs_/theorems.ipynb
@@ -18,7 +18,12 @@
     "# Prepare this notebook for defining the theorems of a theory:\n",
     "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "# from ... import ..."
+    "from proveit import n, x, E, G, V\n",
+    "from proveit.logic import Equals, Forall, Or\n",
+    "# from proveit.logic.sets import InSet\n",
+    "from proveit.numbers import NaturalPos\n",
+    "from proveit.graphs import (G_1_to_n, Graph, GraphUnion, InGraph, NotInGraph,\n",
+    "                            x_in_any_G_1_to_n, x_not_in_any_G_1_to_n)"
    ]
   },
   {
@@ -35,7 +40,77 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "membership_unfolding = (\n",
+    "    Forall(n, Forall((x, G_1_to_n), x_in_any_G_1_to_n, conditions = [InGraph(x, GraphUnion(G_1_to_n))]),\n",
+    "    domain=NaturalPos\n",
+    "))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_folding = (\n",
+    "    Forall(n, Forall((x, G_1_to_n), InGraph(x, GraphUnion(G_1_to_n)), conditions = [x_in_any_G_1_to_n]),\n",
+    "    domain=NaturalPos\n",
+    "))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from proveit.logic import in_bool\n",
+    "union_membership_is_bool = (\n",
+    "    Forall(n, Forall((x, G_1_to_n), in_bool(InGraph(x, GraphUnion(G_1_to_n)))),\n",
+    "    domain=NaturalPos\n",
+    "))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_equiv = (\n",
+    "    Forall(n, Forall((x, G_1_to_n), \n",
+    "    Equals(NotInGraph(x, GraphUnion(G_1_to_n)), x_not_in_any_G_1_to_n)),\n",
+    "    domain=NaturalPos)\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_folding = (\n",
+    "    Forall(n, Forall((x, G_1_to_n), \n",
+    "              NotInGraph(x, GraphUnion(G_1_to_n)),\n",
+    "              conditions=[x_not_in_any_G_1_to_n]),\n",
+    "    domain=NaturalPos)\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from proveit.logic import in_bool\n",
+    "union_nonmembership_is_bool = (\n",
+    "    Forall(n, Forall((x, G_1_to_n), in_bool(NotInGraph(x, GraphUnion(G_1_to_n)))),\n",
+    "    domain=NaturalPos\n",
+    "))"
+   ]
   },
   {
    "cell_type": "code",
diff --git a/packages/proveit/graphs/union/graph_union.py b/packages/proveit/graphs/union/graph_union.py
new file mode 100644
index 000000000000..0c7db04b02a6
--- /dev/null
+++ b/packages/proveit/graphs/union/graph_union.py
@@ -0,0 +1,53 @@
+from proveit import Literal, Operation, USE_DEFAULTS, relation_prover
+from proveit import m, n, A, S, x
+
+
+class GraphUnion(Operation):
+    '''
+    GraphUnion(G1, G2, ..., Gn) represents the union of graphs
+    G1, G2, ..., Gn. The union of graphs G_{i} = (V_{i}, E_{i})
+    with vertex sets V_{i} and edge sets E_{i} gives a graph
+    G = (V, E) = (U V_{i}, U E_{i}) with vertex set V consisting
+    of the union of the vertex sets V_{i} and an edge set E
+    consisting of the union of the edge sets E_{i}.
+    For example, the GraphUnion of two graphs G1 = (V1, E1) and
+    G2 = (V2, E2) is given by:
+
+        G1 U G2 = (V1 U V2, E1 U E2).
+
+    '''
+
+    # Operator of the GraphUnion operation. We use the same notation
+    # as we do for union of sets more generally, relying on context
+    # to make clear what type of union operation is occurring.
+    _operator_ = Literal(
+            string_format='U', latex_format=r'\cup',theory=__file__)
+
+    def __init__(self, *operands, styles=None):
+        '''
+        The union of any number of graphs: G1 U G2 U ... U Gn
+        '''
+        Operation.__init__(self, GraphUnion._operator_, operands,
+                           styles=styles)
+
+    def membership_object(self, element):
+        from .graph_union_membership import GraphUnionMembership
+        return GraphUnionMembership(element, self)
+
+    def nonmembership_object(self, element):
+        from .graph_union_membership import GraphUnionNonmembership
+        return GraphUnionNonmembership(element, self)
+
+    # keeping this here for now; the graph version will need the
+    # concept of subgraph (instead of subset).
+    # @relation_prover
+    # def deduce_superset_eq_relation(self, superset, **defaults_config):
+    #     # Check for special case of a union subset
+    #     # A_1 union ... union ... A_m \subseteq S
+    #     from . import union_inclusion
+    #     _A = self.operands
+    #     _m = _A.num_elements()
+    #     _S = superset
+    #     return union_inclusion.instantiate(
+    #                 {A:_A, m:_m, S:_S})
+            
\ No newline at end of file
diff --git a/packages/proveit/graphs/union/graph_union_membership.py b/packages/proveit/graphs/union/graph_union_membership.py
new file mode 100644
index 000000000000..957126c7d111
--- /dev/null
+++ b/packages/proveit/graphs/union/graph_union_membership.py
@@ -0,0 +1,170 @@
+from proveit import USE_DEFAULTS, equality_prover, prover
+from proveit.logic import SetMembership, SetNonmembership
+from proveit.numbers import num
+from proveit import m, n, x, G
+from proveit.graphs import GraphMembership, GraphNonmembership
+
+
+class GraphUnionMembership(GraphMembership):
+    '''
+    GraphUnionMembership represents membership in a union of
+    multiple graphs and provides methods that apply to membership
+    in a union of graphs. See GraphUnion class for related concepts.
+    Note that the membership relation is InGraph instead of InSet.
+    '''
+
+    def __init__(self, element, domain):
+        GraphMembership.__init__(self, element, domain)
+
+    # for future consideration, borrowed from sets UnionMembership
+    # def side_effects(self, judgment):
+    #     '''
+    #     Unfold the enumerated set membership as a side-effect.
+    #     '''
+    #     yield self.unfold
+
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        Given self = elem in (G1 U G2 U ... U Gn), deduce and return 
+            [elem in (G1 U G2 U ... U Gn)] = 
+            [(elem in G1) V (elem in G2) V ... V (elem in Gn)].
+        '''
+        from . import graph_union_membership_def
+        element = self.element
+        operands = self.domain.operands
+        _G_sub = operands
+        _n_sub = _G_sub.num_elements()
+        return graph_union_membership_def.instantiate(
+                {n: _n_sub, x: element, G: _G_sub}, auto_simplify=False)
+
+    def as_defined(self):
+        '''
+        From self=[elem in (G1 U G2 U ... U Gn)], return
+        [(elem in G1) V (elem in G2) V ... V (elem in Gn)].
+        '''
+        from proveit.logic import Or
+        from proveit.graphs import InGraph
+        element = self.element
+        return Or(*self.domain.operands.map_elements(
+                lambda subset : InGraph(element, subset)))
+
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        From self = [elem in (G1 U G2 U ... U Gn)], derive and return
+        [(elem in G1) V (elem in G2) V ... V (elem in Gn)].
+        '''
+        from . import membership_unfolding 
+        element = self.element
+        operands = self.domain.operands
+        _G_sub = operands
+        _n_sub = _G_sub.num_elements()
+        return membership_unfolding.instantiate(
+            {n:_n_sub, x:element, G:_G_sub}, auto_simplify=False)
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Called on self = [elem in (G1 U G2 U ... U Gn)], and knowing or
+        assuming [[elem in G1] V [elem in G2] V ... V [elem in Gn]],
+        derive and return self.
+        '''
+        from . import membership_folding
+        element = self.element
+        operands = self.domain.operands
+        _G_sub = operands
+        _n_sub = _G_sub.num_elements()
+        return membership_folding.instantiate(
+                {n:_n_sub, x: element, G:_G_sub})
+
+    @prover
+    def deduce_in_bool(self, **defaults_config):
+        '''
+        Deduce that self = (elem in (G1 U G2 U ... U Gn)) is in Bool.
+        Used as helper function elsewhere and not usually explicitly
+        called by the user.
+        '''
+        from . import union_membership_is_bool
+        element = self.element
+        operands = self.domain.operands
+        _G_sub = operands
+        _n_sub = _G_sub.num_elements()
+        return union_membership_is_bool.instantiate(
+                {n:_n_sub, x:element, G:_G_sub})
+
+
+class GraphUnionNonmembership(GraphNonmembership):
+    '''
+    Defines methods that apply to non-membership in a union of graphs.
+    '''
+
+    def __init__(self, element, domain):
+        GraphNonmembership.__init__(self, element, domain)
+
+    def side_effects(self, judgment):
+        '''
+        Currently no side-effects for union nonmembership.
+        '''
+        return
+        yield
+
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self=[elem not in (G1 U G2 U ... U Gn)], deduce and return:
+        |- [elem not in (G1 U G2 U ... U Gn)]
+         = [(elem not in G1) AND (elem not in G2) AND ...
+                AND elem not in Gn].
+        '''
+
+        from . import nonmembership_equiv
+        element = self.element
+        operands = self.domain.operands
+        _G_sub = operands
+        _n_sub = _G_sub.num_elements()
+        return nonmembership_equiv.instantiate(
+            {n: _n_sub, x: element, G: _G_sub}, auto_simplify=False)
+
+    def as_defined(self):
+        '''
+        From self=[elem not in (G1 U G2 U ... U Gn)], return
+        [(elem not in G1) AND (elem not in G2) AND ... 
+         AND (elem not in Gn)].
+        '''
+        from proveit.logic import And, NotInSet
+        from proveit.graphs import NotInGraph
+        element = self.element
+        return And(*self.domain.operands.map_elements(
+                lambda subset : NotInGraph(element, subset)))
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        From self = [elem not in (G1 U G2 U ... U Gn)], and knowing
+        or assuming [elem not in G1] AND [elem not in G2] AND ...
+        AND [elem not in Gn], derive and return self.
+        '''
+        from . import nonmembership_folding
+        element = self.element
+        operands = self.domain.operands
+        _G_sub = operands
+        _n_sub = _G_sub.num_elements()
+        return nonmembership_folding.instantiate(
+            {n:_n_sub, x:element, G:_G_sub})
+
+    @prover
+    def deduce_in_bool(self, **defaults_config):
+        '''
+        Deduce that self = (elem NotIn (G1 U G2 U ... U Gn)) is in Bool.
+        Used as helper function elsewhere and not usually explicitly
+        called by the user.
+        '''
+        from . import union_nonmembership_is_bool
+        element = self.element
+        operands = self.domain.operands
+        _G_sub = operands
+        _n_sub = _G_sub.num_elements()
+        return union_nonmembership_is_bool.instantiate(
+                {n:_n_sub, x:element, G:_G_sub})
+

From 8860e23285731519872e772a132456aea660a40e Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 17 Apr 2025 13:22:46 -0500
Subject: [PATCH 005/159] Update graphs demonstration.ipynb with basic class
 testing

Update graphs demonstration.ipynb with some basic class testing: construction of simple examples of Graph(V,E), Path(V,E), and EndPoints(P).
---
 .../graphs/_theory_nbs_/demonstrations.ipynb  | 40 ++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)

diff --git a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
index 4c113ca42ef3..341f5fe9d471 100644
--- a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
@@ -15,15 +15,53 @@
    "outputs": [],
    "source": [
     "import proveit\n",
+    "from proveit import x, E, G, V\n",
+    "from proveit.logic import in_bool, Not\n",
+    "from proveit.graphs import EndPoints, Graph, Graphs, InGraph, NotInGraph, Path\n",
     "%begin demonstrations"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Graphs and Related Constructions & Methods $G = \\textrm{Graph}(V, E)$"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Miscellaneous Testing\n",
+    "Testing various classes and methods related to the class of graphs and the representation of a graph $G = (V, E)$ consisting of a set $V$ of vertices and a set $E$ of edges. Some of this material could eventually be integrated into the `_demonstrations_` page and/or deleted as development continues."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "example_graph = Graph(V, E)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "example_path = Path(V, E)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "example_endpts = EndPoints(example_path)"
+   ]
   },
   {
    "cell_type": "code",

From f8894b1e3d3e245bd22639ee754a50c4d7518a19 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 17 Apr 2025 13:41:20 -0500
Subject: [PATCH 006/159] Update classes/membership/not_in_class.py and related
 theorems

Update classes/membership/not_in_class.py with typo corrections: In several places, the instantiation of theorems used the wrong target for substitution (possibly copied over from some other code and never updated for the new theorems, or the theorems were subtly changed to use different variables and then the code was not updated). These were all cases where the instantiation tried a substitution for S but needed a substitution for C. Also updated the class/membership theorems with a double_negated_membership theorem analogous to the one in sets/membership so the NotInClass.conclude_negation() method (already in the NotInClass methods but utilizing a non-existing theorem) should now work.
---
 .../double_negated_membership/thm_proof.ipynb | 47 +++++++++++++++++++
 .../membership/_theory_nbs_/theorems.ipynb    |  9 ++++
 .../logic/classes/membership/not_in_class.py  | 14 +++---
 3 files changed, 63 insertions(+), 7 deletions(-)
 create mode 100644 packages/proveit/logic/classes/membership/_theory_nbs_/proofs/double_negated_membership/thm_proof.ipynb

diff --git a/packages/proveit/logic/classes/membership/_theory_nbs_/proofs/double_negated_membership/thm_proof.ipynb b/packages/proveit/logic/classes/membership/_theory_nbs_/proofs/double_negated_membership/thm_proof.ipynb
new file mode 100644
index 000000000000..1179e5e862b6
--- /dev/null
+++ b/packages/proveit/logic/classes/membership/_theory_nbs_/proofs/double_negated_membership/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">classes</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">membership</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#double_negated_membership\">double_negated_membership</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving double_negated_membership"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/classes/membership/_theory_nbs_/theorems.ipynb b/packages/proveit/logic/classes/membership/_theory_nbs_/theorems.ipynb
index 4df16c674158..3860d5f3cb82 100644
--- a/packages/proveit/logic/classes/membership/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/logic/classes/membership/_theory_nbs_/theorems.ipynb
@@ -63,6 +63,15 @@
     "    (x, C), NotInClass(x, C), conditions=[Not(InClass(x, C))])"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "double_negated_membership = Forall((x, C), Not(NotInClass(x, C)), conditions=[InClass(x, C)])"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/logic/classes/membership/not_in_class.py b/packages/proveit/logic/classes/membership/not_in_class.py
index 7cd9f6a71d91..e534422d72ef 100644
--- a/packages/proveit/logic/classes/membership/not_in_class.py
+++ b/packages/proveit/logic/classes/membership/not_in_class.py
@@ -2,7 +2,7 @@
                      prover, relation_prover, equality_prover,
                      ProofFailure, UnsatisfiedPrerequisites)
 from proveit.relation import Relation
-from proveit import x, S
+from proveit import x, S, C
 from proveit.util import OrderedSet
 
 
@@ -27,9 +27,9 @@ class NotInClass(Relation):
     def __init__(self, element, domain, *, 
                  operator=None, styles=None):
         '''
-        Create an class nonmembership relation indicating that the
+        Create a class nonmembership relation indicating that the
         given 'element' is NOT in the given 'domain'.  If an 'operator'
-        is provide, use this as the operator instead of
+        is provided, use this as the operator instead of the
         NotInClass._operator_ (e.g., for NotInSet which derives from
         NotInClass but uses a distinct operator).
         '''
@@ -117,7 +117,7 @@ def deduce_in_bool(self, **defaults_config):
         '''
         from . import not_in_class_is_bool
         return not_in_class_is_bool.instantiate(
-                {x: self.element, S: self.domain})
+                {x: self.element, C: self.domain})
 
     @prover
     def unfold_not_in(self, **defaults_config):
@@ -128,7 +128,7 @@ def unfold_not_in(self, **defaults_config):
         # We include the auto_simplify=False to keep the membership
         # result inside the Not() from being reduced to False.
         return unfold_not_in_class.instantiate(
-            {x: self.element, S: self.domain}, auto_simplify=False)
+            {x: self.element, C: self.domain}, auto_simplify=False)
 
     def _build_canonical_form(self):
         '''
@@ -224,7 +224,7 @@ def conclude_negation(self, **defaults_config):
         '''
         from . import double_negated_membership
         return double_negated_membership.instantiate(
-                {x:self.element, S:self.domain})
+                {x:self.element, C:self.domain})
 
     @prover
     def conclude_as_folded(self, **defaults_config):
@@ -233,7 +233,7 @@ def conclude_as_folded(self, **defaults_config):
         '''
         from . import fold_not_in_class
         return fold_not_in_class.instantiate(
-            {x: self.element, S: self.domain})
+            {x: self.element, C: self.domain})
 
     @staticmethod
     def yield_known_nonmemberships(element, assumptions=USE_DEFAULTS):

From a6fc3d55a78ebdf045480ae728215341fd02cd36 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Fri, 18 Apr 2025 15:31:43 -0500
Subject: [PATCH 007/159] Clean up graphs demonstration.ipynb

Clean up proveit/graphs demonstration.ipynb, removing unnecessary imports.
---
 packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
index 341f5fe9d471..cae1d1a21154 100644
--- a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
@@ -16,8 +16,7 @@
    "source": [
     "import proveit\n",
     "from proveit import x, E, G, V\n",
-    "from proveit.logic import in_bool, Not\n",
-    "from proveit.graphs import EndPoints, Graph, Graphs, InGraph, NotInGraph, Path\n",
+    "from proveit.graphs import EndPoints, Graph, Path\n",
     "%begin demonstrations"
    ]
   },

From f375b5053299ee338926d0bbee25f7345bb43964 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Fri, 18 Apr 2025 17:11:49 -0500
Subject: [PATCH 008/159] Update with some temporary notes.

---
 packages/proveit/graphs/graph.py              |  3 ++
 .../membership/_theory_nbs_/axioms.ipynb      | 39 ++++++++++++++++++-
 2 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/packages/proveit/graphs/graph.py b/packages/proveit/graphs/graph.py
index 931dca2691c4..4419ab4507af 100644
--- a/packages/proveit/graphs/graph.py
+++ b/packages/proveit/graphs/graph.py
@@ -29,6 +29,7 @@ def is_proper_class(self):
         '''
         return True
 
+
 class GraphsMembership(ClassMembership):
 
     def __init__(self, element, domain):
@@ -38,6 +39,8 @@ def __init__(self, element, domain):
             raise TypeError("domain expected to be Graphs, not %s"
                             %domain.__class__)
 
+    # def conclude(): see if and when needed
+
 class Graph(Function):
     '''
     Graph(V, E) represents a graph with vertex set V and edge set E.
diff --git a/packages/proveit/graphs/membership/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/membership/_theory_nbs_/axioms.ipynb
index 49ce6ead356a..5769bbdac1e7 100644
--- a/packages/proveit/graphs/membership/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/membership/_theory_nbs_/axioms.ipynb
@@ -48,11 +48,48 @@
     "# this should eventually use an exclusive or (XOR) instead of simple disjunction (OR)\n",
     "in_graph_def = (\n",
     "    Forall((E, V),\n",
-    "    Forall((x, G),\n",
+    "    Forall((x, G,\n",
     "           Equals(InGraph(x, G), Or(InSet(x, V), InSet(x, E))))\n",
     "    ))"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# this should eventually use an exclusive or (XOR) instead of simple disjunction (OR)\n",
+    "(\n",
+    "    Forall((E, V),\n",
+    "    Forall(x,\n",
+    "           Equals(InGraph(x, Graph(V,E)), Or(InSet(x, V), InSet(x, E))))\n",
+    "    ))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "axiomatic definitions of Vertices() and Edges() functions\n",
+    "(and implicitly of Graph(V, E))\n",
+    "\n",
+    "Forall(V,\n",
+    "Forall(E, Vertices(Graph(V,E)) = V,\n",
+    "       conditions = [E subset of V X V]\n",
+    "))\n",
+    "\n",
+    "Forall(V,\n",
+    "Forall(E, Edges(Graph(V,E)) = E,\n",
+    "       conditions = [E subset of V X V]\n",
+    "))\n",
+    "\n",
+    "Forall(V,\n",
+    "Forall(E, Graph(V,E) is elem of class of Graphs,\n",
+    "       conditions = [E subset of V X V]\n",
+    "))"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From 0f9f73b0feefdb78f362c598ef3e9b8f36228195 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 21 Apr 2025 15:46:01 -0500
Subject: [PATCH 009/159] Establish Edges(), Vertices(), Subgraph() classes

In the graphs package, establish the Edges(), Vertices(), Subgraph(), and NotSubgraph() classes, along with the inclusion sub-package (where the Subgraph and NotSubgraph classes live), and along with misc. supporting elements, including first passes at axioms defining the operation or properties of Edges, Vertices, Subgraphs, and NotSubgraphs.
---
 packages/proveit/graphs/__init__.py           |  3 +-
 packages/proveit/graphs/_sub_theories_.txt    |  1 +
 .../proveit/graphs/_theory_nbs_/axioms.ipynb  | 62 ++++++++++++-
 .../proveit/graphs/_theory_nbs_/common.ipynb  | 15 ++-
 packages/proveit/graphs/graph.py              | 46 +++++++++-
 packages/proveit/graphs/inclusion/__init__.py | 10 ++
 .../graphs/inclusion/_brief_description_.txt  |  1 +
 .../graphs/inclusion/_sub_theories_.txt       |  0
 .../graphs/inclusion/_theory_nbs_/__init__.py |  0
 .../inclusion/_theory_nbs_/axioms.ipynb       | 91 +++++++++++++++++++
 .../inclusion/_theory_nbs_/common.ipynb       | 59 ++++++++++++
 .../_theory_nbs_/demonstrations.ipynb         | 91 +++++++++++++++++++
 .../inclusion/_theory_nbs_/theorems.ipynb     | 59 ++++++++++++
 .../inclusion/_theory_nbs_/theory.ipynb       | 33 +++++++
 .../proveit/graphs/inclusion/not_subgraph.py  | 26 ++++++
 packages/proveit/graphs/inclusion/subgraph.py | 33 +++++++
 16 files changed, 523 insertions(+), 7 deletions(-)
 create mode 100644 packages/proveit/graphs/inclusion/__init__.py
 create mode 100644 packages/proveit/graphs/inclusion/_brief_description_.txt
 create mode 100644 packages/proveit/graphs/inclusion/_sub_theories_.txt
 create mode 100644 packages/proveit/graphs/inclusion/_theory_nbs_/__init__.py
 create mode 100644 packages/proveit/graphs/inclusion/_theory_nbs_/axioms.ipynb
 create mode 100644 packages/proveit/graphs/inclusion/_theory_nbs_/common.ipynb
 create mode 100644 packages/proveit/graphs/inclusion/_theory_nbs_/demonstrations.ipynb
 create mode 100644 packages/proveit/graphs/inclusion/_theory_nbs_/theorems.ipynb
 create mode 100644 packages/proveit/graphs/inclusion/_theory_nbs_/theory.ipynb
 create mode 100644 packages/proveit/graphs/inclusion/not_subgraph.py
 create mode 100644 packages/proveit/graphs/inclusion/subgraph.py

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index dfb3f1896134..b588f39b109e 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -1,7 +1,8 @@
-from .graph import EndPoints, Graph, Graphs, Path
+from .graph import Edges, EndPoints, Graph, Graphs, Path, Vertices
 from .membership import (
       GraphMembership, GraphNonmembership, InGraph, NotInGraph)
 from .union import GraphUnion
+from .inclusion import NotSubgraph, Subgraph
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
 #  Make additions above, or add to sys.modules[__name__].__dict__ below.
diff --git a/packages/proveit/graphs/_sub_theories_.txt b/packages/proveit/graphs/_sub_theories_.txt
index 82d9f7cf2873..51b71201909d 100644
--- a/packages/proveit/graphs/_sub_theories_.txt
+++ b/packages/proveit/graphs/_sub_theories_.txt
@@ -1,2 +1,3 @@
 union
 membership
+inclusion
diff --git a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
index cabae40de7a2..d28db01b2e22 100644
--- a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
@@ -18,7 +18,10 @@
     "# Prepare this notebook for defining the axioms of a theory:\n",
     "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "# from ... import ..."
+    "from proveit import E, V\n",
+    "from proveit.logic import Equals, Forall, InClass, InSet\n",
+    "from proveit.logic.sets import CartProd, SubsetEq\n",
+    "from proveit.graphs import Edges, Graph, Graphs, Vertices\n"
    ]
   },
   {
@@ -35,7 +38,62 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "graph_v_e_in_graphs = (\n",
+    "    Forall(V,\n",
+    "    Forall(E, InClass(Graph(V, E), Graphs()), conditions = [SubsetEq(E, CartProd(V, V))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "vertex_set_of_graph_v_e_is_v = (\n",
+    "    Forall(V,\n",
+    "    Forall(E, Equals(Vertices(Graph(V, E)), V), conditions = [SubsetEq(E, CartProd(V, V))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "edge_set_of_graph_v_e_is_e = (\n",
+    "    Forall(V,\n",
+    "    Forall(E, Equals(Edges(Graph(V, E)), E), conditions = [SubsetEq(E, CartProd(V, V))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "axiomatic definitions of Vertices() and Edges() functions\n",
+    "(and implicitly of Graph(V, E))\n",
+    "\n",
+    "Forall(V,\n",
+    "Forall(E, Vertices(Graph(V,E)) = V,\n",
+    "       conditions = [E subset of V X V]\n",
+    "))\n",
+    "\n",
+    "Forall(V,\n",
+    "Forall(E, Edges(Graph(V,E)) = E,\n",
+    "       conditions = [E subset of V X V]\n",
+    "))\n",
+    "\n",
+    "Forall(V,\n",
+    "Forall(E, Graph(V,E) is elem of class of Graphs,\n",
+    "       conditions = [E subset of V X V]\n",
+    "))"
+   ]
   },
   {
    "cell_type": "code",
diff --git a/packages/proveit/graphs/_theory_nbs_/common.ipynb b/packages/proveit/graphs/_theory_nbs_/common.ipynb
index 7741dcafa169..573d26d45828 100644
--- a/packages/proveit/graphs/_theory_nbs_/common.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/common.ipynb
@@ -18,7 +18,7 @@
     "# Prepare this notebook for defining the common expressions of a theory:\n",
     "%common_expressions_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "from proveit import i, n, x, G, ExprRange, IndexedVar, var_range\n",
+    "from proveit import i, n, x, G, ExprRange, IndexedVar, var_range, Variable\n",
     "from proveit.logic import And, Or\n",
     "from proveit.logic.sets import InSet\n",
     "from proveit.numbers import one\n",
@@ -34,6 +34,19 @@
     "%begin common"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G_prime, V_prime, E_prime = (\n",
+    "        Variable(\"G'\", r\"G'\", fence_when_forced=True),\n",
+    "        Variable(\"V'\", r\"V'\", fence_when_forced=True),\n",
+    "        Variable(\"E'\", r\"E'\", fence_when_forced=True)\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/graph.py b/packages/proveit/graphs/graph.py
index 4419ab4507af..2a4583904321 100644
--- a/packages/proveit/graphs/graph.py
+++ b/packages/proveit/graphs/graph.py
@@ -35,7 +35,7 @@ class GraphsMembership(ClassMembership):
     def __init__(self, element, domain):
         from . import Graphs
         ClassMembership.__init__(self, element, domain)
-        if domain != Graphs:
+        if domain != Graphs():
             raise TypeError("domain expected to be Graphs, not %s"
                             %domain.__class__)
 
@@ -66,11 +66,51 @@ def __init__(self, V, E, *, styles=None):
         Function.__init__(
                 self, Graph._operator_, (V, E), styles=styles)
 
+class Vertices(Function):
+    '''
+    Given a graph G(V, E) with vertex set V and edge set E,
+    Vertices(G(V, E)) represents the set V of vertices ---
+    that is, Vertices(G(V,E)) = V.
+    '''
+
+    # the literal operator of the Vertices operation
+    _operator_ = Literal(string_format='Vertices',
+                         latex_format=r'\text{Vertices}',
+                         theory=__file__)
+
+    def __init__(self, G, *, styles=None):
+        '''
+        Given a graph G(V,E) = (V,E), represent the vertex set of G.
+        '''
+        self.graph = G
+        Function.__init__(
+                self, Vertices._operator_, G, styles=styles)
+
+class Edges(Function):
+    '''
+    Given a graph G(V, E) with vertex set V and edge set E,
+    Edges(G(V, E)) represents the set E of vertices ---
+    that is, Edges(G(V,E)) = E.
+    '''
+
+    # the literal operator of the Vertices operation
+    _operator_ = Literal(string_format='Edges',
+                         latex_format=r'\text{Edges}',
+                         theory=__file__)
+
+    def __init__(self, G, *, styles=None):
+        '''
+        Given a graph G(V,E) = (V,E), represent the edge set of G.
+        '''
+        self.graph = G
+        Function.__init__(
+                self, Edges._operator_, G, styles=styles)
+
 
 class Path(Graph):
     '''
-    A Path is a non-empty graph P = (V,E) with vertex set V and edge
-    set E such that:
+    Path(V,E) represents a path. A Path is a non-empty graph
+    P = (V,E) with vertex set V and edge set E such that:
 
         V = {x0, x1, ..., xk}, E = {x0x1, x1x2, ..., x_{k-1}x_{k}},
 
diff --git a/packages/proveit/graphs/inclusion/__init__.py b/packages/proveit/graphs/inclusion/__init__.py
new file mode 100644
index 000000000000..5842d690a754
--- /dev/null
+++ b/packages/proveit/graphs/inclusion/__init__.py
@@ -0,0 +1,10 @@
+from .subgraph import Subgraph
+from .not_subgraph import NotSubgraph
+
+# KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
+#  Make additions above, or add to sys.modules[__name__].__dict__ below.
+# This allows us to import common expression, axioms, and theorems of
+# the theory package directly from the package.
+import sys
+from proveit._core_.theory import TheoryPackage
+sys.modules[__name__] = TheoryPackage(__name__, __file__, locals())
diff --git a/packages/proveit/graphs/inclusion/_brief_description_.txt b/packages/proveit/graphs/inclusion/_brief_description_.txt
new file mode 100644
index 000000000000..4ebf160e05e2
--- /dev/null
+++ b/packages/proveit/graphs/inclusion/_brief_description_.txt
@@ -0,0 +1 @@
+basic concepts involving subgraphs and supergraphs
diff --git a/packages/proveit/graphs/inclusion/_sub_theories_.txt b/packages/proveit/graphs/inclusion/_sub_theories_.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/__init__.py b/packages/proveit/graphs/inclusion/_theory_nbs_/__init__.py
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/inclusion/_theory_nbs_/axioms.ipynb
new file mode 100644
index 000000000000..88a56ebc1f57
--- /dev/null
+++ b/packages/proveit/graphs/inclusion/_theory_nbs_/axioms.ipynb
@@ -0,0 +1,91 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Axioms for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.inclusion</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the axioms of a theory:\n",
+    "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "from proveit import E, V\n",
+    "from proveit.logic import And, Equals, Forall, Not\n",
+    "from proveit.logic.sets import CartProd, SubsetEq\n",
+    "from proveit.graphs import Graph, E_prime, NotSubgraph, Subgraph, V_prime"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin axioms"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "subgroup_def = (\n",
+    "        Forall((V, V_prime),\n",
+    "                  Forall((E, E_prime),\n",
+    "                         Equals(\n",
+    "                         Subgraph(Graph(V_prime, E_prime), Graph(V, E)),\n",
+    "                         And(SubsetEq(V_prime, V), SubsetEq(E_prime, E))\n",
+    "                         ),\n",
+    "                        domains = [CartProd(V, V), CartProd(V_prime, V_prime)])\n",
+    "        )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_subgroup_def = (\n",
+    "        Forall((V, V_prime),\n",
+    "                  Forall((E, E_prime),\n",
+    "                         Equals(\n",
+    "                         NotSubgraph(Graph(V_prime, E_prime), Graph(V, E)),\n",
+    "                         Not(Subgraph(Graph(V_prime, E_prime), Graph(V, E)))\n",
+    "                         ),\n",
+    "                        domains = [CartProd(V, V), CartProd(V_prime, V_prime)])\n",
+    "        )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end axioms"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/common.ipynb b/packages/proveit/graphs/inclusion/_theory_nbs_/common.ipynb
new file mode 100644
index 000000000000..c043ae304de6
--- /dev/null
+++ b/packages/proveit/graphs/inclusion/_theory_nbs_/common.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Common expressions for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.inclusion</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the common expressions of a theory:\n",
+    "%common_expressions_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin common"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end common"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/inclusion/_theory_nbs_/demonstrations.ipynb
new file mode 100644
index 000000000000..1b1fbe3837cc
--- /dev/null
+++ b/packages/proveit/graphs/inclusion/_theory_nbs_/demonstrations.ipynb
@@ -0,0 +1,91 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Demonstrations for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.inclusion</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%begin demonstrations\n",
+    "\n",
+    "from proveit import E, G, H, V, Variable\n",
+    "from proveit.graphs import E_prime, G_prime, Graph, NotSubgraph, Subgraph, V_prime"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Subgraphs & Supergraphs: $G' \\subseteq G$"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### MISC. TESTING"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Basic Constructions"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G, G_prime = (Graph(V, E), Graph(V_prime, E_prime))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Subgraph(G_prime, G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotSubgraph(G_prime, G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end demonstrations"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/inclusion/_theory_nbs_/theorems.ipynb
new file mode 100644
index 000000000000..013ab89e8d9e
--- /dev/null
+++ b/packages/proveit/graphs/inclusion/_theory_nbs_/theorems.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theorems (or conjectures) for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.inclusion</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the theorems of a theory:\n",
+    "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin theorems"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end theorems"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/theory.ipynb b/packages/proveit/graphs/inclusion/_theory_nbs_/theory.ipynb
new file mode 100644
index 000000000000..14d7a773b953
--- /dev/null
+++ b/packages/proveit/graphs/inclusion/_theory_nbs_/theory.ipynb
@@ -0,0 +1,33 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theory of <a class=\"ProveItLink\" href=\"../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../_theory_nbs_/theory.ipynb\">graphs</a>.inclusion\n",
+    "========\n",
+    "\n",
+    "Provide description here."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%theory # toggles between interactive and static modes"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/inclusion/not_subgraph.py b/packages/proveit/graphs/inclusion/not_subgraph.py
new file mode 100644
index 000000000000..d6bbdd1191c5
--- /dev/null
+++ b/packages/proveit/graphs/inclusion/not_subgraph.py
@@ -0,0 +1,26 @@
+from proveit import Literal
+from proveit.relation import Relation
+
+class NotSubgraph(Relation):
+    '''
+    Given graph G'(V',E') with vertex set V' and edge set E',
+    and given graph G(V,E) with vertex set V and edge set E,
+    NotSubgraph(G', G) represents the claim that graph G' is
+    NOT a subgraph of graph G. That would mean that V' is NOT
+    a subset of V and/or E' is NOT a subset of E.
+    '''
+
+    # The operator of the NotSubgraph operation.
+    # Following tradition in graph theory, we use the same operator
+    # for not subgraph as we use for not subset, relying on the context
+    # to distinguish the cases. We modify the string version for clarity.
+    _operator_ = Literal(string_format='not_subgraph', 
+                         latex_format=r'\nsubseteq',
+                         theory=__file__)
+
+    def __init__(self, A, B, *, styles=None):
+        '''
+        Create the expression for (A not_subgraph B)
+        '''
+        Relation.__init__(self, NotSubgraph._operator_, A, B,
+                           styles=styles)
\ No newline at end of file
diff --git a/packages/proveit/graphs/inclusion/subgraph.py b/packages/proveit/graphs/inclusion/subgraph.py
new file mode 100644
index 000000000000..cf88db4dfb36
--- /dev/null
+++ b/packages/proveit/graphs/inclusion/subgraph.py
@@ -0,0 +1,33 @@
+from proveit import Literal
+from proveit.logic.sets.inclusion.inclusion_relation import InclusionRelation
+
+class Subgraph(InclusionRelation):
+    '''
+    Given graph G'(V',E') with vertex set V' and edge set E',
+    and given graph G(V,E) with vertex set V and edge set E,
+    Subgraph(G', G) represents the claim that graph G' is a
+    subgraph of graph G. That would mean that V' is a subset of V,
+    and E' is a subset of E.
+    '''
+
+    # The operator of the Subgraph operation.
+    # Following tradition in graph theory, we use the same operator
+    # for subgraph as we use for subset, relying on the context to
+    # distinguish the cases. We modify the string version for clarity.
+    _operator_ = Literal(string_format='subgraph',
+                         latex_format=r'\subseteq',
+                         theory=__file__)
+
+    # map left-hand-sides to Subgraph Judgments
+    #   (populated in TransitivityRelation.derive_side_effects)
+    known_left_sides = dict()
+    # map right-hand-sides to Subgraph Judgments
+    #   (populated in TransitivityRelation.derive_side_effects)
+    known_right_sides = dict()
+
+    def __init__(self, A, B, *, styles=None):
+        '''
+        Create the expression for (G' subgraph G)
+        '''
+        InclusionRelation.__init__(self, Subgraph._operator_, A, B,
+                                   styles=styles)
\ No newline at end of file

From c704d441d484112e140618dcb2bbd820b601e46a Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 21 Apr 2025 20:45:20 -0500
Subject: [PATCH 010/159] Rename graphs/inclusion axioms, correcting typo

Rename graphs/inclusion axioms to use subgraph_def and not_subgraph_def, instead of subgroup_def and not_subgroup_def.
---
 packages/proveit/graphs/inclusion/_theory_nbs_/axioms.ipynb | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/inclusion/_theory_nbs_/axioms.ipynb
index 88a56ebc1f57..aba5efedd6a9 100644
--- a/packages/proveit/graphs/inclusion/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/inclusion/_theory_nbs_/axioms.ipynb
@@ -39,7 +39,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "subgroup_def = (\n",
+    "subgraph_def = (\n",
     "        Forall((V, V_prime),\n",
     "                  Forall((E, E_prime),\n",
     "                         Equals(\n",
@@ -57,7 +57,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "not_subgroup_def = (\n",
+    "not_subgraph_def = (\n",
     "        Forall((V, V_prime),\n",
     "                  Forall((E, E_prime),\n",
     "                         Equals(\n",

From 0623de78213dea28c527a12c39e6f490a1f512c3 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 21 Apr 2025 20:48:22 -0500
Subject: [PATCH 011/159] Establish and prove basic graphs/inclusion theorems

Establish and prove the basic graphs/inclusion theorems that fold or unfold the axiomatic definitions for Subgraph and NotSubgraph.
---
 .../allowed_presumptions.txt                  |  0
 .../disallowed_presumptions.txt               |  0
 .../fold_not_subgraph_def/thm_proof.ipynb     | 86 +++++++++++++++++
 .../allowed_presumptions.txt                  |  1 +
 .../disallowed_presumptions.txt               |  0
 .../proofs/fold_subgraph_def/thm_proof.ipynb  | 95 +++++++++++++++++++
 .../allowed_presumptions.txt                  |  1 +
 .../disallowed_presumptions.txt               |  0
 .../unfold_not_subgraph_def/thm_proof.ipynb   | 95 +++++++++++++++++++
 .../allowed_presumptions.txt                  |  1 +
 .../disallowed_presumptions.txt               |  0
 .../unfold_subgraph_def/thm_proof.ipynb       | 90 ++++++++++++++++++
 .../inclusion/_theory_nbs_/theorems.ipynb     | 64 ++++++++++++-
 13 files changed, 431 insertions(+), 2 deletions(-)
 create mode 100644 packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_not_subgraph_def/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_not_subgraph_def/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_not_subgraph_def/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_subgraph_def/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_subgraph_def/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_subgraph_def/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_not_subgraph_def/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_not_subgraph_def/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_not_subgraph_def/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_subgraph_def/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_subgraph_def/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_subgraph_def/thm_proof.ipynb

diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_not_subgraph_def/allowed_presumptions.txt b/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_not_subgraph_def/allowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_not_subgraph_def/disallowed_presumptions.txt b/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_not_subgraph_def/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_not_subgraph_def/thm_proof.ipynb b/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_not_subgraph_def/thm_proof.ipynb
new file mode 100644
index 000000000000..795e3aac7b2a
--- /dev/null
+++ b/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_not_subgraph_def/thm_proof.ipynb
@@ -0,0 +1,86 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">inclusion</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#fold_not_subgraph_def\">fold_not_subgraph_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.graphs.inclusion import not_subgraph_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving fold_not_subgraph_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = fold_not_subgraph_def.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_subgraph_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_subgraph_def_inst = not_subgraph_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_subgraph_def/allowed_presumptions.txt b/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_subgraph_def/allowed_presumptions.txt
new file mode 100644
index 000000000000..df2d242c76be
--- /dev/null
+++ b/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_subgraph_def/allowed_presumptions.txt
@@ -0,0 +1 @@
+proveit.logic.equality.lhs_via_equality
diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_subgraph_def/disallowed_presumptions.txt b/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_subgraph_def/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_subgraph_def/thm_proof.ipynb b/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_subgraph_def/thm_proof.ipynb
new file mode 100644
index 000000000000..6cb9fc09ff6c
--- /dev/null
+++ b/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/fold_subgraph_def/thm_proof.ipynb
@@ -0,0 +1,95 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">inclusion</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#fold_subgraph_def\">fold_subgraph_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.graphs.inclusion import subgraph_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving fold_subgraph_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = fold_subgraph_def.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "subgraph_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "subgraph_def_inst = subgraph_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "subgraph_def_inst.derive_left_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_not_subgraph_def/allowed_presumptions.txt b/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_not_subgraph_def/allowed_presumptions.txt
new file mode 100644
index 000000000000..cc2c81dedc51
--- /dev/null
+++ b/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_not_subgraph_def/allowed_presumptions.txt
@@ -0,0 +1 @@
+proveit.logic.equality.rhs_via_equality
diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_not_subgraph_def/disallowed_presumptions.txt b/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_not_subgraph_def/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_not_subgraph_def/thm_proof.ipynb b/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_not_subgraph_def/thm_proof.ipynb
new file mode 100644
index 000000000000..919cf209c715
--- /dev/null
+++ b/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_not_subgraph_def/thm_proof.ipynb
@@ -0,0 +1,95 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">inclusion</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#unfold_not_subgraph_def\">unfold_not_subgraph_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.graphs.inclusion import not_subgraph_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving unfold_not_subgraph_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = unfold_not_subgraph_def.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_subgraph_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_subgraph_def_inst = not_subgraph_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_subgraph_def_inst.derive_right_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_subgraph_def/allowed_presumptions.txt b/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_subgraph_def/allowed_presumptions.txt
new file mode 100644
index 000000000000..cc2c81dedc51
--- /dev/null
+++ b/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_subgraph_def/allowed_presumptions.txt
@@ -0,0 +1 @@
+proveit.logic.equality.rhs_via_equality
diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_subgraph_def/disallowed_presumptions.txt b/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_subgraph_def/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_subgraph_def/thm_proof.ipynb b/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_subgraph_def/thm_proof.ipynb
new file mode 100644
index 000000000000..5bdc81bd98af
--- /dev/null
+++ b/packages/proveit/graphs/inclusion/_theory_nbs_/proofs/unfold_subgraph_def/thm_proof.ipynb
@@ -0,0 +1,90 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">inclusion</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#unfold_subgraph_def\">unfold_subgraph_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import E, V\n",
+    "from proveit.logic import InSet\n",
+    "from proveit.logic.sets import CartProd\n",
+    "from proveit.graphs import E_prime, Graph, V_prime\n",
+    "from proveit.graphs.inclusion import Subgraph, subgraph_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving unfold_subgraph_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "subgraph_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "subgraph_def_inst = subgraph_def.instantiate().instantiate(\n",
+    "    assumptions=[InSet(E, CartProd(V, V)), InSet(E_prime, CartProd(V_prime, V_prime))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "subgraph_def_inst.derive_right_via_equality(assumptions = [Subgraph(Graph(V_prime, E_prime), Graph(V, E))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/inclusion/_theory_nbs_/theorems.ipynb
index 013ab89e8d9e..75451851fece 100644
--- a/packages/proveit/graphs/inclusion/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/inclusion/_theory_nbs_/theorems.ipynb
@@ -18,7 +18,10 @@
     "# Prepare this notebook for defining the theorems of a theory:\n",
     "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "# from ... import ..."
+    "from proveit import E, V\n",
+    "from proveit.logic import And, Equals, Forall, Not\n",
+    "from proveit.logic.sets import CartProd, SubsetEq\n",
+    "from proveit.graphs import Graph, E_prime, NotSubgraph, Subgraph, V_prime"
    ]
   },
   {
@@ -35,7 +38,64 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "unfold_subgraph_def = (\n",
+    "        Forall((V, V_prime),\n",
+    "                  Forall((E, E_prime),\n",
+    "                         And(SubsetEq(V_prime, V), SubsetEq(E_prime, E)),\n",
+    "                         conditions = [Subgraph(Graph(V_prime, E_prime), Graph(V, E))],\n",
+    "                         domains = [CartProd(V, V), CartProd(V_prime, V_prime)])\n",
+    "        )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "fold_subgraph_def = (\n",
+    "        Forall((V, V_prime),\n",
+    "                  Forall((E, E_prime),\n",
+    "                         Subgraph(Graph(V_prime, E_prime), Graph(V, E)),\n",
+    "                         conditions = [And(SubsetEq(V_prime, V), SubsetEq(E_prime, E))],\n",
+    "                         domains = [CartProd(V, V), CartProd(V_prime, V_prime)])\n",
+    "        )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "unfold_not_subgraph_def = (\n",
+    "        Forall((V, V_prime),\n",
+    "                  Forall((E, E_prime),\n",
+    "                         Not(Subgraph(Graph(V_prime, E_prime), Graph(V, E))),\n",
+    "                         conditions = [NotSubgraph(Graph(V_prime, E_prime), Graph(V, E))],\n",
+    "                         domains = [CartProd(V, V), CartProd(V_prime, V_prime)])\n",
+    "        )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "fold_not_subgraph_def = (\n",
+    "        Forall((V, V_prime),\n",
+    "                  Forall((E, E_prime),\n",
+    "                         NotSubgraph(Graph(V_prime, E_prime), Graph(V, E)),\n",
+    "                         conditions = [Not(Subgraph(Graph(V_prime, E_prime), Graph(V, E)))],\n",
+    "                         domains = [CartProd(V, V), CartProd(V_prime, V_prime)])\n",
+    "        )\n",
+    ")"
+   ]
   },
   {
    "cell_type": "code",

From 5cfa44a2c7a59f89979d17e78d69e3bbac360685 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 21 Apr 2025 20:53:35 -0500
Subject: [PATCH 012/159] Change literal op for Graph() from 'Graph' to just
 'G'

Change literal op for Graph() from 'Graph' to just 'G'. This might help expressions, axioms, and theorems be more condensed. Might have to change back if too confusing.
---
 packages/proveit/graphs/graph.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/proveit/graphs/graph.py b/packages/proveit/graphs/graph.py
index 2a4583904321..6546123fedee 100644
--- a/packages/proveit/graphs/graph.py
+++ b/packages/proveit/graphs/graph.py
@@ -53,8 +53,8 @@ class Graph(Function):
     '''
 
     # the literal operator of the Graph operation
-    _operator_ = Literal(string_format='Graph',
-                         latex_format=r'\textrm{Graph}',
+    _operator_ = Literal(string_format='G',
+                         latex_format=r'\textrm{G}',
                          theory=__file__)
 
     def __init__(self, V, E, *, styles=None):

From 1e6ddf531c8329bcc97c07783f0e057ad80f946e Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 22 Apr 2025 10:37:48 -0500
Subject: [PATCH 013/159] Change Vertices & Edges operator literals to single
 character.

Change the Vertices & Edges class operator literals to use a single character (V instead of Vertices, E instead of Edges). This might help expressions, axioms, and theorems be more condensed and readable. Might have to change back if too confusing.
---
 packages/proveit/graphs/graph.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/packages/proveit/graphs/graph.py b/packages/proveit/graphs/graph.py
index 6546123fedee..a0a6e78d891b 100644
--- a/packages/proveit/graphs/graph.py
+++ b/packages/proveit/graphs/graph.py
@@ -74,8 +74,8 @@ class Vertices(Function):
     '''
 
     # the literal operator of the Vertices operation
-    _operator_ = Literal(string_format='Vertices',
-                         latex_format=r'\text{Vertices}',
+    _operator_ = Literal(string_format='V',
+                         latex_format=r'\mathrm{V}',
                          theory=__file__)
 
     def __init__(self, G, *, styles=None):
@@ -94,8 +94,8 @@ class Edges(Function):
     '''
 
     # the literal operator of the Vertices operation
-    _operator_ = Literal(string_format='Edges',
-                         latex_format=r'\text{Edges}',
+    _operator_ = Literal(string_format='E',
+                         latex_format=r'\mathrm{E}',
                          theory=__file__)
 
     def __init__(self, G, *, styles=None):

From a715fd18ed6a7a174dbf2a35a53ea80d2bc4afb8 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 22 Apr 2025 10:38:38 -0500
Subject: [PATCH 014/159] Clean up graphs/axioms page.

Clean up graphs/axioms page, deleting some now-obsolete notes.
---
 .../proveit/graphs/_theory_nbs_/axioms.ipynb  | 23 -------------------
 1 file changed, 23 deletions(-)

diff --git a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
index d28db01b2e22..e380e0863bcb 100644
--- a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
@@ -72,29 +72,6 @@
     ")"
    ]
   },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "axiomatic definitions of Vertices() and Edges() functions\n",
-    "(and implicitly of Graph(V, E))\n",
-    "\n",
-    "Forall(V,\n",
-    "Forall(E, Vertices(Graph(V,E)) = V,\n",
-    "       conditions = [E subset of V X V]\n",
-    "))\n",
-    "\n",
-    "Forall(V,\n",
-    "Forall(E, Edges(Graph(V,E)) = E,\n",
-    "       conditions = [E subset of V X V]\n",
-    "))\n",
-    "\n",
-    "Forall(V,\n",
-    "Forall(E, Graph(V,E) is elem of class of Graphs,\n",
-    "       conditions = [E subset of V X V]\n",
-    "))"
-   ]
-  },
   {
    "cell_type": "code",
    "execution_count": null,

From d910608e1a6bd6a4244d1962789eff91caaab9e0 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 22 Apr 2025 12:03:41 -0500
Subject: [PATCH 015/159] Establish graphs/paths sub-package

Establish graphs/paths sub-package, including the minimal Paths(G) class for representing the set of paths in a graph G.
---
 packages/proveit/graphs/__init__.py           |  4 +-
 packages/proveit/graphs/_sub_theories_.txt    |  1 +
 packages/proveit/graphs/paths/__init__.py     |  9 ++
 .../graphs/paths/_brief_description_.txt      |  1 +
 .../proveit/graphs/paths/_sub_theories_.txt   |  0
 .../graphs/paths/_theory_nbs_/__init__.py     |  0
 .../graphs/paths/_theory_nbs_/axioms.ipynb    | 59 +++++++++++++
 .../graphs/paths/_theory_nbs_/common.ipynb    | 59 +++++++++++++
 .../paths/_theory_nbs_/demonstrations.ipynb   | 82 +++++++++++++++++++
 .../graphs/paths/_theory_nbs_/theorems.ipynb  | 59 +++++++++++++
 .../graphs/paths/_theory_nbs_/theory.ipynb    | 33 ++++++++
 packages/proveit/graphs/paths/paths.py        | 31 +++++++
 12 files changed, 337 insertions(+), 1 deletion(-)
 create mode 100644 packages/proveit/graphs/paths/__init__.py
 create mode 100644 packages/proveit/graphs/paths/_brief_description_.txt
 create mode 100644 packages/proveit/graphs/paths/_sub_theories_.txt
 create mode 100644 packages/proveit/graphs/paths/_theory_nbs_/__init__.py
 create mode 100644 packages/proveit/graphs/paths/_theory_nbs_/axioms.ipynb
 create mode 100644 packages/proveit/graphs/paths/_theory_nbs_/common.ipynb
 create mode 100644 packages/proveit/graphs/paths/_theory_nbs_/demonstrations.ipynb
 create mode 100644 packages/proveit/graphs/paths/_theory_nbs_/theorems.ipynb
 create mode 100644 packages/proveit/graphs/paths/_theory_nbs_/theory.ipynb
 create mode 100644 packages/proveit/graphs/paths/paths.py

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index b588f39b109e..d30008dd3049 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -1,8 +1,10 @@
 from .graph import Edges, EndPoints, Graph, Graphs, Path, Vertices
+from .inclusion import NotSubgraph, Subgraph
 from .membership import (
       GraphMembership, GraphNonmembership, InGraph, NotInGraph)
+from .paths import Paths
 from .union import GraphUnion
-from .inclusion import NotSubgraph, Subgraph
+
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
 #  Make additions above, or add to sys.modules[__name__].__dict__ below.
diff --git a/packages/proveit/graphs/_sub_theories_.txt b/packages/proveit/graphs/_sub_theories_.txt
index 51b71201909d..0caf51f0606d 100644
--- a/packages/proveit/graphs/_sub_theories_.txt
+++ b/packages/proveit/graphs/_sub_theories_.txt
@@ -1,3 +1,4 @@
 union
 membership
 inclusion
+paths
diff --git a/packages/proveit/graphs/paths/__init__.py b/packages/proveit/graphs/paths/__init__.py
new file mode 100644
index 000000000000..b0bb392ce3f8
--- /dev/null
+++ b/packages/proveit/graphs/paths/__init__.py
@@ -0,0 +1,9 @@
+from .paths import Paths
+
+# KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
+#  Make additions above, or add to sys.modules[__name__].__dict__ below.
+# This allows us to import common expression, axioms, and theorems of
+# the theory package directly from the package.
+import sys
+from proveit._core_.theory import TheoryPackage
+sys.modules[__name__] = TheoryPackage(__name__, __file__, locals())
diff --git a/packages/proveit/graphs/paths/_brief_description_.txt b/packages/proveit/graphs/paths/_brief_description_.txt
new file mode 100644
index 000000000000..dae23eda4815
--- /dev/null
+++ b/packages/proveit/graphs/paths/_brief_description_.txt
@@ -0,0 +1 @@
+basic concepts involving paths in a graph and paths as graphs
diff --git a/packages/proveit/graphs/paths/_sub_theories_.txt b/packages/proveit/graphs/paths/_sub_theories_.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/paths/_theory_nbs_/__init__.py b/packages/proveit/graphs/paths/_theory_nbs_/__init__.py
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/paths/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/paths/_theory_nbs_/axioms.ipynb
new file mode 100644
index 000000000000..3f684b183dc5
--- /dev/null
+++ b/packages/proveit/graphs/paths/_theory_nbs_/axioms.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Axioms for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.paths</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the axioms of a theory:\n",
+    "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin axioms"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end axioms"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/paths/_theory_nbs_/common.ipynb b/packages/proveit/graphs/paths/_theory_nbs_/common.ipynb
new file mode 100644
index 000000000000..d51d4e3dc63d
--- /dev/null
+++ b/packages/proveit/graphs/paths/_theory_nbs_/common.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Common expressions for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.paths</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the common expressions of a theory:\n",
+    "%common_expressions_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin common"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end common"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/paths/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/paths/_theory_nbs_/demonstrations.ipynb
new file mode 100644
index 000000000000..0c055623b6c3
--- /dev/null
+++ b/packages/proveit/graphs/paths/_theory_nbs_/demonstrations.ipynb
@@ -0,0 +1,82 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Demonstrations for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.paths</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%begin demonstrations\n",
+    "\n",
+    "from proveit import E, G, V\n",
+    "from proveit.graphs import Graph, Paths"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Paths in Graph $G$: $\\mathrm{Paths}(\\mathrm{G}(V, E))$"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### MISC. TESTING"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Basic Constructions"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G = Graph(V, E)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "example_paths = Paths(G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end demonstrations"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/paths/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/paths/_theory_nbs_/theorems.ipynb
new file mode 100644
index 000000000000..9f33fde2ae7e
--- /dev/null
+++ b/packages/proveit/graphs/paths/_theory_nbs_/theorems.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theorems (or conjectures) for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.paths</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the theorems of a theory:\n",
+    "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin theorems"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end theorems"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/paths/_theory_nbs_/theory.ipynb b/packages/proveit/graphs/paths/_theory_nbs_/theory.ipynb
new file mode 100644
index 000000000000..186e36894cb5
--- /dev/null
+++ b/packages/proveit/graphs/paths/_theory_nbs_/theory.ipynb
@@ -0,0 +1,33 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theory of <a class=\"ProveItLink\" href=\"../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../_theory_nbs_/theory.ipynb\">graphs</a>.paths\n",
+    "========\n",
+    "\n",
+    "Provide description here."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%theory # toggles between interactive and static modes"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/paths/paths.py b/packages/proveit/graphs/paths/paths.py
new file mode 100644
index 000000000000..54e3e6c76ead
--- /dev/null
+++ b/packages/proveit/graphs/paths/paths.py
@@ -0,0 +1,31 @@
+from proveit import Function, Literal
+
+class Paths(Function):
+    '''
+    Given a graph G = G(V, E) with vertex set V and edge set E,
+    Paths(G) represents the set of all paths in the graph G.
+    A Path (in an undirected graph G) is a non-empty graph P = (V,E)
+    with vertex set V and edge set E such that:
+
+        V = {x0, x1, ..., xk},
+        E = {{x0,x1}, {x1,x2}, ..., {x_{k-1},x_{k}},
+
+    where the x_{i} are all distinct. The vertices x0 and xk are said
+    to be linked by the path P and are called its endvertices, or
+    endpoints, or simply its ends. The vertices x1, ..., x_{k-1} are
+    the inner vertices of P. The number of edges in the path P,
+    denoted ||P||, is its length (in this example, ||P|| = k).
+    '''
+
+    # the literal operator of the Paths operation
+    _operator_ = Literal(string_format='Paths',
+                         latex_format=r'\mathrm{Paths}',
+                         theory=__file__)
+
+    def __init__(self, G, *, styles=None):
+        '''
+        Represent the set of paths in the graph G = G(V,E) with vertex
+        set V and edge set E.
+        '''
+        Function.__init__(
+                self, Paths._operator_, G, styles=styles)
\ No newline at end of file

From 1a7eaf8c1461024f280d198bd2fa9ceb6a6219d5 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 22 Apr 2025 16:09:29 -0500
Subject: [PATCH 016/159] Establish KElemSubsets class in logic/sets

Establish the KElemSubsets class in logic/sets/power_set to represent the set of k-element subsets of a set. Also: update related __init__.py files; establish the related KElemSubsetsMembership and KElemSubsetsNonmembership classes; and update PowerSet demonstrations.ipynb with simple construction examples.
---
 packages/proveit/logic/__init__.py            |  2 +-
 packages/proveit/logic/sets/__init__.py       |  2 +-
 .../proveit/logic/sets/power_set/__init__.py  |  1 +
 .../_theory_nbs_/demonstrations.ipynb         | 23 +++++++++-
 .../logic/sets/power_set/k_elem_subsets.py    | 43 +++++++++++++++++++
 .../power_set/k_elem_subsets_membership.py    | 24 +++++++++++
 6 files changed, 91 insertions(+), 4 deletions(-)
 create mode 100644 packages/proveit/logic/sets/power_set/k_elem_subsets.py
 create mode 100644 packages/proveit/logic/sets/power_set/k_elem_subsets_membership.py

diff --git a/packages/proveit/logic/__init__.py b/packages/proveit/logic/__init__.py
index a881ed1b40eb..9e786b710155 100644
--- a/packages/proveit/logic/__init__.py
+++ b/packages/proveit/logic/__init__.py
@@ -24,7 +24,7 @@
     NotProperSubset, superset_eq, not_superset_eq, proper_superset,
     not_proper_superset)
 from .sets import (Union, UnionAll, Intersect, IntersectAll, Difference,
-                   SetOfAll, CartProd, CartExp,
+                   SetOfAll, CartProd, CartExp, KElemSubsets,
                    PowerSet, Disjoint, Distinct, Card)
 from .sets import (Functions, Injections, Surjections, Bijections,
                    Image, InvImage)
diff --git a/packages/proveit/logic/sets/__init__.py b/packages/proveit/logic/sets/__init__.py
index 1229367f29cf..fa241aec0705 100644
--- a/packages/proveit/logic/sets/__init__.py
+++ b/packages/proveit/logic/sets/__init__.py
@@ -11,7 +11,7 @@
 from .intersection import Intersect, IntersectAll
 from .subtraction import Difference
 from .comprehension import SetOfAll
-from .power_set import PowerSet
+from .power_set import PowerSet, KElemSubsets
 from .cartesian_products import CartProd, CartExp
 from .disjointness import Disjoint, Distinct
 from .cardinality import Card
diff --git a/packages/proveit/logic/sets/power_set/__init__.py b/packages/proveit/logic/sets/power_set/__init__.py
index 6f40f95018c6..450b5a76e967 100644
--- a/packages/proveit/logic/sets/power_set/__init__.py
+++ b/packages/proveit/logic/sets/power_set/__init__.py
@@ -1,4 +1,5 @@
 from .power_set import PowerSet
+from .k_elem_subsets import KElemSubsets
 
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb
index 70492f4f0f08..e2037d835585 100644
--- a/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb
@@ -15,8 +15,9 @@
    "outputs": [],
    "source": [
     "import proveit\n",
-    "from proveit.logic import PowerSet, Set\n",
-    "from proveit.numbers import one, two\n",
+    "from proveit import A\n",
+    "from proveit.logic import InSet, KElemSubsets, PowerSet, Set\n",
+    "from proveit.numbers import one, two, three\n",
     "%begin demonstrations"
    ]
   },
@@ -29,6 +30,24 @@
     "PowerSet(Set(one, two))"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "KElemSubsets(Set(one, two, three), two)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(A, KElemSubsets(Set(one, two, three), two))"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/logic/sets/power_set/k_elem_subsets.py b/packages/proveit/logic/sets/power_set/k_elem_subsets.py
new file mode 100644
index 000000000000..e4002ddef826
--- /dev/null
+++ b/packages/proveit/logic/sets/power_set/k_elem_subsets.py
@@ -0,0 +1,43 @@
+from proveit import Literal, Function
+from proveit import n, x
+
+
+class KElemSubsets(Function):
+    '''
+    Given some set S, KElemSubsets(S) represents the set of all
+    k-element subsets of S, denoted [S]^{k}. Such sets are similar
+    in principle to the PowerSet of S (which contains [S]^{k}) and
+    arise often enough in set theory and combinatorics to have
+    somewhat standard notation. In Prove-It, [S]^{k} arises in the
+    context of graph theory, using k = 2 to describe the superset
+    of possible graph edges in a simple graph.
+    '''
+
+    # operator for the KElemSubsets function.
+    _operator_ = Literal(string_format='KElemSubsets', theory=__file__)
+
+    def __init__(self, src_set, k, *, styles=None):
+        '''
+        Create the representation of the set of all k-element subsets
+        of the set src_set.
+        '''
+        Function.__init__(self, KElemSubsets._operator_, (src_set, k),
+                          styles=styles)
+
+    def string(self, **kwargs):
+        return (
+            '[' + self.operands[0].string() + ']^'
+                + self.operands[1].string())
+
+    def latex(self, **kwargs):
+        return (
+            r'\left[' + self.operands[0].latex()
+                      + r'\right]^{' + self.operands[1].latex() + r'}')
+
+    def membership_object(self, element):
+        from .k_elem_subsets_membership import KElemSubsetsMembership
+        return KElemSubsetsMembership(element, self)
+
+    def nonmembership_object(self, element):
+        from .k_elem_subsets_membership import KElemSubsetsNonmembership
+        return KElemSubsetsNonmembership(element, self)
diff --git a/packages/proveit/logic/sets/power_set/k_elem_subsets_membership.py b/packages/proveit/logic/sets/power_set/k_elem_subsets_membership.py
new file mode 100644
index 000000000000..fbca6909c7fa
--- /dev/null
+++ b/packages/proveit/logic/sets/power_set/k_elem_subsets_membership.py
@@ -0,0 +1,24 @@
+# from proveit import USE_DEFAULTS, equality_prover, prover
+from proveit.logic import SetMembership, SetNonmembership
+# from proveit.numbers import num
+# from proveit import m, A, x
+
+
+class KElemSubsetsMembership(SetMembership):
+    '''
+    Defines methods that apply to membership in the set of
+    k-element subsets of a set.
+    '''
+
+    def __init__(self, element, domain):
+        SetMembership.__init__(self, element, domain)
+
+
+class KElemSubsetsNonmembership(SetNonmembership):
+    '''
+    Defines methods that apply to non-membership in the set of
+    k-element subsets of a set.
+    '''
+
+    def __init__(self, element, domain):
+        SetNonmembership.__init__(self, element, domain)

From 9011332a6db5d552a412831bd33354ae99a3aaf2 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 22 Apr 2025 16:49:23 -0500
Subject: [PATCH 017/159] Establish axiomatic definition of KElemSubsets

Establish axiomatic definition of KElemSubsets (in terms of membership, analogous to the PowerSet class axiomatic definition), in the axioms for the PowerSet package.
---
 .../sets/power_set/_theory_nbs_/axioms.ipynb  | 20 +++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/axioms.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/axioms.ipynb
index 1fb12ff6c876..cf145829bfd6 100644
--- a/packages/proveit/logic/sets/power_set/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/axioms.ipynb
@@ -17,8 +17,9 @@
     "import proveit\n",
     "# Prepare this notebook for defining the axioms of a theory:\n",
     "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
-    "from proveit import x, S\n",
-    "from proveit.logic import Equals, Forall, InSet, PowerSet, SubsetEq"
+    "from proveit import k, x, A, S\n",
+    "from proveit.numbers import LessEq, Natural\n",
+    "from proveit.logic import And, Card, Equals, Forall, KElemSubsets, InSet, PowerSet, SubsetEq"
    ]
   },
   {
@@ -40,6 +41,21 @@
     "                                      SubsetEq(x, S)))"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "k_elem_subsets_def = (\n",
+    "    Forall((A, S),\n",
+    "    Forall(k, Equals(InSet(A, KElemSubsets(S, k)), And(SubsetEq(A, S), Equals(Card(A), k))),\n",
+    "    conditions = [LessEq(k, Card(S))],\n",
+    "    domain = Natural)\n",
+    "    )\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From 4c0ac6341d6b81e17e9316b5dae1b89930fe6995 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 22 Apr 2025 17:03:25 -0500
Subject: [PATCH 018/159] Update power_set package with basic fold & unfold
 theorems

Update power_set package with the basic theorems (unfold_power_set_def and fold_power_set_def) for unfolding and folding the power_set_def axiom.
---
 .../allowed_presumptions.txt                  |  1 +
 .../disallowed_presumptions.txt               |  0
 .../proofs/fold_power_set_def/thm_proof.ipynb | 95 +++++++++++++++++++
 .../allowed_presumptions.txt                  |  1 +
 .../disallowed_presumptions.txt               |  0
 .../unfold_power_set_def/thm_proof.ipynb      | 95 +++++++++++++++++++
 .../power_set/_theory_nbs_/theorems.ipynb     | 21 +++-
 7 files changed, 211 insertions(+), 2 deletions(-)
 create mode 100644 packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/allowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/disallowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/thm_proof.ipynb
 create mode 100644 packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/allowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/disallowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/thm_proof.ipynb

diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/allowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/allowed_presumptions.txt
new file mode 100644
index 000000000000..df2d242c76be
--- /dev/null
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/allowed_presumptions.txt
@@ -0,0 +1 @@
+proveit.logic.equality.lhs_via_equality
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/disallowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/thm_proof.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/thm_proof.ipynb
new file mode 100644
index 000000000000..343025835fac
--- /dev/null
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/thm_proof.ipynb
@@ -0,0 +1,95 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">power_set</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#fold_power_set_def\">fold_power_set_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.logic.sets.power_set import power_set_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving fold_power_set_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = fold_power_set_def.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "power_set_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "power_set_def_inst = power_set_def.instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "power_set_def_inst.derive_left_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/allowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/allowed_presumptions.txt
new file mode 100644
index 000000000000..cc2c81dedc51
--- /dev/null
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/allowed_presumptions.txt
@@ -0,0 +1 @@
+proveit.logic.equality.rhs_via_equality
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/disallowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/thm_proof.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/thm_proof.ipynb
new file mode 100644
index 000000000000..bd0ca86a837e
--- /dev/null
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/thm_proof.ipynb
@@ -0,0 +1,95 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">power_set</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#unfold_power_set_def\">unfold_power_set_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.logic.sets.power_set import power_set_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving unfold_power_set_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = unfold_power_set_def.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "power_set_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "power_set_def_inst = power_set_def.instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "power_set_def_inst.derive_right_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/theorems.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/theorems.ipynb
index 338e87eb081b..3002525639cd 100644
--- a/packages/proveit/logic/sets/power_set/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/theorems.ipynb
@@ -16,7 +16,11 @@
    "source": [
     "import proveit\n",
     "# Prepare this notebook for defining the theorems of a theory:\n",
-    "%theorems_notebook # Keep this at the top following 'import proveit'."
+    "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "from proveit import x, S\n",
+    "from proveit.logic import Equals, Forall\n",
+    "from proveit.logic.sets import InSet, PowerSet, SubsetEq"
    ]
   },
   {
@@ -33,7 +37,20 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "unfold_power_set_def = Forall((x, S), SubsetEq(x, S),\n",
+    "       conditions = [InSet(x, PowerSet(S))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "fold_power_set_def = Forall((x, S), InSet(x, PowerSet(S)),\n",
+    "       conditions = [SubsetEq(x, S)])"
+   ]
   },
   {
    "cell_type": "code",

From 5ecfee3996b75bd5e6c9c1cf3e395088875fe889 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 22 Apr 2025 17:16:32 -0500
Subject: [PATCH 019/159] Update power_set package with basic fold & unfold
 theorems for k_elem_subsets_def

Update power_set package with the basic theorems (unfold_k_elem_subsets_def and fold_k_elem_subsets_def) for unfolding and folding the k_elem_subsets_def axiom.
---
 .../allowed_presumptions.txt                  |  1 +
 .../disallowed_presumptions.txt               |  0
 .../fold_k_elem_subsets_def/thm_proof.ipynb   | 95 +++++++++++++++++++
 .../allowed_presumptions.txt                  |  1 +
 .../disallowed_presumptions.txt               |  0
 .../unfold_k_elem_subsets_def/thm_proof.ipynb | 95 +++++++++++++++++++
 .../power_set/_theory_nbs_/theorems.ipynb     | 37 +++++++-
 7 files changed, 226 insertions(+), 3 deletions(-)
 create mode 100644 packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_k_elem_subsets_def/allowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_k_elem_subsets_def/disallowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_k_elem_subsets_def/thm_proof.ipynb
 create mode 100644 packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_k_elem_subsets_def/allowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_k_elem_subsets_def/disallowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_k_elem_subsets_def/thm_proof.ipynb

diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_k_elem_subsets_def/allowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_k_elem_subsets_def/allowed_presumptions.txt
new file mode 100644
index 000000000000..df2d242c76be
--- /dev/null
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_k_elem_subsets_def/allowed_presumptions.txt
@@ -0,0 +1 @@
+proveit.logic.equality.lhs_via_equality
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_k_elem_subsets_def/disallowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_k_elem_subsets_def/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_k_elem_subsets_def/thm_proof.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_k_elem_subsets_def/thm_proof.ipynb
new file mode 100644
index 000000000000..33ef5a00985b
--- /dev/null
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_k_elem_subsets_def/thm_proof.ipynb
@@ -0,0 +1,95 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">power_set</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#fold_k_elem_subsets_def\">fold_k_elem_subsets_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.logic.sets.power_set import k_elem_subsets_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving fold_k_elem_subsets_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = fold_k_elem_subsets_def.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "k_elem_subsets_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "k_elem_subsets_def_inst = k_elem_subsets_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "k_elem_subsets_def_inst.derive_left_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_k_elem_subsets_def/allowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_k_elem_subsets_def/allowed_presumptions.txt
new file mode 100644
index 000000000000..cc2c81dedc51
--- /dev/null
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_k_elem_subsets_def/allowed_presumptions.txt
@@ -0,0 +1 @@
+proveit.logic.equality.rhs_via_equality
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_k_elem_subsets_def/disallowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_k_elem_subsets_def/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_k_elem_subsets_def/thm_proof.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_k_elem_subsets_def/thm_proof.ipynb
new file mode 100644
index 000000000000..79b3e40bccc9
--- /dev/null
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_k_elem_subsets_def/thm_proof.ipynb
@@ -0,0 +1,95 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">power_set</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#unfold_k_elem_subsets_def\">unfold_k_elem_subsets_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.logic.sets.power_set import k_elem_subsets_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving unfold_k_elem_subsets_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = unfold_k_elem_subsets_def.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "k_elem_subsets_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "k_elem_subsets_def_inst = k_elem_subsets_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "k_elem_subsets_def_inst.derive_right_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/theorems.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/theorems.ipynb
index 3002525639cd..75ae907b5f19 100644
--- a/packages/proveit/logic/sets/power_set/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/theorems.ipynb
@@ -18,9 +18,10 @@
     "# Prepare this notebook for defining the theorems of a theory:\n",
     "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "from proveit import x, S\n",
-    "from proveit.logic import Equals, Forall\n",
-    "from proveit.logic.sets import InSet, PowerSet, SubsetEq"
+    "from proveit import k, x, A, S\n",
+    "from proveit.logic import And, Equals, Forall\n",
+    "from proveit.logic.sets import Card, InSet, KElemSubsets, PowerSet, SubsetEq\n",
+    "from proveit.numbers import LessEq, Natural"
    ]
   },
   {
@@ -52,6 +53,36 @@
     "       conditions = [SubsetEq(x, S)])"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "unfold_k_elem_subsets_def = (\n",
+    "    Forall((A, S),\n",
+    "    Forall(k, And(SubsetEq(A, S), Equals(Card(A), k)),\n",
+    "    conditions = [LessEq(k, Card(S)), InSet(A, KElemSubsets(S, k))],\n",
+    "    domain = Natural)\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "fold_k_elem_subsets_def = (\n",
+    "    Forall((A, S),\n",
+    "    Forall(k, InSet(A, KElemSubsets(S, k)),\n",
+    "    conditions = [LessEq(k, Card(S)), And(SubsetEq(A, S), Equals(Card(A), k))],\n",
+    "    domain = Natural)\n",
+    "    )\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From 0f57c33212825b8158717d3a0cd2ea1bc0f5a816 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 22 Apr 2025 17:27:27 -0500
Subject: [PATCH 020/159] Updated power_set pkg w/ PowerSetMembership class

Updated the power_set package with a PowerSetMembership class, and updated the PowerSet class accordingly and updated the power_set demonstrations.ipynb notebook.
---
 .../_theory_nbs_/demonstrations.ipynb         | 30 +++++++++++++++++++
 .../proveit/logic/sets/power_set/power_set.py |  8 ++---
 .../sets/power_set/power_set_membership.py    | 21 +++++++++++++
 3 files changed, 53 insertions(+), 6 deletions(-)
 create mode 100644 packages/proveit/logic/sets/power_set/power_set_membership.py

diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb
index e2037d835585..8015eaa0d318 100644
--- a/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb
@@ -21,6 +21,27 @@
     "%begin demonstrations"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Power Sets and k-Element Subsets: $\\mathcal{P}(S)$, $\\left[S\\right]^{k}$"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### MISC. TESTING"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Basic Constructions"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -30,6 +51,15 @@
     "PowerSet(Set(one, two))"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(A, PowerSet(Set(one, two)))"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/logic/sets/power_set/power_set.py b/packages/proveit/logic/sets/power_set/power_set.py
index 234be816515a..f74ebab018ba 100644
--- a/packages/proveit/logic/sets/power_set/power_set.py
+++ b/packages/proveit/logic/sets/power_set/power_set.py
@@ -16,14 +16,10 @@ def __init__(self, operand, *, styles=None):
         Function.__init__(self, PowerSet._operator_, operand,
                           styles=styles)
 
-    """
-    # Needs implementation
-
     def membership_object(self, element):
-        from .powerset_membership import PowerSetMembership
+        from .power_set_membership import PowerSetMembership
         return PowerSetMembership(element, self)
 
     def nonmembership_object(self, element):
-        from .powerset_membership import PowerSetNonmembership
+        from .power_set_membership import PowerSetNonmembership
         return PowerSetNonmembership(element, self)
-    """
diff --git a/packages/proveit/logic/sets/power_set/power_set_membership.py b/packages/proveit/logic/sets/power_set/power_set_membership.py
new file mode 100644
index 000000000000..70cb57c89a82
--- /dev/null
+++ b/packages/proveit/logic/sets/power_set/power_set_membership.py
@@ -0,0 +1,21 @@
+from proveit.logic import SetMembership, SetNonmembership
+
+
+class PowerSetMembership(SetMembership):
+    '''
+    Defines methods that apply to membership in the power set P(S) of
+    a set S.
+    '''
+
+    def __init__(self, element, domain):
+        SetMembership.__init__(self, element, domain)
+
+
+class PowerSetNonembership(SetNonmembership):
+    '''
+    Defines methods that apply to non-membership in the set of
+    k-element subsets of a set.
+    '''
+
+    def __init__(self, element, domain):
+        SetNonmembership.__init__(self, element, domain)

From fab6ad109e148cb7bb1ff1b6b326f78f582249d0 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 23 Apr 2025 11:33:38 -0500
Subject: [PATCH 021/159] Establish k_power_set theory package in logic/sets

Establish k_power_set theory package in logic/sets, for basic concepts and definitions involving the set [S]^{k} of all k-element subsets of a set S. The commit includes the initial class KPowerSet (named because it is analogous to the more general power set and because it has the standard notation [S]^{k}). This will replace the KElemSubsets class created earlier (without its own theory package) and due to be deleted in future commit(s).
---
 packages/proveit/logic/__init__.py            |  2 +-
 packages/proveit/logic/sets/__init__.py       |  1 +
 .../proveit/logic/sets/_sub_theories_.txt     |  1 +
 .../logic/sets/k_power_set/__init__.py        |  9 +++
 .../sets/k_power_set/_brief_description_.txt  |  1 +
 .../logic/sets/k_power_set/_sub_theories_.txt |  0
 .../sets/k_power_set/_theory_nbs_/__init__.py |  0
 .../k_power_set/_theory_nbs_/axioms.ipynb     | 70 +++++++++++++++++++
 .../k_power_set/_theory_nbs_/common.ipynb     | 59 ++++++++++++++++
 .../_theory_nbs_/demonstrations.ipynb         | 47 +++++++++++++
 .../k_power_set/_theory_nbs_/theorems.ipynb   | 59 ++++++++++++++++
 .../k_power_set/_theory_nbs_/theory.ipynb     | 33 +++++++++
 .../logic/sets/k_power_set/k_power_set.py     | 46 ++++++++++++
 .../k_power_set/k_power_set_membership.py     | 24 +++++++
 14 files changed, 351 insertions(+), 1 deletion(-)
 create mode 100644 packages/proveit/logic/sets/k_power_set/__init__.py
 create mode 100644 packages/proveit/logic/sets/k_power_set/_brief_description_.txt
 create mode 100644 packages/proveit/logic/sets/k_power_set/_sub_theories_.txt
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/__init__.py
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/axioms.ipynb
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/common.ipynb
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/demonstrations.ipynb
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/theorems.ipynb
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/theory.ipynb
 create mode 100644 packages/proveit/logic/sets/k_power_set/k_power_set.py
 create mode 100644 packages/proveit/logic/sets/k_power_set/k_power_set_membership.py

diff --git a/packages/proveit/logic/__init__.py b/packages/proveit/logic/__init__.py
index 9e786b710155..4b4924fa674c 100644
--- a/packages/proveit/logic/__init__.py
+++ b/packages/proveit/logic/__init__.py
@@ -24,7 +24,7 @@
     NotProperSubset, superset_eq, not_superset_eq, proper_superset,
     not_proper_superset)
 from .sets import (Union, UnionAll, Intersect, IntersectAll, Difference,
-                   SetOfAll, CartProd, CartExp, KElemSubsets,
+                   SetOfAll, CartProd, CartExp, KPowerSet,
                    PowerSet, Disjoint, Distinct, Card)
 from .sets import (Functions, Injections, Surjections, Bijections,
                    Image, InvImage)
diff --git a/packages/proveit/logic/sets/__init__.py b/packages/proveit/logic/sets/__init__.py
index fa241aec0705..187550363b7b 100644
--- a/packages/proveit/logic/sets/__init__.py
+++ b/packages/proveit/logic/sets/__init__.py
@@ -11,6 +11,7 @@
 from .intersection import Intersect, IntersectAll
 from .subtraction import Difference
 from .comprehension import SetOfAll
+from .k_power_set import KPowerSet
 from .power_set import PowerSet, KElemSubsets
 from .cartesian_products import CartProd, CartExp
 from .disjointness import Disjoint, Distinct
diff --git a/packages/proveit/logic/sets/_sub_theories_.txt b/packages/proveit/logic/sets/_sub_theories_.txt
index e660031b52e5..47ee5afca1e6 100644
--- a/packages/proveit/logic/sets/_sub_theories_.txt
+++ b/packages/proveit/logic/sets/_sub_theories_.txt
@@ -7,6 +7,7 @@ intersection
 subtraction
 comprehension
 power_set
+k_power_set
 cartesian_products
 disjointness
 cardinality
diff --git a/packages/proveit/logic/sets/k_power_set/__init__.py b/packages/proveit/logic/sets/k_power_set/__init__.py
new file mode 100644
index 000000000000..05868d6c61e2
--- /dev/null
+++ b/packages/proveit/logic/sets/k_power_set/__init__.py
@@ -0,0 +1,9 @@
+from .k_power_set import KPowerSet
+
+# KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
+#  Make additions above, or add to sys.modules[__name__].__dict__ below.
+# This allows us to import common expression, axioms, and theorems of
+# the theory package directly from the package.
+import sys
+from proveit._core_.theory import TheoryPackage
+sys.modules[__name__] = TheoryPackage(__name__, __file__, locals())
diff --git a/packages/proveit/logic/sets/k_power_set/_brief_description_.txt b/packages/proveit/logic/sets/k_power_set/_brief_description_.txt
new file mode 100644
index 000000000000..9e2196ca9a06
--- /dev/null
+++ b/packages/proveit/logic/sets/k_power_set/_brief_description_.txt
@@ -0,0 +1 @@
+Define the set of all k-element subsets of another set.
diff --git a/packages/proveit/logic/sets/k_power_set/_sub_theories_.txt b/packages/proveit/logic/sets/k_power_set/_sub_theories_.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/__init__.py b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/__init__.py
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/axioms.ipynb b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/axioms.ipynb
new file mode 100644
index 000000000000..0e2223cd8d80
--- /dev/null
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/axioms.ipynb
@@ -0,0 +1,70 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Axioms for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.logic.sets.k_power_set</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the axioms of a theory:\n",
+    "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "from proveit import k, A, S\n",
+    "from proveit.logic import And, Equals, Forall\n",
+    "from proveit.logic.sets import Card, InSet, KPowerSet, SubsetEq\n",
+    "from proveit.numbers import LessEq, Natural"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin axioms"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "k_power_set_def = (\n",
+    "    Forall((A, S),\n",
+    "    Forall(k, Equals(InSet(A, KPowerSet(S, k)), And(SubsetEq(A, S), Equals(Card(A), k))),\n",
+    "    conditions = [LessEq(k, Card(S))],\n",
+    "    domain = Natural)\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end axioms"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/common.ipynb b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/common.ipynb
new file mode 100644
index 000000000000..e8662e0c65bd
--- /dev/null
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/common.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Common expressions for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.logic.sets.k_power_set</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the common expressions of a theory:\n",
+    "%common_expressions_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin common"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end common"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/demonstrations.ipynb b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/demonstrations.ipynb
new file mode 100644
index 000000000000..0a114a22e14c
--- /dev/null
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/demonstrations.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Demonstrations for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.logic.sets.k_power_set</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%begin demonstrations"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end demonstrations"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/theorems.ipynb b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/theorems.ipynb
new file mode 100644
index 000000000000..d416fbe83be3
--- /dev/null
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/theorems.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theorems (or conjectures) for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.logic.sets.k_power_set</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the theorems of a theory:\n",
+    "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin theorems"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end theorems"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/theory.ipynb b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/theory.ipynb
new file mode 100644
index 000000000000..acc0374c963f
--- /dev/null
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/theory.ipynb
@@ -0,0 +1,33 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theory of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../_theory_nbs_/theory.ipynb\">sets</a>.k_power_set\n",
+    "========\n",
+    "\n",
+    "Provide description here."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%theory # toggles between interactive and static modes"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/k_power_set/k_power_set.py b/packages/proveit/logic/sets/k_power_set/k_power_set.py
new file mode 100644
index 000000000000..d7c3bb322271
--- /dev/null
+++ b/packages/proveit/logic/sets/k_power_set/k_power_set.py
@@ -0,0 +1,46 @@
+from proveit import Literal, Function
+from proveit import n, x
+
+
+class KPowerSet(Function):
+    '''
+    Given a S and a natural number k <= |S|, KPowerSet(S, k)
+    represents the set of all k-element subsets of S, denoted [S]^{k}.
+    Such sets are similar in principle to the PowerSet of S (which
+    contains [S]^{k}) and arise often enough in set theory and 
+    combinatorics to have somewhat standard notation.
+    In Prove-It, [S]^{k} arises in the context of graph theory,
+    using k = 2 to describe the superset of possible graph edges in
+    a simple graph.
+    '''
+
+    # operator for the KPowerSet function.
+    _operator_ = Literal(string_format='KPowerSet', theory=__file__)
+
+    def __init__(self, src_set, k, *, styles=None):
+        '''
+        Create the representation of the set of all k-element subsets
+        of the set src_set.
+        '''
+        Function.__init__(self, KPowerSet._operator_, (src_set, k),
+                          styles=styles)
+
+    def string(self, **kwargs):
+        return (
+            '[' + self.operands[0].string() + ']^'
+                + self.operands[1].string())
+
+    def latex(self, **kwargs):
+        return (
+            r'\left[' + self.operands[0].latex()
+                      + r'\right]^{' + self.operands[1].latex() + r'}')
+
+    # TO BE UPDATED ONCE MEMBERSHIP DEFINED
+    
+    # def membership_object(self, element):
+    #     from .k_elem_subsets_membership import KElemSubsetsMembership
+    #     return KElemSubsetsMembership(element, self)
+
+    # def nonmembership_object(self, element):
+    #     from .k_elem_subsets_membership import KElemSubsetsNonmembership
+    #     return KElemSubsetsNonmembership(element, self)
diff --git a/packages/proveit/logic/sets/k_power_set/k_power_set_membership.py b/packages/proveit/logic/sets/k_power_set/k_power_set_membership.py
new file mode 100644
index 000000000000..8066cb8512ae
--- /dev/null
+++ b/packages/proveit/logic/sets/k_power_set/k_power_set_membership.py
@@ -0,0 +1,24 @@
+# from proveit import USE_DEFAULTS, equality_prover, prover
+from proveit.logic import SetMembership, SetNonmembership
+# from proveit.numbers import num
+# from proveit import m, A, x
+
+
+class KPowerSetMembership(SetMembership):
+    '''
+    Defines methods that apply to membership in the set of
+    k-element subsets of a set.
+    '''
+
+    def __init__(self, element, domain):
+        SetMembership.__init__(self, element, domain)
+
+
+class KPowerSetNonmembership(SetNonmembership):
+    '''
+    Defines methods that apply to non-membership in the set of
+    k-element subsets of a set.
+    '''
+
+    def __init__(self, element, domain):
+        SetNonmembership.__init__(self, element, domain)

From 14b29ce0045f43340ec0d3c2bcf88434bbef3363 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 23 Apr 2025 16:43:19 -0500
Subject: [PATCH 022/159] Update power_set package

Update logic/sets/power_set theory package, completing: basic axioms and theorems; basic methods for PowerSet, PowerSetMembership, and PowerSetNonmembership classes; basic demonstrations; conjecture-based proofs of theorems. Also deletes various files due to renaming of theorems and shifting the KElemSubsets class to its own package under a different name.
---
 .../sets/power_set/_theory_nbs_/axioms.ipynb  |  12 +-
 .../_theory_nbs_/demonstrations.ipynb         | 102 +++++++++++++-
 .../allowed_presumptions.txt                  |   2 +
 .../disallowed_presumptions.txt               |   0
 .../thm_proof.ipynb                           |  14 +-
 .../allowed_presumptions.txt                  |   0
 .../disallowed_presumptions.txt               |   0
 .../thm_proof.ipynb                           |   6 +-
 .../allowed_presumptions.txt                  |   1 -
 .../allowed_presumptions.txt                  |   2 +
 .../disallowed_presumptions.txt               |   0
 .../not_in_power_set_equiv/thm_proof.ipynb    | 132 ++++++++++++++++++
 .../allowed_presumptions.txt                  |   2 +
 .../disallowed_presumptions.txt               |   0
 .../thm_proof.ipynb                           |  14 +-
 .../allowed_presumptions.txt                  |   0
 .../disallowed_presumptions.txt               |   0
 .../thm_proof.ipynb                           |   6 +-
 .../allowed_presumptions.txt                  |   1 -
 .../power_set/_theory_nbs_/theorems.ipynb     |  33 +++--
 .../sets/power_set/power_set_membership.py    | 109 ++++++++++++++-
 21 files changed, 379 insertions(+), 57 deletions(-)
 create mode 100644 packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_not_in_power_set/allowed_presumptions.txt
 rename packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/{fold_k_elem_subsets_def => fold_not_in_power_set}/disallowed_presumptions.txt (100%)
 rename packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/{unfold_k_elem_subsets_def => fold_not_in_power_set}/thm_proof.ipynb (80%)
 rename packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/{fold_k_elem_subsets_def => fold_power_set}/allowed_presumptions.txt (100%)
 rename packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/{fold_power_set_def => fold_power_set}/disallowed_presumptions.txt (100%)
 rename packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/{fold_power_set_def => fold_power_set}/thm_proof.ipynb (92%)
 delete mode 100644 packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/allowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/not_in_power_set_equiv/allowed_presumptions.txt
 rename packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/{unfold_k_elem_subsets_def => not_in_power_set_equiv}/disallowed_presumptions.txt (100%)
 create mode 100644 packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/not_in_power_set_equiv/thm_proof.ipynb
 create mode 100644 packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_not_in_power_set/allowed_presumptions.txt
 rename packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/{unfold_power_set_def => unfold_not_in_power_set}/disallowed_presumptions.txt (100%)
 rename packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/{fold_k_elem_subsets_def => unfold_not_in_power_set}/thm_proof.ipynb (81%)
 rename packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/{unfold_k_elem_subsets_def => unfold_power_set}/allowed_presumptions.txt (100%)
 create mode 100644 packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set/disallowed_presumptions.txt
 rename packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/{unfold_power_set_def => unfold_power_set}/thm_proof.ipynb (91%)
 delete mode 100644 packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/allowed_presumptions.txt

diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/axioms.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/axioms.ipynb
index cf145829bfd6..8bd23a909328 100644
--- a/packages/proveit/logic/sets/power_set/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/axioms.ipynb
@@ -17,9 +17,9 @@
     "import proveit\n",
     "# Prepare this notebook for defining the axioms of a theory:\n",
     "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
-    "from proveit import k, x, A, S\n",
+    "from proveit import x, S\n",
     "from proveit.numbers import LessEq, Natural\n",
-    "from proveit.logic import And, Card, Equals, Forall, KElemSubsets, InSet, PowerSet, SubsetEq"
+    "from proveit.logic import Equals, Forall, InSet, Not, NotInSet, PowerSet, SubsetEq"
    ]
   },
   {
@@ -47,13 +47,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "k_elem_subsets_def = (\n",
-    "    Forall((A, S),\n",
-    "    Forall(k, Equals(InSet(A, KElemSubsets(S, k)), And(SubsetEq(A, S), Equals(Card(A), k))),\n",
-    "    conditions = [LessEq(k, Card(S))],\n",
-    "    domain = Natural)\n",
-    "    )\n",
-    ")"
+    "not_power_set_def = Forall((x, S), Equals(NotInSet(x, PowerSet(S)), Not(InSet(x, PowerSet(S)))))"
    ]
   },
   {
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb
index 8015eaa0d318..7e811e0cd75d 100644
--- a/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb
@@ -16,7 +16,7 @@
    "source": [
     "import proveit\n",
     "from proveit import A\n",
-    "from proveit.logic import InSet, KElemSubsets, PowerSet, Set\n",
+    "from proveit.logic import InSet, NotInSet, NotSubsetEq, PowerSet, Set, SubsetEq\n",
     "from proveit.numbers import one, two, three\n",
     "%begin demonstrations"
    ]
@@ -25,7 +25,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "### Power Sets and k-Element Subsets: $\\mathcal{P}(S)$, $\\left[S\\right]^{k}$"
+    "### Power Set: $\\mathcal{P}(S)$"
    ]
   },
   {
@@ -60,13 +60,107 @@
     "InSet(A, PowerSet(Set(one, two)))"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing `PowerSetMembership.definition()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(A, PowerSet(Set(one, two, three))).definition()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing `PowerSetMembership.as_defined()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(A, PowerSet(Set(one, two, three))).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing `PowerSetMembership.unfold()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(A, PowerSet(Set(one, two, three))).unfold(assumptions = [InSet(A, PowerSet(Set(one, two, three)))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing `PowerSetMembership.conclude()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(A, PowerSet(Set(one, two, three))).conclude(assumptions = [SubsetEq(A, Set(one, two, three))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing `PowerSetNonmembership.definition()`"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
    "source": [
-    "KElemSubsets(Set(one, two, three), two)"
+    "NotInSet(A, PowerSet(Set(one, two, three))).definition()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing `PowerSetNonmembership.as_defined()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(A, PowerSet(Set(one, two, three))).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing `PowerSetNonmembership.conclude()`"
    ]
   },
   {
@@ -75,7 +169,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(A, KElemSubsets(Set(one, two, three), two))"
+    "NotInSet(A, PowerSet(Set(one, two, three))).conclude(assumptions = [NotSubsetEq(A, Set(one, two, three))])"
    ]
   },
   {
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_not_in_power_set/allowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_not_in_power_set/allowed_presumptions.txt
new file mode 100644
index 000000000000..d9e192377716
--- /dev/null
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_not_in_power_set/allowed_presumptions.txt
@@ -0,0 +1,2 @@
+proveit.logic.sets.power_set.not_in_power_set_equiv
+proveit.logic.equality.lhs_via_equality
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_k_elem_subsets_def/disallowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_not_in_power_set/disallowed_presumptions.txt
similarity index 100%
rename from packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_k_elem_subsets_def/disallowed_presumptions.txt
rename to packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_not_in_power_set/disallowed_presumptions.txt
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_k_elem_subsets_def/thm_proof.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_not_in_power_set/thm_proof.ipynb
similarity index 80%
rename from packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_k_elem_subsets_def/thm_proof.ipynb
rename to packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_not_in_power_set/thm_proof.ipynb
index 79b3e40bccc9..1da84a8c05bf 100644
--- a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_k_elem_subsets_def/thm_proof.ipynb
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_not_in_power_set/thm_proof.ipynb
@@ -4,7 +4,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">power_set</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#unfold_k_elem_subsets_def\">unfold_k_elem_subsets_def</a> theorem\n",
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">power_set</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#fold_not_in_power_set\">fold_not_in_power_set</a> theorem\n",
     "========"
    ]
   },
@@ -18,7 +18,7 @@
     "theory = proveit.Theory() # the theorem's theory\n",
     "\n",
     "from proveit import defaults\n",
-    "from proveit.logic.sets.power_set import k_elem_subsets_def"
+    "from proveit.logic.sets.power_set import not_in_power_set_equiv"
    ]
   },
   {
@@ -27,7 +27,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "%proving unfold_k_elem_subsets_def"
+    "%proving fold_not_in_power_set"
    ]
   },
   {
@@ -36,7 +36,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "defaults.assumptions = unfold_k_elem_subsets_def.all_conditions()"
+    "defaults.assumptions = fold_not_in_power_set.all_conditions()"
    ]
   },
   {
@@ -45,7 +45,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "k_elem_subsets_def"
+    "not_in_power_set_equiv"
    ]
   },
   {
@@ -54,7 +54,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "k_elem_subsets_def_inst = k_elem_subsets_def.instantiate().instantiate()"
+    "not_in_power_set_equiv_inst = not_in_power_set_equiv.instantiate()"
    ]
   },
   {
@@ -63,7 +63,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "k_elem_subsets_def_inst.derive_right_via_equality()"
+    "not_in_power_set_equiv_inst.derive_left_via_equality()"
    ]
   },
   {
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_k_elem_subsets_def/allowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set/allowed_presumptions.txt
similarity index 100%
rename from packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_k_elem_subsets_def/allowed_presumptions.txt
rename to packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set/allowed_presumptions.txt
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/disallowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set/disallowed_presumptions.txt
similarity index 100%
rename from packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/disallowed_presumptions.txt
rename to packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set/disallowed_presumptions.txt
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/thm_proof.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set/thm_proof.ipynb
similarity index 92%
rename from packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/thm_proof.ipynb
rename to packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set/thm_proof.ipynb
index 343025835fac..51bd510e64e4 100644
--- a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/thm_proof.ipynb
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set/thm_proof.ipynb
@@ -4,7 +4,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">power_set</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#fold_power_set_def\">fold_power_set_def</a> theorem\n",
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">power_set</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#fold_power_set\">fold_power_set</a> theorem\n",
     "========"
    ]
   },
@@ -27,7 +27,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "%proving fold_power_set_def"
+    "%proving fold_power_set"
    ]
   },
   {
@@ -36,7 +36,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "defaults.assumptions = fold_power_set_def.all_conditions()"
+    "defaults.assumptions = fold_power_set.all_conditions()"
    ]
   },
   {
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/allowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/allowed_presumptions.txt
deleted file mode 100644
index df2d242c76be..000000000000
--- a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_power_set_def/allowed_presumptions.txt
+++ /dev/null
@@ -1 +0,0 @@
-proveit.logic.equality.lhs_via_equality
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/not_in_power_set_equiv/allowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/not_in_power_set_equiv/allowed_presumptions.txt
new file mode 100644
index 000000000000..825fbc520dc4
--- /dev/null
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/not_in_power_set_equiv/allowed_presumptions.txt
@@ -0,0 +1,2 @@
+proveit.logic.equality.sub_right_side_into
+proveit.logic.equality.equals_reversal
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_k_elem_subsets_def/disallowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/not_in_power_set_equiv/disallowed_presumptions.txt
similarity index 100%
rename from packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_k_elem_subsets_def/disallowed_presumptions.txt
rename to packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/not_in_power_set_equiv/disallowed_presumptions.txt
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/not_in_power_set_equiv/thm_proof.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/not_in_power_set_equiv/thm_proof.ipynb
new file mode 100644
index 000000000000..0b447a952f37
--- /dev/null
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/not_in_power_set_equiv/thm_proof.ipynb
@@ -0,0 +1,132 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">power_set</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#not_in_power_set_equiv\">not_in_power_set_equiv</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import x, A, B, S, defaults\n",
+    "from proveit.logic.sets.inclusion import not_subset_eq_def\n",
+    "from proveit.logic.sets.power_set import not_power_set_def, power_set_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving not_in_power_set_equiv"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = not_in_power_set_equiv.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_power_set_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_power_set_def_inst = not_power_set_def.instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "power_set_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "power_set_def_inst = power_set_def.instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "power_set_def_inst.sub_right_side_into(not_power_set_def_inst)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_subset_eq_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_subset_eq_def_inst = not_subset_eq_def.instantiate({A:x, B:S})"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_not_in_power_set/allowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_not_in_power_set/allowed_presumptions.txt
new file mode 100644
index 000000000000..841553163c28
--- /dev/null
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_not_in_power_set/allowed_presumptions.txt
@@ -0,0 +1,2 @@
+proveit.logic.sets.power_set.not_in_power_set_equiv
+proveit.logic.equality.rhs_via_equality
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/disallowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_not_in_power_set/disallowed_presumptions.txt
similarity index 100%
rename from packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/disallowed_presumptions.txt
rename to packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_not_in_power_set/disallowed_presumptions.txt
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_k_elem_subsets_def/thm_proof.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_not_in_power_set/thm_proof.ipynb
similarity index 81%
rename from packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_k_elem_subsets_def/thm_proof.ipynb
rename to packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_not_in_power_set/thm_proof.ipynb
index 33ef5a00985b..e95c3312e22d 100644
--- a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/fold_k_elem_subsets_def/thm_proof.ipynb
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_not_in_power_set/thm_proof.ipynb
@@ -4,7 +4,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">power_set</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#fold_k_elem_subsets_def\">fold_k_elem_subsets_def</a> theorem\n",
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">power_set</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#unfold_not_in_power_set\">unfold_not_in_power_set</a> theorem\n",
     "========"
    ]
   },
@@ -18,7 +18,7 @@
     "theory = proveit.Theory() # the theorem's theory\n",
     "\n",
     "from proveit import defaults\n",
-    "from proveit.logic.sets.power_set import k_elem_subsets_def"
+    "from proveit.logic.sets.power_set import not_in_power_set_equiv"
    ]
   },
   {
@@ -27,7 +27,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "%proving fold_k_elem_subsets_def"
+    "%proving unfold_not_in_power_set"
    ]
   },
   {
@@ -36,7 +36,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "defaults.assumptions = fold_k_elem_subsets_def.all_conditions()"
+    "defaults.assumptions = unfold_not_in_power_set.all_conditions()"
    ]
   },
   {
@@ -45,7 +45,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "k_elem_subsets_def"
+    "not_in_power_set_equiv"
    ]
   },
   {
@@ -54,7 +54,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "k_elem_subsets_def_inst = k_elem_subsets_def.instantiate().instantiate()"
+    "not_in_power_set_equiv_inst = not_in_power_set_equiv.instantiate()"
    ]
   },
   {
@@ -63,7 +63,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "k_elem_subsets_def_inst.derive_left_via_equality()"
+    "not_in_power_set_equiv_inst.derive_right_via_equality()"
    ]
   },
   {
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_k_elem_subsets_def/allowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set/allowed_presumptions.txt
similarity index 100%
rename from packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_k_elem_subsets_def/allowed_presumptions.txt
rename to packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set/allowed_presumptions.txt
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set/disallowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/thm_proof.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set/thm_proof.ipynb
similarity index 91%
rename from packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/thm_proof.ipynb
rename to packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set/thm_proof.ipynb
index bd0ca86a837e..7847228125cc 100644
--- a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/thm_proof.ipynb
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set/thm_proof.ipynb
@@ -4,7 +4,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">power_set</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#unfold_power_set_def\">unfold_power_set_def</a> theorem\n",
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">power_set</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#unfold_power_set\">unfold_power_set</a> theorem\n",
     "========"
    ]
   },
@@ -27,7 +27,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "%proving unfold_power_set_def"
+    "%proving unfold_power_set"
    ]
   },
   {
@@ -36,7 +36,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "defaults.assumptions = unfold_power_set_def.all_conditions()"
+    "defaults.assumptions = unfold_power_set.all_conditions()"
    ]
   },
   {
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/allowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/allowed_presumptions.txt
deleted file mode 100644
index cc2c81dedc51..000000000000
--- a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/unfold_power_set_def/allowed_presumptions.txt
+++ /dev/null
@@ -1 +0,0 @@
-proveit.logic.equality.rhs_via_equality
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/theorems.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/theorems.ipynb
index 75ae907b5f19..6e2c1ad39159 100644
--- a/packages/proveit/logic/sets/power_set/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/theorems.ipynb
@@ -20,7 +20,7 @@
     "\n",
     "from proveit import k, x, A, S\n",
     "from proveit.logic import And, Equals, Forall\n",
-    "from proveit.logic.sets import Card, InSet, KElemSubsets, PowerSet, SubsetEq\n",
+    "from proveit.logic.sets import Card, InSet, NotInSet, NotSubsetEq, PowerSet, SubsetEq\n",
     "from proveit.numbers import LessEq, Natural"
    ]
   },
@@ -39,7 +39,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "unfold_power_set_def = Forall((x, S), SubsetEq(x, S),\n",
+    "unfold_power_set = Forall((x, S), SubsetEq(x, S),\n",
     "       conditions = [InSet(x, PowerSet(S))])"
    ]
   },
@@ -49,7 +49,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "fold_power_set_def = Forall((x, S), InSet(x, PowerSet(S)),\n",
+    "fold_power_set = Forall((x, S), InSet(x, PowerSet(S)),\n",
     "       conditions = [SubsetEq(x, S)])"
    ]
   },
@@ -59,13 +59,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "unfold_k_elem_subsets_def = (\n",
-    "    Forall((A, S),\n",
-    "    Forall(k, And(SubsetEq(A, S), Equals(Card(A), k)),\n",
-    "    conditions = [LessEq(k, Card(S)), InSet(A, KElemSubsets(S, k))],\n",
-    "    domain = Natural)\n",
-    "    )\n",
-    ")"
+    "not_in_power_set_equiv = Forall((x, S), Equals(NotInSet(x, PowerSet(S)), NotSubsetEq(x, S)))"
    ]
   },
   {
@@ -74,13 +68,18 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "fold_k_elem_subsets_def = (\n",
-    "    Forall((A, S),\n",
-    "    Forall(k, InSet(A, KElemSubsets(S, k)),\n",
-    "    conditions = [LessEq(k, Card(S)), And(SubsetEq(A, S), Equals(Card(A), k))],\n",
-    "    domain = Natural)\n",
-    "    )\n",
-    ")"
+    "unfold_not_in_power_set = Forall((x, S), NotSubsetEq(x, S),\n",
+    "        conditions = [NotInSet(x, PowerSet(S))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "fold_not_in_power_set = Forall((x, S), NotInSet(x, PowerSet(S)),\n",
+    "        conditions = [NotSubsetEq(x, S)])"
    ]
   },
   {
diff --git a/packages/proveit/logic/sets/power_set/power_set_membership.py b/packages/proveit/logic/sets/power_set/power_set_membership.py
index 70cb57c89a82..0a4b97b776cd 100644
--- a/packages/proveit/logic/sets/power_set/power_set_membership.py
+++ b/packages/proveit/logic/sets/power_set/power_set_membership.py
@@ -1,21 +1,120 @@
+from proveit import x, S, equality_prover, prover
 from proveit.logic import SetMembership, SetNonmembership
 
 
 class PowerSetMembership(SetMembership):
     '''
-    Defines methods that apply to membership in the power set P(S) of
-    a set S.
+    Defines methods that apply to membership in the power set,
+    PowerSet(S), of a set S.
     '''
 
     def __init__(self, element, domain):
         SetMembership.__init__(self, element, domain)
 
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        Deduce and return 
+            [element in PowerSet(S)] = [SubsetEq(element, S)]
+        where self = [element in PowerSet(S)].
+        '''
+        from . import power_set_def
+        element = self.element
+        operand = self.domain.operand
+        _x_sub = element
+        _S_sub = operand
+        return power_set_def.instantiate(
+                {x: _x_sub, S: _S_sub}, auto_simplify=False)
 
-class PowerSetNonembership(SetNonmembership):
+    def as_defined(self):
+        '''
+        From self=[elem in PowerSet(S)], return [SubsetEq(element, S)]
+        (i.e., not a Judgment).
+        '''
+        from proveit.logic import SubsetEq
+        element = self.element
+        return SubsetEq(element, self.domain.operand)
+
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        From TRUE or assumed self = [element in PowerSet(S)],
+        derive and return [SubsetEq(element, S)].
+        '''
+        from . import unfold_power_set
+        element = self.element
+        operand = self.domain.operand
+        _x_sub = element
+        _S_sub = operand
+        return unfold_power_set.instantiate(
+            {x: _x_sub, S: _S_sub}, auto_simplify=False)
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Called on self = [elem in PowerSet(S)], and knowing or
+        assuming [SubsetEq(elem, S)], derive and
+        return self.
+        '''
+        from . import fold_power_set
+        element = self.element
+        operand = self.domain.operand
+        _x_sub = element
+        _S_sub = operand
+        return fold_power_set.instantiate(
+            {x: _x_sub, S: _S_sub}, auto_simplify=False)
+
+
+class PowerSetNonmembership(SetNonmembership):
     '''
-    Defines methods that apply to non-membership in the set of
-    k-element subsets of a set.
+    Defines methods that apply to non-membership in the power set,
+    PowerSet(S), of a set S.
     '''
 
     def __init__(self, element, domain):
         SetNonmembership.__init__(self, element, domain)
+
+    def side_effects(self, judgment):
+        '''
+        Currently no side-effects for PowerSet nonmembership.
+        '''
+        return
+        yield
+
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self=[elem not in PowerSet(S)], deduce and return
+            |- [elem not in PowerSet(S)] = [NotSubsetEq(elem, S)].
+        '''
+        from . import not_in_power_set_equiv
+        element = self.element
+        operand = self.domain.operand
+        _x_sub = element
+        _S_sub = operand
+        return not_in_power_set_equiv.instantiate(
+            {x: _x_sub, S: _S_sub}, auto_simplify=False)
+
+
+    def as_defined(self):
+        '''
+        From self=[elem not in PowerSet(S)], return
+        [NotSubsetEq(elem, S)] (i.e., not as a Judgment).
+        '''
+        from proveit.logic import NotSubsetEq
+        element = self.element
+        return NotSubsetEq(element, self.domain.operand)
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Called on the self = [elem not in PowerSet(S)], from known
+        or assumed [NotSubsetEq(elem, S)], derive and return self.
+        '''
+        from . import fold_not_in_power_set
+        element = self.element
+        operand = self.domain.operand
+        _x_sub = element
+        _S_sub = operand
+        return fold_not_in_power_set.instantiate(
+            {x: _x_sub, S: _S_sub})

From 7ab4d3ebee1b843d885b3feeff9f9ecfb9c5ae95 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 23 Apr 2025 18:01:31 -0500
Subject: [PATCH 023/159] Remove redundant power_set axiom and update related
 theorem proof

Remove redundant power_set axiom (defining not_in_power_set), redundant because we already have an axiomatic definition of  "not in set", and update related theorem proof to use the more general not_in_set_def.
---
 .../sets/power_set/_theory_nbs_/axioms.ipynb     |  9 ---------
 .../power_set/_theory_nbs_/demonstrations.ipynb  |  7 +++++++
 .../allowed_presumptions.txt                     |  2 +-
 .../not_in_power_set_equiv/thm_proof.ipynb       | 16 ++++++++++------
 4 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/axioms.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/axioms.ipynb
index 8bd23a909328..97058c48a7c9 100644
--- a/packages/proveit/logic/sets/power_set/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/axioms.ipynb
@@ -41,15 +41,6 @@
     "                                      SubsetEq(x, S)))"
    ]
   },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "not_power_set_def = Forall((x, S), Equals(NotInSet(x, PowerSet(S)), Not(InSet(x, PowerSet(S)))))"
-   ]
-  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb
index 7e811e0cd75d..211d3036e2d2 100644
--- a/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb
@@ -60,6 +60,13 @@
     "InSet(A, PowerSet(Set(one, two)))"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Method Testing"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/not_in_power_set_equiv/allowed_presumptions.txt b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/not_in_power_set_equiv/allowed_presumptions.txt
index 825fbc520dc4..7aff58fec040 100644
--- a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/not_in_power_set_equiv/allowed_presumptions.txt
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/not_in_power_set_equiv/allowed_presumptions.txt
@@ -1,2 +1,2 @@
 proveit.logic.equality.sub_right_side_into
-proveit.logic.equality.equals_reversal
+proveit.logic.equality.sub_left_side_into
diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/not_in_power_set_equiv/thm_proof.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/not_in_power_set_equiv/thm_proof.ipynb
index 0b447a952f37..148bce242fdb 100644
--- a/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/not_in_power_set_equiv/thm_proof.ipynb
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/proofs/not_in_power_set_equiv/thm_proof.ipynb
@@ -18,8 +18,10 @@
     "theory = proveit.Theory() # the theorem's theory\n",
     "\n",
     "from proveit import x, A, B, S, defaults\n",
+    "from proveit.logic.sets import PowerSet\n",
     "from proveit.logic.sets.inclusion import not_subset_eq_def\n",
-    "from proveit.logic.sets.power_set import not_power_set_def, power_set_def"
+    "from proveit.logic.sets.membership import not_in_set_def\n",
+    "from proveit.logic.sets.power_set import power_set_def"
    ]
   },
   {
@@ -46,7 +48,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "not_power_set_def"
+    "not_in_set_def"
    ]
   },
   {
@@ -55,7 +57,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "not_power_set_def_inst = not_power_set_def.instantiate()"
+    "not_in_set_def_inst = not_in_set_def.instantiate({x:x, S:PowerSet(S)})"
    ]
   },
   {
@@ -82,7 +84,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "power_set_def_inst.sub_right_side_into(not_power_set_def_inst)"
+    "x_not_in_power_set_eq_not_x_subset = power_set_def_inst.sub_right_side_into(not_in_set_def_inst)"
    ]
   },
   {
@@ -109,7 +111,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "%qed"
+    "not_subset_eq_def_inst.sub_left_side_into(x_not_in_power_set_eq_not_x_subset)"
    ]
   },
   {
@@ -117,7 +119,9 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "%qed"
+   ]
   }
  ],
  "metadata": {

From 27c22e594bdb30813ccdae92a72c3b8381beeb58 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 24 Apr 2025 10:41:35 -0500
Subject: [PATCH 024/159] Add PowerSetNonmembership.unfold() method

Update the PowerSetNonmembership() class (in logic/sets/power_set_membership) with unfold() method (previously overlooked). Update power_set_membership demonstrations nb to accommodate.
---
 .../_theory_nbs_/demonstrations.ipynb          | 18 ++++++++++++++++++
 .../sets/power_set/power_set_membership.py     | 14 ++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb b/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb
index 211d3036e2d2..6b2fff2efa5e 100644
--- a/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/logic/sets/power_set/_theory_nbs_/demonstrations.ipynb
@@ -163,6 +163,24 @@
     "NotInSet(A, PowerSet(Set(one, two, three))).as_defined()"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing `PowerSetNonmembership.unfold()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(A, PowerSet(Set(one, two, three))).unfold(\n",
+    "    assumptions = [NotInSet(A, PowerSet(Set(one, two, three)))]\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
diff --git a/packages/proveit/logic/sets/power_set/power_set_membership.py b/packages/proveit/logic/sets/power_set/power_set_membership.py
index 0a4b97b776cd..d13a5fab06d6 100644
--- a/packages/proveit/logic/sets/power_set/power_set_membership.py
+++ b/packages/proveit/logic/sets/power_set/power_set_membership.py
@@ -105,6 +105,20 @@ def as_defined(self):
         element = self.element
         return NotSubsetEq(element, self.domain.operand)
 
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        From TRUE or assumed self = [element not in PowerSet(S)],
+        derive and return [NotSubsetEq(element, S)].
+        '''
+        from . import unfold_not_in_power_set
+        element = self.element
+        operand = self.domain.operand
+        _x_sub = element
+        _S_sub = operand
+        return unfold_not_in_power_set.instantiate(
+            {x: _x_sub, S: _S_sub}, auto_simplify=False)
+
     @prover
     def conclude(self, **defaults_config):
         '''

From 3d8d48c9a9b343df232f18b3381ad67f31bce7c7 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 24 Apr 2025 10:47:03 -0500
Subject: [PATCH 025/159] Update k_power_set and k_power_set_membership
 packages

Update k_power_set and k_power_set_membership packages: cleaning up k_power_set.py; elaborating standard methods for the KPowerSetMembership and KPowerSetNonmembership classes; adding basic theorems for KPowerSetMembership and KPowerSetNonmembership; establishing proofs of several of the basic theorems; updating the k_power_set_membership demonstrations.ipynb notebook.
---
 .../_theory_nbs_/demonstrations.ipynb         | 186 +++++++++++++++++-
 .../fold_k_power_set/allowed_presumptions.txt |   1 +
 .../disallowed_presumptions.txt               |   0
 .../proofs/fold_k_power_set/thm_proof.ipynb   |  95 +++++++++
 .../fold_not_in_k_power_set/thm_proof.ipynb   |  47 +++++
 .../allowed_presumptions.txt                  |   2 +
 .../disallowed_presumptions.txt               |   0
 .../not_in_k_power_set_equiv/thm_proof.ipynb  | 181 +++++++++++++++++
 .../allowed_presumptions.txt                  |   1 +
 .../disallowed_presumptions.txt               |   0
 .../proofs/unfold_k_power_set/thm_proof.ipynb |  95 +++++++++
 .../allowed_presumptions.txt                  |   1 +
 .../disallowed_presumptions.txt               |   0
 .../unfold_not_in_k_power_set/thm_proof.ipynb |  68 +++++++
 .../k_power_set/_theory_nbs_/theorems.ipynb   |  81 +++++++-
 .../logic/sets/k_power_set/k_power_set.py     |  20 +-
 .../k_power_set/k_power_set_membership.py     | 132 ++++++++++++-
 17 files changed, 892 insertions(+), 18 deletions(-)
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_k_power_set/allowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_k_power_set/disallowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_k_power_set/thm_proof.ipynb
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_not_in_k_power_set/thm_proof.ipynb
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/not_in_k_power_set_equiv/allowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/not_in_k_power_set_equiv/disallowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/not_in_k_power_set_equiv/thm_proof.ipynb
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_k_power_set/allowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_k_power_set/disallowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_k_power_set/thm_proof.ipynb
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_not_in_k_power_set/allowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_not_in_k_power_set/disallowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_not_in_k_power_set/thm_proof.ipynb

diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/demonstrations.ipynb b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/demonstrations.ipynb
index 0a114a22e14c..08eb6da8d651 100644
--- a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/demonstrations.ipynb
@@ -15,7 +15,101 @@
    "outputs": [],
    "source": [
     "import proveit\n",
-    "%begin demonstrations"
+    "%begin demonstrations\n",
+    "\n",
+    "from proveit import A\n",
+    "from proveit.logic import And, Equals, NotEquals\n",
+    "from proveit.logic.sets import (\n",
+    "        Card, InSet, KPowerSet, NotInSet, NotSubsetEq, Set, SubsetEq)\n",
+    "from proveit.numbers import one, two, three, four"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `KPowerSet(S)`, the Set of k-Element Subsets of Set $S$:\n",
+    "\n",
+    "### $[S]^{k} = \\{A | (A \\subseteq S) \\land |A|=k\\}$"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### MISC. TESTING"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Basic Constructions"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "KPowerSet(Set(one, two, three), two)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(A, KPowerSet(Set(one, two, three), two))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Method Testing"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing `KPowerSetMembership.definition()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# somewhat surprisingly, we have to assume the correct cardinality for the enumerated set\n",
+    "InSet(A, KPowerSet(Set(one, two, three), two)).definition(assumptions=[Equals(Card(Set(one, two, three)), three)])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing `KPowerSetMembership.as_defined()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(A, KPowerSet(Set(one, two, three), two)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing `KPowerSetMembership.unfold()`"
    ]
   },
   {
@@ -23,7 +117,95 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "InSet(A, KPowerSet(Set(one, two, three), two)).unfold(\n",
+    "    assumptions=[InSet(A, KPowerSet(Set(one, two, three), two)), Equals(Card(Set(one, two, three)), three)])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing `KPowerSetMembership.conclude()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(A, KPowerSet(Set(one, two, three), two)).conclude(\n",
+    "    assumptions=[And(SubsetEq(A, Set(one, two, three)), Equals(Card(A), two)), Equals(Card(Set(one, two, three)), three)])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing `KPowerSetNonmembership.definition()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(A, KPowerSet(Set(one, two, three), two)).definition(assumptions = [Equals(Card(Set(one, two, three)), three)])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing `KPowerSetNonmembership.as_defined()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(A, KPowerSet(Set(one, two, three), two)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing `KPowerSetNonmembership.unfold()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(A, KPowerSet(Set(one, two, three), two)).unfold(\n",
+    "    assumptions = [NotInSet(A, KPowerSet(Set(one, two, three), two)), Equals(Card(Set(one, two, three)), three)]\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing `KPowerSetNonmembership.conclude()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(A, KPowerSet(Set(one, two, three), two)).conclude(\n",
+    "    assumptions = [And(NotSubsetEq(A, Set(one, two, three)), NotEquals(Card(A), two)),\n",
+    "                   Equals(Card(Set(one, two, three)), three)])"
+   ]
   },
   {
    "cell_type": "code",
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_k_power_set/allowed_presumptions.txt b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_k_power_set/allowed_presumptions.txt
new file mode 100644
index 000000000000..df2d242c76be
--- /dev/null
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_k_power_set/allowed_presumptions.txt
@@ -0,0 +1 @@
+proveit.logic.equality.lhs_via_equality
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_k_power_set/disallowed_presumptions.txt b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_k_power_set/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_k_power_set/thm_proof.ipynb b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_k_power_set/thm_proof.ipynb
new file mode 100644
index 000000000000..8c3a1ca90b8e
--- /dev/null
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_k_power_set/thm_proof.ipynb
@@ -0,0 +1,95 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">k_power_set</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#fold_k_power_set\">fold_k_power_set</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.logic.sets.k_power_set import k_power_set_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving fold_k_power_set"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = fold_k_power_set.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "k_power_set_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "k_power_set_def_inst = k_power_set_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "k_power_set_def_inst.derive_left_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_not_in_k_power_set/thm_proof.ipynb b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_not_in_k_power_set/thm_proof.ipynb
new file mode 100644
index 000000000000..0244167e6d76
--- /dev/null
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_not_in_k_power_set/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">k_power_set</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#fold_not_in_k_power_set\">fold_not_in_k_power_set</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving fold_not_in_k_power_set"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/not_in_k_power_set_equiv/allowed_presumptions.txt b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/not_in_k_power_set_equiv/allowed_presumptions.txt
new file mode 100644
index 000000000000..0531e29d50c6
--- /dev/null
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/not_in_k_power_set_equiv/allowed_presumptions.txt
@@ -0,0 +1,2 @@
+proveit.logic.equality.sub_right_side_into
+proveit.logic.booleans.conjunction.demorgans_law_or_to_and_bin
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/not_in_k_power_set_equiv/disallowed_presumptions.txt b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/not_in_k_power_set_equiv/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/not_in_k_power_set_equiv/thm_proof.ipynb b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/not_in_k_power_set_equiv/thm_proof.ipynb
new file mode 100644
index 000000000000..8cd4e4d1454b
--- /dev/null
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/not_in_k_power_set_equiv/thm_proof.ipynb
@@ -0,0 +1,181 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">k_power_set</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#not_in_k_power_set_equiv\">not_in_k_power_set_equiv</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import k, x, A, S, defaults\n",
+    "from proveit.logic import Equals, Not, Or\n",
+    "from proveit.logic.sets import SubsetEq\n",
+    "from proveit.logic.sets.membership import not_in_set_def\n",
+    "from proveit.logic.sets.k_power_set import k_power_set_def, KPowerSet"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving not_in_k_power_set_equiv"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = not_in_k_power_set_equiv.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "a_not_in_k_power_set = not_in_k_power_set_equiv.instance_expr.instance_expr.lhs"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = defaults.assumptions + [a_not_in_k_power_set]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_in_set_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "a_not_k_power_set_01 = not_in_set_def.instantiate({x:A, S:KPowerSet(S, k)})"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "assert False"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "k_power_set_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "k_power_set_def_inst = k_power_set_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_in_set_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "a_not_k_power_set_01 = not_in_set_def.instantiate({x:A, S:KPowerSet(S, k)})"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "a_not_k_power_set_02 = k_power_set_def_inst.sub_right_side_into(a_not_k_power_set_01)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "negated_conjunction = a_not_k_power_set_02.rhs"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "conj = negated_conjunction.operand"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "disjunction_of_negations = Or(Not(negated_conjunction.operand.operands[0]), Not(negated_conjunction.operand.operands[1]))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "conj.conclude_via_demorgans(assumptions = [Not(disjunction_of_negations)])"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_k_power_set/allowed_presumptions.txt b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_k_power_set/allowed_presumptions.txt
new file mode 100644
index 000000000000..cc2c81dedc51
--- /dev/null
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_k_power_set/allowed_presumptions.txt
@@ -0,0 +1 @@
+proveit.logic.equality.rhs_via_equality
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_k_power_set/disallowed_presumptions.txt b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_k_power_set/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_k_power_set/thm_proof.ipynb b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_k_power_set/thm_proof.ipynb
new file mode 100644
index 000000000000..e37dbec9931d
--- /dev/null
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_k_power_set/thm_proof.ipynb
@@ -0,0 +1,95 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">k_power_set</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#unfold_k_power_set\">unfold_k_power_set</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.logic.sets.k_power_set import k_power_set_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving unfold_k_power_set"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = unfold_k_power_set.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "k_power_set_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "k_power_set_def_inst = k_power_set_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "k_power_set_def_inst.derive_right_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_not_in_k_power_set/allowed_presumptions.txt b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_not_in_k_power_set/allowed_presumptions.txt
new file mode 100644
index 000000000000..0d975a1bf879
--- /dev/null
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_not_in_k_power_set/allowed_presumptions.txt
@@ -0,0 +1 @@
+proveit.logic.sets.k_power_set.not_in_k_power_set_equiv
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_not_in_k_power_set/disallowed_presumptions.txt b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_not_in_k_power_set/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_not_in_k_power_set/thm_proof.ipynb b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_not_in_k_power_set/thm_proof.ipynb
new file mode 100644
index 000000000000..100d8852fdc3
--- /dev/null
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_not_in_k_power_set/thm_proof.ipynb
@@ -0,0 +1,68 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">k_power_set</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#unfold_not_in_k_power_set\">unfold_not_in_k_power_set</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.logic.sets.k_power_set import not_in_k_power_set_equiv"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving unfold_not_in_k_power_set"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = unfold_not_in_k_power_set.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_in_k_power_set_equiv"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/theorems.ipynb b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/theorems.ipynb
index d416fbe83be3..c7e4e2541a35 100644
--- a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/theorems.ipynb
@@ -18,7 +18,11 @@
     "# Prepare this notebook for defining the theorems of a theory:\n",
     "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "# from ... import ..."
+    "from proveit import k, A, S\n",
+    "from proveit.logic import And, Equals, Forall, NotEquals, Or\n",
+    "from proveit.logic.sets import (\n",
+    "        Card, InSet, KPowerSet, NotInSet, NotSubsetEq, PowerSet, SubsetEq)\n",
+    "from proveit.numbers import LessEq, Natural"
    ]
   },
   {
@@ -30,6 +34,81 @@
     "%begin theorems"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "unfold_k_power_set = (\n",
+    "    Forall((A, S),\n",
+    "    Forall(k, And(SubsetEq(A, S), Equals(Card(A), k)),\n",
+    "    conditions = [LessEq(k, Card(S)), InSet(A, KPowerSet(S, k))],\n",
+    "    domain = Natural)\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "fold_k_power_set = (\n",
+    "    Forall((A, S),\n",
+    "    Forall(k, InSet(A, KPowerSet(S, k)),\n",
+    "    conditions = [LessEq(k, Card(S)), And(SubsetEq(A, S), Equals(Card(A), k))],\n",
+    "    domain = Natural)\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_in_k_power_set_equiv = (\n",
+    "    Forall((A, S),\n",
+    "    Forall(k, Equals(NotInSet(A, KPowerSet(S, k)), Or(NotSubsetEq(A, S), NotEquals(Card(A), k))),\n",
+    "    conditions = [LessEq(k, Card(S))],\n",
+    "    domain = Natural)\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "unfold_not_in_k_power_set = (\n",
+    "    Forall((A, S),\n",
+    "    Forall(k, Or(NotSubsetEq(A, S), NotEquals(Card(A), k)),\n",
+    "    conditions = [LessEq(k, Card(S)), NotInSet(A, KPowerSet(S, k))],\n",
+    "    domain = Natural)\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "fold_not_in_k_power_set = (\n",
+    "    Forall((A, S),\n",
+    "    Forall(k, NotInSet(A, KPowerSet(S, k)),\n",
+    "    conditions = [LessEq(k, Card(S)), Or(NotSubsetEq(A, S), NotEquals(Card(A), k))],\n",
+    "    domain = Natural)\n",
+    "    )\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/logic/sets/k_power_set/k_power_set.py b/packages/proveit/logic/sets/k_power_set/k_power_set.py
index d7c3bb322271..d163422691c1 100644
--- a/packages/proveit/logic/sets/k_power_set/k_power_set.py
+++ b/packages/proveit/logic/sets/k_power_set/k_power_set.py
@@ -4,11 +4,11 @@
 
 class KPowerSet(Function):
     '''
-    Given a S and a natural number k <= |S|, KPowerSet(S, k)
+    Given a set S and a natural number k <= |S|, KPowerSet(S, k)
     represents the set of all k-element subsets of S, denoted [S]^{k}.
     Such sets are similar in principle to the PowerSet of S (which
-    contains [S]^{k}) and arise often enough in set theory and 
-    combinatorics to have somewhat standard notation.
+    contains all the elements of [S]^{k}) and arise often enough in
+    set theory and combinatorics to have somewhat standard notation.
     In Prove-It, [S]^{k} arises in the context of graph theory,
     using k = 2 to describe the superset of possible graph edges in
     a simple graph.
@@ -35,12 +35,10 @@ def latex(self, **kwargs):
             r'\left[' + self.operands[0].latex()
                       + r'\right]^{' + self.operands[1].latex() + r'}')
 
-    # TO BE UPDATED ONCE MEMBERSHIP DEFINED
-    
-    # def membership_object(self, element):
-    #     from .k_elem_subsets_membership import KElemSubsetsMembership
-    #     return KElemSubsetsMembership(element, self)
+    def membership_object(self, element):
+        from .k_power_set_membership import KPowerSetMembership
+        return KPowerSetMembership(element, self)
 
-    # def nonmembership_object(self, element):
-    #     from .k_elem_subsets_membership import KElemSubsetsNonmembership
-    #     return KElemSubsetsNonmembership(element, self)
+    def nonmembership_object(self, element):
+        from .k_power_set_membership import KPowerSetNonmembership
+        return KPowerSetNonmembership(element, self)
diff --git a/packages/proveit/logic/sets/k_power_set/k_power_set_membership.py b/packages/proveit/logic/sets/k_power_set/k_power_set_membership.py
index 8066cb8512ae..27c605987229 100644
--- a/packages/proveit/logic/sets/k_power_set/k_power_set_membership.py
+++ b/packages/proveit/logic/sets/k_power_set/k_power_set_membership.py
@@ -1,7 +1,7 @@
-# from proveit import USE_DEFAULTS, equality_prover, prover
-from proveit.logic import SetMembership, SetNonmembership
-# from proveit.numbers import num
-# from proveit import m, A, x
+from proveit import k, A, S, equality_prover, prover
+from proveit.logic import (
+        And, Equals, NotEquals, Or, SetMembership, SetNonmembership)
+from proveit.logic.sets import Card, NotSubsetEq, SubsetEq
 
 
 class KPowerSetMembership(SetMembership):
@@ -13,6 +13,64 @@ class KPowerSetMembership(SetMembership):
     def __init__(self, element, domain):
         SetMembership.__init__(self, element, domain)
 
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        Deduce and return 
+        [elem in KPowerSet(S, k)] = [SubsetEq(elem, S) AND |elem|=k]
+        where self = [element in KPowerSet(S)].
+        '''
+        from . import k_power_set_def
+        element = self.element
+        operands = self.domain.operands
+        _A_sub = element
+        _S_sub = operands[0]
+        _k_sub = operands[1]
+        return k_power_set_def.instantiate(
+                {A:_A_sub, S: _S_sub, k:_k_sub}, auto_simplify=False)
+
+    def as_defined(self):
+        '''
+        From self=[elem in KPowerSet(S, k)], return
+        [SubsetEq(elem, S) AND |elem|=k] (i.e. not a Judgment).
+        '''
+        element = self.element
+        superset = self.domain.operands[0]
+        subset_size = self.domain.operands[1]
+        return And(SubsetEq(element, superset),
+                   Equals(Card(element), subset_size))
+
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        From TRUE or assumed self = [elem in KPowerSet(S, k)],
+        derive and return [SubsetEq(elem, S) AND |elem| = k].
+        '''
+        from . import unfold_k_power_set
+        element = self.element
+        operands = self.domain.operands
+        _A_sub = element
+        _S_sub = operands[0]
+        _k_sub = operands[1]
+        return unfold_k_power_set.instantiate(
+            {A:_A_sub, S: _S_sub, k:_k_sub}, auto_simplify=False)
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Called on self = [elem in KPowerSet(S, k)], and knowing or
+        assuming [SubsetEq(elem, S) AND |elem| =k], derive and
+        return self.
+        '''
+        from . import fold_k_power_set
+        element = self.element
+        operands = self.domain.operands
+        _A_sub = element
+        _S_sub = operands[0]
+        _k_sub = operands[1]
+        return fold_k_power_set.instantiate(
+            {A:_A_sub, S: _S_sub, k:_k_sub}, auto_simplify=False)
+
 
 class KPowerSetNonmembership(SetNonmembership):
     '''
@@ -22,3 +80,69 @@ class KPowerSetNonmembership(SetNonmembership):
 
     def __init__(self, element, domain):
         SetNonmembership.__init__(self, element, domain)
+
+    def side_effects(self, judgment):
+        '''
+        Currently no side-effects for KPowerSet nonmembership.
+        '''
+        return
+        yield
+
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self=[elem not in KPowerSet(S, k)], deduce and return
+            |- [elem not in KPowerSet(S, k)] =
+               [NotSubsetEq(elem, S) OR |elem| != k].
+        '''
+        from . import not_in_k_power_set_equiv
+        element = self.element
+        operands = self.domain.operands
+        _A_sub = element
+        _S_sub = operands[0]
+        _k_sub = operands[1]
+        return not_in_k_power_set_equiv.instantiate(
+            {A:_A_sub, S: _S_sub, k:_k_sub}, auto_simplify=False)
+
+    def as_defined(self):
+        '''
+        From self=[elem not in KPowerSet(S, k)], return
+        [NotSubsetEq(elem, S) OR |elem| != k] (i.e., not a Judgment).
+        '''
+        element = self.element
+        superset = self.domain.operands[0]
+        subset_size = self.domain.operands[1]
+        return Or(NotSubsetEq(element, superset),
+                   NotEquals(Card(element), subset_size))
+
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        From TRUE or assumed self = [elem not in KPowerSet(S, k)],
+        derive and return [NotSubsetEq(elem, S) OR |elem| != k].
+        '''
+        from . import unfold_not_in_k_power_set
+        element = self.element
+        operands = self.domain.operands
+        _A_sub = element
+        _S_sub = operands[0]
+        _k_sub = operands[1]
+        return unfold_not_in_k_power_set.instantiate(
+            {A:_A_sub, S: _S_sub, k:_k_sub}, auto_simplify=False)
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Called on the self = [elem not in KPowerSet(S, k)], from known
+        or assumed [NotSubsetEq(elem, S) OR |elem| != k], derive and 
+        return self.
+        '''
+        from . import fold_not_in_k_power_set
+        element = self.element
+        operands = self.domain.operands
+        _A_sub = element
+        _S_sub = operands[0]
+        _k_sub = operands[1]
+        return fold_not_in_k_power_set.instantiate(
+            {A:_A_sub, S: _S_sub, k:_k_sub}, auto_simplify=False)
+

From 256eb5702d4a62be15763fc63b03c58d05e9d07d Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 24 Apr 2025 17:00:19 -0500
Subject: [PATCH 026/159] Establish proofs of fold & unfold not_in_k_power_set
 theorems

Establish the proofs of fold_not_in_k_power_set & unfold_not_in_k_power_set theorems in the k_power_set package.
---
 .../allowed_presumptions.txt                  |  2 +
 .../disallowed_presumptions.txt               |  0
 .../fold_not_in_k_power_set/thm_proof.ipynb   | 41 ++++++++++++++++++-
 .../allowed_presumptions.txt                  |  1 +
 .../unfold_not_in_k_power_set/thm_proof.ipynb | 27 ++++++++++++
 5 files changed, 70 insertions(+), 1 deletion(-)
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_not_in_k_power_set/allowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_not_in_k_power_set/disallowed_presumptions.txt

diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_not_in_k_power_set/allowed_presumptions.txt b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_not_in_k_power_set/allowed_presumptions.txt
new file mode 100644
index 000000000000..f715d6503bb1
--- /dev/null
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_not_in_k_power_set/allowed_presumptions.txt
@@ -0,0 +1,2 @@
+proveit.logic.sets.k_power_set.not_in_k_power_set_equiv
+proveit.logic.equality.lhs_via_equality
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_not_in_k_power_set/disallowed_presumptions.txt b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_not_in_k_power_set/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_not_in_k_power_set/thm_proof.ipynb b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_not_in_k_power_set/thm_proof.ipynb
index 0244167e6d76..158dd8208b3a 100644
--- a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_not_in_k_power_set/thm_proof.ipynb
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/fold_not_in_k_power_set/thm_proof.ipynb
@@ -15,7 +15,10 @@
    "outputs": [],
    "source": [
     "import proveit\n",
-    "theory = proveit.Theory() # the theorem's theory"
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.logic.sets.k_power_set import not_in_k_power_set_equiv"
    ]
   },
   {
@@ -27,6 +30,42 @@
     "%proving fold_not_in_k_power_set"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = fold_not_in_k_power_set.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_in_k_power_set_equiv_inst = not_in_k_power_set_equiv.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_in_k_power_set_equiv_inst.derive_left_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_not_in_k_power_set/allowed_presumptions.txt b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_not_in_k_power_set/allowed_presumptions.txt
index 0d975a1bf879..5744b061c28f 100644
--- a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_not_in_k_power_set/allowed_presumptions.txt
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_not_in_k_power_set/allowed_presumptions.txt
@@ -1 +1,2 @@
 proveit.logic.sets.k_power_set.not_in_k_power_set_equiv
+proveit.logic.equality.rhs_via_equality
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_not_in_k_power_set/thm_proof.ipynb b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_not_in_k_power_set/thm_proof.ipynb
index 100d8852fdc3..17905d367079 100644
--- a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_not_in_k_power_set/thm_proof.ipynb
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/unfold_not_in_k_power_set/thm_proof.ipynb
@@ -48,6 +48,33 @@
     "not_in_k_power_set_equiv"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_in_k_power_set_equiv_inst = not_in_k_power_set_equiv.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "not_in_k_power_set_equiv_inst.derive_right_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From ffb0c961cd022dd5fd868e62527d4d31c93cf7a3 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 24 Apr 2025 17:09:44 -0500
Subject: [PATCH 027/159] Update graphs axioms to use KPowerSet for edges
 constraint

Update graphs axioms to use KPowerSet(V, 2) for edges constraint in terms of two-element subsets of the set V of vertices.
---
 packages/proveit/graphs/_theory_nbs_/axioms.ipynb | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
index e380e0863bcb..12c6c7c92165 100644
--- a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
@@ -20,7 +20,8 @@
     "\n",
     "from proveit import E, V\n",
     "from proveit.logic import Equals, Forall, InClass, InSet\n",
-    "from proveit.logic.sets import CartProd, SubsetEq\n",
+    "from proveit.logic.sets import CartProd, KPowerSet, SubsetEq\n",
+    "from proveit.numbers import two\n",
     "from proveit.graphs import Edges, Graph, Graphs, Vertices\n"
    ]
   },
@@ -41,7 +42,7 @@
    "source": [
     "graph_v_e_in_graphs = (\n",
     "    Forall(V,\n",
-    "    Forall(E, InClass(Graph(V, E), Graphs()), conditions = [SubsetEq(E, CartProd(V, V))])\n",
+    "    Forall(E, InClass(Graph(V, E), Graphs()), conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
     "    )\n",
     ")"
    ]
@@ -54,7 +55,7 @@
    "source": [
     "vertex_set_of_graph_v_e_is_v = (\n",
     "    Forall(V,\n",
-    "    Forall(E, Equals(Vertices(Graph(V, E)), V), conditions = [SubsetEq(E, CartProd(V, V))])\n",
+    "    Forall(E, Equals(Vertices(Graph(V, E)), V), conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
     "    )\n",
     ")"
    ]
@@ -67,7 +68,7 @@
    "source": [
     "edge_set_of_graph_v_e_is_e = (\n",
     "    Forall(V,\n",
-    "    Forall(E, Equals(Edges(Graph(V, E)), E), conditions = [SubsetEq(E, CartProd(V, V))])\n",
+    "    Forall(E, Equals(Edges(Graph(V, E)), E), conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
     "    )\n",
     ")"
    ]

From a08e417d558b3d09587a59cdabd79b682824be5d Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 24 Apr 2025 17:22:01 -0500
Subject: [PATCH 028/159] Update graphs inclusion axioms & theorems to use
 KPowerSet

Update the graphs/inclusion package axioms & theorems to use KPowerSet(V, 2) instead of Cart(V, V) for the constraint on edge sets E and E'.
---
 .../graphs/inclusion/_theory_nbs_/axioms.ipynb        |  7 ++++---
 .../graphs/inclusion/_theory_nbs_/theorems.ipynb      | 11 ++++++-----
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/inclusion/_theory_nbs_/axioms.ipynb
index aba5efedd6a9..eead97fb19fd 100644
--- a/packages/proveit/graphs/inclusion/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/inclusion/_theory_nbs_/axioms.ipynb
@@ -20,7 +20,8 @@
     "\n",
     "from proveit import E, V\n",
     "from proveit.logic import And, Equals, Forall, Not\n",
-    "from proveit.logic.sets import CartProd, SubsetEq\n",
+    "from proveit.logic.sets import KPowerSet, SubsetEq\n",
+    "from proveit.numbers import two\n",
     "from proveit.graphs import Graph, E_prime, NotSubgraph, Subgraph, V_prime"
    ]
   },
@@ -46,7 +47,7 @@
     "                         Subgraph(Graph(V_prime, E_prime), Graph(V, E)),\n",
     "                         And(SubsetEq(V_prime, V), SubsetEq(E_prime, E))\n",
     "                         ),\n",
-    "                        domains = [CartProd(V, V), CartProd(V_prime, V_prime)])\n",
+    "                        domains = [KPowerSet(V, two), KPowerSet(V_prime, two)])\n",
     "        )\n",
     ")"
    ]
@@ -64,7 +65,7 @@
     "                         NotSubgraph(Graph(V_prime, E_prime), Graph(V, E)),\n",
     "                         Not(Subgraph(Graph(V_prime, E_prime), Graph(V, E)))\n",
     "                         ),\n",
-    "                        domains = [CartProd(V, V), CartProd(V_prime, V_prime)])\n",
+    "                        domains = [KPowerSet(V, two), KPowerSet(V_prime, two)])\n",
     "        )\n",
     ")"
    ]
diff --git a/packages/proveit/graphs/inclusion/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/inclusion/_theory_nbs_/theorems.ipynb
index 75451851fece..ceae4fbfb7b1 100644
--- a/packages/proveit/graphs/inclusion/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/inclusion/_theory_nbs_/theorems.ipynb
@@ -20,7 +20,8 @@
     "\n",
     "from proveit import E, V\n",
     "from proveit.logic import And, Equals, Forall, Not\n",
-    "from proveit.logic.sets import CartProd, SubsetEq\n",
+    "from proveit.logic.sets import KPowerSet, SubsetEq\n",
+    "from proveit.numbers import two\n",
     "from proveit.graphs import Graph, E_prime, NotSubgraph, Subgraph, V_prime"
    ]
   },
@@ -44,7 +45,7 @@
     "                  Forall((E, E_prime),\n",
     "                         And(SubsetEq(V_prime, V), SubsetEq(E_prime, E)),\n",
     "                         conditions = [Subgraph(Graph(V_prime, E_prime), Graph(V, E))],\n",
-    "                         domains = [CartProd(V, V), CartProd(V_prime, V_prime)])\n",
+    "                         domains = [KPowerSet(V, two), KPowerSet(V_prime, two)])\n",
     "        )\n",
     ")"
    ]
@@ -60,7 +61,7 @@
     "                  Forall((E, E_prime),\n",
     "                         Subgraph(Graph(V_prime, E_prime), Graph(V, E)),\n",
     "                         conditions = [And(SubsetEq(V_prime, V), SubsetEq(E_prime, E))],\n",
-    "                         domains = [CartProd(V, V), CartProd(V_prime, V_prime)])\n",
+    "                         domains = [KPowerSet(V, two), KPowerSet(V_prime, two)])\n",
     "        )\n",
     ")"
    ]
@@ -76,7 +77,7 @@
     "                  Forall((E, E_prime),\n",
     "                         Not(Subgraph(Graph(V_prime, E_prime), Graph(V, E))),\n",
     "                         conditions = [NotSubgraph(Graph(V_prime, E_prime), Graph(V, E))],\n",
-    "                         domains = [CartProd(V, V), CartProd(V_prime, V_prime)])\n",
+    "                         domains = [KPowerSet(V, two), KPowerSet(V_prime, two)])\n",
     "        )\n",
     ")"
    ]
@@ -92,7 +93,7 @@
     "                  Forall((E, E_prime),\n",
     "                         NotSubgraph(Graph(V_prime, E_prime), Graph(V, E)),\n",
     "                         conditions = [Not(Subgraph(Graph(V_prime, E_prime), Graph(V, E)))],\n",
-    "                         domains = [CartProd(V, V), CartProd(V_prime, V_prime)])\n",
+    "                         domains = [KPowerSet(V, two), KPowerSet(V_prime, two)])\n",
     "        )\n",
     ")"
    ]

From 3c0c9976942d106c6ae4b8adafd4f631ace68c7f Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 29 Apr 2025 14:24:52 -0500
Subject: [PATCH 029/159] Establish the graphs/endpoints theory package

Establish the graphs/endpoints theory package for representing the endpoints of a path. This also includes a primitive demonstrations.ipynb notebook, but no axiomatic definition(s) yet. Eventually the axiomatic definition(s) will likely involve the fact that, for a non-trivial path (i.e. one having more than one vertex), the endpoints should always be "the" two vertices of degree 1.
---
 packages/proveit/graphs/__init__.py           |   1 +
 packages/proveit/graphs/_sub_theories_.txt    |   5 +-
 .../proveit/graphs/_theory_nbs_/theory.ipynb  |   9 +-
 packages/proveit/graphs/endpoints/__init__.py |   9 ++
 .../graphs/endpoints/_brief_description_.txt  |   1 +
 .../graphs/endpoints/_sub_theories_.txt       |   0
 .../graphs/endpoints/_theory_nbs_/__init__.py |   0
 .../endpoints/_theory_nbs_/axioms.ipynb       |  59 ++++++++++
 .../endpoints/_theory_nbs_/common.ipynb       |  59 ++++++++++
 .../_theory_nbs_/demonstrations.ipynb         | 101 ++++++++++++++++++
 .../endpoints/_theory_nbs_/theorems.ipynb     |  59 ++++++++++
 .../endpoints/_theory_nbs_/theory.ipynb       |  33 ++++++
 .../proveit/graphs/endpoints/endpoints.py     |  31 ++++++
 .../graphs/endpoints/endpoints_membership.py  |  21 ++++
 14 files changed, 386 insertions(+), 2 deletions(-)
 create mode 100644 packages/proveit/graphs/endpoints/__init__.py
 create mode 100644 packages/proveit/graphs/endpoints/_brief_description_.txt
 create mode 100644 packages/proveit/graphs/endpoints/_sub_theories_.txt
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/__init__.py
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/axioms.ipynb
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/common.ipynb
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/theory.ipynb
 create mode 100644 packages/proveit/graphs/endpoints/endpoints.py
 create mode 100644 packages/proveit/graphs/endpoints/endpoints_membership.py

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index d30008dd3049..42f69286e59b 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -1,4 +1,5 @@
 from .graph import Edges, EndPoints, Graph, Graphs, Path, Vertices
+from .endpoints import Endpoints
 from .inclusion import NotSubgraph, Subgraph
 from .membership import (
       GraphMembership, GraphNonmembership, InGraph, NotInGraph)
diff --git a/packages/proveit/graphs/_sub_theories_.txt b/packages/proveit/graphs/_sub_theories_.txt
index 0caf51f0606d..e6076965fd8d 100644
--- a/packages/proveit/graphs/_sub_theories_.txt
+++ b/packages/proveit/graphs/_sub_theories_.txt
@@ -1,4 +1,7 @@
+vertices
+edges
+inclusion
 union
 membership
-inclusion
 paths
+endpoints
diff --git a/packages/proveit/graphs/_theory_nbs_/theory.ipynb b/packages/proveit/graphs/_theory_nbs_/theory.ipynb
index c73a8d0d9dc3..8357d51ace91 100644
--- a/packages/proveit/graphs/_theory_nbs_/theory.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/theory.ipynb
@@ -7,7 +7,7 @@
     "Theory of <a class=\"ProveItLink\" href=\"../../_theory_nbs_/theory.ipynb\">proveit</a>.graphs\n",
     "========\n",
     "\n",
-    "Provide description here."
+    "Basic concepts in graph theory."
    ]
   },
   {
@@ -19,6 +19,13 @@
     "import proveit\n",
     "%theory # toggles between interactive and static modes"
    ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
   }
  ],
  "metadata": {
diff --git a/packages/proveit/graphs/endpoints/__init__.py b/packages/proveit/graphs/endpoints/__init__.py
new file mode 100644
index 000000000000..76d3d1048bdf
--- /dev/null
+++ b/packages/proveit/graphs/endpoints/__init__.py
@@ -0,0 +1,9 @@
+from .endpoints import Endpoints
+
+# KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
+#  Make additions above, or add to sys.modules[__name__].__dict__ below.
+# This allows us to import common expression, axioms, and theorems of
+# the theory package directly from the package.
+import sys
+from proveit._core_.theory import TheoryPackage
+sys.modules[__name__] = TheoryPackage(__name__, __file__, locals())
diff --git a/packages/proveit/graphs/endpoints/_brief_description_.txt b/packages/proveit/graphs/endpoints/_brief_description_.txt
new file mode 100644
index 000000000000..79ae73411a60
--- /dev/null
+++ b/packages/proveit/graphs/endpoints/_brief_description_.txt
@@ -0,0 +1 @@
+basic concepts involving the endpoints of paths
diff --git a/packages/proveit/graphs/endpoints/_sub_theories_.txt b/packages/proveit/graphs/endpoints/_sub_theories_.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/__init__.py b/packages/proveit/graphs/endpoints/_theory_nbs_/__init__.py
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/axioms.ipynb
new file mode 100644
index 000000000000..042a4bbeb5ef
--- /dev/null
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/axioms.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Axioms for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.endpoints</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the axioms of a theory:\n",
+    "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin axioms"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end axioms"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/common.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/common.ipynb
new file mode 100644
index 000000000000..93fb1ef700d5
--- /dev/null
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/common.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Common expressions for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.endpoints</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the common expressions of a theory:\n",
+    "%common_expressions_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin common"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end common"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
new file mode 100644
index 000000000000..7bb71a77f262
--- /dev/null
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
@@ -0,0 +1,101 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Demonstrations for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.endpoints</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%begin demonstrations\n",
+    "\n",
+    "from proveit import e, v, E, G, P, V\n",
+    "from proveit.logic.sets import NotInSet, InSet, SubsetEq\n",
+    "from proveit.graphs import Endpoints, Graph, Paths, Vertices"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Endpoints of a Path $P$ in a Graph $G$: $\\mathrm{Endpts}(P)$"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### MISC. TESTING"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Basic Constructions"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Endpoints(P)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Endpoints(P))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(v, Endpoints(P))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "SubsetEq(Endpoints(P), Vertices(Graph(V, E)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end demonstrations"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
new file mode 100644
index 000000000000..5de92d131006
--- /dev/null
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theorems (or conjectures) for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.endpoints</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the theorems of a theory:\n",
+    "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin theorems"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end theorems"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/theory.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/theory.ipynb
new file mode 100644
index 000000000000..df59d50d32a9
--- /dev/null
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/theory.ipynb
@@ -0,0 +1,33 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theory of <a class=\"ProveItLink\" href=\"../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../_theory_nbs_/theory.ipynb\">graphs</a>.endpoints\n",
+    "========\n",
+    "\n",
+    "Provide description here."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%theory # toggles between interactive and static modes"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/endpoints/endpoints.py b/packages/proveit/graphs/endpoints/endpoints.py
new file mode 100644
index 000000000000..c29b4e1eef37
--- /dev/null
+++ b/packages/proveit/graphs/endpoints/endpoints.py
@@ -0,0 +1,31 @@
+from proveit import Function, Literal
+
+class Endpoints(Function):
+    '''
+    Endpoints(P) denotes the set of two endpoints of a Path P = (V, E),
+    where Path P has vertex set V and edge set E. Endpoints(P) will be
+    a subset of the Path P's vertex set V, and for a non-trivial path
+    consisting of more than one vertex will consist of the 1-degree
+    vertices.
+    Endpoints(P) will not "know" the original path P whence it came.
+    '''
+
+    # the literal operator of the Endpoints operator
+    _operator_ = Literal(
+            string_format='Endpts', latex_format=r'\mathrm{Endpts}',
+            theory=__file__)
+
+    def __init__(self, P, *, styles=None):
+        '''
+        Create the endpoints set EndPts(P) for Path P.
+        '''
+        Function.__init__(
+                self, Endpoints._operator_, P, styles=styles)
+
+    def membership_object(self, element):
+        from .endpoints_membership import EndpointsMembership
+        return EndpointsMembership(element, self)
+
+    def nonmembership_object(self, element):
+        from .endpoints_membership import EndpointsNonmembership
+        return EndpointsNonmembership(element, self)
\ No newline at end of file
diff --git a/packages/proveit/graphs/endpoints/endpoints_membership.py b/packages/proveit/graphs/endpoints/endpoints_membership.py
new file mode 100644
index 000000000000..c2c876ef24cb
--- /dev/null
+++ b/packages/proveit/graphs/endpoints/endpoints_membership.py
@@ -0,0 +1,21 @@
+from proveit.logic import SetMembership, SetNonmembership
+
+
+class EndpointsMembership(SetMembership):
+    '''
+    Defines methods that apply to membership in the set Endpoints(P)
+    of the endpoints of path P.
+    '''
+
+    def __init__(self, element, domain):
+        SetMembership.__init__(self, element, domain)
+
+
+class EndpointsNonmembership(SetNonmembership):
+    '''
+    Defines methods that apply to non-membership in the set 
+    Endpoints(P) of the endpoints of path P.
+    '''
+
+    def __init__(self, element, domain):
+        SetNonmembership.__init__(self, element, domain)
\ No newline at end of file

From f6a90d933f0216ce00fda2f737adaba46dde74c0 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 29 Apr 2025 14:27:31 -0500
Subject: [PATCH 030/159] Update graphs/paths theory pkg with PathsMembership
 class

Update graphs/paths theory package with corresponding PathsMembership and PathsNonmembership classes.
---
 .../paths/_theory_nbs_/demonstrations.ipynb   | 21 ++++++++++++++++++-
 packages/proveit/graphs/paths/paths.py        | 10 ++++++++-
 .../proveit/graphs/paths/paths_membership.py  | 21 +++++++++++++++++++
 3 files changed, 50 insertions(+), 2 deletions(-)
 create mode 100644 packages/proveit/graphs/paths/paths_membership.py

diff --git a/packages/proveit/graphs/paths/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/paths/_theory_nbs_/demonstrations.ipynb
index 0c055623b6c3..bb203fead6fa 100644
--- a/packages/proveit/graphs/paths/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/paths/_theory_nbs_/demonstrations.ipynb
@@ -17,7 +17,8 @@
     "import proveit\n",
     "%begin demonstrations\n",
     "\n",
-    "from proveit import E, G, V\n",
+    "from proveit import E, G, P, V\n",
+    "from proveit.logic.sets import NotInSet, InSet\n",
     "from proveit.graphs import Graph, Paths"
    ]
   },
@@ -60,6 +61,24 @@
     "example_paths = Paths(G)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(P, example_paths)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(P, example_paths)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/paths/paths.py b/packages/proveit/graphs/paths/paths.py
index 54e3e6c76ead..4488674d18da 100644
--- a/packages/proveit/graphs/paths/paths.py
+++ b/packages/proveit/graphs/paths/paths.py
@@ -28,4 +28,12 @@ def __init__(self, G, *, styles=None):
         set V and edge set E.
         '''
         Function.__init__(
-                self, Paths._operator_, G, styles=styles)
\ No newline at end of file
+                self, Paths._operator_, G, styles=styles)
+
+    def membership_object(self, element):
+        from .paths_membership import PathsMembership
+        return PathsMembership(element, self)
+
+    def nonmembership_object(self, element):
+        from .paths_membership import PathsNonmembership
+        return PathsNonmembership(element, self)
\ No newline at end of file
diff --git a/packages/proveit/graphs/paths/paths_membership.py b/packages/proveit/graphs/paths/paths_membership.py
new file mode 100644
index 000000000000..3548f97dbf79
--- /dev/null
+++ b/packages/proveit/graphs/paths/paths_membership.py
@@ -0,0 +1,21 @@
+from proveit.logic import SetMembership, SetNonmembership
+
+
+class PathsMembership(SetMembership):
+    '''
+    Defines methods that apply to membership in the set Paths(G)
+    of all paths in a graph G.
+    '''
+
+    def __init__(self, element, domain):
+        SetMembership.__init__(self, element, domain)
+
+
+class PathsNonmembership(SetNonmembership):
+    '''
+    Defines methods that apply to non-membership in the set Paths(G)
+    of all paths in a graph G.
+    '''
+
+    def __init__(self, element, domain):
+        SetNonmembership.__init__(self, element, domain)
\ No newline at end of file

From 432f2dcaae7092ef4e01aecadc38a3c9632e30b6 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 29 Apr 2025 14:32:58 -0500
Subject: [PATCH 031/159] Establish edges and vertices sub-theory packages

Establish the graphs/edges and graphs/vertices sub-theory packages. No classes, methods, or axioms yet defined.
---
 packages/proveit/graphs/edges/__init__.py     |  9 +++
 .../graphs/edges/_brief_description_.txt      |  1 +
 .../proveit/graphs/edges/_sub_theories_.txt   |  0
 .../graphs/edges/_theory_nbs_/__init__.py     |  0
 .../graphs/edges/_theory_nbs_/axioms.ipynb    | 59 +++++++++++++++++++
 .../graphs/edges/_theory_nbs_/common.ipynb    | 59 +++++++++++++++++++
 .../edges/_theory_nbs_/demonstrations.ipynb   | 47 +++++++++++++++
 .../graphs/edges/_theory_nbs_/theorems.ipynb  | 59 +++++++++++++++++++
 .../graphs/edges/_theory_nbs_/theory.ipynb    | 33 +++++++++++
 packages/proveit/graphs/vertices/__init__.py  |  9 +++
 .../graphs/vertices/_brief_description_.txt   |  1 +
 .../graphs/vertices/_sub_theories_.txt        |  0
 .../graphs/vertices/_theory_nbs_/__init__.py  |  0
 .../graphs/vertices/_theory_nbs_/axioms.ipynb | 59 +++++++++++++++++++
 .../graphs/vertices/_theory_nbs_/common.ipynb | 59 +++++++++++++++++++
 .../_theory_nbs_/demonstrations.ipynb         | 47 +++++++++++++++
 .../vertices/_theory_nbs_/theorems.ipynb      | 59 +++++++++++++++++++
 .../graphs/vertices/_theory_nbs_/theory.ipynb | 33 +++++++++++
 18 files changed, 534 insertions(+)
 create mode 100644 packages/proveit/graphs/edges/__init__.py
 create mode 100644 packages/proveit/graphs/edges/_brief_description_.txt
 create mode 100644 packages/proveit/graphs/edges/_sub_theories_.txt
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/__init__.py
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/axioms.ipynb
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/common.ipynb
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/demonstrations.ipynb
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/theorems.ipynb
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/theory.ipynb
 create mode 100644 packages/proveit/graphs/vertices/__init__.py
 create mode 100644 packages/proveit/graphs/vertices/_brief_description_.txt
 create mode 100644 packages/proveit/graphs/vertices/_sub_theories_.txt
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/__init__.py
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/axioms.ipynb
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/common.ipynb
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/theorems.ipynb
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/theory.ipynb

diff --git a/packages/proveit/graphs/edges/__init__.py b/packages/proveit/graphs/edges/__init__.py
new file mode 100644
index 000000000000..dba3de849ed8
--- /dev/null
+++ b/packages/proveit/graphs/edges/__init__.py
@@ -0,0 +1,9 @@
+
+
+# KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
+#  Make additions above, or add to sys.modules[__name__].__dict__ below.
+# This allows us to import common expression, axioms, and theorems of
+# the theory package directly from the package.
+import sys
+from proveit._core_.theory import TheoryPackage
+sys.modules[__name__] = TheoryPackage(__name__, __file__, locals())
diff --git a/packages/proveit/graphs/edges/_brief_description_.txt b/packages/proveit/graphs/edges/_brief_description_.txt
new file mode 100644
index 000000000000..f030605d7a3d
--- /dev/null
+++ b/packages/proveit/graphs/edges/_brief_description_.txt
@@ -0,0 +1 @@
+basic concepts involving edges in a graph
diff --git a/packages/proveit/graphs/edges/_sub_theories_.txt b/packages/proveit/graphs/edges/_sub_theories_.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/__init__.py b/packages/proveit/graphs/edges/_theory_nbs_/__init__.py
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/axioms.ipynb
new file mode 100644
index 000000000000..c3b6f18e38e2
--- /dev/null
+++ b/packages/proveit/graphs/edges/_theory_nbs_/axioms.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Axioms for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.edges</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the axioms of a theory:\n",
+    "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin axioms"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end axioms"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/common.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/common.ipynb
new file mode 100644
index 000000000000..4f5cd0d8325c
--- /dev/null
+++ b/packages/proveit/graphs/edges/_theory_nbs_/common.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Common expressions for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.edges</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the common expressions of a theory:\n",
+    "%common_expressions_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin common"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end common"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/demonstrations.ipynb
new file mode 100644
index 000000000000..ffc5a49da433
--- /dev/null
+++ b/packages/proveit/graphs/edges/_theory_nbs_/demonstrations.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Demonstrations for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.edges</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%begin demonstrations"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end demonstrations"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/theorems.ipynb
new file mode 100644
index 000000000000..9d6f851d762f
--- /dev/null
+++ b/packages/proveit/graphs/edges/_theory_nbs_/theorems.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theorems (or conjectures) for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.edges</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the theorems of a theory:\n",
+    "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin theorems"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end theorems"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/theory.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/theory.ipynb
new file mode 100644
index 000000000000..9f2732a2722c
--- /dev/null
+++ b/packages/proveit/graphs/edges/_theory_nbs_/theory.ipynb
@@ -0,0 +1,33 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theory of <a class=\"ProveItLink\" href=\"../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../_theory_nbs_/theory.ipynb\">graphs</a>.edges\n",
+    "========\n",
+    "\n",
+    "Provide description here."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%theory # toggles between interactive and static modes"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/vertices/__init__.py b/packages/proveit/graphs/vertices/__init__.py
new file mode 100644
index 000000000000..dba3de849ed8
--- /dev/null
+++ b/packages/proveit/graphs/vertices/__init__.py
@@ -0,0 +1,9 @@
+
+
+# KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
+#  Make additions above, or add to sys.modules[__name__].__dict__ below.
+# This allows us to import common expression, axioms, and theorems of
+# the theory package directly from the package.
+import sys
+from proveit._core_.theory import TheoryPackage
+sys.modules[__name__] = TheoryPackage(__name__, __file__, locals())
diff --git a/packages/proveit/graphs/vertices/_brief_description_.txt b/packages/proveit/graphs/vertices/_brief_description_.txt
new file mode 100644
index 000000000000..b7e26aef2066
--- /dev/null
+++ b/packages/proveit/graphs/vertices/_brief_description_.txt
@@ -0,0 +1 @@
+basic concepts involving vertices in a graph
diff --git a/packages/proveit/graphs/vertices/_sub_theories_.txt b/packages/proveit/graphs/vertices/_sub_theories_.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/__init__.py b/packages/proveit/graphs/vertices/_theory_nbs_/__init__.py
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/axioms.ipynb
new file mode 100644
index 000000000000..975f0bc93229
--- /dev/null
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/axioms.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Axioms for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.vertices</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the axioms of a theory:\n",
+    "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin axioms"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end axioms"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/common.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/common.ipynb
new file mode 100644
index 000000000000..d47aa5e24580
--- /dev/null
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/common.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Common expressions for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.vertices</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the common expressions of a theory:\n",
+    "%common_expressions_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin common"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end common"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
new file mode 100644
index 000000000000..020da9b2c256
--- /dev/null
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Demonstrations for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.vertices</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%begin demonstrations"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end demonstrations"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/theorems.ipynb
new file mode 100644
index 000000000000..bac3aa47e030
--- /dev/null
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/theorems.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theorems (or conjectures) for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.vertices</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the theorems of a theory:\n",
+    "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin theorems"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end theorems"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/theory.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/theory.ipynb
new file mode 100644
index 000000000000..c47105a3cb48
--- /dev/null
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/theory.ipynb
@@ -0,0 +1,33 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theory of <a class=\"ProveItLink\" href=\"../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../_theory_nbs_/theory.ipynb\">graphs</a>.vertices\n",
+    "========\n",
+    "\n",
+    "Provide description here."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%theory # toggles between interactive and static modes"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}

From ca02aefce8ac89b4c5d7b083d8f59202f0901066 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 29 Apr 2025 14:42:16 -0500
Subject: [PATCH 032/159] Update initial work on proof of
 not_in_k_power_set_equiv theorem

Update initial work on proof of not_in_k_power_set_equiv theorem. According to @wwitzel , the theorem is not provable with current axioms/theorems/tools.
---
 .../allowed_presumptions.txt                  |  4 ++
 .../not_in_k_power_set_equiv/thm_proof.ipynb  | 51 +++++++++++++------
 2 files changed, 40 insertions(+), 15 deletions(-)

diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/not_in_k_power_set_equiv/allowed_presumptions.txt b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/not_in_k_power_set_equiv/allowed_presumptions.txt
index 0531e29d50c6..c4a4e2ab8a68 100644
--- a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/not_in_k_power_set_equiv/allowed_presumptions.txt
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/not_in_k_power_set_equiv/allowed_presumptions.txt
@@ -1,2 +1,6 @@
 proveit.logic.equality.sub_right_side_into
 proveit.logic.booleans.conjunction.demorgans_law_or_to_and_bin
+proveit.logic.booleans.negation.closure
+proveit.logic.booleans.disjunction.binary_closure
+proveit.logic.booleans.implication.contrapose_neg_antecedent
+proveit.logic.sets.inclusion.subset_eq_is_bool
diff --git a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/not_in_k_power_set_equiv/thm_proof.ipynb b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/not_in_k_power_set_equiv/thm_proof.ipynb
index 8cd4e4d1454b..6cfbc0f14035 100644
--- a/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/not_in_k_power_set_equiv/thm_proof.ipynb
+++ b/packages/proveit/logic/sets/k_power_set/_theory_nbs_/proofs/not_in_k_power_set_equiv/thm_proof.ipynb
@@ -33,6 +33,29 @@
     "%proving not_in_k_power_set_equiv"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Prove-It's message to simply execute \"%qed\" is just teasing us, apparently.\n",
+    "\n",
+    "General chalkboard-mathematics proof consists of a sequence of transformations:\n",
+    "\n",
+    "$\\begin{align}\n",
+    "A \\notin [S]^{k}\n",
+    "&=\n",
+    "\\lnot(A \\in [S]^{k}) & \\text{[not\\_in\\_set\\_def]}\\\\\n",
+    "&=\n",
+    "\\lnot\\big((A \\subseteq S)\\land(|A| = k)\\big) & \\text{[k\\_power\\_set\\_def]}\\\\\n",
+    "&=\n",
+    "(\\lnot(A \\subseteq S)\\lor \\lnot(|A| = k)) & \\text{[De Morgan's Law(s)]}\\\\\n",
+    "&=\n",
+    "((A \\not\\subseteq S)\\lor (|A| \\ne k)) & \\text{[Negation Definitions]}\n",
+    "\\end{align}$\n",
+    "\n",
+    "Currently we have no good way to complete the proof. In particular, there appears to be no good way to “apply De Morgan’s” law in the desired way, in part because we need an equality-based theorem."
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -57,7 +80,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "defaults.assumptions = defaults.assumptions + [a_not_in_k_power_set]"
+    "not_in_set_def"
    ]
   },
   {
@@ -66,7 +89,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "not_in_set_def"
+    "a_not_k_power_set_01 = not_in_set_def.instantiate({x:A, S:KPowerSet(S, k)})"
    ]
   },
   {
@@ -75,7 +98,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "a_not_k_power_set_01 = not_in_set_def.instantiate({x:A, S:KPowerSet(S, k)})"
+    "k_power_set_def"
    ]
   },
   {
@@ -84,7 +107,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "assert False"
+    "k_power_set_def_inst = k_power_set_def.instantiate().instantiate()"
    ]
   },
   {
@@ -93,7 +116,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "k_power_set_def"
+    "a_not_k_power_set_02 = k_power_set_def_inst.sub_right_side_into(a_not_k_power_set_01)"
    ]
   },
   {
@@ -102,7 +125,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "k_power_set_def_inst = k_power_set_def.instantiate().instantiate()"
+    "A_subseteq_S = k_power_set_def_inst.rhs.operands[0]"
    ]
   },
   {
@@ -111,7 +134,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "not_in_set_def"
+    "card_A_eq_k = k_power_set_def_inst.rhs.operands[1]"
    ]
   },
   {
@@ -120,7 +143,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "a_not_k_power_set_01 = not_in_set_def.instantiate({x:A, S:KPowerSet(S, k)})"
+    "dm_01 = a_not_k_power_set_02.rhs.operand.conclude_via_demorgans(assumptions = [Not(Or(Not(A_subseteq_S), Not(card_A_eq_k)))])"
    ]
   },
   {
@@ -129,7 +152,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "a_not_k_power_set_02 = k_power_set_def_inst.sub_right_side_into(a_not_k_power_set_01)"
+    "dm_01.assumptions[0]"
    ]
   },
   {
@@ -138,7 +161,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "negated_conjunction = a_not_k_power_set_02.rhs"
+    "dm_02 = dm_01.as_implication(dm_01.assumptions[0])"
    ]
   },
   {
@@ -147,7 +170,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "conj = negated_conjunction.operand"
+    "dm_03 = dm_02.contrapose()"
    ]
   },
   {
@@ -156,7 +179,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "disjunction_of_negations = Or(Not(negated_conjunction.operand.operands[0]), Not(negated_conjunction.operand.operands[1]))"
+    "dm_04 = dm_03.derive_consequent(assumptions = [dm_03.antecedent])"
    ]
   },
   {
@@ -164,9 +187,7 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": [
-    "conj.conclude_via_demorgans(assumptions = [Not(disjunction_of_negations)])"
-   ]
+   "source": []
   }
  ],
  "metadata": {

From 78714df1ceb8cbb284336a04308ed5d58134196f Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 30 Apr 2025 16:37:47 -0500
Subject: [PATCH 033/159] Update graphs/vertices theory sub-pkg

Update graphs/vertices theory sub-package, establishing the Vertices, VerticesMembership, and VerticesNonmembership classes, along with associated axioms, theorems, and demonstrations notebook. This removes the Vertices class from the more general graphs.py and into its own theory package.
---
 packages/proveit/graphs/__init__.py           |   3 +-
 .../proveit/graphs/_theory_nbs_/axioms.ipynb  |  13 --
 packages/proveit/graphs/graph.py              |  19 --
 packages/proveit/graphs/vertices/__init__.py  |   2 +-
 .../graphs/vertices/_theory_nbs_/axioms.ipynb |  14 +-
 .../_theory_nbs_/demonstrations.ipynb         | 206 +++++++++++++++++-
 .../membership_def/allowed_presumptions.txt   |   0
 .../disallowed_presumptions.txt               |   0
 .../proofs/membership_def/thm_proof.ipynb     | 105 +++++++++
 .../allowed_presumptions.txt                  |   2 +
 .../disallowed_presumptions.txt               |   0
 .../proofs/membership_folding/thm_proof.ipynb |  95 ++++++++
 .../allowed_presumptions.txt                  |   2 +
 .../disallowed_presumptions.txt               |   0
 .../membership_unfolding/thm_proof.ipynb      |  95 ++++++++
 .../allowed_presumptions.txt                  |   0
 .../disallowed_presumptions.txt               |   0
 .../proofs/nonmembership_def/thm_proof.ipynb  | 105 +++++++++
 .../allowed_presumptions.txt                  |   2 +
 .../disallowed_presumptions.txt               |   0
 .../nonmembership_folding/thm_proof.ipynb     |  95 ++++++++
 .../allowed_presumptions.txt                  |   2 +
 .../disallowed_presumptions.txt               |   0
 .../nonmembership_unfolding/thm_proof.ipynb   |  95 ++++++++
 .../vertices/_theory_nbs_/theorems.ipynb      |  84 ++++++-
 packages/proveit/graphs/vertices/vertices.py  |  32 +++
 .../graphs/vertices/vertices_membership.py    | 137 ++++++++++++
 27 files changed, 1069 insertions(+), 39 deletions(-)
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/vertices/vertices.py
 create mode 100644 packages/proveit/graphs/vertices/vertices_membership.py

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index 42f69286e59b..9652ad78c7b1 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -1,10 +1,11 @@
-from .graph import Edges, EndPoints, Graph, Graphs, Path, Vertices
+from .graph import Edges, EndPoints, Graph, Graphs, Path
 from .endpoints import Endpoints
 from .inclusion import NotSubgraph, Subgraph
 from .membership import (
       GraphMembership, GraphNonmembership, InGraph, NotInGraph)
 from .paths import Paths
 from .union import GraphUnion
+from .vertices import Vertices
 
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
diff --git a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
index 12c6c7c92165..43f066b37043 100644
--- a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
@@ -47,19 +47,6 @@
     ")"
    ]
   },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "vertex_set_of_graph_v_e_is_v = (\n",
-    "    Forall(V,\n",
-    "    Forall(E, Equals(Vertices(Graph(V, E)), V), conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
-    "    )\n",
-    ")"
-   ]
-  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/graph.py b/packages/proveit/graphs/graph.py
index a0a6e78d891b..ab377d02fd69 100644
--- a/packages/proveit/graphs/graph.py
+++ b/packages/proveit/graphs/graph.py
@@ -66,25 +66,6 @@ def __init__(self, V, E, *, styles=None):
         Function.__init__(
                 self, Graph._operator_, (V, E), styles=styles)
 
-class Vertices(Function):
-    '''
-    Given a graph G(V, E) with vertex set V and edge set E,
-    Vertices(G(V, E)) represents the set V of vertices ---
-    that is, Vertices(G(V,E)) = V.
-    '''
-
-    # the literal operator of the Vertices operation
-    _operator_ = Literal(string_format='V',
-                         latex_format=r'\mathrm{V}',
-                         theory=__file__)
-
-    def __init__(self, G, *, styles=None):
-        '''
-        Given a graph G(V,E) = (V,E), represent the vertex set of G.
-        '''
-        self.graph = G
-        Function.__init__(
-                self, Vertices._operator_, G, styles=styles)
 
 class Edges(Function):
     '''
diff --git a/packages/proveit/graphs/vertices/__init__.py b/packages/proveit/graphs/vertices/__init__.py
index dba3de849ed8..f9eda29ea412 100644
--- a/packages/proveit/graphs/vertices/__init__.py
+++ b/packages/proveit/graphs/vertices/__init__.py
@@ -1,4 +1,4 @@
-
+from .vertices import Vertices
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
 #  Make additions above, or add to sys.modules[__name__].__dict__ below.
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/axioms.ipynb
index 975f0bc93229..99f37e6de565 100644
--- a/packages/proveit/graphs/vertices/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/axioms.ipynb
@@ -18,7 +18,11 @@
     "# Prepare this notebook for defining the axioms of a theory:\n",
     "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "# from ... import ..."
+    "from proveit import E, V\n",
+    "from proveit.logic import Equals, Forall\n",
+    "from proveit.logic.sets import KPowerSet, SubsetEq\n",
+    "from proveit.numbers import two\n",
+    "from proveit.graphs import Graph, Vertices"
    ]
   },
   {
@@ -35,7 +39,13 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "vertices_def = (\n",
+    "    Forall(V,\n",
+    "    Forall(E, Equals(Vertices(Graph(V, E)), V), conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
+    "    )\n",
+    ")"
+   ]
   },
   {
    "cell_type": "code",
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
index 020da9b2c256..4b3cdc33bffb 100644
--- a/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
@@ -15,7 +15,211 @@
    "outputs": [],
    "source": [
     "import proveit\n",
-    "%begin demonstrations"
+    "%begin demonstrations\n",
+    "\n",
+    "from proveit import v, E, G, P, V\n",
+    "from proveit.logic.sets import NotInSet, InSet, KPowerSet, SubsetEq\n",
+    "from proveit.numbers import two\n",
+    "from proveit.graphs import Graph, Vertices"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Vertices of Graph $G$: $\\mathrm{V}(\\mathrm{G}(V, E)) = V$"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### MISC. TESTING"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Basic Constructions"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G = Graph(V, E)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Vertices(G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Vertices(G))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(v, Vertices(G))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing Membership methods"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`VerticesMembership.definition()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Vertices(G)).definition(assumptions = [SubsetEq(E, KPowerSet(V, two))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`VerticesMembership.as_defined()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Vertices(G)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`VerticesMembership.unfold()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Vertices(G)).unfold(assumptions = [SubsetEq(E, KPowerSet(V, two)), InSet(v, Vertices(G))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`VerticesMembership.conclude()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Vertices(G)).conclude(assumptions = [SubsetEq(E, KPowerSet(V, two)), InSet(v, V)])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing Nonmembership methods"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`VerticesNonmembership.definition()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(v, Vertices(G)).definition(assumptions = [SubsetEq(E, KPowerSet(V, two))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`VerticesNonmembership.as_defined()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(v, Vertices(G)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`VerticesNonmembership.unfold()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(v, Vertices(G)).unfold(assumptions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(v, Vertices(G))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`VerticesNonmembership.conclude()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(v, Vertices(G)).conclude(assumptions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(v, V)])"
    ]
   },
   {
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/allowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/allowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/disallowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/thm_proof.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/thm_proof.ipynb
new file mode 100644
index 000000000000..81c3a941bace
--- /dev/null
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/thm_proof.ipynb
@@ -0,0 +1,105 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">vertices</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_def\">membership_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import v, X, V, defaults, Lambda\n",
+    "from proveit.logic import InSet\n",
+    "from proveit.graphs.vertices import vertices_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = membership_def.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "vertices_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "vertices_def_inst = vertices_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "subst_lambda = Lambda(X, InSet(v, X))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "vertices_def_inst.substitution(subst_lambda)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
new file mode 100644
index 000000000000..ba8ca63a6c5a
--- /dev/null
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
@@ -0,0 +1,2 @@
+proveit.graphs.vertices.membership_def
+proveit.logic.equality.lhs_via_equality
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/disallowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..3230ad107abf
--- /dev/null
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
@@ -0,0 +1,95 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">vertices</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_folding\">membership_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.graphs.vertices import membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving membership_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = membership_folding.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_def_inst =  membership_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_def_inst.derive_left_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
new file mode 100644
index 000000000000..d592d98ccdde
--- /dev/null
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
@@ -0,0 +1,2 @@
+proveit.graphs.vertices.membership_def
+proveit.logic.equality.rhs_via_equality
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/disallowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
new file mode 100644
index 000000000000..42aedaa25511
--- /dev/null
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
@@ -0,0 +1,95 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">vertices</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_unfolding\">membership_unfolding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.graphs.vertices import membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving membership_unfolding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = membership_unfolding.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_def_inst = membership_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_def_inst.derive_right_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/allowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/allowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/disallowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb
new file mode 100644
index 000000000000..8513092bd187
--- /dev/null
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb
@@ -0,0 +1,105 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">vertices</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_def\">nonmembership_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import v, X, defaults, Lambda\n",
+    "from proveit.logic import NotInSet\n",
+    "from proveit.graphs.vertices import vertices_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving nonmembership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = nonmembership_def.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "vertices_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "vertices_def_inst = vertices_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "subst_lambda = Lambda(X, NotInSet(v, X))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "vertices_def_inst.substitution(subst_lambda)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt
new file mode 100644
index 000000000000..5855e4ad2662
--- /dev/null
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt
@@ -0,0 +1,2 @@
+proveit.graphs.vertices.nonmembership_def
+proveit.logic.equality.lhs_via_equality
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/disallowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..f05907202e77
--- /dev/null
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
@@ -0,0 +1,95 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">vertices</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_folding\">nonmembership_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.graphs.vertices import nonmembership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving nonmembership_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = nonmembership_folding.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def_inst = nonmembership_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def_inst.derive_left_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt
new file mode 100644
index 000000000000..9ccaf2367b89
--- /dev/null
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt
@@ -0,0 +1,2 @@
+proveit.graphs.vertices.nonmembership_def
+proveit.logic.equality.rhs_via_equality
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/disallowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb
new file mode 100644
index 000000000000..47539825822e
--- /dev/null
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb
@@ -0,0 +1,95 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">vertices</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_unfolding\">nonmembership_unfolding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.graphs.vertices import nonmembership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving nonmembership_unfolding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = nonmembership_unfolding.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def_inst = nonmembership_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def_inst.derive_right_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/theorems.ipynb
index bac3aa47e030..e4c7f0620414 100644
--- a/packages/proveit/graphs/vertices/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/theorems.ipynb
@@ -18,7 +18,11 @@
     "# Prepare this notebook for defining the theorems of a theory:\n",
     "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "# from ... import ..."
+    "from proveit import v, E, V\n",
+    "from proveit.logic import Equals, Forall\n",
+    "from proveit.logic.sets import InSet, KPowerSet, NotInSet, SubsetEq\n",
+    "from proveit.numbers import two\n",
+    "from proveit.graphs import Graph, Vertices"
    ]
   },
   {
@@ -35,7 +39,83 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "membership_def = (\n",
+    "    Forall((v, V),\n",
+    "    Forall(E, Equals(InSet(v, Vertices(Graph(V, E))), InSet(v, V)), conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_unfolding = (\n",
+    "    Forall(V,\n",
+    "        Forall((v, E), InSet(v, V),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two)), InSet(v, Vertices(Graph(V, E)))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_folding = (\n",
+    "    Forall(V,\n",
+    "        Forall((v, E), InSet(v, Vertices(Graph(V, E))),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two)), InSet(v, V)])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def = (\n",
+    "    Forall(V,\n",
+    "        Forall((v, E), Equals(NotInSet(v, Vertices(Graph(V, E))), NotInSet(v, V)),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_unfolding = (\n",
+    "    Forall(V,\n",
+    "        Forall((v, E), NotInSet(v, V),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(v, Vertices(Graph(V, E)))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_folding = (\n",
+    "    Forall(V,\n",
+    "        Forall((v, E), NotInSet(v, Vertices(Graph(V, E))),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(v, V)])\n",
+    "    )\n",
+    ")"
+   ]
   },
   {
    "cell_type": "code",
diff --git a/packages/proveit/graphs/vertices/vertices.py b/packages/proveit/graphs/vertices/vertices.py
new file mode 100644
index 000000000000..7a97e936afff
--- /dev/null
+++ b/packages/proveit/graphs/vertices/vertices.py
@@ -0,0 +1,32 @@
+from proveit import Function, Literal
+
+class Vertices(Function):
+    '''
+    Given a graph G(V, E) with vertex set V and edge set E,
+    Vertices(G(V, E)) represents the set V of vertices ---
+    that is, Vertices(G(V,E)) = V. The notation will use V(G),
+    in which case we might see things like V(G) = V, but the operator
+    V will appear in mathrm to distinguish it from the set V in
+    italics.
+    '''
+
+    # the literal operator of the Vertices operation
+    _operator_ = Literal(string_format='V',
+                         latex_format=r'\mathrm{V}',
+                         theory=__file__)
+
+    def __init__(self, G, *, styles=None):
+        '''
+        Given a graph G(V,E) = (V,E), represent the vertex set of G.
+        '''
+        self.graph = G
+        Function.__init__(
+                self, Vertices._operator_, G, styles=styles)
+
+    def membership_object(self, element):
+        from .vertices_membership import VerticesMembership
+        return VerticesMembership(element, self)
+
+    def nonmembership_object(self, element):
+        from .vertices_membership import VerticesNonmembership
+        return VerticesNonmembership(element, self)
diff --git a/packages/proveit/graphs/vertices/vertices_membership.py b/packages/proveit/graphs/vertices/vertices_membership.py
new file mode 100644
index 000000000000..245ec0edb86f
--- /dev/null
+++ b/packages/proveit/graphs/vertices/vertices_membership.py
@@ -0,0 +1,137 @@
+from proveit import v, E, V, equality_prover, prover
+from proveit.logic import SetMembership, SetNonmembership
+
+
+class VerticesMembership(SetMembership):
+    '''
+    Defines methods that apply to membership in the set
+    Vertices(G(V,E)) of the vertices V of graph G.
+    '''
+
+    def __init__(self, element, domain):
+        SetMembership.__init__(self, element, domain)
+
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self = [elem in Vertices(Graph(V,E))], deduce and return:
+            [elem in Vertices(Graph(V,E))] = [elem in V]
+        '''
+
+        from . import membership_def
+        element = self.element
+        _V_sub  = self.domain.graph.vertex_set
+        _E_sub  = self.domain.graph.edge_set
+        return membership_def.instantiate(
+                {v:element, V:_V_sub, E:_E_sub },auto_simplify=False)
+
+    def as_defined(self):
+        '''
+        From self = [elem in Vertices(Graph(V,E))], return: [elem in V]
+        (i.e. an expression, not a Judgment)
+        '''
+        from proveit.logic import InSet
+        element = self.element
+        _V = self.domain.graph.vertex_set
+        return InSet(element, _V)
+
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        From self = [elem in Vertices(Graph(V,E))],
+        derive and return [elem in V], knowing or assuming self.
+        '''
+        from . import membership_unfolding
+        element = self.element
+        _V_sub  = self.domain.graph.vertex_set
+        _E_sub  = self.domain.graph.edge_set
+        return membership_unfolding.instantiate(
+            {v:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Called on self = [elem in Vertices(Graph(V,E))], and
+        knowing or assuming [elem in V] (and that E is a subset
+        of [V]^2, a subset of the set of 2-element subsets of V)
+        derive and return self.
+        '''
+        from . import membership_folding
+        element = self.element
+        _V_sub  = self.domain.graph.vertex_set
+        _E_sub  = self.domain.graph.edge_set
+        return membership_folding.instantiate(
+            {v:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
+
+
+
+class VerticesNonmembership(SetNonmembership):
+    '''
+    Defines methods that apply to non-membership in the set
+    Vertices(G(V,E)) of the vertices V of graph G.
+    '''
+
+    def __init__(self, element, domain):
+        SetNonmembership.__init__(self, element, domain)
+
+    def side_effects(self, judgment):
+        '''
+        Currently no side-effects for VerticesNonmembership.
+        '''
+        return
+        yield
+
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self = [elem not in Vertices(Graph(V,E))], deduce and
+        return: [elem not in Vertices(Graph(V,E))] = [elem not in V].
+        '''
+
+        from . import nonmembership_def
+        element = self.element
+        _V_sub  = self.domain.graph.vertex_set
+        _E_sub  = self.domain.graph.edge_set
+        return nonmembership_def.instantiate(
+                {v:element, V:_V_sub, E:_E_sub },auto_simplify=False)
+
+    def as_defined(self):
+        '''
+        From self = [elem not in Vertices(Graph(V,E))],
+        return: [elem not in V] (i.e. an expression, not a Judgment)
+        '''
+        from proveit.logic import NotInSet
+        element = self.element
+        _V = self.domain.graph.vertex_set
+        return NotInSet(element, _V)
+
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        From self = [elem not in Vertices(Graph(V,E))],
+        derive and return [elem not in V], knowing or assuming self,
+        (and that E is a subset of [V]^2, i.e., a subset of the set
+        of 2-element subsets of V).
+        '''
+        from . import nonmembership_unfolding
+        element = self.element
+        _V_sub  = self.domain.graph.vertex_set
+        _E_sub  = self.domain.graph.edge_set
+        return nonmembership_unfolding.instantiate(
+            {v:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Called on self = [elem not in Vertices(Graph(V,E))], and
+        knowing or assuming [elem not in V] (and that E is a subset
+        of [V]^2, a subset of the set of 2-element subsets of V)
+        derive and return self.
+        '''
+        from . import nonmembership_folding
+        element = self.element
+        _V_sub  = self.domain.graph.vertex_set
+        _E_sub  = self.domain.graph.edge_set
+        return nonmembership_folding.instantiate(
+            {v:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
+

From 036f19506e9d5dab7eb78719de359b7a46f2afb0 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 30 Apr 2025 22:17:45 -0500
Subject: [PATCH 034/159] Update graphs/edges theory sub-pkg

Update graphs/edges theory sub-package, establishing the Edges, EdgesMembership, and EdgesNonmembership classes, along with associated axioms, theorems, and demonstrations notebook. This removes the Edges class from the more general graphs.py and into its own theory package.
---
 packages/proveit/graphs/__init__.py           |   3 +-
 .../graphs/_theory_nbs_/demonstrations.ipynb  |   4 +-
 packages/proveit/graphs/edges/__init__.py     |   2 +-
 .../graphs/edges/_theory_nbs_/axioms.ipynb    |  14 +-
 .../edges/_theory_nbs_/demonstrations.ipynb   | 202 +++++++++++++++++-
 .../membership_def/allowed_presumptions.txt   |   0
 .../disallowed_presumptions.txt               |   0
 .../proofs/membership_def/thm_proof.ipynb     |  98 +++++++++
 .../allowed_presumptions.txt                  |   2 +
 .../disallowed_presumptions.txt               |   0
 .../proofs/membership_folding/thm_proof.ipynb |  88 ++++++++
 .../allowed_presumptions.txt                  |   2 +
 .../disallowed_presumptions.txt               |   0
 .../membership_unfolding/thm_proof.ipynb      |  88 ++++++++
 .../allowed_presumptions.txt                  |   0
 .../disallowed_presumptions.txt               |   0
 .../proofs/nonmembership_def/thm_proof.ipynb  |  59 +++++
 .../allowed_presumptions.txt                  |   2 +
 .../disallowed_presumptions.txt               |   0
 .../nonmembership_folding/thm_proof.ipynb     |  88 ++++++++
 .../allowed_presumptions.txt                  |   2 +
 .../disallowed_presumptions.txt               |   0
 .../nonmembership_unfolding/thm_proof.ipynb   |  88 ++++++++
 .../graphs/edges/_theory_nbs_/theorems.ipynb  |  84 +++++++-
 packages/proveit/graphs/edges/edges.py        |  32 +++
 .../proveit/graphs/edges/edges_membership.py  | 136 ++++++++++++
 packages/proveit/graphs/graph.py              |  42 ----
 27 files changed, 984 insertions(+), 52 deletions(-)
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_def/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_def/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/edges/edges.py
 create mode 100644 packages/proveit/graphs/edges/edges_membership.py

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index 9652ad78c7b1..ac46db86e2fb 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -1,4 +1,5 @@
-from .graph import Edges, EndPoints, Graph, Graphs, Path
+from .graph import Graph, Graphs, Path
+from .edges import Edges
 from .endpoints import Endpoints
 from .inclusion import NotSubgraph, Subgraph
 from .membership import (
diff --git a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
index cae1d1a21154..fcda0bf2537a 100644
--- a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
@@ -16,7 +16,7 @@
    "source": [
     "import proveit\n",
     "from proveit import x, E, G, V\n",
-    "from proveit.graphs import EndPoints, Graph, Path\n",
+    "from proveit.graphs import Endpoints, Graph, Path\n",
     "%begin demonstrations"
    ]
   },
@@ -59,7 +59,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "example_endpts = EndPoints(example_path)"
+    "example_endpts = Endpoints(example_path)"
    ]
   },
   {
diff --git a/packages/proveit/graphs/edges/__init__.py b/packages/proveit/graphs/edges/__init__.py
index dba3de849ed8..744731235907 100644
--- a/packages/proveit/graphs/edges/__init__.py
+++ b/packages/proveit/graphs/edges/__init__.py
@@ -1,4 +1,4 @@
-
+from .edges import Edges
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
 #  Make additions above, or add to sys.modules[__name__].__dict__ below.
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/axioms.ipynb
index c3b6f18e38e2..4a6c2b0f6c5f 100644
--- a/packages/proveit/graphs/edges/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/edges/_theory_nbs_/axioms.ipynb
@@ -18,7 +18,11 @@
     "# Prepare this notebook for defining the axioms of a theory:\n",
     "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "# from ... import ..."
+    "from proveit import E, V\n",
+    "from proveit.logic import Equals, Forall\n",
+    "from proveit.logic.sets import KPowerSet, SubsetEq\n",
+    "from proveit.numbers import two\n",
+    "from proveit.graphs import Graph, Edges"
    ]
   },
   {
@@ -35,7 +39,13 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "edges_def = (\n",
+    "    Forall(V,\n",
+    "    Forall(E, Equals(Edges(Graph(V, E)), E), conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
+    "    )\n",
+    ")"
+   ]
   },
   {
    "cell_type": "code",
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/demonstrations.ipynb
index ffc5a49da433..48c3570a2a63 100644
--- a/packages/proveit/graphs/edges/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/edges/_theory_nbs_/demonstrations.ipynb
@@ -15,7 +15,187 @@
    "outputs": [],
    "source": [
     "import proveit\n",
-    "%begin demonstrations"
+    "%begin demonstrations\n",
+    "\n",
+    "from proveit import e, E, G, P, V\n",
+    "from proveit.logic import InSet, NotInSet, SubsetEq\n",
+    "from proveit.logic.sets import KPowerSet\n",
+    "from proveit.numbers import two\n",
+    "from proveit.graphs import Graph, Edges"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Edges of Graph $G$: $\\mathrm{E}(\\mathrm{G}(V, E)) = E$"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### MISC. TESTING"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Basic Constructions"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G = Graph(V, E)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Edges(G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(e, Edges(G))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(e, Edges(G))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing Membership methods"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EdgesMembership.definition()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(e, Edges(G)).definition(assumptions = [SubsetEq(E, KPowerSet(V, two))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EdgesMembership.as_defined()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(e, Edges(G)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EdgesMembership.unfold()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(e, Edges(G)).unfold(assumptions = [SubsetEq(E, KPowerSet(V, two)), InSet(e, Edges(G))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EdgesMembership.conclude()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(e, Edges(G)).conclude(assumptions = [SubsetEq(E, KPowerSet(V, two)), InSet(e, E)])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing Nonmembership methods"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EdgesNonmembership.definition()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(e, Edges(G)).definition(assumptions = [SubsetEq(E, KPowerSet(V, two))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EdgesNonmembership.as_defined()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(e, Edges(G)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EdgesNonmembership.unfold()`"
    ]
   },
   {
@@ -23,7 +203,25 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "NotInSet(e, Edges(G)).unfold(assumptions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(e, Edges(G))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EdgesNonmembership.conclude()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(e, Edges(G)).conclude(assumptions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(e, E)])"
+   ]
   },
   {
    "cell_type": "code",
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/allowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/allowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/disallowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/thm_proof.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/thm_proof.ipynb
new file mode 100644
index 000000000000..37b6eac26709
--- /dev/null
+++ b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/thm_proof.ipynb
@@ -0,0 +1,98 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">edges</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_def\">membership_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import e, X, defaults, Lambda\n",
+    "from proveit.logic.sets import InSet\n",
+    "from proveit.graphs.edges import edges_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = membership_def.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "edges_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "edges_def_inst = edges_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "subst_lambda = Lambda(X, InSet(e, X))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "edges_def_inst.substitution(subst_lambda)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
new file mode 100644
index 000000000000..ddeb342add31
--- /dev/null
+++ b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
@@ -0,0 +1,2 @@
+proveit.graphs.edges.membership_def
+proveit.logic.equality.lhs_via_equality
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/disallowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..97b9992173ac
--- /dev/null
+++ b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
@@ -0,0 +1,88 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">edges</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_folding\">membership_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.graphs.edges import membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving membership_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = membership_folding.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_def_inst = membership_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_def_inst.derive_left_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
new file mode 100644
index 000000000000..b4418331dce4
--- /dev/null
+++ b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
@@ -0,0 +1,2 @@
+proveit.graphs.edges.membership_def
+proveit.logic.equality.rhs_via_equality
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/disallowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
new file mode 100644
index 000000000000..78ebf51d0369
--- /dev/null
+++ b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
@@ -0,0 +1,88 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">edges</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_unfolding\">membership_unfolding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.graphs.edges import membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving membership_unfolding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = membership_unfolding.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_def_inst = membership_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_def_inst.derive_right_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_def/allowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_def/allowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_def/disallowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_def/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb
new file mode 100644
index 000000000000..10d8e2f1a3c6
--- /dev/null
+++ b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">edges</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_def\">nonmembership_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.graphs.edges import edges_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving nonmembership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt
new file mode 100644
index 000000000000..4ca789ee9bbd
--- /dev/null
+++ b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt
@@ -0,0 +1,2 @@
+proveit.graphs.edges.nonmembership_def
+proveit.logic.equality.lhs_via_equality
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/disallowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..88409bd17ede
--- /dev/null
+++ b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
@@ -0,0 +1,88 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">edges</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_folding\">nonmembership_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.graphs.edges import nonmembership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving nonmembership_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = nonmembership_folding.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def_inst = nonmembership_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def_inst.derive_left_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt
new file mode 100644
index 000000000000..6a5ce129b5ee
--- /dev/null
+++ b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt
@@ -0,0 +1,2 @@
+proveit.graphs.edges.nonmembership_def
+proveit.logic.equality.rhs_via_equality
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/disallowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb
new file mode 100644
index 000000000000..58493897d840
--- /dev/null
+++ b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb
@@ -0,0 +1,88 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">edges</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_unfolding\">nonmembership_unfolding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.graphs.edges import nonmembership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving nonmembership_unfolding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = nonmembership_unfolding.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def_inst = nonmembership_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def_inst.derive_right_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/theorems.ipynb
index 9d6f851d762f..1ccf7057fd79 100644
--- a/packages/proveit/graphs/edges/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/edges/_theory_nbs_/theorems.ipynb
@@ -18,7 +18,11 @@
     "# Prepare this notebook for defining the theorems of a theory:\n",
     "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "# from ... import ..."
+    "from proveit import e, E, V\n",
+    "from proveit.logic import Equals, Forall\n",
+    "from proveit.logic.sets import InSet, KPowerSet, NotInSet, SubsetEq\n",
+    "from proveit.numbers import two\n",
+    "from proveit.graphs import Graph, Edges"
    ]
   },
   {
@@ -35,7 +39,83 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "membership_def = (\n",
+    "    Forall(V,\n",
+    "    Forall((e, E), Equals(InSet(e, Edges(Graph(V, E))), InSet(e, E)), conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_unfolding = (\n",
+    "    Forall(V,\n",
+    "        Forall((e, E), InSet(e, E),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two)), InSet(e, Edges(Graph(V, E)))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_folding = (\n",
+    "    Forall(V,\n",
+    "        Forall((e, E), InSet(e, Edges(Graph(V, E))),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two)), InSet(e, E)])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def = (\n",
+    "    Forall(V,\n",
+    "        Forall((e, E), Equals(NotInSet(e, Edges(Graph(V, E))), NotInSet(e, E)),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_unfolding = (\n",
+    "    Forall(V,\n",
+    "        Forall((e, E), NotInSet(e, E),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(e, Edges(Graph(V, E)))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_folding = (\n",
+    "    Forall(V,\n",
+    "        Forall((e, E), NotInSet(e, Edges(Graph(V, E))),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(e, E)])\n",
+    "    )\n",
+    ")"
+   ]
   },
   {
    "cell_type": "code",
diff --git a/packages/proveit/graphs/edges/edges.py b/packages/proveit/graphs/edges/edges.py
new file mode 100644
index 000000000000..86a6cbcf0462
--- /dev/null
+++ b/packages/proveit/graphs/edges/edges.py
@@ -0,0 +1,32 @@
+from proveit import Function, Literal
+
+class Edges(Function):
+    '''
+    Given a graph G(V, E) with vertex set V and edge set E,
+    Edges(G(V, E)) represents the set E of vertices ---
+    that is, Edges(G(V,E)) = E. The notation will use E(G),
+    in which case we might see things like E(G) = E, but the operator
+    E will appear in mathrm to distinguish it from the set E in
+    italics.
+    '''
+
+    # the literal operator of the Vertices operation
+    _operator_ = Literal(string_format='E',
+                         latex_format=r'\mathrm{E}',
+                         theory=__file__)
+
+    def __init__(self, G, *, styles=None):
+        '''
+        Given a graph G(V,E) = (V,E), represent the edge set of G.
+        '''
+        self.graph = G
+        Function.__init__(
+                self, Edges._operator_, G, styles=styles)
+
+    def membership_object(self, element):
+        from .edges_membership import EdgesMembership
+        return EdgesMembership(element, self)
+
+    def nonmembership_object(self, element):
+        from .edges_membership import EdgesNonmembership
+        return EdgesNonmembership(element, self)
\ No newline at end of file
diff --git a/packages/proveit/graphs/edges/edges_membership.py b/packages/proveit/graphs/edges/edges_membership.py
new file mode 100644
index 000000000000..2df527078327
--- /dev/null
+++ b/packages/proveit/graphs/edges/edges_membership.py
@@ -0,0 +1,136 @@
+from proveit import e, E, V, equality_prover, prover
+from proveit.logic import SetMembership, SetNonmembership
+
+
+class EdgesMembership(SetMembership):
+    '''
+    Defines methods that apply to membership in the set
+    Edges(G(V,E)) of the edges E of graph G.
+    '''
+
+    def __init__(self, element, domain):
+        SetMembership.__init__(self, element, domain)
+
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self = [elem in Edges(Graph(V,E))], deduce and return:
+            [elem in Edges(Graph(V,E))] = [elem in E]
+        '''
+
+        from . import membership_def
+        element = self.element
+        _V_sub  = self.domain.graph.vertex_set
+        _E_sub  = self.domain.graph.edge_set
+        return membership_def.instantiate(
+                {e:element, V:_V_sub, E:_E_sub },auto_simplify=False)
+
+    def as_defined(self):
+        '''
+        From self = [elem in Edges(Graph(V,E))], return: [elem in E]
+        (i.e. an expression, not a Judgment)
+        '''
+        from proveit.logic import InSet
+        element = self.element
+        _E = self.domain.graph.edge_set
+        return InSet(element, _E)
+
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        From self = [elem in Edges(Graph(V,E))],
+        derive and return [elem in E], knowing or assuming self.
+        '''
+        from . import membership_unfolding
+        element = self.element
+        _V_sub  = self.domain.graph.vertex_set
+        _E_sub  = self.domain.graph.edge_set
+        return membership_unfolding.instantiate(
+            {e:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Called on self = [elem in Edges(Graph(V,E))], and
+        knowing or assuming [elem in E] (and that E is a subset
+        of [V]^2, a subset of the set of 2-element subsets of V)
+        derive and return self.
+        '''
+        from . import membership_folding
+        element = self.element
+        _V_sub  = self.domain.graph.vertex_set
+        _E_sub  = self.domain.graph.edge_set
+        return membership_folding.instantiate(
+            {e:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
+
+
+class EdgesNonmembership(SetNonmembership):
+    '''
+    Defines methods that apply to non-membership in the set
+    Edges(G(V,E)) of the edges E of graph G.
+    '''
+
+    def __init__(self, element, domain):
+        SetNonmembership.__init__(self, element, domain)
+
+    def side_effects(self, judgment):
+        '''
+        Currently no side-effects for EdgesNonmembership.
+        '''
+        return
+        yield
+
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self = [elem not in Edges(Graph(V,E))], deduce and
+        return: [elem not in Edges(Graph(V,E))] = [elem not in E].
+        '''
+
+        from . import nonmembership_def
+        element = self.element
+        _V_sub  = self.domain.graph.vertex_set
+        _E_sub  = self.domain.graph.edge_set
+        return nonmembership_def.instantiate(
+                {e:element, V:_V_sub, E:_E_sub },auto_simplify=False)
+
+    def as_defined(self):
+        '''
+        From self = [elem not in Edges(Graph(V,E))],
+        return: [elem not in E] (i.e. an expression, not a Judgment)
+        '''
+        from proveit.logic import NotInSet
+        element = self.element
+        _E = self.domain.graph.edge_set
+        return NotInSet(element, _E)
+
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        From self = [elem not in Edges(Graph(V,E))],
+        derive and return [elem not in E], knowing or assuming self,
+        (and that E is a subset of [V]^2, i.e., a subset of the set
+        of 2-element subsets of V).
+        '''
+        from . import nonmembership_unfolding
+        element = self.element
+        _V_sub  = self.domain.graph.vertex_set
+        _E_sub  = self.domain.graph.edge_set
+        return nonmembership_unfolding.instantiate(
+            {e:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Called on self = [elem not in Edges(Graph(V,E))], and
+        knowing or assuming [elem not in E] (and that E is a subset
+        of [V]^2, a subset of the set of 2-element subsets of V)
+        derive and return self.
+        '''
+        from . import nonmembership_folding
+        element = self.element
+        _V_sub  = self.domain.graph.vertex_set
+        _E_sub  = self.domain.graph.edge_set
+        return nonmembership_folding.instantiate(
+            {e:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
+
diff --git a/packages/proveit/graphs/graph.py b/packages/proveit/graphs/graph.py
index ab377d02fd69..a70d4da7cad4 100644
--- a/packages/proveit/graphs/graph.py
+++ b/packages/proveit/graphs/graph.py
@@ -67,27 +67,6 @@ def __init__(self, V, E, *, styles=None):
                 self, Graph._operator_, (V, E), styles=styles)
 
 
-class Edges(Function):
-    '''
-    Given a graph G(V, E) with vertex set V and edge set E,
-    Edges(G(V, E)) represents the set E of vertices ---
-    that is, Edges(G(V,E)) = E.
-    '''
-
-    # the literal operator of the Vertices operation
-    _operator_ = Literal(string_format='E',
-                         latex_format=r'\mathrm{E}',
-                         theory=__file__)
-
-    def __init__(self, G, *, styles=None):
-        '''
-        Given a graph G(V,E) = (V,E), represent the edge set of G.
-        '''
-        self.graph = G
-        Function.__init__(
-                self, Edges._operator_, G, styles=styles)
-
-
 class Path(Graph):
     '''
     Path(V,E) represents a path. A Path is a non-empty graph
@@ -116,24 +95,3 @@ def __init__(self, V, E, *, styles=None):
         self.edge_set   = E
         Function.__init__(
                 self, Path._operator_, (V, E), styles=styles)
-
-
-class EndPoints(Function):
-    '''
-    EndPoints(P) denotes the set of two endpoints of a Path P = (V, E),
-    where Path P has vertex set V and edge set E. EndPoints(P) will be
-    a subset of the Path P's vertex set V.
-    EndPoints(P) will not "know" the original path P whence it came.
-    '''
-
-    # the literal operator of the EndPoints operator
-    _operator_ = Literal(
-            string_format='EndPts', latex_format=r'\text{EndPts}',
-            theory=__file__)
-
-    def __init__(self, P, *, styles=None):
-        '''
-        Create the endpoints set EndPts(P) for Path P.
-        '''
-        Function.__init__(
-                self, EndPoints._operator_, P, styles=styles)

From 46952d2500641cc144e5898d837c6b6863594b9a Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Fri, 2 May 2025 09:20:54 -0500
Subject: [PATCH 035/159] Update vertices theory pkg with Degree class

Update the graphs/vertices theory package with Degree class to represent with Degree(v, G) the degree or valency of a vertex v within a graph G. Useful in general, of course, but anticipated to be immediately used in axioms and theorems related to the Endpoints() class.
---
 packages/proveit/graphs/__init__.py           |  2 +-
 packages/proveit/graphs/vertices/__init__.py  |  2 +-
 .../_theory_nbs_/demonstrations.ipynb         | 11 ++++++++-
 packages/proveit/graphs/vertices/vertices.py  | 24 +++++++++++++++++++
 4 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index ac46db86e2fb..c1403a720f34 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -6,7 +6,7 @@
       GraphMembership, GraphNonmembership, InGraph, NotInGraph)
 from .paths import Paths
 from .union import GraphUnion
-from .vertices import Vertices
+from .vertices import Degree, Vertices
 
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
diff --git a/packages/proveit/graphs/vertices/__init__.py b/packages/proveit/graphs/vertices/__init__.py
index f9eda29ea412..b79b83996227 100644
--- a/packages/proveit/graphs/vertices/__init__.py
+++ b/packages/proveit/graphs/vertices/__init__.py
@@ -1,4 +1,4 @@
-from .vertices import Vertices
+from .vertices import Degree, Vertices
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
 #  Make additions above, or add to sys.modules[__name__].__dict__ below.
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
index 4b3cdc33bffb..2a8891e2c66a 100644
--- a/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
@@ -20,7 +20,7 @@
     "from proveit import v, E, G, P, V\n",
     "from proveit.logic.sets import NotInSet, InSet, KPowerSet, SubsetEq\n",
     "from proveit.numbers import two\n",
-    "from proveit.graphs import Graph, Vertices"
+    "from proveit.graphs import Degree, Graph, Vertices"
    ]
   },
   {
@@ -80,6 +80,15 @@
     "NotInSet(v, Vertices(G))"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Degree(v)"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
diff --git a/packages/proveit/graphs/vertices/vertices.py b/packages/proveit/graphs/vertices/vertices.py
index 7a97e936afff..baea7ad5c46d 100644
--- a/packages/proveit/graphs/vertices/vertices.py
+++ b/packages/proveit/graphs/vertices/vertices.py
@@ -30,3 +30,27 @@ def membership_object(self, element):
     def nonmembership_object(self, element):
         from .vertices_membership import VerticesNonmembership
         return VerticesNonmembership(element, self)
+
+
+class Degree(Function):
+    '''
+    Degree(v, G), denoted deg(v), represents the degree or valency of
+    the vertex v occuring in the graph G. For an undirected graph with
+    no loops, deg(v) will be equal to the number of edges incident
+    with vertex v. For vertex v in a directed graph, deg(v) will equal
+    the sum of the in-degree and out-degree of vertex v.
+    '''
+
+    # the literal operator of the Degree operation
+    _operator_ = Literal(string_format='deg',
+                         latex_format=r'\mathrm{deg}',
+                         theory=__file__)
+
+    def __init__(self, v, G, *, styles=None):
+        '''
+        Given a vertex v of a graph G(V,E) = (V,E), represent the
+        degree of the vertex v.
+        '''
+        Function.__init__(
+                self, Degree._operator_, (v, G), styles=styles)
+

From 4af3def36c0f4179a3e90f68ac71bf211a8a99d8 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Fri, 2 May 2025 14:38:45 -0500
Subject: [PATCH 036/159] Establish paths_of theory sub-package

Establish graphs/paths_of theory sub-package and the corresponding PathsOf(G) class to represent the set of all paths in a given graph G. This is what Paths(G) was used for up to this point, but will now use Paths() (no argument) to represent the class of graphs that are paths.
---
 packages/proveit/graphs/__init__.py           |   1 +
 packages/proveit/graphs/_sub_theories_.txt    |   1 +
 packages/proveit/graphs/paths_of/__init__.py  |   9 ++
 .../graphs/paths_of/_brief_description_.txt   |   1 +
 .../graphs/paths_of/_sub_theories_.txt        |   0
 .../graphs/paths_of/_theory_nbs_/__init__.py  |   0
 .../graphs/paths_of/_theory_nbs_/axioms.ipynb |  59 ++++++++++
 .../graphs/paths_of/_theory_nbs_/common.ipynb |  59 ++++++++++
 .../_theory_nbs_/demonstrations.ipynb         | 101 ++++++++++++++++++
 .../paths_of/_theory_nbs_/theorems.ipynb      |  59 ++++++++++
 .../graphs/paths_of/_theory_nbs_/theory.ipynb |  33 ++++++
 packages/proveit/graphs/paths_of/paths_of.py  |  53 +++++++++
 .../graphs/paths_of/paths_of_membership.py    |  21 ++++
 13 files changed, 397 insertions(+)
 create mode 100644 packages/proveit/graphs/paths_of/__init__.py
 create mode 100644 packages/proveit/graphs/paths_of/_brief_description_.txt
 create mode 100644 packages/proveit/graphs/paths_of/_sub_theories_.txt
 create mode 100644 packages/proveit/graphs/paths_of/_theory_nbs_/__init__.py
 create mode 100644 packages/proveit/graphs/paths_of/_theory_nbs_/axioms.ipynb
 create mode 100644 packages/proveit/graphs/paths_of/_theory_nbs_/common.ipynb
 create mode 100644 packages/proveit/graphs/paths_of/_theory_nbs_/demonstrations.ipynb
 create mode 100644 packages/proveit/graphs/paths_of/_theory_nbs_/theorems.ipynb
 create mode 100644 packages/proveit/graphs/paths_of/_theory_nbs_/theory.ipynb
 create mode 100644 packages/proveit/graphs/paths_of/paths_of.py
 create mode 100644 packages/proveit/graphs/paths_of/paths_of_membership.py

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index c1403a720f34..0b99d4ee9968 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -5,6 +5,7 @@
 from .membership import (
       GraphMembership, GraphNonmembership, InGraph, NotInGraph)
 from .paths import Paths
+from .paths_of import PathsOf
 from .union import GraphUnion
 from .vertices import Degree, Vertices
 
diff --git a/packages/proveit/graphs/_sub_theories_.txt b/packages/proveit/graphs/_sub_theories_.txt
index e6076965fd8d..29648cf9807e 100644
--- a/packages/proveit/graphs/_sub_theories_.txt
+++ b/packages/proveit/graphs/_sub_theories_.txt
@@ -4,4 +4,5 @@ inclusion
 union
 membership
 paths
+paths_of
 endpoints
diff --git a/packages/proveit/graphs/paths_of/__init__.py b/packages/proveit/graphs/paths_of/__init__.py
new file mode 100644
index 000000000000..0e31c3e0c200
--- /dev/null
+++ b/packages/proveit/graphs/paths_of/__init__.py
@@ -0,0 +1,9 @@
+from .paths_of import PathsOf
+
+# KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
+#  Make additions above, or add to sys.modules[__name__].__dict__ below.
+# This allows us to import common expression, axioms, and theorems of
+# the theory package directly from the package.
+import sys
+from proveit._core_.theory import TheoryPackage
+sys.modules[__name__] = TheoryPackage(__name__, __file__, locals())
diff --git a/packages/proveit/graphs/paths_of/_brief_description_.txt b/packages/proveit/graphs/paths_of/_brief_description_.txt
new file mode 100644
index 000000000000..8a9fbaa01a54
--- /dev/null
+++ b/packages/proveit/graphs/paths_of/_brief_description_.txt
@@ -0,0 +1 @@
+basic concepts involving paths within a specified graph
diff --git a/packages/proveit/graphs/paths_of/_sub_theories_.txt b/packages/proveit/graphs/paths_of/_sub_theories_.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/paths_of/_theory_nbs_/__init__.py b/packages/proveit/graphs/paths_of/_theory_nbs_/__init__.py
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/paths_of/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/paths_of/_theory_nbs_/axioms.ipynb
new file mode 100644
index 000000000000..79ec4ea43cdd
--- /dev/null
+++ b/packages/proveit/graphs/paths_of/_theory_nbs_/axioms.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Axioms for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.paths_of</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the axioms of a theory:\n",
+    "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin axioms"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end axioms"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/paths_of/_theory_nbs_/common.ipynb b/packages/proveit/graphs/paths_of/_theory_nbs_/common.ipynb
new file mode 100644
index 000000000000..8b25f72fbf20
--- /dev/null
+++ b/packages/proveit/graphs/paths_of/_theory_nbs_/common.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Common expressions for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.paths_of</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the common expressions of a theory:\n",
+    "%common_expressions_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin common"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end common"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/paths_of/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/paths_of/_theory_nbs_/demonstrations.ipynb
new file mode 100644
index 000000000000..baf4cca32605
--- /dev/null
+++ b/packages/proveit/graphs/paths_of/_theory_nbs_/demonstrations.ipynb
@@ -0,0 +1,101 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Demonstrations for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.paths_of</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%begin demonstrations\n",
+    "\n",
+    "from proveit import E, G, P, V\n",
+    "from proveit.logic.sets import InSet, NotInSet\n",
+    "from proveit.graphs import Graph, PathsOf"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Paths in Graph $G$: $\\mathrm{PathsOf}(\\mathrm{G}(V, E))$"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### MISC. TESTING"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Basic Constructions"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G = Graph(V, E)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "paths_of_g = PathsOf(G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(P, paths_of_g)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(P, paths_of_g)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end demonstrations"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/paths_of/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/paths_of/_theory_nbs_/theorems.ipynb
new file mode 100644
index 000000000000..1e67f0ce4c5f
--- /dev/null
+++ b/packages/proveit/graphs/paths_of/_theory_nbs_/theorems.ipynb
@@ -0,0 +1,59 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theorems (or conjectures) for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.paths_of</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "# Prepare this notebook for defining the theorems of a theory:\n",
+    "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
+    "\n",
+    "# from ... import ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%begin theorems"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end theorems"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/paths_of/_theory_nbs_/theory.ipynb b/packages/proveit/graphs/paths_of/_theory_nbs_/theory.ipynb
new file mode 100644
index 000000000000..98c28c67e646
--- /dev/null
+++ b/packages/proveit/graphs/paths_of/_theory_nbs_/theory.ipynb
@@ -0,0 +1,33 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Theory of <a class=\"ProveItLink\" href=\"../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../_theory_nbs_/theory.ipynb\">graphs</a>.paths_of\n",
+    "========\n",
+    "\n",
+    "Provide description here."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%theory # toggles between interactive and static modes"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/paths_of/paths_of.py b/packages/proveit/graphs/paths_of/paths_of.py
new file mode 100644
index 000000000000..d80c0f3b6045
--- /dev/null
+++ b/packages/proveit/graphs/paths_of/paths_of.py
@@ -0,0 +1,53 @@
+from proveit import Function, Literal
+
+'''
+Consider:
+(1) Changing the current Paths(G) function to PathsOf(G)
+(2) Adding a new Paths class to denote the set of all graphs
+    that are also paths. Paths() would then be a subset (subclass?)
+    of Graphs().
+(3) Move the Path(V,E) class from graph.py to here to represent
+    a specific path with vertex set V and edge set E.
+    A path P = Path(V, E) would be an element of the Paths() class,
+    and also an element of the Graphs() class.
+This might work well.
+'''
+
+class PathsOf(Function):
+    '''
+    Given a graph G = G(V, E) with vertex set V and edge set E,
+    PathsOf(G) represents the set of all paths in the graph G.
+    A Path (in an undirected graph G) is a non-empty graph P = (V,E)
+    with non-empty vertex set V and (possibly empty) edge set E such
+    that:
+            V = {x0, x1, ..., xk},
+            E = {{x0,x1}, {x1,x2}, ..., {x_{k-1},x_{k}},
+
+    where the x_{i} are all distinct. The vertices x0 and xk are said
+    to be linked by the path P and are called its endvertices, or
+    endpoints, or simply its ends. The vertices x1, ..., x_{k-1} are
+    the inner vertices of P. The number of edges in the path P,
+    denoted ||P||, is its length (in this example, ||P|| = k).
+    '''
+
+    # the literal operator of the PathsOf operation
+    _operator_ = Literal(string_format='PathsOf',
+                         latex_format=r'\mathrm{PathsOf}',
+                         theory=__file__)
+
+    def __init__(self, G, *, styles=None):
+        '''
+        Represent the set of paths in the graph G = G(V,E) with vertex
+        set V and edge set E.
+        '''
+        Function.__init__(
+                self, PathsOf._operator_, G, styles=styles)
+
+    # the membership stuff still to be updated!
+    def membership_object(self, element):
+        from .paths_of_membership import PathsOfMembership
+        return PathsOfMembership(element, self)
+
+    def nonmembership_object(self, element):
+        from .paths_of_membership import PathsOfNonmembership
+        return PathsOfNonmembership(element, self)
diff --git a/packages/proveit/graphs/paths_of/paths_of_membership.py b/packages/proveit/graphs/paths_of/paths_of_membership.py
new file mode 100644
index 000000000000..02e0e1539701
--- /dev/null
+++ b/packages/proveit/graphs/paths_of/paths_of_membership.py
@@ -0,0 +1,21 @@
+from proveit.logic import SetMembership, SetNonmembership
+
+
+class PathsOfMembership(SetMembership):
+    '''
+    Defines methods that apply to membership in the set PathsOf(G)
+    of all paths in graph G.
+    '''
+
+    def __init__(self, element, domain):
+        SetMembership.__init__(self, element, domain)
+
+
+class PathsOfNonmembership(SetNonmembership):
+    '''
+    Defines methods that apply to non-membership in the set PathsOf(G)
+    of all paths in graph G.
+    '''
+
+    def __init__(self, element, domain):
+        SetNonmembership.__init__(self, element, domain)
\ No newline at end of file

From c9b57b59e3050dc2741dd741c29df48855ab7542 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sat, 3 May 2025 10:52:00 -0500
Subject: [PATCH 037/159] Update graphs/paths sub-theory package

Update the graphs/paths sub-theory package, following up on previous commit that created a separate theory package for the PathsOf(G) class, now establishing Paths() as the class of graphs that are paths, along with updates to related demonstrations notebook and paths_membership.py classes.
---
 packages/proveit/graphs/__init__.py           |  2 +-
 packages/proveit/graphs/paths/__init__.py     |  2 +-
 .../paths/_theory_nbs_/demonstrations.ipynb   | 41 +++++++++--
 packages/proveit/graphs/paths/paths.py        | 73 ++++++++++++++-----
 .../proveit/graphs/paths/paths_membership.py  | 12 +--
 5 files changed, 99 insertions(+), 31 deletions(-)

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index 0b99d4ee9968..c45dce1a2c54 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -4,7 +4,7 @@
 from .inclusion import NotSubgraph, Subgraph
 from .membership import (
       GraphMembership, GraphNonmembership, InGraph, NotInGraph)
-from .paths import Paths
+from .paths import Path, Paths
 from .paths_of import PathsOf
 from .union import GraphUnion
 from .vertices import Degree, Vertices
diff --git a/packages/proveit/graphs/paths/__init__.py b/packages/proveit/graphs/paths/__init__.py
index b0bb392ce3f8..355de8e870a3 100644
--- a/packages/proveit/graphs/paths/__init__.py
+++ b/packages/proveit/graphs/paths/__init__.py
@@ -1,4 +1,4 @@
-from .paths import Paths
+from .paths import Path, Paths
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
 #  Make additions above, or add to sys.modules[__name__].__dict__ below.
diff --git a/packages/proveit/graphs/paths/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/paths/_theory_nbs_/demonstrations.ipynb
index bb203fead6fa..9a3eaf7c9fca 100644
--- a/packages/proveit/graphs/paths/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/paths/_theory_nbs_/demonstrations.ipynb
@@ -18,15 +18,16 @@
     "%begin demonstrations\n",
     "\n",
     "from proveit import E, G, P, V\n",
+    "from proveit.logic import InClass, NotInClass\n",
     "from proveit.logic.sets import NotInSet, InSet\n",
-    "from proveit.graphs import Graph, Paths"
+    "from proveit.graphs import Path, Paths"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "### Paths in Graph $G$: $\\mathrm{Paths}(\\mathrm{G}(V, E))$"
+    "### The Class of Paths, and Elements of That Class: $\\mathrm{Paths}$, $\\mathrm{Path}(V, E)$"
    ]
   },
   {
@@ -49,7 +50,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "G = Graph(V, E)"
+    "paths_class = Paths()"
    ]
   },
   {
@@ -58,7 +59,8 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "example_paths = Paths(G)"
+    "# does this not automatically convert to InClass notation?\n",
+    "InSet(P, paths_class)"
    ]
   },
   {
@@ -67,7 +69,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(P, example_paths)"
+    "NotInSet(P, paths_class)"
    ]
   },
   {
@@ -76,7 +78,34 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "NotInSet(P, example_paths)"
+    "InClass(P, paths_class)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInClass(P, paths_class)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "example_path = Path(V, E)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(example_path, Paths())"
    ]
   },
   {
diff --git a/packages/proveit/graphs/paths/paths.py b/packages/proveit/graphs/paths/paths.py
index 4488674d18da..a7237f751abc 100644
--- a/packages/proveit/graphs/paths/paths.py
+++ b/packages/proveit/graphs/paths/paths.py
@@ -1,14 +1,15 @@
 from proveit import Function, Literal
+from proveit.logic import ClassMembership
+from proveit.graphs import Graph
 
-class Paths(Function):
+class Paths(Literal):
     '''
-    Given a graph G = G(V, E) with vertex set V and edge set E,
-    Paths(G) represents the set of all paths in the graph G.
-    A Path (in an undirected graph G) is a non-empty graph P = (V,E)
-    with vertex set V and edge set E such that:
-
-        V = {x0, x1, ..., xk},
-        E = {{x0,x1}, {x1,x2}, ..., {x_{k-1},x_{k}},
+    Paths() represents the set of all graphs that are (undirected)
+    paths. A undirected path is a non-empty graph P = (V,E)
+    with non-empty vertex set V and (possibly empty) edge set E such
+    that:
+            V = {x0, x1, ..., xk},
+            E = {{x0,x1}, {x1,x2}, ..., {x_{k-1},x_{k}},
 
     where the x_{i} are all distinct. The vertices x0 and xk are said
     to be linked by the path P and are called its endvertices, or
@@ -17,18 +18,20 @@ class Paths(Function):
     denoted ||P||, is its length (in this example, ||P|| = k).
     '''
 
-    # the literal operator of the Paths operation
-    _operator_ = Literal(string_format='Paths',
-                         latex_format=r'\mathrm{Paths}',
-                         theory=__file__)
+    # the literal string for representing the class of Paths
+    def __init__(self, *, styles=None):
+        Literal.__init__(self, string_format='Paths', 
+                         latex_format=r'\textrm{Paths}',
+                         styles=styles)
 
-    def __init__(self, G, *, styles=None):
+    @property
+    def is_proper_class(self):
         '''
-        Represent the set of paths in the graph G = G(V,E) with vertex
-        set V and edge set E.
+        Paths consitute a proper class (i.e. instead of a set).
+        This indicates that InClass() should be used instead of
+        InSet() when this is a domain.
         '''
-        Function.__init__(
-                self, Paths._operator_, G, styles=styles)
+        return True
 
     def membership_object(self, element):
         from .paths_membership import PathsMembership
@@ -36,4 +39,38 @@ def membership_object(self, element):
 
     def nonmembership_object(self, element):
         from .paths_membership import PathsNonmembership
-        return PathsNonmembership(element, self)
\ No newline at end of file
+        return PathsNonmembership(element, self)
+
+
+class Path(Graph):
+    '''
+    Path(V,E) represents the special type of graph called a path,
+    with vertex set V and edge set E. A path is a non-empty graph
+    P = (V,E) with vertex set V and (possibly empty) edge set E such
+    that:
+
+        V = {x0, x1, ..., xk}, E = {x0x1, x1x2, ..., x_{k-1}x_{k}},
+
+    where the x_{i} are all distinct. The vertices x0 and xk are said
+    to be linked by the path P and are called its endvertices, or
+    endpoints, or simply its ends. The vertices x1, ..., x_{k-1} are
+    the inner vertices of P. The number of edges in the path P,
+    denoted ||P||, is its length (in this example, ||P|| = k).
+    '''
+
+    # the literal operator of the Path operator
+    _operator_ = Literal(string_format='Path',
+                         latex_format=r'\text{Path}',
+                         theory=__file__)
+
+    def __init__(self, V, E, *, styles=None):
+        '''
+        Create or represent a path, Path(V,E), with vertex set V
+        and edge set E. If explicit sets of vertices and edges are
+        provided, they are NOT currently verified to represent a
+        valid path.
+        '''
+        self.vertex_set = V
+        self.edge_set   = E
+        Function.__init__(self, Path._operator_, (V, E), styles=styles)
+
diff --git a/packages/proveit/graphs/paths/paths_membership.py b/packages/proveit/graphs/paths/paths_membership.py
index 3548f97dbf79..781f00e1864f 100644
--- a/packages/proveit/graphs/paths/paths_membership.py
+++ b/packages/proveit/graphs/paths/paths_membership.py
@@ -1,21 +1,23 @@
-from proveit.logic import SetMembership, SetNonmembership
+# from proveit.logic import SetMembership, SetNonmembership
+from proveit.logic import ClassMembership, ClassNonmembership
 
 
-class PathsMembership(SetMembership):
+
+class PathsMembership(ClassMembership):
     '''
     Defines methods that apply to membership in the set Paths(G)
     of all paths in a graph G.
     '''
 
     def __init__(self, element, domain):
-        SetMembership.__init__(self, element, domain)
+        ClassMembership.__init__(self, element, domain)
 
 
-class PathsNonmembership(SetNonmembership):
+class PathsNonmembership(ClassNonmembership):
     '''
     Defines methods that apply to non-membership in the set Paths(G)
     of all paths in a graph G.
     '''
 
     def __init__(self, element, domain):
-        SetNonmembership.__init__(self, element, domain)
\ No newline at end of file
+        ClassNonmembership.__init__(self, element, domain)
\ No newline at end of file

From cbbfc112a78ecb4bdd077d28446c5db685560609 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sat, 3 May 2025 10:53:18 -0500
Subject: [PATCH 038/159] Update graphs/vertices demonstrations.ipynb

Update graphs/vertices demonstrations.ipynb for change in Degree class from one to two arguments.
---
 .../proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
index 2a8891e2c66a..3a6fcb9a5022 100644
--- a/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
@@ -86,7 +86,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Degree(v)"
+    "Degree(v, G)"
    ]
   },
   {

From 318aeac3ee5f3899492214f711d7291a27f05d22 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sat, 3 May 2025 10:55:43 -0500
Subject: [PATCH 039/159] Update graphs axioms to delete redundant Edges axiom

Update graphs axioms to delete redundant Edges axiom, because Edges class now appears in its own sub-theory package with Edges-defining axiom appearing there instead.
---
 packages/proveit/graphs/_theory_nbs_/axioms.ipynb | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
index 43f066b37043..2b7f642ce1bf 100644
--- a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
@@ -47,19 +47,6 @@
     ")"
    ]
   },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "edge_set_of_graph_v_e_is_e = (\n",
-    "    Forall(V,\n",
-    "    Forall(E, Equals(Edges(Graph(V, E)), E), conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
-    "    )\n",
-    ")"
-   ]
-  },
   {
    "cell_type": "code",
    "execution_count": null,

From d76f50a2edd1b1eba55be51264fc35461d3dfe3c Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sat, 3 May 2025 10:58:06 -0500
Subject: [PATCH 040/159] Remove unnecessary import in
 GraphsMembership.__init__()

Remove unnecessary import in GraphsMembership.__init__(). Would need this import if GraphsMembership class appeared in separate .py file.
---
 packages/proveit/graphs/graph.py | 1 -
 1 file changed, 1 deletion(-)

diff --git a/packages/proveit/graphs/graph.py b/packages/proveit/graphs/graph.py
index a70d4da7cad4..6d7d58f16899 100644
--- a/packages/proveit/graphs/graph.py
+++ b/packages/proveit/graphs/graph.py
@@ -33,7 +33,6 @@ def is_proper_class(self):
 class GraphsMembership(ClassMembership):
 
     def __init__(self, element, domain):
-        from . import Graphs
         ClassMembership.__init__(self, element, domain)
         if domain != Graphs():
             raise TypeError("domain expected to be Graphs, not %s"

From 2fcfaa476c212d052e6764f08ee248dcc0a831fb Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sun, 4 May 2025 06:38:39 -0500
Subject: [PATCH 041/159] Update VerticesMembership.as_defined() method

Update VerticesMembership.as_defined() method to acknowledge that it works only for cases in which the domain Vertices(G) has as operand an explicit graph object of the form Graph(V,E) with explicit vertex set V, passing up a NotImplementedError() otherwise. Tested in vertices demonstrations.ipynb and in a related endpoints theorem proof notebook.
---
 .../_theory_nbs_/demonstrations.ipynb         | 39 +++++++++++++++----
 .../graphs/vertices/vertices_membership.py    | 23 ++++++++---
 2 files changed, 49 insertions(+), 13 deletions(-)

diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
index 3a6fcb9a5022..ebecb0c9bb6c 100644
--- a/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
@@ -89,6 +89,24 @@
     "Degree(v, G)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Vertices(P)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Vertices(P))"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -128,6 +146,20 @@
     "InSet(v, Vertices(G)).as_defined()"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# the domain's argument must be an explicit Graph with specified vertex set\n",
+    "from proveit import H\n",
+    "try:\n",
+    "    InSet(v, Vertices(H)).as_defined()\n",
+    "except Exception as the_exception:\n",
+    "    print(f\"Exception: {the_exception}\")"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -231,13 +263,6 @@
     "NotInSet(v, Vertices(G)).conclude(assumptions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(v, V)])"
    ]
   },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/vertices/vertices_membership.py b/packages/proveit/graphs/vertices/vertices_membership.py
index 245ec0edb86f..7280e15e65c2 100644
--- a/packages/proveit/graphs/vertices/vertices_membership.py
+++ b/packages/proveit/graphs/vertices/vertices_membership.py
@@ -1,5 +1,6 @@
 from proveit import v, E, V, equality_prover, prover
 from proveit.logic import SetMembership, SetNonmembership
+from proveit.graphs import Graph
 
 
 class VerticesMembership(SetMembership):
@@ -28,12 +29,22 @@ def definition(self, **defaults_config):
     def as_defined(self):
         '''
         From self = [elem in Vertices(Graph(V,E))], return: [elem in V]
-        (i.e. an expression, not a Judgment)
-        '''
-        from proveit.logic import InSet
-        element = self.element
-        _V = self.domain.graph.vertex_set
-        return InSet(element, _V)
+        (i.e. an expression, not a Judgment). Only works if the
+        Vertices domain has as an operand an actual Graph object
+        Graph(V,E) with a specified vertex set V.
+        '''
+        if isinstance(self.domain.operand, Graph):
+            from proveit.logic import InSet
+            element = self.element
+            _V =  self.domain.graph.vertex_set
+            return InSet(element, _V)
+        else:
+            raise NotImplementedError(
+                "VerticesMembership.as_defined() called on "
+                f"self = {self.expr} with domain = {self.expr.domain}, "
+                "but the method is implemented only for domains of "
+                "the form Vertices(G) where G is an explicit Graph "
+                "object of the form Graph(V,E) with a named vertex set.")
 
     @prover
     def unfold(self, **defaults_config):

From b7e133687395877804ae21a0848bff973bb60fb1 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sun, 4 May 2025 06:54:51 -0500
Subject: [PATCH 042/159] Update graphs demonstrations.ipynb notebook

Update graphs demonstrations.ipynb notebook to include an example expressing that a graph G is in the class Graphs of graphs. Still TBA: raise an error when trying to use InSet if InClass is actually required.
---
 .../proveit/graphs/_theory_nbs_/demonstrations.ipynb | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
index fcda0bf2537a..66649c3a4757 100644
--- a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
@@ -16,7 +16,8 @@
    "source": [
     "import proveit\n",
     "from proveit import x, E, G, V\n",
-    "from proveit.graphs import Endpoints, Graph, Path\n",
+    "from proveit.logic import InClass\n",
+    "from proveit.graphs import Endpoints, Graph, Graphs, Path\n",
     "%begin demonstrations"
    ]
   },
@@ -44,6 +45,15 @@
     "example_graph = Graph(V, E)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InClass(example_graph, Graphs())"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From 15d1a4419a97de877e4a7821d4ec3e70036f5d8e Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sun, 4 May 2025 07:33:33 -0500
Subject: [PATCH 043/159] Update graphs/endpoints axioms to use SetOfAll
 construct

Update graphs/endpoints definitional axiom to use SetOfAll construct (instead of the more indirect InSet membership approach) and rework to also include the special case of a trivial path (a graph with a single vertex).
---
 .../endpoints/_theory_nbs_/axioms.ipynb       | 22 +++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/axioms.ipynb
index 042a4bbeb5ef..8c1a3ea9f657 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/axioms.ipynb
@@ -18,7 +18,11 @@
     "# Prepare this notebook for defining the axioms of a theory:\n",
     "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "# from ... import ..."
+    "from proveit import v, P\n",
+    "from proveit.logic import Equals, Forall, NotEquals\n",
+    "from proveit.logic.sets import EmptySet, SetOfAll\n",
+    "from proveit.numbers import one, LessEq\n",
+    "from proveit.graphs import Degree, Edges, Endpoints, Paths, Vertices"
    ]
   },
   {
@@ -30,12 +34,26 @@
     "%begin axioms"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### The following defines endpoints for any path $P$, including a trivial path consisting of just a single isolated vertex."
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "endpoints_def = (\n",
+    "    Forall(P,\n",
+    "       Equals(Endpoints(P), SetOfAll(v, v, conditions = [LessEq(Degree(v, P), one)], domain = Vertices(P))),\n",
+    "       domain = Paths()\n",
+    "    )\n",
+    ")"
+   ]
   },
   {
    "cell_type": "code",

From db74f3f6e83681bf7e4b5764a8a2d582bfbaecb9 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sun, 4 May 2025 07:36:45 -0500
Subject: [PATCH 044/159] Begin updating graphs/endpoints theorems

Begin updating graphs/endpoints theorems, to be consistent with rewriting of the endpoints_def axiom in terms of set comprehension SetOfAll. Commit includes one rewritten theorem (membership_unfolding) (the others temporarily commented out) along with a tentative proof of the theorem.
---
 .../allowed_presumptions.txt                  |   4 +
 .../disallowed_presumptions.txt               |   0
 .../membership_unfolding/thm_proof.ipynb      | 108 ++++++++++++++++++
 .../endpoints/_theory_nbs_/theorems.ipynb     |  58 +++++++++-
 .../proveit/graphs/endpoints/endpoints.py     |   2 +-
 5 files changed, 170 insertions(+), 2 deletions(-)
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb

diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
new file mode 100644
index 000000000000..a584ff39dfc4
--- /dev/null
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
@@ -0,0 +1,4 @@
+proveit.logic.equality.rhs_via_equality
+proveit.logic.equality.sub_right_side_into
+proveit.logic.sets.comprehension.unfold_basic_comprehension
+proveit.logic.sets.comprehension.in_superset_if_in_comprehension
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/disallowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
new file mode 100644
index 000000000000..146a68b71cc4
--- /dev/null
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
@@ -0,0 +1,108 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">endpoints</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_unfolding\">membership_unfolding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import v, P, X, defaults, Lambda\n",
+    "from proveit.logic import InSet\n",
+    "from proveit.graphs import Vertices\n",
+    "from proveit.graphs.endpoints import endpoints_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving membership_unfolding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = membership_unfolding.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "endpoints_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "endpoints_def_inst = endpoints_def.instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "temp_lambda = Lambda(X, InSet(v, X))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "endpoints_def_membership = endpoints_def_inst.substitution(temp_lambda)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "endpoints_def_membership.rhs.domain.unfold_membership(v)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
index 5de92d131006..9a90a122670e 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
@@ -18,7 +18,14 @@
     "# Prepare this notebook for defining the theorems of a theory:\n",
     "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "# from ... import ..."
+    "from proveit import v, E, P, V\n",
+    "from proveit.logic import And, Equals, Forall, InClass, NotEquals\n",
+    "from proveit.logic.sets import EmptySet, InSet, KPowerSet, SubsetEq\n",
+    "from proveit.numbers import one, two, LessEq\n",
+    "from proveit.graphs import Degree, Endpoints, Path, Vertices\n",
+    "\n",
+    "from proveit.logic.sets import SetOfAll\n",
+    "from proveit.graphs import Paths"
    ]
   },
   {
@@ -30,6 +37,55 @@
     "%begin theorems"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_unfolding = (\n",
+    "    Forall(P,\n",
+    "    Forall(v,\n",
+    "           And(InSet(v, Vertices(P)), LessEq(Degree(v, P), one)),\n",
+    "           domain = Endpoints(P)),\n",
+    "    domain = Paths())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# membership_unfolding = (\n",
+    "#     Forall(V,\n",
+    "#            Forall((v, E),\n",
+    "#                   And(InSet(v, V), LessEq(Degree(v), one)),\n",
+    "#                   conditions = [SubsetEq(E, KPowerSet(V, two)),\n",
+    "#                                 InSet(v, Endpoints(Path(V, E)))]\n",
+    "#            )\n",
+    "#     )\n",
+    "# )"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# membership_folding = (\n",
+    "#     Forall(V,\n",
+    "#            Forall((v, E),\n",
+    "#                   InSet(v, Endpoints(Path(V, E))),\n",
+    "#                   conditions = [SubsetEq(E, KPowerSet(V, two)),\n",
+    "#                                 NotEquals(E, EmptySet), And(InSet(v, V), Equals(Degree(v), one))]\n",
+    "#            )\n",
+    "#     )\n",
+    "# )"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/endpoints/endpoints.py b/packages/proveit/graphs/endpoints/endpoints.py
index c29b4e1eef37..b37d933ca0e8 100644
--- a/packages/proveit/graphs/endpoints/endpoints.py
+++ b/packages/proveit/graphs/endpoints/endpoints.py
@@ -7,7 +7,6 @@ class Endpoints(Function):
     a subset of the Path P's vertex set V, and for a non-trivial path
     consisting of more than one vertex will consist of the 1-degree
     vertices.
-    Endpoints(P) will not "know" the original path P whence it came.
     '''
 
     # the literal operator of the Endpoints operator
@@ -19,6 +18,7 @@ def __init__(self, P, *, styles=None):
         '''
         Create the endpoints set EndPts(P) for Path P.
         '''
+        self.path = P
         Function.__init__(
                 self, Endpoints._operator_, P, styles=styles)
 

From 5afe0409aa3e524d54f7586d74e211b1fa80e6a7 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sun, 4 May 2025 07:41:09 -0500
Subject: [PATCH 045/159] Update paths_of.py

Update paths_of.py in paths_of package, just cleaning up & deleting obsolete comments.
---
 packages/proveit/graphs/paths_of/paths_of.py | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/packages/proveit/graphs/paths_of/paths_of.py b/packages/proveit/graphs/paths_of/paths_of.py
index d80c0f3b6045..654b90deb36b 100644
--- a/packages/proveit/graphs/paths_of/paths_of.py
+++ b/packages/proveit/graphs/paths_of/paths_of.py
@@ -1,18 +1,5 @@
 from proveit import Function, Literal
 
-'''
-Consider:
-(1) Changing the current Paths(G) function to PathsOf(G)
-(2) Adding a new Paths class to denote the set of all graphs
-    that are also paths. Paths() would then be a subset (subclass?)
-    of Graphs().
-(3) Move the Path(V,E) class from graph.py to here to represent
-    a specific path with vertex set V and edge set E.
-    A path P = Path(V, E) would be an element of the Paths() class,
-    and also an element of the Graphs() class.
-This might work well.
-'''
-
 class PathsOf(Function):
     '''
     Given a graph G = G(V, E) with vertex set V and edge set E,
@@ -43,7 +30,6 @@ def __init__(self, G, *, styles=None):
         Function.__init__(
                 self, PathsOf._operator_, G, styles=styles)
 
-    # the membership stuff still to be updated!
     def membership_object(self, element):
         from .paths_of_membership import PathsOfMembership
         return PathsOfMembership(element, self)

From 73703ed1b2d939071c7b135c752a081e00923c24 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sun, 4 May 2025 07:44:40 -0500
Subject: [PATCH 046/159] Update graphs.py, shfiting Path class to paths pkg

Update graphs.py, deleting the Path class which now appears in graphs/paths theory package inside paths.py.
---
 packages/proveit/graphs/graph.py | 27 ---------------------------
 1 file changed, 27 deletions(-)

diff --git a/packages/proveit/graphs/graph.py b/packages/proveit/graphs/graph.py
index 6d7d58f16899..7cc548c8da92 100644
--- a/packages/proveit/graphs/graph.py
+++ b/packages/proveit/graphs/graph.py
@@ -66,31 +66,4 @@ def __init__(self, V, E, *, styles=None):
                 self, Graph._operator_, (V, E), styles=styles)
 
 
-class Path(Graph):
-    '''
-    Path(V,E) represents a path. A Path is a non-empty graph
-    P = (V,E) with vertex set V and edge set E such that:
-
-        V = {x0, x1, ..., xk}, E = {x0x1, x1x2, ..., x_{k-1}x_{k}},
-
-    where the x_{i} are all distinct. The vertices x0 and xk are said
-    to be linked by the path P and are called its endvertices, or
-    endpoints, or simply its ends. The vertices x1, ..., x_{k-1} are
-    the inner vertices of P. The number of edges in the path P,
-    denoted ||P||, is its length (in this example, ||P|| = k).
-    '''
-
-    # the literal operator of the Path operator
-    _operator_ = Literal(string_format='Path',
-                         latex_format=r'\text{Path}',
-                         theory=__file__)
 
-    def __init__(self, V, E, *, styles=None):
-        '''
-        Create or represent a Path, Path(V,E), with vertex set V
-        and edge set E.
-        '''
-        self.vertex_set = V
-        self.edge_set   = E
-        Function.__init__(
-                self, Path._operator_, (V, E), styles=styles)

From 5dcc9158e04cccb519b1c95867941f3dc9642815 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sun, 4 May 2025 07:47:20 -0500
Subject: [PATCH 047/159] Update EndpointsMembership methods

Update EndpointsMembership methods with introduction of EndpointsMembership.definition() method.
---
 .../graphs/endpoints/endpoints_membership.py      | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/packages/proveit/graphs/endpoints/endpoints_membership.py b/packages/proveit/graphs/endpoints/endpoints_membership.py
index c2c876ef24cb..5c0cf121a635 100644
--- a/packages/proveit/graphs/endpoints/endpoints_membership.py
+++ b/packages/proveit/graphs/endpoints/endpoints_membership.py
@@ -10,6 +10,21 @@ class EndpointsMembership(SetMembership):
     def __init__(self, element, domain):
         SetMembership.__init__(self, element, domain)
 
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self = [elem in Endpoints(P)], where P is a non-trivial
+        path (i.e. a path with at least one edge), deduce and return:
+            [elem in Vertices(Graph(V,E))] = [elem in V]
+        '''
+
+        from . import membership_def
+        element = self.element
+        _V_sub  = self.domain.graph.vertex_set
+        _E_sub  = self.domain.graph.edge_set
+        return membership_def.instantiate(
+                {v:element, V:_V_sub, E:_E_sub },auto_simplify=False)
+
 
 class EndpointsNonmembership(SetNonmembership):
     '''

From 2eb06feac73fba4f1c2011091a4ac5a9f6b485a5 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Fri, 7 Mar 2025 14:34:09 -0700
Subject: [PATCH 048/159] Update SetOfAll.unfold_membership() method

Update SetOfAll.unfold_membership() method in the logic/sets/comprehension theory package, making the method serviceable for many cases but still not quite complete, with some errors still arising when there are multiple instance_vars for the SetOfAll expression. See working and non-working examples in the comprehension package demonstrations notebook (saved in a subsequent commit).
---
 .../logic/sets/comprehension/set_of_all.py    | 71 +++++++++++++------
 1 file changed, 50 insertions(+), 21 deletions(-)

diff --git a/packages/proveit/logic/sets/comprehension/set_of_all.py b/packages/proveit/logic/sets/comprehension/set_of_all.py
index f8ed875100a9..56af5d16fa5c 100644
--- a/packages/proveit/logic/sets/comprehension/set_of_all.py
+++ b/packages/proveit/logic/sets/comprehension/set_of_all.py
@@ -1,6 +1,7 @@
 from proveit import (
         ExprTuple, Function, Literal, OperationOverInstances,
-        Lambda, composite_expression, relation_prover, defaults)
+        Lambda, composite_expression, relation_prover, defaults,
+        prover)
 from proveit import f, n, x, y, Q, R, S
 
 
@@ -130,7 +131,7 @@ def deduce_subset_eq_relation(self, subset, **defaults_config):
     # The below must be updated
     # Being updated gradually by wdc starting 12/21/2021
 
-    @relation_prover
+    @prover
     def unfold_membership(self, element, **defaults_config):
         '''
         From (x in {y | Q(y)})_{y in S}, derive and return
@@ -140,41 +141,69 @@ def unfold_membership(self, element, **defaults_config):
         From (x in {f(y) | ..Q(y)..})_{y in S}, derive and return
         exists_{y in S | ..Q(y)..} x = f(y).
         Also derive x in S, but this is not returned.
+        As an example, consider the set A defined by:
+
+            A = SetOfAll(i, ExprTuple(i, zero),
+                domain = Interval(zero, num(10)))
+
+        which gives a set of tuples like this:
+
+            {(0,0), (1,0), ... (10,0)}.
+
+        Then A.unfold_membership(x, assumptions = [InSet(x, A)])
+        yields the judgment:
+
+            x in A |- Exists_{i in {0, 1, ..., 10}} s.t. x = (i, 0).
+
         '''
         from . import (unfold, unfold_basic_comprehension,
                        in_superset_if_in_comprehension)
         from proveit.logic import And
+        from proveit.numbers import num
         if len(self.explicit_conditions())==1:
             explicit_conditions = self.explicit_conditions()[0]
         else:
+            # which includes case of no explicit conditions!
             explicit_conditions = And(*self.explicit_conditions())
-        # why is the following line there before testing number of vars
-        _Q_op, _Q_op_sub = Function(Q, self.all_instance_vars()), explicit_conditions
+        _Q_op, _Q_op_sub = (
+                Function(Q, self.all_instance_vars()), explicit_conditions)
         if (len(self.all_instance_vars()) == 1 and
             self.instance_element == self.instance_var):
-            # simple case of {x | Q(x)}_{x in S};
-            # derive x in S side-effect
-            print("(1) SetOfAll.unfold_membership(): inside first if.")
-            print("_Q_op = ")
-            display(_Q_op)
-            print("_Q_op_sub = ")
-            display(_Q_op_sub)
+            # simple case of {x | Q(x)}_{x in S}; derive (but don't)
+            # explicitly return) side-effect that x is in S;
+            # we do this here because some cases below do not include
+            # the membership in the returned result
             in_superset_if_in_comprehension.instantiate(
                     {S: self.domain, _Q_op: _Q_op_sub,
                      x: element, y: self.instance_var})
-            print("SetOfAll.unfold_membership(): end")
             if len(self.explicit_conditions())==1:
                 _Q_op, _Q_op_sub = (
                     Function(Q, self.all_instance_vars()), explicit_conditions)
-            #     return unfold_basic1_cond_comprehension.instantiate(
-            #             {S:self.domain, Q_op:Q_op_sub,
-            #              x:element, y:self.instance_vars[0]})
-            # else:
-            #     return unfold_basic_comprehension.instantiate({S:self.domain, Q_op:Q_op_sub, x:element}, {y:self.instance_vars[0]}, assumptions=assumptions)
-        # else:
-        #     f_op, f_sub = Function(f, self.instance_vars), self.instance_element
-        #     return unfold_comprehension.instantiate({S:self.domain,  Q_op:Q_op_sub, f_op:f_sub, x:element}, {y_multi:self.instance_vars}).derive_conclusion(assumptions)
-
+                _y_sub = self.all_instance_vars
+                return unfold_basic_comprehension.instantiate(
+                        {S:self.domain, _Q_op:_Q_op_sub, x:element,
+                         y:self.all_instance_vars()[0]})
+            else:
+                # multiple explicit conditions, so we use the And(*)
+                # construction from earlier for the _Q_op_sub
+                return unfold_basic_comprehension.instantiate(
+                        {S:self.domain, _Q_op:_Q_op_sub, x:element,
+                         y:self.all_instance_vars()[0]})
+        else: 
+            # cases where we have:
+            # (1) multiple instance_vars,
+            # (2) and/or instance_element is not just an instance_var
+            _n_sub = num(len(self.all_instance_vars()))
+            _f_op, _f_sub = (
+                Function(f, self.all_instance_vars()), self.instance_element)
+            if len(self.explicit_conditions())<=1:
+                should_auto_simplify = True # will simplify And()
+            else:
+                should_auto_simplify = False
+            return unfold.instantiate(
+                {n:_n_sub, S:self.all_domains(),  _Q_op:_Q_op_sub, _f_op:_f_sub,
+                x:element, y:self.all_instance_vars()},
+                auto_simplify = should_auto_simplify).derive_consequent()
 
 
     """

From 1c8fb94488efb4f0d080049b690aea07c3b06a29 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sun, 4 May 2025 10:34:52 -0500
Subject: [PATCH 049/159] Update Edges, Vertices, Graph classes with longer
 notation

Update Edges, Vertices, Graph classes with longer notation: instead of the abbreviations E, V, and G, this switches the output notation back to the full labels Edges, Vertices, and Graph.
---
 packages/proveit/graphs/edges/edges.py       | 4 ++--
 packages/proveit/graphs/graph.py             | 4 ++--
 packages/proveit/graphs/vertices/vertices.py | 9 +++------
 3 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/packages/proveit/graphs/edges/edges.py b/packages/proveit/graphs/edges/edges.py
index 86a6cbcf0462..b43bf03db4c3 100644
--- a/packages/proveit/graphs/edges/edges.py
+++ b/packages/proveit/graphs/edges/edges.py
@@ -11,8 +11,8 @@ class Edges(Function):
     '''
 
     # the literal operator of the Vertices operation
-    _operator_ = Literal(string_format='E',
-                         latex_format=r'\mathrm{E}',
+    _operator_ = Literal(string_format='Edges',
+                         latex_format=r'\mathrm{Edges}',
                          theory=__file__)
 
     def __init__(self, G, *, styles=None):
diff --git a/packages/proveit/graphs/graph.py b/packages/proveit/graphs/graph.py
index 7cc548c8da92..15007061564c 100644
--- a/packages/proveit/graphs/graph.py
+++ b/packages/proveit/graphs/graph.py
@@ -52,8 +52,8 @@ class Graph(Function):
     '''
 
     # the literal operator of the Graph operation
-    _operator_ = Literal(string_format='G',
-                         latex_format=r'\textrm{G}',
+    _operator_ = Literal(string_format='Graph',
+                         latex_format=r'\textrm{Graph}',
                          theory=__file__)
 
     def __init__(self, V, E, *, styles=None):
diff --git a/packages/proveit/graphs/vertices/vertices.py b/packages/proveit/graphs/vertices/vertices.py
index baea7ad5c46d..608f91581899 100644
--- a/packages/proveit/graphs/vertices/vertices.py
+++ b/packages/proveit/graphs/vertices/vertices.py
@@ -4,15 +4,12 @@ class Vertices(Function):
     '''
     Given a graph G(V, E) with vertex set V and edge set E,
     Vertices(G(V, E)) represents the set V of vertices ---
-    that is, Vertices(G(V,E)) = V. The notation will use V(G),
-    in which case we might see things like V(G) = V, but the operator
-    V will appear in mathrm to distinguish it from the set V in
-    italics.
+    that is, Vertices(G(V,E)) = V.
     '''
 
     # the literal operator of the Vertices operation
-    _operator_ = Literal(string_format='V',
-                         latex_format=r'\mathrm{V}',
+    _operator_ = Literal(string_format='Vertices',
+                         latex_format=r'\mathrm{Vertices}',
                          theory=__file__)
 
     def __init__(self, G, *, styles=None):

From 70cab32b02a857b273b591c2c46df5184f0b073b Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sun, 4 May 2025 20:12:40 -0500
Subject: [PATCH 050/159] Update VerticesNonmembership.as_defined()

Update VerticesNonmembership.as_defined() method to acknowledge that it works only for cases in which the domain Vertices(G) has as operand an explicit graph object of the form Graph(V,E) with explicit vertex set V, passing up a NotImplementedError() otherwise. Tested in vertices demonstrations.ipynb.
---
 .../_theory_nbs_/demonstrations.ipynb         | 25 ++++++++++++++++++-
 .../graphs/vertices/vertices_membership.py    | 16 +++++++++---
 2 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
index ebecb0c9bb6c..e0a009279c08 100644
--- a/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
@@ -27,7 +27,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "### Vertices of Graph $G$: $\\mathrm{V}(\\mathrm{G}(V, E)) = V$"
+    "### Vertices of Graph $G$: $\\mathrm{Vertices}(\\mathrm{Graph}(V, E)) = V$"
    ]
   },
   {
@@ -121,6 +121,15 @@
     "`VerticesMembership.definition()`"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Vertices(Graph(V, E))).definition(assumptions = [SubsetEq(E, KPowerSet(V, two))])"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -231,6 +240,20 @@
     "NotInSet(v, Vertices(G)).as_defined()"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# the domain's argument must be an explicit Graph with specified vertex set\n",
+    "from proveit import H\n",
+    "try:\n",
+    "    NotInSet(v, Vertices(H)).as_defined()\n",
+    "except Exception as the_exception:\n",
+    "    print(f\"Exception: {the_exception}\")"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
diff --git a/packages/proveit/graphs/vertices/vertices_membership.py b/packages/proveit/graphs/vertices/vertices_membership.py
index 7280e15e65c2..0b9308f3c5ea 100644
--- a/packages/proveit/graphs/vertices/vertices_membership.py
+++ b/packages/proveit/graphs/vertices/vertices_membership.py
@@ -111,10 +111,18 @@ def as_defined(self):
         From self = [elem not in Vertices(Graph(V,E))],
         return: [elem not in V] (i.e. an expression, not a Judgment)
         '''
-        from proveit.logic import NotInSet
-        element = self.element
-        _V = self.domain.graph.vertex_set
-        return NotInSet(element, _V)
+        if isinstance(self.domain.operand, Graph):
+            from proveit.logic import NotInSet
+            element = self.element
+            _V =  self.domain.graph.vertex_set
+            return NotInSet(element, _V)
+        else:
+            raise NotImplementedError(
+                "VerticesNonmembership.as_defined() called on "
+                f"self = {self.expr} with domain = {self.expr.domain}, "
+                "but the method is implemented only for domains of "
+                "the form Vertices(G) where G is an explicit Graph "
+                "object of the form Graph(V,E) with a named vertex set.")
 
     @prover
     def unfold(self, **defaults_config):

From 60b2efdbd5546a2ff5cdf0b5e946351235aa5eb6 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sun, 4 May 2025 20:18:04 -0500
Subject: [PATCH 051/159] Update endpoints_membership pkg with
 membership_folding theorem

Update endpoints_membership package with membership_folding theorem and begin proof of the theorem. Completion of proof will require further update of the SetOfAll class methods (which will be cherry-picked from the QEC branch).
---
 .../allowed_presumptions.txt                  |   0
 .../disallowed_presumptions.txt               |   0
 .../proofs/membership_folding/thm_proof.ipynb | 105 ++++++++++++++++++
 .../endpoints/_theory_nbs_/theorems.ipynb     |  17 +++
 .../graphs/endpoints/endpoints_membership.py  |   1 +
 5 files changed, 123 insertions(+)
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb

diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/disallowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..ed6d0ed2bb51
--- /dev/null
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
@@ -0,0 +1,105 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">endpoints</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_folding\">membership_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import v, X, defaults, Lambda\n",
+    "from proveit.logic.sets import InSet\n",
+    "from proveit.graphs.endpoints import endpoints_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving membership_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = membership_folding.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "endpoints_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "endpoints_def_inst = endpoints_def.instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "temp_lambda = Lambda(X, InSet(v, X))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "endpoints_def_membership = endpoints_def_inst.substitution(temp_lambda)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# endpoints_def_membership.rhs.domain.unfold_membership(v)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
index 9a90a122670e..01fffe635f3d 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
@@ -52,6 +52,23 @@
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_folding = (\n",
+    "    Forall(P,\n",
+    "    Forall(v,\n",
+    "           InSet(v, Endpoints(P)),\n",
+    "           conditions = [LessEq(Degree(v, P), one)],\n",
+    "           domain = Vertices(P)\n",
+    "          ),\n",
+    "    domain = Paths())\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/endpoints/endpoints_membership.py b/packages/proveit/graphs/endpoints/endpoints_membership.py
index 5c0cf121a635..5425ea0e920f 100644
--- a/packages/proveit/graphs/endpoints/endpoints_membership.py
+++ b/packages/proveit/graphs/endpoints/endpoints_membership.py
@@ -1,3 +1,4 @@
+from proveit import equality_prover
 from proveit.logic import SetMembership, SetNonmembership
 
 

From 39673341b6814945c38b040e3e97cd19e886739c Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sun, 4 May 2025 20:19:45 -0500
Subject: [PATCH 052/159] Update proveit/graphs/__initi__.py to remove obsolete
 import

Update proveit/graphs/__initi__.py to remove obsolete import of Path from graph.py (Path class is now in graphs/paths/paths.py).
---
 packages/proveit/graphs/__init__.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index c45dce1a2c54..2aec5e84fd40 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -1,4 +1,4 @@
-from .graph import Graph, Graphs, Path
+from .graph import Graph, Graphs
 from .edges import Edges
 from .endpoints import Endpoints
 from .inclusion import NotSubgraph, Subgraph

From a84825e0061475300d45d0b8c5fa7b5aba565a7c Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 5 May 2025 09:15:20 -0500
Subject: [PATCH 053/159] Establish _sub_theories_.txt files for misc packages

Establish _sub_theories_.txt files for composite, conditional, label, lambda_expr, and operation sub-theory packages in expression theory package. These txt files keep getting re-created and persist in the GitHub Desktop system, so I am committing them to see if they can finally be tucked away.
---
 packages/proveit/_core_/expression/composite/_sub_theories_.txt   | 0
 packages/proveit/_core_/expression/conditional/_sub_theories_.txt | 0
 packages/proveit/_core_/expression/label/_sub_theories_.txt       | 0
 packages/proveit/_core_/expression/lambda_expr/_sub_theories_.txt | 0
 packages/proveit/_core_/expression/operation/_sub_theories_.txt   | 0
 5 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 packages/proveit/_core_/expression/composite/_sub_theories_.txt
 create mode 100644 packages/proveit/_core_/expression/conditional/_sub_theories_.txt
 create mode 100644 packages/proveit/_core_/expression/label/_sub_theories_.txt
 create mode 100644 packages/proveit/_core_/expression/lambda_expr/_sub_theories_.txt
 create mode 100644 packages/proveit/_core_/expression/operation/_sub_theories_.txt

diff --git a/packages/proveit/_core_/expression/composite/_sub_theories_.txt b/packages/proveit/_core_/expression/composite/_sub_theories_.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/_core_/expression/conditional/_sub_theories_.txt b/packages/proveit/_core_/expression/conditional/_sub_theories_.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/_core_/expression/label/_sub_theories_.txt b/packages/proveit/_core_/expression/label/_sub_theories_.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/_core_/expression/lambda_expr/_sub_theories_.txt b/packages/proveit/_core_/expression/lambda_expr/_sub_theories_.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/_core_/expression/operation/_sub_theories_.txt b/packages/proveit/_core_/expression/operation/_sub_theories_.txt
new file mode 100644
index 000000000000..e69de29bb2d1

From f7234a142682bfc1cb09465e760d92850cb78100 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sat, 8 Mar 2025 10:06:53 -0700
Subject: [PATCH 054/159] Add comprehension_membership_is_bool_basic theorem to
 logic/sets/comprehension

Add comprehension_membership_is_bool_basic thm to logic/sets/comprehension, possibly to be up-graded later to something more general, and needed for some QEC-related work in which SetOfAll comprehensions are being used. See related subsequent commit(s) for comprehension membership class.
---
 .../thm_proof.ipynb                           | 47 +++++++++++++++++++
 .../comprehension/_theory_nbs_/theorems.ipynb | 15 ++++++
 2 files changed, 62 insertions(+)
 create mode 100644 packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/comprehension_membership_is_bool_basic/thm_proof.ipynb

diff --git a/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/comprehension_membership_is_bool_basic/thm_proof.ipynb b/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/comprehension_membership_is_bool_basic/thm_proof.ipynb
new file mode 100644
index 000000000000..7831eff79de7
--- /dev/null
+++ b/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/comprehension_membership_is_bool_basic/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">comprehension</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#comprehension_membership_is_bool_basic\">comprehension_membership_is_bool_basic</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving comprehension_membership_is_bool_basic"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/comprehension/_theory_nbs_/theorems.ipynb b/packages/proveit/logic/sets/comprehension/_theory_nbs_/theorems.ipynb
index c5debd15ef42..7d5c1fec1c5c 100644
--- a/packages/proveit/logic/sets/comprehension/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/logic/sets/comprehension/_theory_nbs_/theorems.ipynb
@@ -257,6 +257,21 @@
     "        domain=S, conditions=[Qx]))"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from proveit import Function\n",
+    "from proveit.logic import in_bool\n",
+    "comprehension_membership_is_bool_basic = (\n",
+    "    Forall((S, Q, f, x, y),\n",
+    "       in_bool(InSet(x, SetOfAll(y, Function(f, y), condition=Function(Q, y), domain=S ))),\n",
+    "       conditions = [in_bool(InSet(y, S))])\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From 869df9cce4ad72f7214af8ae38fb22cb1a42b55e Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 19 Mar 2025 15:43:50 -0500
Subject: [PATCH 055/159] Establish SetOfAllMembership & SetOfAllNonmembership
 classes

Establish SetOfAllMembership & SetOfAllNonmembership classes, along with related methods and some supporting theorems, and extensive testing in the logic/sets/comprehension demonstrations notebook. The motivation for these updates/changes is partly the need for a "set-of-all-membership-in-bool" theorem and related method when dealing more extensively with the SetOfAll class of set comprehensions (for example in some of the QEC proofs related to code distance conservation). NOTE: several of the SetOfAll and SetOfAllMembership class methods still return errors when the SetOfAll utilizes multiple instance variables combined with multiple explicit conditions, and this is still a bit of a mystery. A few cases within the new methods also also behave oddly in that they return an error when first called but then work fine on the second and subsequent calls. Also a bit of a mystery.
---
 .../_theory_nbs_/demonstrations.ipynb         |  23 +-
 .../allowed_presumptions.txt                  |   0
 .../disallowed_presumptions.txt               |   0
 .../thm_proof.ipynb                           |  47 ++
 .../nonmembership_equiv/thm_proof.ipynb       |  47 ++
 .../nonmembership_equiv_basic/thm_proof.ipynb |  47 ++
 .../proofs/nonmembership_fold/thm_proof.ipynb |  47 ++
 .../nonmembership_fold_basic/thm_proof.ipynb  |  47 ++
 .../comprehension/_theory_nbs_/theorems.ipynb | 107 +++-
 .../logic/sets/comprehension/set_of_all.py    |  44 +-
 .../comprehension/set_of_all_membership.py    | 520 ++++++++++++++++++
 11 files changed, 887 insertions(+), 42 deletions(-)
 create mode 100644 packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/comprehension_membership_is_bool/allowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/comprehension_membership_is_bool/disallowed_presumptions.txt
 create mode 100644 packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/comprehension_membership_is_bool/thm_proof.ipynb
 create mode 100644 packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/nonmembership_equiv/thm_proof.ipynb
 create mode 100644 packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/nonmembership_equiv_basic/thm_proof.ipynb
 create mode 100644 packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/nonmembership_fold/thm_proof.ipynb
 create mode 100644 packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/nonmembership_fold_basic/thm_proof.ipynb
 create mode 100644 packages/proveit/logic/sets/comprehension/set_of_all_membership.py

diff --git a/packages/proveit/logic/sets/comprehension/_theory_nbs_/demonstrations.ipynb b/packages/proveit/logic/sets/comprehension/_theory_nbs_/demonstrations.ipynb
index 232a531c3957..81fd7283a35f 100644
--- a/packages/proveit/logic/sets/comprehension/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/logic/sets/comprehension/_theory_nbs_/demonstrations.ipynb
@@ -94,6 +94,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
+    "# in cases of a single instance variable, we can use the instance_var attribute\n",
     "squares_of_unit_interval.instance_var"
    ]
   },
@@ -103,7 +104,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "# instance_vars is no longer an attribute, but all_instance_vars() will work\n",
+    "# but all_instance_vars() will work for single or multiple instance variables\n",
     "squares_of_unit_interval.all_instance_vars()"
    ]
   },
@@ -122,6 +123,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
+    "# conditions attribute and all_conditions() function return domains and explicit conditions\n",
     "squares_of_unit_interval.all_conditions()"
    ]
   },
@@ -185,24 +187,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "squares_of_unit_interval.all_domains()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "len(squares_of_unit_interval.all_instance_vars())"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
+    "# to obtain the instance element\n",
     "squares_of_unit_interval.instance_element"
    ]
   },
diff --git a/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/comprehension_membership_is_bool/allowed_presumptions.txt b/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/comprehension_membership_is_bool/allowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/comprehension_membership_is_bool/disallowed_presumptions.txt b/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/comprehension_membership_is_bool/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/comprehension_membership_is_bool/thm_proof.ipynb b/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/comprehension_membership_is_bool/thm_proof.ipynb
new file mode 100644
index 000000000000..893d29b2a752
--- /dev/null
+++ b/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/comprehension_membership_is_bool/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">comprehension</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#comprehension_membership_is_bool\">comprehension_membership_is_bool</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving comprehension_membership_is_bool"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/nonmembership_equiv/thm_proof.ipynb b/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/nonmembership_equiv/thm_proof.ipynb
new file mode 100644
index 000000000000..e0ccda559988
--- /dev/null
+++ b/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/nonmembership_equiv/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">comprehension</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_equiv\">nonmembership_equiv</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving nonmembership_equiv"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/nonmembership_equiv_basic/thm_proof.ipynb b/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/nonmembership_equiv_basic/thm_proof.ipynb
new file mode 100644
index 000000000000..5a81c9545f11
--- /dev/null
+++ b/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/nonmembership_equiv_basic/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">comprehension</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_equiv_basic\">nonmembership_equiv_basic</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving nonmembership_equiv_basic"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/nonmembership_fold/thm_proof.ipynb b/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/nonmembership_fold/thm_proof.ipynb
new file mode 100644
index 000000000000..7e1a6e94c354
--- /dev/null
+++ b/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/nonmembership_fold/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">comprehension</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_fold\">nonmembership_fold</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving nonmembership_fold"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/nonmembership_fold_basic/thm_proof.ipynb b/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/nonmembership_fold_basic/thm_proof.ipynb
new file mode 100644
index 000000000000..dbdc505d2480
--- /dev/null
+++ b/packages/proveit/logic/sets/comprehension/_theory_nbs_/proofs/nonmembership_fold_basic/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">comprehension</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_fold_basic\">nonmembership_fold_basic</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving nonmembership_fold_basic"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/comprehension/_theory_nbs_/theorems.ipynb b/packages/proveit/logic/sets/comprehension/_theory_nbs_/theorems.ipynb
index 7d5c1fec1c5c..1aae1aaf96cb 100644
--- a/packages/proveit/logic/sets/comprehension/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/logic/sets/comprehension/_theory_nbs_/theorems.ipynb
@@ -17,12 +17,12 @@
     "import proveit\n",
     "# Prepare this notebook for defining the theorems of a theory:\n",
     "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
-    "from proveit.logic import And, Implies, Forall, Equals, InSet, SetOfAll, Exists, SubsetEq\n",
-    "from proveit import f, n, x, y, S, Q, R, fx, Qx, Qy, Rx\n",
+    "from proveit import f, i, n, x, y, S, Q, R, fx, Qx, Qy, Rx, ExprRange, Function, IndexedVar\n",
+    "from proveit.logic import And, Equals, Exists, Forall, Implies, in_bool, InSet, Not, NotEquals, NotInSet, Or, SetOfAll, SubsetEq\n",
     "from proveit.core_expr_types import (x_1_to_n, y_1_to_n, f__x_1_to_n, f__y_1_to_n, \n",
     "                                     Q__x_1_to_n, Q__y_1_to_n, R__x_1_to_n, R__y_1_to_n, S_1_to_n)\n",
-    "from proveit.logic.sets import basic_comprehension_y, general_comprehension_fyn\n",
-    "from proveit.numbers import NaturalPos"
+    "from proveit.logic.sets import basic_comprehension_y, each_y_in_S_in_bool, general_comprehension_fyn\n",
+    "from proveit.numbers import one, NaturalPos\n"
    ]
   },
   {
@@ -103,6 +103,21 @@
     "    )"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Forall(n,\n",
+    "    Forall((S_1_to_n, Q, f, x),\n",
+    "        InSet(x, general_comprehension_fyn),\n",
+    "        conditions = [Exists(y_1_to_n, Equals(x, f__y_1_to_n), domains=[S_1_to_n], conditions=[Q__y_1_to_n])]\n",
+    "    ),\n",
+    "    domain=NaturalPos\n",
+    "    )"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -257,6 +272,21 @@
     "        domain=S, conditions=[Qx]))"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "comprehension_membership_is_bool = (\n",
+    "    Forall(n,\n",
+    "    Forall((S_1_to_n, Q, f, x, ExprRange(i, IndexedVar(y, i), one, n)),\n",
+    "       in_bool(InSet(x, general_comprehension_fyn)),\n",
+    "       conditions = [each_y_in_S_in_bool]),\n",
+    "    domain=NaturalPos)\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -267,11 +297,78 @@
     "from proveit.logic import in_bool\n",
     "comprehension_membership_is_bool_basic = (\n",
     "    Forall((S, Q, f, x, y),\n",
-    "       in_bool(InSet(x, SetOfAll(y, Function(f, y), condition=Function(Q, y), domain=S ))),\n",
+    "       in_bool(InSet(x, SetOfAll(y, y, condition=Function(Q, y), domain=S ))),\n",
     "       conditions = [in_bool(InSet(y, S))])\n",
     ")"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Non-membership Theorems"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_equiv = (\n",
+    "    Forall(n, \n",
+    "    Forall((S_1_to_n, Q, f, x), \n",
+    "    Equals(NotInSet(x, general_comprehension_fyn),\n",
+    "           Forall(y_1_to_n, NotEquals(x, f__y_1_to_n), \n",
+    "    domains=[S_1_to_n], conditions=[Q__y_1_to_n])).with_wrap_before_operator()),\n",
+    "    domain=NaturalPos)\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_equiv_basic = (\n",
+    "        Forall((S, Q, x),\n",
+    "               Equals(NotInSet(x, basic_comprehension_y),\n",
+    "                       Or(NotInSet(x, S), Not(Qx)))\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_fold = (\n",
+    "    Forall(n, \n",
+    "    Forall((S_1_to_n, Q, f, x), \n",
+    "          NotInSet(x, general_comprehension_fyn),\n",
+    "          conditions=[Forall(y_1_to_n, NotEquals(x, f__y_1_to_n), \n",
+    "                  domains=[S_1_to_n], conditions=[Q__y_1_to_n])]),\n",
+    "    domain=NaturalPos)\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_fold_basic = (\n",
+    "        Forall((S, Q, x),\n",
+    "               NotInSet(x, basic_comprehension_y),\n",
+    "               conditions=[Or(NotInSet(x, S), Not(Qx))]\n",
+    "    )\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/logic/sets/comprehension/set_of_all.py b/packages/proveit/logic/sets/comprehension/set_of_all.py
index 56af5d16fa5c..3f4945d2e6b6 100644
--- a/packages/proveit/logic/sets/comprehension/set_of_all.py
+++ b/packages/proveit/logic/sets/comprehension/set_of_all.py
@@ -36,6 +36,14 @@ def __init__(self, instance_param_or_params, instance_element,
             assert False, ("Expecting either 'instance_param' or 'instance_params' "
                            "to be set")
 
+    def membership_object(self, element):
+        from .set_of_all_membership import SetOfAllMembership
+        return SetOfAllMembership(element, self)
+
+    def nonmembership_object(self, element):
+        from .set_of_all_membership import SetOfAllNonmembership
+        return SetOfAllNonmembership(element, self)
+
     def _formatted(self, format_type, fence=False, **kwargs):
         from proveit import ExprRange
         out_str = ''
@@ -155,54 +163,54 @@ def unfold_membership(self, element, **defaults_config):
 
             x in A |- Exists_{i in {0, 1, ..., 10}} s.t. x = (i, 0).
 
+        This method might now be obsolete with the establishment of
+        the SetOfAllMemberhip class and related methods.
+
         '''
         from . import (unfold, unfold_basic_comprehension,
                        in_superset_if_in_comprehension)
         from proveit.logic import And
         from proveit.numbers import num
+
         if len(self.explicit_conditions())==1:
             explicit_conditions = self.explicit_conditions()[0]
         else:
             # which includes case of no explicit conditions!
             explicit_conditions = And(*self.explicit_conditions())
+
         _Q_op, _Q_op_sub = (
                 Function(Q, self.all_instance_vars()), explicit_conditions)
+
         if (len(self.all_instance_vars()) == 1 and
             self.instance_element == self.instance_var):
-            # simple case of {x | Q(x)}_{x in S}; derive (but don't)
-            # explicitly return) side-effect that x is in S;
+            # simple case of {y | Q(y)}_{y in S}
+            # or {y | Q1(y), ..., Qn(y)}_{y in S}: derive (but don't
+            # explicitly return) side-effect (x in S);
             # we do this here because some cases below do not include
-            # the membership in the returned result
+            # the membership (x in S) in the returned result
             in_superset_if_in_comprehension.instantiate(
                     {S: self.domain, _Q_op: _Q_op_sub,
                      x: element, y: self.instance_var})
-            if len(self.explicit_conditions())==1:
-                _Q_op, _Q_op_sub = (
-                    Function(Q, self.all_instance_vars()), explicit_conditions)
-                _y_sub = self.all_instance_vars
-                return unfold_basic_comprehension.instantiate(
-                        {S:self.domain, _Q_op:_Q_op_sub, x:element,
-                         y:self.all_instance_vars()[0]})
-            else:
-                # multiple explicit conditions, so we use the And(*)
-                # construction from earlier for the _Q_op_sub
-                return unfold_basic_comprehension.instantiate(
-                        {S:self.domain, _Q_op:_Q_op_sub, x:element,
-                         y:self.all_instance_vars()[0]})
+            _y_sub = self.all_instance_vars()[0]
+            return unfold_basic_comprehension.instantiate(
+                    {S:self.domain, _Q_op:_Q_op_sub, x:element, y:_y_sub})
         else: 
             # cases where we have:
             # (1) multiple instance_vars,
             # (2) and/or instance_element is not just an instance_var
+            # In fact, this doesn't yet work with multiple instance vars
             _n_sub = num(len(self.all_instance_vars()))
             _f_op, _f_sub = (
                 Function(f, self.all_instance_vars()), self.instance_element)
+            _y_sub = self.all_instance_vars()
             if len(self.explicit_conditions())<=1:
-                should_auto_simplify = True # will simplify And()
+                should_auto_simplify = True
+                # will simplify vacuous And() and trivial And(Q(y))
             else:
                 should_auto_simplify = False
             return unfold.instantiate(
                 {n:_n_sub, S:self.all_domains(),  _Q_op:_Q_op_sub, _f_op:_f_sub,
-                x:element, y:self.all_instance_vars()},
+                x:element, y:_y_sub},
                 auto_simplify = should_auto_simplify).derive_consequent()
 
 
diff --git a/packages/proveit/logic/sets/comprehension/set_of_all_membership.py b/packages/proveit/logic/sets/comprehension/set_of_all_membership.py
new file mode 100644
index 000000000000..b9e8ebf0036f
--- /dev/null
+++ b/packages/proveit/logic/sets/comprehension/set_of_all_membership.py
@@ -0,0 +1,520 @@
+from proveit import USE_DEFAULTS, equality_prover, prover, Function
+from proveit.logic import And, SetMembership, SetNonmembership
+from proveit.numbers import num
+from proveit import f, n, x, y, S, Q
+
+class SetOfAllMembership(SetMembership):
+    '''
+    Defines methods that apply to membership in a set comprehension,
+    i.e. membership in a SetOfAll construction such as x being in the
+    set of all squares of positive integers:
+
+        InSet(x, SetOfAll(i, Exp(i, two), conditions=[greater(i, zero)],
+                          domain=Integer))
+
+    '''
+
+    def __init__(self, element, domain):
+        SetMembership.__init__(self, element, domain)
+
+    def side_effects(self, judgment):
+        '''
+        Unfold the comprehension set membership as a side-effect.
+        '''
+        yield self.unfold # STILL TO BE ADDRESSED
+
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        Deduce and return an equality depending on the form of the
+        SetOfAll set comprehension serving as the domain.
+        (1) From [x in {y | Q(y)}_{y in S}], deduce and return
+            [x in {y|Q(y)}_{y in S}] = [(x in S) and Q(x)].
+        (2) From [x in {y | Q1(y), Q2(y),...,Qn(y)}_{y in S}], deduce
+            and return [x in {y | Q1(y), Q2(y),...,Qn(y)}_{y in S}] =
+            [(x in S) and (Q1(y) and Q2(y),..., and Qn(y))].
+        (3) From [x in {f(y) | ..Q(y)..}]_{y in S}], deduce and return
+            [x in {f(y) | ..Q(y)..}]_{y in S}] =
+                exists_{y in S | ..Q(y)..} [x = f(y)].
+        The process for producing the outcome is very similar to the
+        process used in the unfold() method defined further below.
+        '''
+
+        from . import comprehension_def, basic_comprehension
+
+        element = self.element
+
+        if len(self.domain.explicit_conditions())==1:
+            explicit_conditions = self.domain.explicit_conditions()[0]
+        else:
+            # which includes case of no explicit conditions!
+            explicit_conditions = And(*self.domain.explicit_conditions())
+
+        _Q_op, _Q_op_sub = (
+                Function(Q, self.domain.all_instance_vars()),
+                explicit_conditions)
+
+        if (len(self.domain.all_instance_vars()) == 1 and
+            self.domain.instance_element == self.domain.instance_var):
+            # simple case of [x in {y | Q(y)}_{y in S}]
+            # or [x in {y | Q1(y), ..., Qn(y)}_{y in S}]:
+            _S_sub = self.domain.all_domains()[0] # only 1 instance var
+            _y_sub = self.domain.all_instance_vars()
+            return basic_comprehension.instantiate(
+                    {S:_S_sub, _Q_op:_Q_op_sub, x:element, y:_y_sub})
+        else: 
+            # cases where we have:
+            # (1) multiple instance_vars,
+            # (2) and/or instance_element is not just an instance_var
+            # In fact, this doesn't yet work with multiple instance vars
+            _n_sub = num(len(self.domain.all_instance_vars()))
+            _f_op, _f_op_sub = (
+                    Function(f, self.domain.all_instance_vars()),
+                    self.domain.instance_element)
+            _S_sub = self.domain.all_domains()
+            _y_sub = self.domain.all_instance_vars()
+            # if len(self.domain.explicit_conditions())<=1:
+            #     should_auto_simplify = True
+            #     # will simplify vacuous And() and trivial And(Q(y))
+            # else:
+            #     should_auto_simplify = False
+            return comprehension_def.instantiate(
+                {n:_n_sub, S:_S_sub, _Q_op:_Q_op_sub, _f_op:_f_op_sub,
+                x:element, y:_y_sub})
+
+    def as_defined(self):
+        '''
+        TBA. The idea here is to return (but do not derive) the
+        'unfolded' version (i.e. the definition) of a
+        SetOfAllMembership expression, depending on the form of the
+        membership object:
+        (1) From (x in {y | Q(y)})_{y in S}, return [(x in S) and Q(x)].
+        (2) From (x in {y | ..Q(y)..})_{y in S},
+            return [(x in S) and ..Q(x)..].
+        (3) From (x in {f(y) | ..Q(y)..})_{y in S}, return
+            exists_{y in S | ..Q(y)..} x = f(y).
+        In the case of a simple Union() membership, the disjunction of
+        memberships is easily constructed and you might want such a
+        definition without having to instantiate the unfold theorem
+        and actually derive the definition result.
+        In the case of a SetOfAllMembership, the situation is more
+        complicated, with the explicit conditions potentially being
+        quite varied.
+
+        # From the original UnionMembership comments:
+        From self=[elem in (A U B U ...)], return
+        [(element in A) or (element in B) or ...].
+        '''
+
+        # From the original UnionMembership code:
+        # from proveit.logic import Or, InSet
+        # element = self.element
+        # return Or(*self.domain.operands.map_elements(
+        #         lambda subset : InSet(element, subset)))
+
+        raise NotImplementedError(
+                "SetOfAllMembership.as_defined() not yet implemented.")
+
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        Return an 'unfolded' version of a SetOfAllMembership expression,
+        depending on the form of the membership object:
+        (1) From (x in {y | Q(y)})_{y in S}, derive and return
+            [(x in S) and Q(x)].
+        (2) From (x in {y | ..Q(y)..})_{y in S}, derive and return
+            [(x in S) and ..Q(x)..].
+        (3) From (x in {f(y) | ..Q(y)..})_{y in S}, derive and return
+            exists_{y in S | ..Q(y)..} x = f(y) (and derive x in S,
+            but this is not returned).
+
+        Examples.
+
+        (1) Let A1 = SetOfAll(y, y, y >= 0, domain = Real). Then
+            (x in A1).unfold(assumptions=[x in A1]) derives and returns
+            {x in A1} |- (x in Real) AND (x >= 0)
+
+        (2) Let A2 = SetOfAll(y, y, conditions=[y > 0, y < 11],
+                     domain = Integer). Then
+            (x in A2).unfold(assumptions=[x in A2]) derives and returns
+            {x in A2} |- (x in Integer) AND ((x > 0) AND (x < 11))
+
+        (3) Let A3 = SetOfAll(i, ExprTuple(i, zero),
+                     domain = Interval(zero, num(10))),
+            which gives a set of tuples like this:
+                {(0,0), (1,0), ... (10,0)}
+            Then (x in A3).unfold(assumptions=[x in A3]) derives and
+            returns:
+            x in A3 |- Exists_{i in {0, 1, ..., 10}} s.t. x = (i, 0).
+
+        The method currently returns an error when the underlying
+        SetOfAll set uses multiple instance variables with multiple
+        explicit conditions. The reason for this is unclear but appears
+        to be the result of the instantiation of the unfold theorem
+        producing an antecedent that does not exactly match the
+        original membership object.
+        '''
+
+        from . import (unfold, unfold_basic_comprehension,
+                       in_superset_if_in_comprehension)
+
+        element = self.element
+
+        if len(self.domain.explicit_conditions())==1:
+            explicit_conditions = self.domain.explicit_conditions()[0]
+        else:
+            # which includes case of no explicit conditions!
+            explicit_conditions = And(*self.domain.explicit_conditions())
+        _Q_op, _Q_op_sub = (
+                Function(Q, self.domain.all_instance_vars()),
+                explicit_conditions)
+        if (len(self.domain.all_instance_vars()) == 1 and
+            self.domain.instance_element == self.domain.instance_var):
+            # simple case of [x in {y | Q(y)}_{y in S}]
+            # or [x in {y | Q1(y), ..., Qn(y)}_{y in S}]: derive
+            # (but don't) explicitly return) side-effect (x in S);
+            # We do this here because some cases below do not include
+            # the membership (x in S) in the returned result
+            in_superset_if_in_comprehension.instantiate(
+                    {S: self.domain.domain, _Q_op: _Q_op_sub,
+                     x: element, y: self.domain.instance_var})
+            if len(self.domain.explicit_conditions())==1:
+                _Q_op, _Q_op_sub = (
+                    Function(Q, self.domain.all_instance_vars()),
+                    explicit_conditions)
+                _y_sub = self.domain.all_instance_vars()
+                return unfold_basic_comprehension.instantiate(
+                        {S:self.domain.domain, _Q_op:_Q_op_sub,
+                         x:element, y:_y_sub})
+            else:
+                # multiple explicit conditions, so we use the And(*)
+                # construction from earlier for the _Q_op_sub
+                return unfold_basic_comprehension.instantiate(
+                        {S:self.domain.domain, _Q_op:_Q_op_sub, x:element,
+                         y:self.domain.all_instance_vars()[0]})
+        else: 
+            # cases where we have:
+            # (1) multiple instance_vars,
+            # (2) and/or instance_element is not just an instance_var
+            # In fact, this doesn't yet work with multiple instance vars
+            _n_sub = num(len(self.domain.all_instance_vars()))
+            _f_op, _f_op_sub = (
+                    Function(f, self.domain.all_instance_vars()),
+                    self.domain.instance_element)
+            if len(self.domain.explicit_conditions())<=1:
+                should_auto_simplify = True
+                # will simplify vacuous And() and trivial And(Q(y))
+            else:
+                should_auto_simplify = False
+            return unfold.instantiate(
+                {n:_n_sub, S:self.domain.all_domains(),
+                _Q_op:_Q_op_sub, _f_op:_f_op_sub,
+                x:element, y:self.domain.all_instance_vars()},
+                auto_simplify = should_auto_simplify).derive_consequent()
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Called on a SetOfAllMembership object such as
+        self = [elem in SetOfAll()], and depending on the form of self,
+        derive and return self, knowing or assuming the rhs of the
+        SetOfAll comprehension definition theorem (or the condition in
+        the SetOfAll fold theorem):
+        (1) From self = (x in {y}_{y in S}) and knowing or assuming
+            that (x in S), derive and return self.
+        (2) From self = (x in {y | Q(y)}_{y in S}) and knowing or
+            assuming that ((x in S) AND (Q(x))), derive and return self.
+        (3) From self = (x in {y | Q1(y), Q2(y),...,Qn(y)}_{y in S})
+            and knowing or assuming that ((x in S) AND (Q1(x) and ...
+            Qn(x))), derive and return self.
+        (4) From self = (x in {f(y1,...,yn) | Q(y1,...yn)}_{y1 in S1,
+            ...,yn in Sn}) and knowing or assuming that
+            Exists_{y1 in S1,...,yn in Sn | Q(y1,...,yn)} such that
+            [x = f(y1,...,yn)], derive and return self.
+
+        There are some cases for which the method works only when
+        called a second time on the same input. Not sure why.
+
+        This method does not work for cases in which the underlying
+        SetOfAll domain has both multiple instance variables
+        and multiple explicit conditions simultaneously.
+        '''
+
+        from . import (fold, fold_basic_comprehension,
+                       in_superset_if_in_comprehension)
+        element = self.element
+
+        if len(self.domain.explicit_conditions())==1:
+            explicit_conditions = self.domain.explicit_conditions()[0]
+        else:
+            # which includes case of no explicit conditions!
+            explicit_conditions = And(*self.domain.explicit_conditions())
+        _Q_op, _Q_op_sub = (
+                Function(Q, self.domain.all_instance_vars()),
+                explicit_conditions)
+
+        if (len(self.domain.all_instance_vars()) == 1 and
+            self.domain.instance_element == self.domain.instance_var):
+            # cases like [x in {y}_{y in S}]
+            #         or [x in {y | Q(y)}_{y in S}]
+            #         or [x in {y | Q1(y), Q2(y),...,Qn(y)}_{y in S}]
+            _S_sub = self.domain.domain
+            _y_sub = self.domain.all_instance_vars()[0]
+            return fold_basic_comprehension.instantiate(
+                    {S:_S_sub, _Q_op:_Q_op_sub, x:element,
+                     y:_y_sub})
+        else: 
+            # cases where we have:
+            # (1) multiple instance_vars,
+            # (2) and/or instance_element is not just an instance_var
+            # In fact, this doesn't yet work with multiple instance vars
+            _n_sub = num(len(self.domain.all_instance_vars()))
+            _f_op, _f_sub = (
+                    Function(f, self.domain.all_instance_vars()),
+                    self.domain.instance_element)
+            if len(self.domain.explicit_conditions())<=1:
+                should_auto_simplify = True
+                # will simplify vacuous And() and trivial And(Q(y))
+            else:
+                should_auto_simplify = False
+            return fold.instantiate(
+                {n:_n_sub, S:self.domain.all_domains(), 
+                _Q_op:_Q_op_sub, _f_op:_f_sub,
+                x:element, y:self.domain.all_instance_vars()},
+                auto_simplify = should_auto_simplify).derive_consequent()
+
+    @prover
+    def deduce_in_bool(self, **defaults_config):
+        '''
+        Deduce that self = (x in SetOfAll()) is in Bool. Used as 
+        helper function elsewhere and not usually explicitly called
+        by the user.
+        '''
+        from . import (comprehension_membership_is_bool,
+                       comprehension_membership_is_bool_basic)
+
+        element = self.element
+
+        if len(self.domain.explicit_conditions())==1:
+            explicit_conditions = self.domain.explicit_conditions()[0]
+        else:
+            # which includes case of no explicit conditions!
+            explicit_conditions = And(*self.domain.explicit_conditions())
+        _Q_op, _Q_op_sub = (
+                Function(Q, self.domain.all_instance_vars()),
+                explicit_conditions)
+        if (len(self.domain.all_instance_vars()) == 1 and
+            self.domain.instance_element == self.domain.instance_var):
+            # simple case of [x in {y | Q(y)}_{y in S}]
+            # or [x in {y | Q1(y), ..., Qn(y)}_{y in S}]:
+            _S_sub = self.domain.domain # since only 1 instance var
+            _y_sub = self.domain.all_instance_vars()[0]
+            return comprehension_membership_is_bool_basic.instantiate(
+                    {S:self.domain.domain, _Q_op:_Q_op_sub,
+                         x:element, y:_y_sub})
+        else: 
+            # cases where we have:
+            # (1) multiple instance_vars,
+            # (2) and/or instance_element is not just an instance_var
+            # In fact, this doesn't yet work with multiple instance vars [?]
+            _n_sub = num(len(self.domain.all_instance_vars()))
+            _S_sub = self.domain.all_domains()
+            _f_op, _f_op_sub = (
+                    Function(f, self.domain.all_instance_vars()),
+                    self.domain.instance_element)
+            _y_op_sub  = self.domain.all_instance_vars()
+            if len(self.domain.explicit_conditions())<=1:
+                should_auto_simplify = True
+                # will simplify vacuous And() and trivial And(Q(y))
+            else:
+                should_auto_simplify = False
+            return comprehension_membership_is_bool.instantiate(
+                {n:_n_sub, S:_S_sub, _Q_op:_Q_op_sub, _f_op:_f_op_sub,
+                x:element, y:_y_op_sub},
+                auto_simplify = should_auto_simplify)
+
+
+class SetOfAllNonmembership(SetNonmembership):
+    '''
+    Defines methods that apply to non-membership in a set comprehension,
+    i.e. non-membership in a SetOfAll construction.
+    '''
+
+    def __init__(self, element, domain):
+        SetNonmembership.__init__(self, element, domain)
+
+    def side_effects(self, judgment):
+        '''
+        Currently no side-effects for comprehension non-membership.
+        '''
+        return
+        yield
+
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        Deduce and return an equality depending on the form of the
+        SetOfAll set comprehension serving as the (non)-domain.
+        (1) From [x NotIn {y | Q(y)}_{y in S}], deduce and return
+            [x NotIn {y|Q(y)}_{y in S}] = [(x NotIn S) OR Not(Q(x))].
+        (2) From [x NotIn {y | Q1(y), Q2(y),...,Qn(y)}_{y in S}],
+            deduce and return
+            [x NotIn {y | Q1(y), Q2(y),...,Qn(y)}_{y in S}] =
+            [(x NotIn S) OR Not(Q1(y)) and Q2(y),..., and Qn(y))].
+        (3) From [x NotIn {f(y) | Q1(y),...,Qn(y)}]_{y in S}],
+            deduce and return
+            [x NotIn {f(y) | Q1(y),...,Qn(y)}]_{y in S}] = 
+            Forall_{y in S | Q1(y),...,Qn(y)}[x NotEqual f(y)].
+        In cases (2) and (3), the Q1(y),...,Qn(y) are interpreted
+        as Q(y) = And(Q1(y),...,Qn(y)).
+
+        Note: this method raises an error when the SetOfAllNonmembership
+        expression has both multiple instance variables and multiple
+        explicit conditions simultaneously.
+        '''
+
+        from . import nonmembership_equiv, nonmembership_equiv_basic
+
+        element = self.element
+
+        if len(self.domain.explicit_conditions())==1:
+            explicit_conditions = self.domain.explicit_conditions()[0]
+        else:
+            # which includes case of no explicit conditions!
+            explicit_conditions = And(*self.domain.explicit_conditions())
+
+        _Q_op, _Q_op_sub = (
+                Function(Q, self.domain.all_instance_vars()),
+                explicit_conditions)
+
+        if (len(self.domain.all_instance_vars()) == 1 and
+            self.domain.instance_element == self.domain.instance_var):
+            # simple case of [x in {y | Q(y)}_{y in S}]
+            # or [x in {y | Q1(y), ..., Qn(y)}_{y in S}]:
+            _S_sub = self.domain.all_domains()[0] # only 1 instance var
+            _y_sub = self.domain.all_instance_vars()
+            return nonmembership_equiv_basic.instantiate(
+                    {S:_S_sub, _Q_op:_Q_op_sub, x:element, y:_y_sub})
+        else: 
+            # cases where we have:
+            # (1) multiple instance_vars,
+            # (2) and/or instance_element is not just an instance_var
+            # In fact, this doesn't yet work with multiple instance vars
+            _n_sub = num(len(self.domain.all_instance_vars()))
+            _f_op, _f_op_sub = (
+                    Function(f, self.domain.all_instance_vars()),
+                    self.domain.instance_element)
+            _S_sub = self.domain.all_domains()
+            _y_sub = self.domain.all_instance_vars()
+            # if len(self.domain.explicit_conditions())<=1:
+            #     should_auto_simplify = True
+            #     # will simplify vacuous And() and trivial And(Q(y))
+            # else:
+            #     should_auto_simplify = False
+            return nonmembership_equiv.instantiate(
+                {n:_n_sub, S:_S_sub, _Q_op:_Q_op_sub, _f_op:_f_op_sub,
+                x:element, y:_y_sub})
+
+    def as_defined(self):
+        '''
+        TBA. The idea here is to return (but do not derive) the
+        'unfolded' version (i.e. the definition) of a
+        SetOfAllNonmembership expression, depending on the form of the
+        membership object:
+        (1) From (x NotIn {y | Q(y)})_{y in S}, return
+            [(x NotIn S) OR Not(Q(x))].
+        (2) From (x NotIn {y | ..Q(y)..})_{y in S},
+            return [(x NotIn S) OR (..Not(Q(x))..)].
+        (3) From (x NotIn {f(y) | ..Q(y)..})_{y in S}, return
+            Forall_{y in S | ...Q(y)...}[x NotEqual f(y)].
+        In the case of a simple Union() membership, the disjunction of
+        memberships is easily constructed and you might want such a
+        definition without having to instantiate the unfold theorem
+        and actually derive the definition result.
+        In the case of a SetOfAllNonmembership, the situation is more
+        complicated, with the explicit conditions potentially being
+        quite varied.
+        # From original UnionNonmembership:
+        From self=[elem not in (A U B U ...)], return
+        [(element not in A) and (element not in B) and ...].
+        '''
+        # code from original UnionNonmembership:
+        # from proveit.logic import And, NotInSet
+        # element = self.element
+        # return And(*self.domain.operands.map_elements(
+        #         lambda subset : NotInSet(element, subset)))
+
+        raise NotImplementedError(
+                "SetOfAllNonmembership.as_defined() not yet implemented.")
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Called on a SetOfAllNonmembership object such as
+        self = [elem NotIn SetOfAll()], and depending on the form of
+        the SetOfAll set comprehension serving as the (non)-domain,
+        derive and return self, knowing or assuming the rhs of the
+        SetOfAllNonmembership definition theorem:
+        (1) From self = (x NotIn {y}_{y in S}) and knowing or
+            assuming [(x NotIn S)], derive and return self.
+        (2) From self = (x NotIn {y | Q(y)}_{y in S}) and knowing or
+            assuming that ((x NotIn S) OR (Not(Q(x))), derive and
+            return self.
+        (3) From self = (x in {y | Q1(y), Q2(y),...,Qn(y)}_{y in S})
+            and knowing or assuming that
+            [(x NotIn S) OR Not(Q1(y)) and Q2(y),..., and Qn(y))],
+            derive and return self.
+        (4) From self = (x NotIn {f(y1,...,yn) | Q(y1,...yn)}_{y1 in S1,
+            ...,yn in Sn}) and knowing or assuming that
+            Forall_{y1 in S1,...,yn in Sn | Q(y1,...,yn)}[x NotEqual
+            f(y1,...,yn)], derive and return self.
+
+        There are some cases for which the method works only when
+        called a second time on the same input. Not sure why.
+
+        This method does not work for cases in which the underlying
+        SetOfAll (non)-domain has both multiple instance variables
+        and multiple explicit conditions simultaneously.
+        '''
+
+        from . import (nonmembership_fold, nonmembership_fold_basic)
+        element = self.element
+
+        if len(self.domain.explicit_conditions())==1:
+            explicit_conditions = self.domain.explicit_conditions()[0]
+        else:
+            # which includes case of no explicit conditions!
+            explicit_conditions = And(*self.domain.explicit_conditions())
+        _Q_op, _Q_op_sub = (
+                Function(Q, self.domain.all_instance_vars()),
+                explicit_conditions)
+
+        if (len(self.domain.all_instance_vars()) == 1 and
+            self.domain.instance_element == self.domain.instance_var):
+            # cases like [x NotIn {y}_{y in S}]
+            #       or [x NotIn {y | Q(y)}_{y in S}]
+            #       or [x NotIn {y | Q1(y), Q2(y),...,Qn(y)}_{y in S}]
+            _S_sub = self.domain.domain
+            _y_sub = self.domain.all_instance_vars()[0]
+            return nonmembership_fold_basic.instantiate(
+                    {S:_S_sub, _Q_op:_Q_op_sub, x:element,
+                     y:_y_sub})
+        else: 
+            # cases where we have:
+            # (1) multiple instance_vars,
+            # (2) and/or instance_element is not just an instance_var
+            # In fact, this doesn't yet work with multiple instance vars
+            _n_sub = num(len(self.domain.all_instance_vars()))
+            _f_op, _f_sub = (
+                    Function(f, self.domain.all_instance_vars()),
+                    self.domain.instance_element)
+            if len(self.domain.explicit_conditions())<=1:
+                should_auto_simplify = True
+                # will simplify vacuous And() and trivial And(Q(y))
+            else:
+                should_auto_simplify = False
+            return nonmembership_fold.instantiate(
+                {n:_n_sub, S:self.domain.all_domains(), 
+                _Q_op:_Q_op_sub, _f_op:_f_sub,
+                x:element, y:self.domain.all_instance_vars()},
+                auto_simplify = should_auto_simplify)

From 4a5626862c002ad86735ff21dbbba174c93cd4a9 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 15 Apr 2025 10:21:20 -0500
Subject: [PATCH 056/159] Update set_of_all.py and set_of_all_membership.py as
 dev continues

Update the SetOfAll (in logic/sets/comprehension/set_of_all.py) and SetOfAllMembership (in ... set_of_all_membership.py) class and methods in continuing development. Current methods are only mdoerately functional, with errors arising in a number of cases where the presence of multiple explicit conditions cause incompatibilities between components of the instantiated theorems and the expected or "natural" assumptions the user might construct or prove. Development and testing is ongoing.
---
 .../logic/sets/comprehension/set_of_all.py    |  24 ++-
 .../comprehension/set_of_all_membership.py    | 152 ++++++++++++++++--
 2 files changed, 160 insertions(+), 16 deletions(-)

diff --git a/packages/proveit/logic/sets/comprehension/set_of_all.py b/packages/proveit/logic/sets/comprehension/set_of_all.py
index 3f4945d2e6b6..e3d7387e1870 100644
--- a/packages/proveit/logic/sets/comprehension/set_of_all.py
+++ b/packages/proveit/logic/sets/comprehension/set_of_all.py
@@ -16,8 +16,8 @@ def __init__(self, instance_param_or_params, instance_element,
                  conditions=None, styles=None, _lambda_map=None):
         '''
         Create an expression representing the set of all
-        instance_element for instance parameter(s) such that the conditions
-        are satisfied:
+        instance_element for instance parameter(s) such that the
+        conditions are satisfied:
         {instance_element | conditions}_{instance_param_or_params \in S}
         '''
         OperationOverInstances.__init__(
@@ -33,8 +33,8 @@ def __init__(self, instance_param_or_params, instance_element,
             if not hasattr(self, 'domains') or None in self.domains:
                 raise ValueError("SetOfAll requires domains")
         else:
-            assert False, ("Expecting either 'instance_param' or 'instance_params' "
-                           "to be set")
+            assert False, ("Expecting either 'instance_param' or "
+                           "'instance_params' to be set")
 
     def membership_object(self, element):
         from .set_of_all_membership import SetOfAllMembership
@@ -95,6 +95,22 @@ def _formatted(self, format_type, fence=False, **kwargs):
         out_str += '}'
         return out_str
 
+    # @equality_prover('shallow_simplified', 'shallow_simplify')
+    # def shallow_simplification(self, *, must_evaluate=False,
+    #                            **defaults_config):
+    #     '''
+    #     From this forall statement, evaluate it to TRUE or FALSE if
+    #     possible by calling the domain's forall_evaluation method
+
+    #     A possible fix --- play around with this and test 20250321
+    #     possibly look at Operation.shallow_simplification as model.
+    #     Consider a simplification() method??
+    #     '''
+    #     with defaults.temporary() as temp_defaults:
+    #         temp_defaults.preserved_exprs.add(self.condition)
+        
+    #         return OperationOverInstances.shallow_simplification(self)
+
     @relation_prover
     def deduce_superset_eq_relation(self, superset, **defaults_config):
         '''
diff --git a/packages/proveit/logic/sets/comprehension/set_of_all_membership.py b/packages/proveit/logic/sets/comprehension/set_of_all_membership.py
index b9e8ebf0036f..e99cf3cc09c5 100644
--- a/packages/proveit/logic/sets/comprehension/set_of_all_membership.py
+++ b/packages/proveit/logic/sets/comprehension/set_of_all_membership.py
@@ -61,7 +61,8 @@ def definition(self, **defaults_config):
             _S_sub = self.domain.all_domains()[0] # only 1 instance var
             _y_sub = self.domain.all_instance_vars()
             return basic_comprehension.instantiate(
-                    {S:_S_sub, _Q_op:_Q_op_sub, x:element, y:_y_sub})
+                    {S:_S_sub, _Q_op:_Q_op_sub, x:element, y:_y_sub},
+                    preserved_exprs = {self.domain})
         else: 
             # cases where we have:
             # (1) multiple instance_vars,
@@ -215,6 +216,8 @@ def unfold(self, **defaults_config):
     @prover
     def conclude(self, **defaults_config):
         '''
+        STILL UNDER ACTIVE TESTING as of 4/15/2025
+
         Called on a SetOfAllMembership object such as
         self = [elem in SetOfAll()], and depending on the form of self,
         derive and return self, knowing or assuming the rhs of the
@@ -238,8 +241,16 @@ def conclude(self, **defaults_config):
         This method does not work for cases in which the underlying
         SetOfAll domain has both multiple instance variables
         and multiple explicit conditions simultaneously.
+
+        Errors are arising especially with expressions that involve
+        multiple explicit conditions, producing instantiated forms
+        of the applied theorems whose component(s) do not quite
+        match the "natural" or expected assumption(s) one might have
+        or might construct. This turns out to be a thorny problem.
         '''
 
+        from proveit import defaults
+        # print(f"\nEntering the SetOfAllMembership.conclude() method!\n")
         from . import (fold, fold_basic_comprehension,
                        in_superset_if_in_comprehension)
         element = self.element
@@ -249,21 +260,41 @@ def conclude(self, **defaults_config):
         else:
             # which includes case of no explicit conditions!
             explicit_conditions = And(*self.domain.explicit_conditions())
+
         _Q_op, _Q_op_sub = (
                 Function(Q, self.domain.all_instance_vars()),
                 explicit_conditions)
 
         if (len(self.domain.all_instance_vars()) == 1 and
             self.domain.instance_element == self.domain.instance_var):
+            # print(f"Entering IF branch in SetOfAllMembership.conclude().")
             # cases like [x in {y}_{y in S}]
             #         or [x in {y | Q(y)}_{y in S}]
             #         or [x in {y | Q1(y), Q2(y),...,Qn(y)}_{y in S}]
             _S_sub = self.domain.domain
             _y_sub = self.domain.all_instance_vars()[0]
+            # temp_inst = fold_basic_comprehension.instantiate(
+            #         {S:_S_sub, _Q_op:_Q_op_sub, x:element,
+            #          y:_y_sub}, preserve_expr = self.domain.condition,
+            #          auto_simplify = False)
+            # display(temp_inst.domain.condition)
+            # defaults._temp_inst = temp_inst
+            # defaults._temp_expr = self.expr 
+
+            # return fold_basic_comprehension.instantiate(
+            #         {S:_S_sub, _Q_op:_Q_op_sub, x:element, y:_y_sub},
+            #          preserved_exprs = {self.domain.condition},
+            #          auto_simplify = True)
+            # testing this alternative 20250412 for changes in Conditional.shallow_simplification
             return fold_basic_comprehension.instantiate(
-                    {S:_S_sub, _Q_op:_Q_op_sub, x:element,
-                     y:_y_sub})
+                    {S:_S_sub, _Q_op:_Q_op_sub, x:element, y:_y_sub},
+                     preserved_exprs = {self.domain.condition},
+                     # preserve_expr = self.domain.operands[0].body.condition,
+                     # preserve_expr = self.domain.condition,
+                     auto_simplify = True)
+
         else: 
+            # print(f"\nEntering ELSE branch in SetOfAllMembership.conclude().\n")
             # cases where we have:
             # (1) multiple instance_vars,
             # (2) and/or instance_element is not just an instance_var
@@ -272,15 +303,93 @@ def conclude(self, **defaults_config):
             _f_op, _f_sub = (
                     Function(f, self.domain.all_instance_vars()),
                     self.domain.instance_element)
-            if len(self.domain.explicit_conditions())<=1:
+            # self.domain.condition == self.domain.domain
+            # if len(self.domain.explicit_conditions())<1: # changing from <= 1 to < 1 20250405
+            if (len(self.domain.conditions) == len(self.domain.explicit_domains())):
+                # want to be able to simplify empty And() created
+                # above for 'explicit_conditions'
                 should_auto_simplify = True
-                # will simplify vacuous And() and trivial And(Q(y))
+                # print(f"should_auto_simplify = {should_auto_simplify}")
+                # print()
             else:
+                # generally don't mess with anything
                 should_auto_simplify = False
+                # print(f"should_auto_simplify = {should_auto_simplify}")
+                # print()
+
+            # BEGIN TESTING
+            # temporarily keeping these try-except blocks;
+            # see further down for "testing" without the try-except
+            # print(f"---- Begin testing section in SetOfAllMembership.conclude() ----")
+            try:
+                temp_inst = fold.instantiate(
+                    {n:_n_sub, S:self.domain.all_domains(), 
+                    _Q_op:_Q_op_sub, _f_op:_f_sub,
+                    x:element, y:self.domain.all_instance_vars()},
+                    # preserved_exprs = {self.domain.condition},
+                    auto_simplify = should_auto_simplify)
+                print("'fold' instantiation gives: ")
+                display(temp_inst)
+                display(temp_inst.expr.antecedent)
+                print(f"assumption:")
+                display(defaults.assumptions[0])
+                print(f"assumption==antecedent = {defaults.assumptions[0]==temp_inst.expr.antecedent}")
+                print()
+                print(f"In the TRY block, the derive_consequent() returns: ")
+                return temp_inst.derive_consequent()
+
+            except Exception as the_exception:
+                print(f"Exception raised under should_auto_simplify = {should_auto_simplify}")
+                print(f"Switching to should_auto_simplify = {not should_auto_simplify}")
+                temp_inst = fold.instantiate(
+                    {n:_n_sub, S:self.domain.all_domains(), 
+                    _Q_op:_Q_op_sub, _f_op:_f_sub,
+                    x:element, y:self.domain.all_instance_vars()},
+                    # preserved_exprs = {self.domain.condition},
+                    auto_simplify = not should_auto_simplify)
+                print("'fold' instantiation gives: ")
+                display(temp_inst)
+                print()
+                print(f"The derive_consequent() returns: ")
+                return temp_inst.derive_consequent()
+
+
+            # temp_inst = fold.instantiate(
+            #         {n:_n_sub, S:self.domain.all_domains(), 
+            #         _Q_op:_Q_op_sub, _f_op:_f_sub,
+            #         x:element, y:self.domain.all_instance_vars()},
+            #         # preserved_exprs = {self.domain.condition},
+            #         auto_simplify = should_auto_simplify)
+
+            # Use the following when testing for when self.domain
+            # conditional's condition no longer being simplified inside
+            # the Conditional.shallow_simplification() method
+            # print()
+            # print(f"preserve_expr = {self.domain.operands[0].body.condition}")
+            # print()
+            # temp_inst = fold.instantiate(
+            #         {n:_n_sub, S:self.domain.all_domains(), 
+            #         _Q_op:_Q_op_sub, _f_op:_f_sub,
+            #         x:element, y:self.domain.all_instance_vars()},
+            #         preserve_expr = self.domain.operands[0].body.condition,
+            #         auto_simplify = True)
+            # print("'fold' instantiation gives: ")
+            # display(temp_inst)
+            # print()
+            # print(f"assumption==antecedent = {defaults.assumptions[0]==temp_inst.expr.antecedent}")
+            # print()
+            # print(f"And the derive_consequent() returns: ")
+            # return temp_inst.derive_consequent()
+
+            # END TESTING
+
+            # this block will not be reached while the testing
+            # block above are un-commented-out
             return fold.instantiate(
                 {n:_n_sub, S:self.domain.all_domains(), 
                 _Q_op:_Q_op_sub, _f_op:_f_sub,
                 x:element, y:self.domain.all_instance_vars()},
+                # preserved_exprs = {self.domain.condition},
                 auto_simplify = should_auto_simplify).derive_consequent()
 
     @prover
@@ -508,13 +617,32 @@ def conclude(self, **defaults_config):
             _f_op, _f_sub = (
                     Function(f, self.domain.all_instance_vars()),
                     self.domain.instance_element)
-            if len(self.domain.explicit_conditions())<=1:
+
+            if (len(self.domain.conditions) == len(self.domain.explicit_domains())):
+                # want to be able to simplify any empty And() created
+                # above for 'explicit_conditions'
                 should_auto_simplify = True
-                # will simplify vacuous And() and trivial And(Q(y))
             else:
+                # otherwise, generally don't mess with anything
                 should_auto_simplify = False
-            return nonmembership_fold.instantiate(
-                {n:_n_sub, S:self.domain.all_domains(), 
-                _Q_op:_Q_op_sub, _f_op:_f_sub,
-                x:element, y:self.domain.all_instance_vars()},
-                auto_simplify = should_auto_simplify)
+
+            # See the try-except block below as current alternative
+            # return nonmembership_fold.instantiate(
+            #     {n:_n_sub, S:self.domain.all_domains(), 
+            #     _Q_op:_Q_op_sub, _f_op:_f_sub,
+            #     x:element, y:self.domain.all_instance_vars()},
+            #     auto_simplify = should_auto_simplify)
+
+            try:
+                return nonmembership_fold.instantiate(
+                        {n:_n_sub, S:self.domain.all_domains(), 
+                        _Q_op:_Q_op_sub, _f_op:_f_sub,
+                        x:element, y:self.domain.all_instance_vars()},
+                        auto_simplify = should_auto_simplify)
+
+            except Exception as the_exception:
+                return nonmembership_fold.instantiate(
+                        {n:_n_sub, S:self.domain.all_domains(), 
+                        _Q_op:_Q_op_sub, _f_op:_f_sub,
+                        x:element, y:self.domain.all_instance_vars()},
+                        auto_simplify = not should_auto_simplify)

From 654e7b19d676749042eeb23b7cdaa4d5bd136f5b Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 5 May 2025 13:53:26 -0500
Subject: [PATCH 057/159] Finish proof of endpoints/membership_folding theorem

Finish proof of endpoints/membership_folding theorem, possible now that SetOfAll class methods updated by cherry-picking from 329-QEC branch.
---
 .../membership_folding/allowed_presumptions.txt       |  2 ++
 .../proofs/membership_folding/thm_proof.ipynb         | 11 ++++++++++-
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
index e69de29bb2d1..c46ffd0527d6 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
@@ -0,0 +1,2 @@
+proveit.logic.sets.comprehension.fold_basic_comprehension
+proveit.logic.equality.sub_left_side_into
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
index ed6d0ed2bb51..9fd99da4b589 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
@@ -82,7 +82,16 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "# endpoints_def_membership.rhs.domain.unfold_membership(v)"
+    "endpoints_def_membership.rhs.conclude()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
    ]
   },
   {

From ecb5bed0ace388d6c41dfa5489a58762f790b440 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 5 May 2025 13:54:43 -0500
Subject: [PATCH 058/159] Update allowed_presumptions for
 endpoints/membership_unfolding theorem proof

Update the allowed_presumptions.txt file for endpoints/membership_unfolding theorem proof (deleting some presumptions from earlier proof efforts).
---
 .../proofs/membership_unfolding/allowed_presumptions.txt        | 2 --
 1 file changed, 2 deletions(-)

diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
index a584ff39dfc4..9d6ce22982f4 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
@@ -1,4 +1,2 @@
-proveit.logic.equality.rhs_via_equality
 proveit.logic.equality.sub_right_side_into
 proveit.logic.sets.comprehension.unfold_basic_comprehension
-proveit.logic.sets.comprehension.in_superset_if_in_comprehension

From ac5cbf22a1bf0e4ce77be29fc855f311738743f7 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 5 May 2025 14:50:28 -0500
Subject: [PATCH 059/159] Establish and prove endpoints theorem
 nonmembership_def

Establish and prove the graph/endpoints nonmembership_def theorem.
---
 .../allowed_presumptions.txt                  |   0
 .../disallowed_presumptions.txt               |   0
 .../proofs/nonmembership_def/thm_proof.ipynb  | 105 ++++++++++++++++++
 .../endpoints/_theory_nbs_/theorems.ipynb     |  14 ++-
 4 files changed, 117 insertions(+), 2 deletions(-)
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb

diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/allowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/allowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/disallowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb
new file mode 100644
index 000000000000..9d0ce535a316
--- /dev/null
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb
@@ -0,0 +1,105 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">endpoints</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_def\">nonmembership_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import v, X, defaults, Lambda\n",
+    "from proveit.logic.sets import NotInSet\n",
+    "from proveit.graphs.endpoints import endpoints_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving nonmembership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = nonmembership_def.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "endpoints_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "endpoints_def_inst = endpoints_def.instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "temp_lambda = Lambda(X, NotInSet(v, X))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "endpoints_def_inst.substitution(temp_lambda)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
index 01fffe635f3d..35ae506d2c5a 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
@@ -20,7 +20,7 @@
     "\n",
     "from proveit import v, E, P, V\n",
     "from proveit.logic import And, Equals, Forall, InClass, NotEquals\n",
-    "from proveit.logic.sets import EmptySet, InSet, KPowerSet, SubsetEq\n",
+    "from proveit.logic.sets import EmptySet, InSet, KPowerSet, NotInSet, SubsetEq\n",
     "from proveit.numbers import one, two, LessEq\n",
     "from proveit.graphs import Degree, Endpoints, Path, Vertices\n",
     "\n",
@@ -108,7 +108,17 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "nonmembership_def = (\n",
+    "    Forall(P,\n",
+    "       Forall(v,\n",
+    "       Equals(NotInSet(v, Endpoints(P)),\n",
+    "              NotInSet(v, SetOfAll(v, v, conditions = [LessEq(Degree(v, P), one)], domain = Vertices(P))))\n",
+    "       ),\n",
+    "       domain = Paths()\n",
+    "    )\n",
+    ")"
+   ]
   },
   {
    "cell_type": "code",

From 7054f1f77aaaa20fb293b9adcea5ef4fffde9e29 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 5 May 2025 15:08:34 -0500
Subject: [PATCH 060/159] Add EndpointsNonmembership.side_effects() method

Add the EndpointsNonmembership.side_effects() method (in endpoints_membership.py in the graphs/endpoints package).
---
 .../proveit/graphs/endpoints/endpoints_membership.py     | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/packages/proveit/graphs/endpoints/endpoints_membership.py b/packages/proveit/graphs/endpoints/endpoints_membership.py
index 5425ea0e920f..06cbab078762 100644
--- a/packages/proveit/graphs/endpoints/endpoints_membership.py
+++ b/packages/proveit/graphs/endpoints/endpoints_membership.py
@@ -34,4 +34,11 @@ class EndpointsNonmembership(SetNonmembership):
     '''
 
     def __init__(self, element, domain):
-        SetNonmembership.__init__(self, element, domain)
\ No newline at end of file
+        SetNonmembership.__init__(self, element, domain)
+
+    def side_effects(self, judgment):
+        '''
+        Currently no side-effects for EndpointsNonmembership.
+        '''
+        return
+        yield

From 33ac2112ab992212ece874cd3ca1f0ec381406f4 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 5 May 2025 15:10:53 -0500
Subject: [PATCH 061/159] Establish nonmembership_unfolding & _folding thms to
 endpoints_membership pkg

Establish and prove the nonmembership_unfolding & nonmembership_folding theorems to endpoints_membership package.
---
 .../allowed_presumptions.txt                  |  2 +
 .../disallowed_presumptions.txt               |  0
 .../nonmembership_folding/thm_proof.ipynb     | 95 +++++++++++++++++++
 .../allowed_presumptions.txt                  |  2 +
 .../disallowed_presumptions.txt               |  0
 .../nonmembership_unfolding/thm_proof.ipynb   | 95 +++++++++++++++++++
 .../endpoints/_theory_nbs_/theorems.ipynb     | 34 +++++++
 7 files changed, 228 insertions(+)
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb

diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt
new file mode 100644
index 000000000000..21885e9bdad8
--- /dev/null
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt
@@ -0,0 +1,2 @@
+proveit.graphs.endpoints.nonmembership_def
+proveit.logic.equality.lhs_via_equality
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/disallowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..4b17614dc223
--- /dev/null
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
@@ -0,0 +1,95 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">endpoints</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_folding\">nonmembership_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.graphs.endpoints import nonmembership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving nonmembership_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = nonmembership_folding.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def_inst = nonmembership_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def_inst.derive_left_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt
new file mode 100644
index 000000000000..9f467aab5ac2
--- /dev/null
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt
@@ -0,0 +1,2 @@
+proveit.graphs.endpoints.nonmembership_def
+proveit.logic.equality.rhs_via_equality
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/disallowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb
new file mode 100644
index 000000000000..33a5fb32a73d
--- /dev/null
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb
@@ -0,0 +1,95 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">endpoints</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_unfolding\">nonmembership_unfolding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import defaults\n",
+    "from proveit.graphs.endpoints import nonmembership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving nonmembership_unfolding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = nonmembership_unfolding.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def_inst = nonmembership_def.instantiate().instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_def_inst.derive_right_via_equality()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
index 35ae506d2c5a..a19e46f8fe53 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
@@ -120,6 +120,40 @@
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_unfolding = (\n",
+    "    Forall(P,\n",
+    "       Forall(v,\n",
+    "              NotInSet(v, SetOfAll(v, v, conditions = [LessEq(Degree(v, P), one)], domain = Vertices(P))),\n",
+    "              conditions = [NotInSet(v, Endpoints(P))]\n",
+    "       ),\n",
+    "       domain = Paths()\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nonmembership_folding = (\n",
+    "    Forall(P,\n",
+    "       Forall(v,\n",
+    "              NotInSet(v, Endpoints(P)),\n",
+    "              conditions = [NotInSet(v, SetOfAll(v, v, conditions = [LessEq(Degree(v, P), one)], domain = Vertices(P)))]\n",
+    "       ),\n",
+    "       domain = Paths()\n",
+    "    )\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From 233b85483bf41d6d2b308997bd44d5d1b20f2f92 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 5 May 2025 15:28:07 -0500
Subject: [PATCH 062/159] Establish & prove endpoints_membership membership_def
 theorem

Establish & prove the membership_def theorem for the graphs/endpoints package.
---
 .../membership_def/allowed_presumptions.txt   |   0
 .../disallowed_presumptions.txt               |   0
 .../proofs/membership_def/thm_proof.ipynb     | 105 ++++++++++++++++++
 .../endpoints/_theory_nbs_/theorems.ipynb     |  51 +++------
 4 files changed, 122 insertions(+), 34 deletions(-)
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/allowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/disallowed_presumptions.txt
 create mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/thm_proof.ipynb

diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/allowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/allowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/disallowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/thm_proof.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/thm_proof.ipynb
new file mode 100644
index 000000000000..126f258f8def
--- /dev/null
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/thm_proof.ipynb
@@ -0,0 +1,105 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">endpoints</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_def\">membership_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "\n",
+    "from proveit import v, X, defaults, Lambda\n",
+    "from proveit.logic.sets import InSet\n",
+    "from proveit.graphs.endpoints import endpoints_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = membership_def.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "endpoints_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "endpoints_def_inst = endpoints_def.instantiate()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "temp_lambda = Lambda(X, InSet(v, X))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "endpoints_def_inst.substitution(temp_lambda)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%qed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
index a19e46f8fe53..2786143ebe49 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
@@ -37,6 +37,23 @@
     "%begin theorems"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "membership_def = (\n",
+    "    Forall(P,\n",
+    "       Forall(v,\n",
+    "       Equals(InSet(v, Endpoints(P)),\n",
+    "              InSet(v, SetOfAll(v, v, conditions = [LessEq(Degree(v, P), one)], domain = Vertices(P))))\n",
+    "       ),\n",
+    "       domain = Paths()\n",
+    "    )\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -69,40 +86,6 @@
     ")"
    ]
   },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# membership_unfolding = (\n",
-    "#     Forall(V,\n",
-    "#            Forall((v, E),\n",
-    "#                   And(InSet(v, V), LessEq(Degree(v), one)),\n",
-    "#                   conditions = [SubsetEq(E, KPowerSet(V, two)),\n",
-    "#                                 InSet(v, Endpoints(Path(V, E)))]\n",
-    "#            )\n",
-    "#     )\n",
-    "# )"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# membership_folding = (\n",
-    "#     Forall(V,\n",
-    "#            Forall((v, E),\n",
-    "#                   InSet(v, Endpoints(Path(V, E))),\n",
-    "#                   conditions = [SubsetEq(E, KPowerSet(V, two)),\n",
-    "#                                 NotEquals(E, EmptySet), And(InSet(v, V), Equals(Degree(v), one))]\n",
-    "#            )\n",
-    "#     )\n",
-    "# )"
-   ]
-  },
   {
    "cell_type": "code",
    "execution_count": null,

From d71531aa58567d8cbae27cb2f5f9c61b5d3375dd Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 5 May 2025 17:12:33 -0500
Subject: [PATCH 063/159] Add EndpointsMembership .definition() and
 .as_defined() methods

Add EndpointsMembership.definition() and EndpointsMembership.as_defined() methods and augment endpoints package demonstrations.ipynb notebook with related tests.
---
 .../_theory_nbs_/demonstrations.ipynb         | 67 ++++++++++++++++++-
 .../graphs/endpoints/endpoints_membership.py  | 39 +++++++++--
 2 files changed, 98 insertions(+), 8 deletions(-)

diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
index 7bb71a77f262..153c48d95cda 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
@@ -18,8 +18,9 @@
     "%begin demonstrations\n",
     "\n",
     "from proveit import e, v, E, G, P, V\n",
+    "from proveit.logic import InClass\n",
     "from proveit.logic.sets import NotInSet, InSet, SubsetEq\n",
-    "from proveit.graphs import Endpoints, Graph, Paths, Vertices"
+    "from proveit.graphs import Endpoints, Graph, Path, Paths, Vertices"
    ]
   },
   {
@@ -79,6 +80,70 @@
     "SubsetEq(Endpoints(P), Vertices(Graph(V, E)))"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing Membership methods"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EndpointsMembership.definition()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Endpoints(P)).definition(assumptions = [InClass(P, Paths())])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Endpoints(Path(V, E))).definition(assumptions = [InClass(Path(V, E), Paths())])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EndpointsMembership.as_defined()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Endpoints(P)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Endpoints(Path(V, E))).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/endpoints/endpoints_membership.py b/packages/proveit/graphs/endpoints/endpoints_membership.py
index 06cbab078762..619e4199aa81 100644
--- a/packages/proveit/graphs/endpoints/endpoints_membership.py
+++ b/packages/proveit/graphs/endpoints/endpoints_membership.py
@@ -1,4 +1,4 @@
-from proveit import equality_prover
+from proveit import v, P, equality_prover
 from proveit.logic import SetMembership, SetNonmembership
 
 
@@ -14,17 +14,42 @@ def __init__(self, element, domain):
     @equality_prover('defined', 'define')
     def definition(self, **defaults_config):
         '''
-        From self = [elem in Endpoints(P)], where P is a non-trivial
-        path (i.e. a path with at least one edge), deduce and return:
-            [elem in Vertices(Graph(V,E))] = [elem in V]
+        From self = [elem in Endpoints(P)], where P is a path (i.e. P
+        is an element of the Paths class, or P has been explicitly
+        constructed as a Path(V,E) with vertex set V and edge set E),
+        deduce and return:
+            [elem in Endpoints(P)]
+            = [elem in {v | deg(v) <= 1}_{Vertices(P)}],
+        where the rhs of that equality is a SetOfAll construction.
         '''
 
         from . import membership_def
         element = self.element
-        _V_sub  = self.domain.graph.vertex_set
-        _E_sub  = self.domain.graph.edge_set
+        _P_sub  = self.domain.path  # or self.domain.operand
+        # _V_sub  = self.domain.graph.vertex_set
+        # _E_sub  = self.domain.graph.edge_set
         return membership_def.instantiate(
-                {v:element, V:_V_sub, E:_E_sub },auto_simplify=False)
+                {v:element, P:_P_sub },auto_simplify=False)
+
+    def as_defined(self):
+        '''
+        From self = [elem in Endpoints(P)], return:
+        [elem in {v | deg(v) <= 1}_{Vertices(P)}],
+        i.e. the elem is in the SetOfAll v from Vertices(P) such
+        that deg(v) <= 1. 
+        The method returns an expression, not a Judgment, and does
+        not check that P is actually in the class of Paths.
+        '''
+        from proveit.logic import InSet, SetOfAll
+        from proveit.numbers import one, LessEq
+        from proveit.graphs import Degree, Vertices
+        element   = self.element
+        _domain   = self.domain
+        _path     = self.domain.path
+        _setofall = SetOfAll(
+                v, v, conditions = [LessEq(Degree(v, _path),one)],
+                domain = Vertices(_path))
+        return InSet(element, _setofall)
 
 
 class EndpointsNonmembership(SetNonmembership):

From d34adb22b3772671a9be8e4564cc662e39682d2b Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 5 May 2025 17:35:46 -0500
Subject: [PATCH 064/159] Update endpoints pkg membership theorems

Update graphs/endpoints package membership_folding and membership_unfolding theorems to restate each theorem. Previous theorem statements took the folding/unfolding too far in the sense of also unfolding the underlying SetOfAll set (not incorrect, just farther than technically correct for these fold/unfold theorems).
---
 .../allowed_presumptions.txt                  |  3 +-
 .../proofs/membership_folding/thm_proof.ipynb |  2 +-
 .../allowed_presumptions.txt                  |  1 -
 .../membership_unfolding/thm_proof.ipynb      | 57 -------------------
 .../endpoints/_theory_nbs_/theorems.ipynb     |  5 +-
 5 files changed, 4 insertions(+), 64 deletions(-)

diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
index c46ffd0527d6..df2d242c76be 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
@@ -1,2 +1 @@
-proveit.logic.sets.comprehension.fold_basic_comprehension
-proveit.logic.equality.sub_left_side_into
+proveit.logic.equality.lhs_via_equality
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
index 9fd99da4b589..c866ec2997ec 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
@@ -82,7 +82,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "endpoints_def_membership.rhs.conclude()"
+    "endpoints_def_membership.derive_left_via_equality()"
    ]
   },
   {
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
index 9d6ce22982f4..6aa517e4925f 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
@@ -1,2 +1 @@
 proveit.logic.equality.sub_right_side_into
-proveit.logic.sets.comprehension.unfold_basic_comprehension
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
index 146a68b71cc4..c183136ca760 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
@@ -17,9 +17,6 @@
     "import proveit\n",
     "theory = proveit.Theory() # the theorem's theory\n",
     "\n",
-    "from proveit import v, P, X, defaults, Lambda\n",
-    "from proveit.logic import InSet\n",
-    "from proveit.graphs import Vertices\n",
     "from proveit.graphs.endpoints import endpoints_def"
    ]
   },
@@ -32,60 +29,6 @@
     "%proving membership_unfolding"
    ]
   },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "defaults.assumptions = membership_unfolding.all_conditions()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "endpoints_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "endpoints_def_inst = endpoints_def.instantiate()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "temp_lambda = Lambda(X, InSet(v, X))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "endpoints_def_membership = endpoints_def_inst.substitution(temp_lambda)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "endpoints_def_membership.rhs.domain.unfold_membership(v)"
-   ]
-  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
index 2786143ebe49..79818e842e7d 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
@@ -63,7 +63,7 @@
     "membership_unfolding = (\n",
     "    Forall(P,\n",
     "    Forall(v,\n",
-    "           And(InSet(v, Vertices(P)), LessEq(Degree(v, P), one)),\n",
+    "           InSet(v, SetOfAll(v, v, conditions = [LessEq(Degree(v, P), one)], domain = Vertices(P))),\n",
     "           domain = Endpoints(P)),\n",
     "    domain = Paths())\n",
     ")"
@@ -79,8 +79,7 @@
     "    Forall(P,\n",
     "    Forall(v,\n",
     "           InSet(v, Endpoints(P)),\n",
-    "           conditions = [LessEq(Degree(v, P), one)],\n",
-    "           domain = Vertices(P)\n",
+    "           conditions = [InSet(v, SetOfAll(v, v, conditions = [LessEq(Degree(v, P), one)], domain = Vertices(P)))]\n",
     "          ),\n",
     "    domain = Paths())\n",
     ")"

From 9100f75ba88361c71df169ca10781cbf2beaa8e7 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 5 May 2025 17:38:48 -0500
Subject: [PATCH 065/159] Add EndpointsMembership.unfold() method

Add EndpointsMembership.unfold() method and augment endpoints package demonstrations.ipynb notebook with related tests.
---
 .../_theory_nbs_/demonstrations.ipynb         | 20 ++++++++++++++++++-
 .../graphs/endpoints/endpoints_membership.py  | 18 ++++++++++++++---
 2 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
index 153c48d95cda..3e1df0b2eb3e 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
@@ -137,12 +137,30 @@
     "InSet(v, Endpoints(Path(V, E))).as_defined()"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EndpointsMembership.unfold()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Endpoints(P)).unfold(assumptions = [InClass(P, Paths()), InSet(v, Endpoints(P))])"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "InSet(v, Endpoints(Path(V, E))).unfold(assumptions = [InClass(P, Paths()), InSet(v, Endpoints(P))])"
+   ]
   },
   {
    "cell_type": "code",
diff --git a/packages/proveit/graphs/endpoints/endpoints_membership.py b/packages/proveit/graphs/endpoints/endpoints_membership.py
index 619e4199aa81..77e5b59db1db 100644
--- a/packages/proveit/graphs/endpoints/endpoints_membership.py
+++ b/packages/proveit/graphs/endpoints/endpoints_membership.py
@@ -1,4 +1,4 @@
-from proveit import v, P, equality_prover
+from proveit import v, P, equality_prover, prover
 from proveit.logic import SetMembership, SetNonmembership
 
 
@@ -26,8 +26,6 @@ def definition(self, **defaults_config):
         from . import membership_def
         element = self.element
         _P_sub  = self.domain.path  # or self.domain.operand
-        # _V_sub  = self.domain.graph.vertex_set
-        # _E_sub  = self.domain.graph.edge_set
         return membership_def.instantiate(
                 {v:element, P:_P_sub },auto_simplify=False)
 
@@ -51,6 +49,20 @@ def as_defined(self):
                 domain = Vertices(_path))
         return InSet(element, _setofall)
 
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        From self = [elem in Endpoints(P)],
+        derive and return [elem in {v | deg(v) <= 1}_{Vertices(P)}],
+        knowing or assuming self (and that P is a member of the
+        class of all Paths).
+        '''
+        from . import membership_unfolding
+        element = self.element
+        _P_sub  = self.domain.path  # or self.domain.operand
+        return membership_unfolding.instantiate(
+                {v:element, P:_P_sub },auto_simplify=False)
+
 
 class EndpointsNonmembership(SetNonmembership):
     '''

From 04b137a8223bbbe843b2c308e01014870bc53e47 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 5 May 2025 17:42:16 -0500
Subject: [PATCH 066/159] Update graphs/endpoints demonstrations.ipynb

Update graphs/endpoints demonstrations.ipynb, correcting an error where insufficient assumptions were being made for calling the EndpointsMembership.unfold() method.
---
 .../proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
index 3e1df0b2eb3e..1baff530e544 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
@@ -159,7 +159,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(v, Endpoints(Path(V, E))).unfold(assumptions = [InClass(P, Paths()), InSet(v, Endpoints(P))])"
+    "InSet(v, Endpoints(Path(V, E))).unfold(assumptions = [InClass(Path(V, E), Paths()), InSet(v, Endpoints(Path(V, E)))])"
    ]
   },
   {

From bffea93c320d4b2ed1789fa693661e034e49fa43 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 5 May 2025 17:53:23 -0500
Subject: [PATCH 067/159] Add EndpointsMembership.conclude() method

Add EndpointsMembership.conclude() method and augment endpoints package demonstrations.ipynb notebook with related tests.
---
 .../_theory_nbs_/demonstrations.ipynb         | 35 +++++++++++++++++--
 .../graphs/endpoints/endpoints_membership.py  | 14 ++++++++
 2 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
index 1baff530e544..9937bd8221be 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
@@ -18,9 +18,10 @@
     "%begin demonstrations\n",
     "\n",
     "from proveit import e, v, E, G, P, V\n",
-    "from proveit.logic import InClass\n",
-    "from proveit.logic.sets import NotInSet, InSet, SubsetEq\n",
-    "from proveit.graphs import Endpoints, Graph, Path, Paths, Vertices"
+    "from proveit.logic import Equals, InClass\n",
+    "from proveit.logic.sets import NotInSet, InSet, SetOfAll, SubsetEq\n",
+    "from proveit.numbers import one\n",
+    "from proveit.graphs import Degree, Endpoints, Graph, Path, Paths, Vertices"
    ]
   },
   {
@@ -162,6 +163,34 @@
     "InSet(v, Endpoints(Path(V, E))).unfold(assumptions = [InClass(Path(V, E), Paths()), InSet(v, Endpoints(Path(V, E)))])"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EndpointsMembership.conclude()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from proveit.logic import And\n",
+    "InSet(v, Endpoints(P)).conclude(\n",
+    "    assumptions = [InClass(P, Paths()), And(InSet(v, Vertices(P)), Equals(Degree(v, P), one))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Endpoints(P)).conclude(\n",
+    "    assumptions = [InClass(P, Paths()), InSet(v, SetOfAll(v, v, conditions = [Equals(Degree(v, P), one)], domain = Vertices(P)))])"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/endpoints/endpoints_membership.py b/packages/proveit/graphs/endpoints/endpoints_membership.py
index 77e5b59db1db..7d5dfbaff743 100644
--- a/packages/proveit/graphs/endpoints/endpoints_membership.py
+++ b/packages/proveit/graphs/endpoints/endpoints_membership.py
@@ -63,6 +63,20 @@ class of all Paths).
         return membership_unfolding.instantiate(
                 {v:element, P:_P_sub },auto_simplify=False)
 
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Called on self = [elem in Endpoints(P)], and
+        knowing or assuming [elem in {v | deg(v) <= 1}_{Vertices(P)}]
+        (and that P is a member of the class of Paths)
+        derive and return self.
+        '''
+        from . import membership_folding
+        element = self.element
+        _P_sub  = self.domain.path
+        return membership_folding.instantiate(
+            {v:element, P:_P_sub}, auto_simplify=False)
+
 
 class EndpointsNonmembership(SetNonmembership):
     '''

From 369d62e87f4d6459c43461123f8dc8d2f8dee3a5 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 5 May 2025 17:59:52 -0500
Subject: [PATCH 068/159] Add EndpointsNonmembership.definition() method

Add EndpointsNonmembership.definition() method and augment endpoints package demonstrations.ipynb notebook with related tests.
---
 .../_theory_nbs_/demonstrations.ipynb         | 32 +++++++++++++++++++
 .../graphs/endpoints/endpoints_membership.py  | 18 +++++++++++
 2 files changed, 50 insertions(+)

diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
index 9937bd8221be..2a93f155ac08 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
@@ -191,6 +191,38 @@
     "    assumptions = [InClass(P, Paths()), InSet(v, SetOfAll(v, v, conditions = [Equals(Degree(v, P), one)], domain = Vertices(P)))])"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Testing Nonmembership methods"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EndpointsNonmembership.definition()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(v, Endpoints(P)).definition(assumptions = [InClass(P, Paths())])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(v, Endpoints(Path(V, E))).definition(assumptions = [InClass(Path(V, E), Paths())])"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/endpoints/endpoints_membership.py b/packages/proveit/graphs/endpoints/endpoints_membership.py
index 7d5dfbaff743..5e7eb906aa64 100644
--- a/packages/proveit/graphs/endpoints/endpoints_membership.py
+++ b/packages/proveit/graphs/endpoints/endpoints_membership.py
@@ -93,3 +93,21 @@ def side_effects(self, judgment):
         '''
         return
         yield
+
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self = [elem not in Endpoints(P)], where P is a path
+        (i.e. P is an element of the Paths class, or P has been
+        explicitly constructed as a Path(V,E) with vertex set V and
+        edge set E), deduce and return:
+            [elem not in Endpoints(P)]
+            = [elem not in {v | deg(v) <= 1}_{Vertices(P)}],
+        where the rhs of that equality is a SetOfAll construction.
+        '''
+
+        from . import nonmembership_def
+        element = self.element
+        _P_sub  = self.domain.path  # or self.domain.operand
+        return nonmembership_def.instantiate(
+                {v:element, P:_P_sub },auto_simplify=False)

From c7f66aa6bcff0951dd12ea6a95bf5742770250f4 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 5 May 2025 18:03:26 -0500
Subject: [PATCH 069/159] Add EndpointsNonmembership.as_defined() method

Add EndpointsNonmembership.as_defined() method and augment endpoints package demonstrations.ipynb notebook with related tests.
---
 .../_theory_nbs_/demonstrations.ipynb         | 25 +++++++++++++++++++
 .../graphs/endpoints/endpoints_membership.py  | 21 ++++++++++++++++
 2 files changed, 46 insertions(+)

diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
index 2a93f155ac08..37227c4e0e9c 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
@@ -223,6 +223,31 @@
     "NotInSet(v, Endpoints(Path(V, E))).definition(assumptions = [InClass(Path(V, E), Paths())])"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EndpointsNonmembership.as_defined()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(v, Endpoints(P)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(v, Endpoints(Path(V, E))).as_defined()"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/endpoints/endpoints_membership.py b/packages/proveit/graphs/endpoints/endpoints_membership.py
index 5e7eb906aa64..a8e53caf0dcf 100644
--- a/packages/proveit/graphs/endpoints/endpoints_membership.py
+++ b/packages/proveit/graphs/endpoints/endpoints_membership.py
@@ -111,3 +111,24 @@ def definition(self, **defaults_config):
         _P_sub  = self.domain.path  # or self.domain.operand
         return nonmembership_def.instantiate(
                 {v:element, P:_P_sub },auto_simplify=False)
+
+    def as_defined(self):
+        '''
+        From self = [elem not in Endpoints(P)], return:
+        [elem not in {v | deg(v) <= 1}_{Vertices(P)}],
+        i.e. the elem is not in the SetOfAll v from Vertices(P) such
+        that deg(v) <= 1. 
+        The method returns an expression, not a Judgment, and does
+        not check that P is actually in the class of Paths.
+        '''
+        from proveit.logic import NotInSet, SetOfAll
+        from proveit.numbers import one, LessEq
+        from proveit.graphs import Degree, Vertices
+        element   = self.element
+        _domain   = self.domain
+        _path     = self.domain.path
+        _setofall = SetOfAll(
+                v, v, conditions = [LessEq(Degree(v, _path),one)],
+                domain = Vertices(_path))
+        return NotInSet(element, _setofall)
+

From c96a97f0ac2e39d25ff2b4af1d2c7270ad78c2d9 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 5 May 2025 18:07:07 -0500
Subject: [PATCH 070/159] Add EndpointsNonmembership.unfold() method

Add EndpointsNonmembership.unfold() method and augment endpoints package demonstrations.ipynb notebook with related tests.
---
 .../_theory_nbs_/demonstrations.ipynb         | 25 +++++++++++++++++++
 .../graphs/endpoints/endpoints_membership.py  | 14 +++++++++++
 2 files changed, 39 insertions(+)

diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
index 37227c4e0e9c..5b20f0eca706 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
@@ -248,6 +248,31 @@
     "NotInSet(v, Endpoints(Path(V, E))).as_defined()"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EndpointsNonmembership.unfold()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(v, Endpoints(P)).unfold(assumptions = [InClass(P, Paths()), NotInSet(v, Endpoints(P))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(v, Endpoints(Path(V, E))).unfold(assumptions = [InClass(Path(V, E), Paths()), NotInSet(v, Endpoints(Path(V, E)))])"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/endpoints/endpoints_membership.py b/packages/proveit/graphs/endpoints/endpoints_membership.py
index a8e53caf0dcf..a7bb6e7bb154 100644
--- a/packages/proveit/graphs/endpoints/endpoints_membership.py
+++ b/packages/proveit/graphs/endpoints/endpoints_membership.py
@@ -132,3 +132,17 @@ def as_defined(self):
                 domain = Vertices(_path))
         return NotInSet(element, _setofall)
 
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        From self = [elem not in Endpoints(P)],
+        derive and return [elem not in {v | deg(v) <= 1}_{Vertices(P)}],
+        knowing or assuming self (and that P is a member of the
+        class of all Paths).
+        '''
+        from . import nonmembership_unfolding
+        element = self.element
+        _P_sub  = self.domain.path  # or self.domain.operand
+        return nonmembership_unfolding.instantiate(
+                {v:element, P:_P_sub },auto_simplify=False)
+

From 5513ff57b3db8564cacdeee5c3ff24a3307b8ea2 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 5 May 2025 18:15:10 -0500
Subject: [PATCH 071/159] Add EndpointsNonmembership.conclude() method

Add EndpointsNonmembership.conclude() method and augment endpoints package demonstrations.ipynb notebook with related tests.
---
 .../_theory_nbs_/demonstrations.ipynb         | 35 +++++++++++++++++--
 .../graphs/endpoints/endpoints_membership.py  | 15 ++++++++
 2 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
index 5b20f0eca706..cc1ea82b7857 100644
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
@@ -20,7 +20,7 @@
     "from proveit import e, v, E, G, P, V\n",
     "from proveit.logic import Equals, InClass\n",
     "from proveit.logic.sets import NotInSet, InSet, SetOfAll, SubsetEq\n",
-    "from proveit.numbers import one\n",
+    "from proveit.numbers import one, LessEq\n",
     "from proveit.graphs import Degree, Endpoints, Graph, Path, Paths, Vertices"
    ]
   },
@@ -178,7 +178,7 @@
    "source": [
     "from proveit.logic import And\n",
     "InSet(v, Endpoints(P)).conclude(\n",
-    "    assumptions = [InClass(P, Paths()), And(InSet(v, Vertices(P)), Equals(Degree(v, P), one))])"
+    "    assumptions = [InClass(P, Paths()), And(InSet(v, Vertices(P)), LessEq(Degree(v, P), one))])"
    ]
   },
   {
@@ -188,7 +188,7 @@
    "outputs": [],
    "source": [
     "InSet(v, Endpoints(P)).conclude(\n",
-    "    assumptions = [InClass(P, Paths()), InSet(v, SetOfAll(v, v, conditions = [Equals(Degree(v, P), one)], domain = Vertices(P)))])"
+    "    assumptions = [InClass(P, Paths()), InSet(v, SetOfAll(v, v, conditions = [LessEq(Degree(v, P), one)], domain = Vertices(P)))])"
    ]
   },
   {
@@ -273,6 +273,35 @@
     "NotInSet(v, Endpoints(Path(V, E))).unfold(assumptions = [InClass(Path(V, E), Paths()), NotInSet(v, Endpoints(Path(V, E)))])"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EndpointsNonmembership.conclude()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(v, Endpoints(P)).conclude(\n",
+    "    assumptions = [InClass(P, Paths()),\n",
+    "                   NotInSet(v, SetOfAll(v, v, conditions = [LessEq(Degree(v, P), one)], domain = Vertices(P)))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(v, Endpoints(Path(V, E))).conclude(\n",
+    "    assumptions = [InClass(Path(V, E), Paths()),\n",
+    "                   NotInSet(v, SetOfAll(v, v, conditions = [LessEq(Degree(v, Path(V, E)), one)], domain = Vertices(Path(V, E))))])"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/endpoints/endpoints_membership.py b/packages/proveit/graphs/endpoints/endpoints_membership.py
index a7bb6e7bb154..85d5c877b018 100644
--- a/packages/proveit/graphs/endpoints/endpoints_membership.py
+++ b/packages/proveit/graphs/endpoints/endpoints_membership.py
@@ -146,3 +146,18 @@ class of all Paths).
         return nonmembership_unfolding.instantiate(
                 {v:element, P:_P_sub },auto_simplify=False)
 
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Called on self = [elem not in Endpoints(P)], and
+        knowing or assuming:
+                [elem not in {v | deg(v) <= 1}_{Vertices(P)}]
+        (and that P is a member of the class of Paths),
+        derive and return self.
+        '''
+        from . import nonmembership_folding
+        element = self.element
+        _P_sub  = self.domain.path
+        return nonmembership_folding.instantiate(
+            {v:element, P:_P_sub}, auto_simplify=False)
+

From 3c06c6d9cf18e8547d605348b0ffe4b095806536 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 3 Jun 2025 16:55:24 -0500
Subject: [PATCH 072/159] Begin to establish IntegerEven number set

Begin to establish the IntegerEven number set (the IntegerEvenSet class and the related IntegerEvenMembership class) and begin filling in details, including the standard theorem about membership being Boolean, along with beginning testing in the integers/demonstrations.ipynb nb. The IntegerEvenSet is tucked away inside the integers package and integers.py.
---
 packages/proveit/numbers/__init__.py          |  2 +-
 .../proveit/numbers/number_sets/__init__.py   |  4 +-
 .../integers/_theory_nbs_/common.ipynb        | 12 +++-
 .../_theory_nbs_/demonstrations.ipynb         | 27 ++++++-
 .../thm_proof.ipynb                           | 47 +++++++++++++
 .../integers/_theory_nbs_/theorems.ipynb      | 12 +++-
 .../numbers/number_sets/integers/integer.py   | 15 ++++
 .../integers/integer_membership.py            | 70 ++++++++++++++++++-
 8 files changed, 182 insertions(+), 7 deletions(-)
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_membership_is_bool/thm_proof.ipynb

diff --git a/packages/proveit/numbers/__init__.py b/packages/proveit/numbers/__init__.py
index 03a471ce5102..944600976136 100644
--- a/packages/proveit/numbers/__init__.py
+++ b/packages/proveit/numbers/__init__.py
@@ -2,7 +2,7 @@
 
 from .number_sets import (
     ZeroSet, Natural, NaturalPos,
-    Integer, IntegerNonZero, IntegerNeg, IntegerNonPos,
+    Integer, IntegerEven, IntegerNonZero, IntegerNeg, IntegerNonPos,
     Rational, RationalNonZero, RationalPos, RationalNeg, RationalNonNeg,
     RationalNonPos,
     Real, RealNonZero, RealNeg, RealPos, RealNonNeg, RealNonPos,
diff --git a/packages/proveit/numbers/number_sets/__init__.py b/packages/proveit/numbers/number_sets/__init__.py
index 953641ce9c77..57d50c6bcf0e 100644
--- a/packages/proveit/numbers/number_sets/__init__.py
+++ b/packages/proveit/numbers/number_sets/__init__.py
@@ -1,6 +1,6 @@
 from .integers import (
-        Integer, IntegerNeg, IntegerNonZero, IntegerNonPos,
-        Interval, infinity)
+        Integer, IntegerEven, IntegerNeg, IntegerNonZero,
+        IntegerNonPos, Interval, infinity)
 from .natural_numbers import ZeroSet, Natural, NaturalPos
 from .rational_numbers import (Rational, RationalNonZero,
                                RationalPos, RationalNeg,
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/common.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/common.ipynb
index 0a9a13fb199b..c655860c9966 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/common.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/common.ipynb
@@ -18,7 +18,8 @@
     "# Prepare this notebook for defining the common expressions of a theory:\n",
     "%common_expressions_notebook # Keep this at the top following 'import proveit'.\n",
     "from proveit import Literal\n",
-    "from proveit.numbers.number_sets.integers.integer import IntegerSet, IntegerNegSet, IntegerNonZeroSet, IntegerNonPosSet\n",
+    "from proveit.numbers.number_sets.integers.integer import (\n",
+    "        IntegerSet, IntegerEvenSet, IntegerNegSet, IntegerNonZeroSet, IntegerNonPosSet)\n",
     "%begin common"
    ]
   },
@@ -31,6 +32,15 @@
     "Integer = IntegerSet()"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "IntegerEven = IntegerEvenSet()"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
index ffdc655aabda..0cbcc3167c2f 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
@@ -19,7 +19,7 @@
     "from proveit.logic import Boolean, NotEquals, InSet, NotInSet, Or\n",
     "from proveit.numbers import Neg, Less, LessEq, greater, greater_eq, number_ordering\n",
     "from proveit.numbers import (zero, one, two, three, four, five, six, seven,\n",
-    "                             eight, nine, Integer, IntegerNonZero, IntegerNeg, IntegerNonPos,\n",
+    "                             eight, nine, Integer, IntegerEven, IntegerNonZero, IntegerNeg, IntegerNonPos,\n",
     "                             Interval, Natural, NaturalPos)\n",
     "%begin demonstrations"
    ]
@@ -769,6 +769,31 @@
     "InSet(x, Integer).prove(assumptions=[InSet(x, IntegerNonPos)])"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Even Integers and subsets thereof"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(x, IntegerEven)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(InSet(x, IntegerEven), Boolean).prove()"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_membership_is_bool/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_membership_is_bool/thm_proof.ipynb
new file mode 100644
index 000000000000..3873221d9ee3
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_membership_is_bool/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#even_int_membership_is_bool\">even_int_membership_is_bool</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving even_int_membership_is_bool"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
index 0871ba5728a1..59db6ed11a28 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
@@ -25,7 +25,8 @@
     "from proveit.logic.sets import Card, Disjoint, x_equals_any_y\n",
     "from proveit.numbers import zero, one, num, frac, Neg\n",
     "from proveit.numbers import (ZeroSet, Natural, NaturalPos, \n",
-    "                             Integer, IntegerNeg, IntegerNonZero, IntegerNonPos, Interval, Complex)\n",
+    "                             Integer, IntegerEven, IntegerNeg, IntegerNonZero, IntegerNonPos,\n",
+    "                             Interval, Complex)\n",
     "from proveit.numbers import Add, subtract, greater, greater_eq, Less, LessEq, number_ordering\n",
     "from proveit.numbers import Pzero, Pone, Pm, P_mAddOne, Pn"
    ]
@@ -494,6 +495,15 @@
     "nonpos_int_membership_is_bool = Forall(x, in_bool(InSet(x, IntegerNonPos)))"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "even_int_membership_is_bool = Forall(x, in_bool(InSet(x, IntegerEven)))"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/numbers/number_sets/integers/integer.py b/packages/proveit/numbers/number_sets/integers/integer.py
index 69d7e443e0fe..7da87db1fb2c 100644
--- a/packages/proveit/numbers/number_sets/integers/integer.py
+++ b/packages/proveit/numbers/number_sets/integers/integer.py
@@ -273,6 +273,21 @@ def membership_object(self, element):
         from .integer_membership import IntegerNonPosMembership    
         return IntegerNonPosMembership(element)
 
+class IntegerEvenSet(NumberSet):
+    '''
+    Class to represent the even integers {..., -2, 0, 2, 4, ...}
+    and provide related methods. The even integer set appears as
+    'IntegerEven' in string output and as mathbb 'E' in LaTeX output.
+    '''
+    def __init__(self, *, styles=None):
+        NumberSet.__init__(self, 'IntegerEven', r'\mathbb{E}',
+                           theory=__file__, styles=styles,
+                           fence_when_forced=True)
+
+    def membership_object(self, element):
+        from .integer_membership import IntegerEvenMembership    
+        return IntegerEvenMembership(element)
+
 
 if proveit.defaults.running_theory_notebook is None:
     # Import some fundamental theorems without quantifiers when not 
diff --git a/packages/proveit/numbers/number_sets/integers/integer_membership.py b/packages/proveit/numbers/number_sets/integers/integer_membership.py
index 7c7d76c64276..f2dd6053a20d 100644
--- a/packages/proveit/numbers/number_sets/integers/integer_membership.py
+++ b/packages/proveit/numbers/number_sets/integers/integer_membership.py
@@ -2,7 +2,7 @@
 from proveit import a, x
 from proveit.logic import NotEquals, InSet
 from proveit.numbers import Less, LessEq
-from proveit.numbers import (zero, Integer, IntegerNeg,
+from proveit.numbers import (zero, Integer, IntegerEven, IntegerNeg,
                              IntegerNonPos, IntegerNonZero)
 from proveit.numbers.number_sets.number_set import NumberMembership
 
@@ -265,3 +265,71 @@ def derive_element_in_rational_nonpos(self, **defaults_config):
                 nonpos_int_within_rational_nonpos)
         return nonpos_int_within_rational_nonpos.derive_superset_membership(
             self.element, auto_simplify=False)
+
+class IntegerEvenMembership(NumberMembership):
+    '''
+    Defines methods that apply to membership in IntegerEven (the
+    set of even integers, E = {..., -2, 0, 2, 4, ...}).
+    '''
+
+    def __init__(self, element):
+        NumberMembership.__init__(self, element, IntegerEven)
+
+    def _readily_provable(self):
+        return NumberMembership._readily_provable(self)
+
+    # @prover
+    # def conclude(self, **defaults_config):
+    #     # Use proven, not readily provable here:
+    #     if (InSet(self.element, Integer).proven() and
+    #             NotEquals(self.element, zero).proven()):
+    #         return self.conclude_as_last_resort()
+    #     return NumberMembership.conclude(self)
+
+    # @prover
+    # def conclude_as_last_resort(self, **defaults_config):
+    #     '''
+    #     Conclude element in IntegerNonZero by proving it is integer
+    #     and non-zero.  This is called via NumberMembership.conclude
+    #     if the 'deduce_in_number_set' method of the element raises
+    #     a NotImplementedError.
+    #     '''
+    #     from . import nonzero_int_is_int_nonzero
+    #     return nonzero_int_is_int_nonzero.instantiate({a:self.element})
+
+    def side_effects(self, judgment):
+        '''
+        Yield side-effects when proving 'n in IntegerEven' for 
+        # a given n. No side-effects provided yet.
+        '''
+        # yield self.derive_element_not_zero
+        # yield self.derive_element_in_integer
+        # yield self.derive_element_in_rational_nonzero
+        return
+        yield
+
+    @relation_prover
+    def deduce_in_bool(self, **defaults_config):
+        from . import even_int_membership_is_bool
+        return even_int_membership_is_bool.instantiate(
+            {x: self.element}, auto_simplify=False)
+
+    # @prover
+    # def derive_element_not_zero(self, **defaults_config):
+    #     from . import nonzero_if_in_nonzero_int
+    #     return nonzero_if_in_nonzero_int.instantiate(
+    #         {a: self.element}, auto_simplify=False)
+
+    @prover
+    def derive_element_in_integer(self, **defaults_config):
+        from . import nonzero_int_within_int
+        return nonzero_int_within_int.derive_superset_membership(
+            self.element, auto_simplify=False)
+
+    # @prover
+    # def derive_element_in_rational_nonzero(self, **defaults_config):
+    #     from proveit.numbers.number_sets.rational_numbers import (
+    #             nonzero_int_within_rational_nonzero)
+    #     return nonzero_int_within_rational_nonzero.derive_superset_membership(
+    #         self.element, auto_simplify=False)
+

From 032381ae062afc3ef40c107359bbdfb54b89a90d Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 3 Jun 2025 17:09:20 -0500
Subject: [PATCH 073/159] Augment IntegerEvenMembership with side-effect in
 Integer

Augment IntegerEvenMembership methods to include side-effect that derives membership element in superset Integer. Includes related theorem about even integers being a proper subset of the integers.
---
 .../_theory_nbs_/demonstrations.ipynb         |  9 ++++
 .../even_int_within_int/thm_proof.ipynb       | 47 +++++++++++++++++++
 .../integers/_theory_nbs_/theorems.ipynb      |  9 ++++
 .../integers/integer_membership.py            |  9 ++--
 4 files changed, 68 insertions(+), 6 deletions(-)
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_within_int/thm_proof.ipynb

diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
index 0cbcc3167c2f..d4f41e1196b5 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
@@ -794,6 +794,15 @@
     "InSet(InSet(x, IntegerEven), Boolean).prove()"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(x, Integer).prove(assumptions=[InSet(x, IntegerEven)])"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_within_int/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_within_int/thm_proof.ipynb
new file mode 100644
index 000000000000..dc0afc6b8928
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_within_int/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#even_int_within_int\">even_int_within_int</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving even_int_within_int"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
index 59db6ed11a28..b9632b8b56f4 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
@@ -380,6 +380,15 @@
     "zero_is_int = InSet(zero, Integer)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "even_int_within_int = ProperSubset(IntegerEven, Integer)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/numbers/number_sets/integers/integer_membership.py b/packages/proveit/numbers/number_sets/integers/integer_membership.py
index f2dd6053a20d..fe0dc800df6a 100644
--- a/packages/proveit/numbers/number_sets/integers/integer_membership.py
+++ b/packages/proveit/numbers/number_sets/integers/integer_membership.py
@@ -302,11 +302,8 @@ def side_effects(self, judgment):
         Yield side-effects when proving 'n in IntegerEven' for 
         # a given n. No side-effects provided yet.
         '''
-        # yield self.derive_element_not_zero
-        # yield self.derive_element_in_integer
+        yield self.derive_element_in_integer
         # yield self.derive_element_in_rational_nonzero
-        return
-        yield
 
     @relation_prover
     def deduce_in_bool(self, **defaults_config):
@@ -322,8 +319,8 @@ def deduce_in_bool(self, **defaults_config):
 
     @prover
     def derive_element_in_integer(self, **defaults_config):
-        from . import nonzero_int_within_int
-        return nonzero_int_within_int.derive_superset_membership(
+        from . import even_int_within_int
+        return even_int_within_int.derive_superset_membership(
             self.element, auto_simplify=False)
 
     # @prover

From e4ef686b82a8d30ae5c8b02282fbf4f4f7ecdf2c Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 3 Jun 2025 21:08:05 -0500
Subject: [PATCH 074/159] Establish axiomatic def of even integers
 (IntegerEvenSet)

Establish axiomatic def of IntegerEven (i.e. even integers) as {2z}_{z \in Z} (in axioms for numbers/number_sets/integers).
---
 .../integers/_theory_nbs_/axioms.ipynb        | 24 +++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/axioms.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/axioms.ipynb
index f0d3b9a1ee3c..9cf588a7227f 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/axioms.ipynb
@@ -18,10 +18,10 @@
     "# Prepare this notebook for defining the axioms of a theory:\n",
     "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
     "from proveit.logic import And, Equals, Forall, Iff, Implies, InSet, SetEquiv, SetOfAll, SubsetProper, Union\n",
-    "from proveit.numbers import Complex, Integer, Interval, Natural, NaturalPos, Neg\n",
-    "from proveit.numbers import Add, greater, Less, LessEq, number_ordering\n",
-    "from proveit.numbers import zero, one, num\n",
-    "from proveit import a, b, n, m, x, y, S\n",
+    "from proveit.numbers import Complex, Integer, IntegerEven, Interval, Natural, NaturalPos, Neg\n",
+    "from proveit.numbers import Add, greater, Less, LessEq, Mult, number_ordering\n",
+    "from proveit.numbers import zero, one, two, num\n",
+    "from proveit import a, b, n, m, x, y, z, S\n",
     "%begin axioms"
    ]
   },
@@ -80,6 +80,22 @@
     "#add_by_zero = Forall(x, Equals(Add(x, zero), x), domain=Complex)"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Define some significant subsets of the integers: Evens, Odds, etc."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "even_integers_def = Equals(IntegerEven, SetOfAll(z, Mult(two, z), domain = Integer))"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},

From b89f583fb154a58482aa23d4ff657fcb2f960c77 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 3 Jun 2025 21:11:59 -0500
Subject: [PATCH 075/159] Establish even_int_is_double_int existential theorem

Establish the even_int_is_double_int existential theorem for even integers (i.e. for elements of IntegerEven set). The theorem is then utilized in the IntegerEvenMembership.derive_element_as_double_int() method (see later commit). Proof of the even_int_is_double_int will likely require the SetOfAll class updates available in the QEC-development branch.
---
 .../allowed_presumptions.txt                  |  0
 .../disallowed_presumptions.txt               |  0
 .../even_int_is_double_int/thm_proof.ipynb    | 64 +++++++++++++++++++
 .../integers/_theory_nbs_/theorems.ipynb      | 20 ++++--
 4 files changed, 80 insertions(+), 4 deletions(-)
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_is_double_int/allowed_presumptions.txt
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_is_double_int/disallowed_presumptions.txt
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_is_double_int/thm_proof.ipynb

diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_is_double_int/allowed_presumptions.txt b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_is_double_int/allowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_is_double_int/disallowed_presumptions.txt b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_is_double_int/disallowed_presumptions.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_is_double_int/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_is_double_int/thm_proof.ipynb
new file mode 100644
index 000000000000..8ab055b78fcb
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_is_double_int/thm_proof.ipynb
@@ -0,0 +1,64 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#even_int_is_double_int\">even_int_is_double_int</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory\n",
+    "from proveit import defaults"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving even_int_is_double_int"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "defaults.assumptions = even_int_is_double_int.all_conditions()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof will likely rely on updates to the `SetOfAll` and `SetOfAllMembership` classes currently available the QEC-development branch."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
index b9632b8b56f4..f897dccaeec2 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
@@ -18,16 +18,16 @@
     "# Prepare this notebook for defining the theorems of a theory:\n",
     "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
     "from proveit import Operation, IndexedVar\n",
-    "from proveit import a, b, c, d, e, f, g, h, i, m, n, x, y, S, P\n",
+    "from proveit import a, b, c, d, e, f, g, h, i, m, n, x, y, z, S, P\n",
     "from proveit.core_expr_types import (y_1_to_n)\n",
-    "from proveit.logic import (And, Equals, Forall, Implies, in_bool, InSet, NotInSet, Set,\n",
+    "from proveit.logic import (And, Equals, Exists, Forall, Implies, in_bool, InSet, NotInSet, Set,\n",
     "                           NotEquals, Or, ProperSubset, SubsetEq, SetEquiv, EmptySet)\n",
     "from proveit.logic.sets import Card, Disjoint, x_equals_any_y\n",
-    "from proveit.numbers import zero, one, num, frac, Neg\n",
+    "from proveit.numbers import zero, one, two, num, frac, Neg\n",
     "from proveit.numbers import (ZeroSet, Natural, NaturalPos, \n",
     "                             Integer, IntegerEven, IntegerNeg, IntegerNonZero, IntegerNonPos,\n",
     "                             Interval, Complex)\n",
-    "from proveit.numbers import Add, subtract, greater, greater_eq, Less, LessEq, number_ordering\n",
+    "from proveit.numbers import Add, subtract, greater, greater_eq, Less, LessEq, Mult, number_ordering\n",
     "from proveit.numbers import Pzero, Pone, Pm, P_mAddOne, Pn"
    ]
   },
@@ -460,6 +460,18 @@
     "        domain=Integer)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "even_int_is_double_int = Forall(\n",
+    "        a, Exists(z, Equals(a, Mult(two, z)), domain = Integer),\n",
+    "        domain = IntegerEven\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},

From 21ecaa6cdc16ac008974e1e7c667ab2749d7afae Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 3 Jun 2025 21:14:51 -0500
Subject: [PATCH 076/159] Establish
 IntegerEvenMembership.derive_element_as_double_int() method

Establish IntegerEvenMembership.derive_element_as_double_int() method, which is also used in the IntegerEvenMembership.side_effects() method, returning an existential claim: if x in IntegerEven, then there exists an integer z such that x = 2z.
---
 .../number_sets/integers/integer_membership.py        | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/packages/proveit/numbers/number_sets/integers/integer_membership.py b/packages/proveit/numbers/number_sets/integers/integer_membership.py
index fe0dc800df6a..bf9d6482f1c7 100644
--- a/packages/proveit/numbers/number_sets/integers/integer_membership.py
+++ b/packages/proveit/numbers/number_sets/integers/integer_membership.py
@@ -300,10 +300,14 @@ def _readily_provable(self):
     def side_effects(self, judgment):
         '''
         Yield side-effects when proving 'n in IntegerEven' for 
-        # a given n. No side-effects provided yet.
+        # a given n:
+        (1) An even integer n is an integer;
+        (2) An even integer n can be expressed as 2z for some
+            integer z.
         '''
         yield self.derive_element_in_integer
         # yield self.derive_element_in_rational_nonzero
+        yield self.derive_element_as_double_int
 
     @relation_prover
     def deduce_in_bool(self, **defaults_config):
@@ -330,3 +334,8 @@ def derive_element_in_integer(self, **defaults_config):
     #     return nonzero_int_within_rational_nonzero.derive_superset_membership(
     #         self.element, auto_simplify=False)
 
+    @prover
+    def derive_element_as_double_int(self, **defaults_config):
+        from . import even_int_is_double_int
+        _a_sub = self.element
+        return even_int_is_double_int.instantiate({a:_a_sub})

From 0e3cd5be18d249b2dcfcef29bcedfa63090751c6 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 3 Jun 2025 21:17:24 -0500
Subject: [PATCH 077/159] Update
 numbers/number_sets/integers/demonstrations.ipynb

Update numbers/number_sets/integers/demonstrations.ipynb to include demonstration and testing of IntegerEvenMembership side-effect that x in IntegerEven means there exists z in Integer such that x = 2z.
---
 .../integers/_theory_nbs_/demonstrations.ipynb  | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
index d4f41e1196b5..ce471113de5b 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
@@ -15,9 +15,9 @@
    "outputs": [],
    "source": [
     "import proveit\n",
-    "from proveit import a, b, c, d, n, x, ProofFailure\n",
-    "from proveit.logic import Boolean, NotEquals, InSet, NotInSet, Or\n",
-    "from proveit.numbers import Neg, Less, LessEq, greater, greater_eq, number_ordering\n",
+    "from proveit import a, b, c, d, n, x, z, ProofFailure\n",
+    "from proveit.logic import Boolean, Equals, Exists, NotEquals, InSet, NotInSet, Or\n",
+    "from proveit.numbers import Neg, Less, LessEq, greater, greater_eq, number_ordering, Mult\n",
     "from proveit.numbers import (zero, one, two, three, four, five, six, seven,\n",
     "                             eight, nine, Integer, IntegerEven, IntegerNonZero, IntegerNeg, IntegerNonPos,\n",
     "                             Interval, Natural, NaturalPos)\n",
@@ -773,7 +773,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "#### Even Integers and subsets thereof"
+    "#### Even Integers (`IntegerEven`), Even Integer Membership (`IntegerEvenMembership`), and subsets of even integers"
    ]
   },
   {
@@ -803,6 +803,15 @@
     "InSet(x, Integer).prove(assumptions=[InSet(x, IntegerEven)])"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Exists(z, Equals(x, Mult(two, z)), domain = Integer).prove(assumptions=[InSet(x, IntegerEven)])"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From f431e8e6bb12d5747dfa0ee2b7906c9e74ef33c2 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 4 Jun 2025 11:20:38 -0500
Subject: [PATCH 078/159] Add even_int_within_rational theorem to
 number_sets/rationals pkg

Add even_int_within_rational theorem (unproven) to numbers/number_sets/rationals package: even integers are rational numbers. This is then utilized in the IntegerEvenMembership.derive_element_in_rational() method (separate later commit).
---
 .../even_int_within_rational/thm_proof.ipynb  | 47 +++++++++++++++++++
 .../_theory_nbs_/theorems.ipynb               | 11 ++++-
 2 files changed, 57 insertions(+), 1 deletion(-)
 create mode 100644 packages/proveit/numbers/number_sets/rational_numbers/_theory_nbs_/proofs/even_int_within_rational/thm_proof.ipynb

diff --git a/packages/proveit/numbers/number_sets/rational_numbers/_theory_nbs_/proofs/even_int_within_rational/thm_proof.ipynb b/packages/proveit/numbers/number_sets/rational_numbers/_theory_nbs_/proofs/even_int_within_rational/thm_proof.ipynb
new file mode 100644
index 000000000000..9ffde96fa254
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/rational_numbers/_theory_nbs_/proofs/even_int_within_rational/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">rational_numbers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#even_int_within_rational\">even_int_within_rational</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving even_int_within_rational"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/rational_numbers/_theory_nbs_/theorems.ipynb b/packages/proveit/numbers/number_sets/rational_numbers/_theory_nbs_/theorems.ipynb
index 16a57802154b..507f1ff3fe7a 100644
--- a/packages/proveit/numbers/number_sets/rational_numbers/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/numbers/number_sets/rational_numbers/_theory_nbs_/theorems.ipynb
@@ -22,7 +22,7 @@
     "from proveit.numbers import frac, GCD, Less, LessEq, greater, greater_eq\n",
     "from proveit.numbers import one, zero\n",
     "from proveit.numbers import (ZeroSet, Natural, NaturalPos, Integer, IntegerNonZero, IntegerNeg, IntegerNonPos,\n",
-    "                             Rational, RationalPos, RationalNeg,\n",
+    "                             IntegerEven, Rational, RationalPos, RationalNeg,\n",
     "                             RationalNonNeg, RationalNonPos, RationalNonZero, NaturalPos)"
    ]
   },
@@ -161,6 +161,15 @@
     "nonpos_int_within_rational_nonpos = ProperSubset(IntegerNonPos, RationalNonPos)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "even_int_within_rational = ProperSubset(IntegerEven, Rational)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From 99b96e9706c712877a9f87215ad79f5d1a7ff3f4 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 4 Jun 2025 11:22:17 -0500
Subject: [PATCH 079/159] Add even_int_within_real theorem to number_sets/reals
 pkg

Add even_int_within_real theorem (unproven) to numbers/number_sets/reals package: even integers are real numbers. This is then utilized in the IntegerEvenMembership.derive_element_in_real() method (separate later commit).
---
 .../even_int_within_real/thm_proof.ipynb      | 47 +++++++++++++++++++
 .../real_numbers/_theory_nbs_/theorems.ipynb  | 11 ++++-
 2 files changed, 57 insertions(+), 1 deletion(-)
 create mode 100644 packages/proveit/numbers/number_sets/real_numbers/_theory_nbs_/proofs/even_int_within_real/thm_proof.ipynb

diff --git a/packages/proveit/numbers/number_sets/real_numbers/_theory_nbs_/proofs/even_int_within_real/thm_proof.ipynb b/packages/proveit/numbers/number_sets/real_numbers/_theory_nbs_/proofs/even_int_within_real/thm_proof.ipynb
new file mode 100644
index 000000000000..00d3cbffbc97
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/real_numbers/_theory_nbs_/proofs/even_int_within_real/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">real_numbers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#even_int_within_real\">even_int_within_real</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving even_int_within_real"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/real_numbers/_theory_nbs_/theorems.ipynb b/packages/proveit/numbers/number_sets/real_numbers/_theory_nbs_/theorems.ipynb
index 2d60c602bdc9..419b38f29099 100644
--- a/packages/proveit/numbers/number_sets/real_numbers/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/numbers/number_sets/real_numbers/_theory_nbs_/theorems.ipynb
@@ -25,7 +25,7 @@
     "                             Less, LessEq, Mult, Neg, number_ordering, sqrt)\n",
     "from proveit.numbers import (\n",
     "    zero, one, two, e, pi, ZeroSet, Complex, \n",
-    "    Integer, Natural, NaturalPos, IntegerNeg, IntegerNonPos, IntegerNonZero,\n",
+    "    Integer, Natural, NaturalPos, IntegerEven, IntegerNeg, IntegerNonPos, IntegerNonZero,\n",
     "    Rational, RationalNonZero, RationalPos, RationalNeg, RationalNonNeg, RationalNonPos, \n",
     "    Real, RealNonNeg, RealPos, RealNeg, RealNonPos, RealNonZero)\n"
    ]
@@ -174,6 +174,15 @@
     "nonpos_int_within_real_nonpos = ProperSubset(IntegerNonPos, RealNonPos)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "even_int_within_real = ProperSubset(IntegerEven, Real)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From 1a6f0def96204fabaf644550446eedce5afb3bff Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 4 Jun 2025 11:25:10 -0500
Subject: [PATCH 080/159] Add derive_element_in_rational/real methods to
 IntegerEvenMembership class

Add the derive_element_in_rational() and derive_element_in_real() methods to IntegerEvenMembership class. These are then also utilized in the IntegerEvenMembership class side_effects() method.
---
 .../integers/integer_membership.py            | 21 +++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/packages/proveit/numbers/number_sets/integers/integer_membership.py b/packages/proveit/numbers/number_sets/integers/integer_membership.py
index bf9d6482f1c7..9872d4eb1d83 100644
--- a/packages/proveit/numbers/number_sets/integers/integer_membership.py
+++ b/packages/proveit/numbers/number_sets/integers/integer_membership.py
@@ -302,11 +302,14 @@ def side_effects(self, judgment):
         Yield side-effects when proving 'n in IntegerEven' for 
         # a given n:
         (1) An even integer n is an integer;
-        (2) An even integer n can be expressed as 2z for some
+        (2) An even integer n is a rational number;
+        (3) An even integer is a real number;
+        (4) An even integer n can be expressed as 2z for some
             integer z.
         '''
         yield self.derive_element_in_integer
-        # yield self.derive_element_in_rational_nonzero
+        yield self.derive_element_in_rational
+        yield self.derive_element_in_real
         yield self.derive_element_as_double_int
 
     @relation_prover
@@ -334,6 +337,20 @@ def derive_element_in_integer(self, **defaults_config):
     #     return nonzero_int_within_rational_nonzero.derive_superset_membership(
     #         self.element, auto_simplify=False)
 
+    @prover
+    def derive_element_in_rational(self, **defaults_config):
+        from proveit.numbers.number_sets.rational_numbers import (
+                even_int_within_rational)
+        return even_int_within_rational.derive_superset_membership(
+                self.element, auto_simplify=False)
+
+    @prover
+    def derive_element_in_real(self, **defaults_config):
+        from proveit.numbers.number_sets.real_numbers import (
+                even_int_within_real)
+        return even_int_within_real.derive_superset_membership(
+                self.element, auto_simplify=False)
+
     @prover
     def derive_element_as_double_int(self, **defaults_config):
         from . import even_int_is_double_int

From 1bacc44ec7e8f72d15e9f72ef8cc2c418b0af916 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 4 Jun 2025 12:26:02 -0500
Subject: [PATCH 081/159] Add double_int_is_even thm to number_sets/integers
 pkg

Add the double_int_is_even theorem to the numbers/number_sets/integers package, which then helps with the IntegerEvenMembership.conclude() method (separate later commit).
---
 .../proofs/double_int_is_even/thm_proof.ipynb | 47 +++++++++++++++++++
 .../integers/_theory_nbs_/theorems.ipynb      | 13 +++++
 2 files changed, 60 insertions(+)
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/double_int_is_even/thm_proof.ipynb

diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/double_int_is_even/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/double_int_is_even/thm_proof.ipynb
new file mode 100644
index 000000000000..04d5fcf83f47
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/double_int_is_even/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#double_int_is_even\">double_int_is_even</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving double_int_is_even"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
index f897dccaeec2..9d41912b032f 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
@@ -472,6 +472,19 @@
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "double_int_is_even = Forall(\n",
+    "        a,\n",
+    "        InSet(a, IntegerEven),\n",
+    "        condition = Exists(z, Equals(a, Mult(two, z)), domain = Integer)\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},

From cbf0388fa3c5606b8748bac2c4031cb3a2447f7f Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 4 Jun 2025 12:30:01 -0500
Subject: [PATCH 082/159] Add IntegerEvenMembership.conclude() method

Add IntegerEvenMembership.conclude() and IntegerEvenMembership.conclude_as_last_resort() methods, which then rely on the previously committed double_int_is_even theorem. Commit also includes some clean-up, deleting obsolete text and code.
---
 .../integers/integer_membership.py            | 62 ++++++++-----------
 1 file changed, 27 insertions(+), 35 deletions(-)

diff --git a/packages/proveit/numbers/number_sets/integers/integer_membership.py b/packages/proveit/numbers/number_sets/integers/integer_membership.py
index 9872d4eb1d83..c013ff39523e 100644
--- a/packages/proveit/numbers/number_sets/integers/integer_membership.py
+++ b/packages/proveit/numbers/number_sets/integers/integer_membership.py
@@ -1,8 +1,8 @@
 from proveit import prover, relation_prover
-from proveit import a, x
-from proveit.logic import NotEquals, InSet
-from proveit.numbers import Less, LessEq
-from proveit.numbers import (zero, Integer, IntegerEven, IntegerNeg,
+from proveit import a, x, z
+from proveit.logic import Equals, Exists, InSet, NotEquals
+from proveit.numbers import Less, LessEq, Mult
+from proveit.numbers import (zero, two, Integer, IntegerEven, IntegerNeg,
                              IntegerNonPos, IntegerNonZero)
 from proveit.numbers.number_sets.number_set import NumberMembership
 
@@ -278,24 +278,29 @@ def __init__(self, element):
     def _readily_provable(self):
         return NumberMembership._readily_provable(self)
 
-    # @prover
-    # def conclude(self, **defaults_config):
-    #     # Use proven, not readily provable here:
-    #     if (InSet(self.element, Integer).proven() and
-    #             NotEquals(self.element, zero).proven()):
-    #         return self.conclude_as_last_resort()
-    #     return NumberMembership.conclude(self)
-
-    # @prover
-    # def conclude_as_last_resort(self, **defaults_config):
-    #     '''
-    #     Conclude element in IntegerNonZero by proving it is integer
-    #     and non-zero.  This is called via NumberMembership.conclude
-    #     if the 'deduce_in_number_set' method of the element raises
-    #     a NotImplementedError.
-    #     '''
-    #     from . import nonzero_int_is_int_nonzero
-    #     return nonzero_int_is_int_nonzero.instantiate({a:self.element})
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Conclude element in IntegerEven using the fact that the
+        element can be expressed as 2z for some z in Integer.
+        '''
+        # Use proven, not readily provable here:
+        if Exists(z, Equals(self.element, Mult(two, z)), domain=Integer).proven():
+            return self.conclude_as_last_resort()
+        return NumberMembership.conclude(self)
+
+    @prover
+    def conclude_as_last_resort(self, **defaults_config):
+        '''
+        Conclude element in IntegerEven using the fact that the
+        element can be expressed as 2z for some Integer z.
+        This is called via NumberMembership.conclude
+        if the 'deduce_in_number_set' method of the element raises
+        a NotImplementedError.
+        '''
+        from . import double_int_is_even
+        _a_sub = self.element
+        return double_int_is_even.instantiate({a:_a_sub})
 
     def side_effects(self, judgment):
         '''
@@ -318,25 +323,12 @@ def deduce_in_bool(self, **defaults_config):
         return even_int_membership_is_bool.instantiate(
             {x: self.element}, auto_simplify=False)
 
-    # @prover
-    # def derive_element_not_zero(self, **defaults_config):
-    #     from . import nonzero_if_in_nonzero_int
-    #     return nonzero_if_in_nonzero_int.instantiate(
-    #         {a: self.element}, auto_simplify=False)
-
     @prover
     def derive_element_in_integer(self, **defaults_config):
         from . import even_int_within_int
         return even_int_within_int.derive_superset_membership(
             self.element, auto_simplify=False)
 
-    # @prover
-    # def derive_element_in_rational_nonzero(self, **defaults_config):
-    #     from proveit.numbers.number_sets.rational_numbers import (
-    #             nonzero_int_within_rational_nonzero)
-    #     return nonzero_int_within_rational_nonzero.derive_superset_membership(
-    #         self.element, auto_simplify=False)
-
     @prover
     def derive_element_in_rational(self, **defaults_config):
         from proveit.numbers.number_sets.rational_numbers import (

From 2dd396cefffe27957141cc7c79bf4474a8f90199 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 4 Jun 2025 12:31:51 -0500
Subject: [PATCH 083/159] Update number_sets/integers demonstrations nb

Update number_sets/integers demonstrations.ipynb for further testing and demonstration of IntegerEvenMembership methods (mainly the conclude() method).
---
 .../_theory_nbs_/demonstrations.ipynb         | 175 +++++++++++++++++-
 1 file changed, 174 insertions(+), 1 deletion(-)

diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
index ce471113de5b..977092dfd808 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
@@ -20,7 +20,7 @@
     "from proveit.numbers import Neg, Less, LessEq, greater, greater_eq, number_ordering, Mult\n",
     "from proveit.numbers import (zero, one, two, three, four, five, six, seven,\n",
     "                             eight, nine, Integer, IntegerEven, IntegerNonZero, IntegerNeg, IntegerNonPos,\n",
-    "                             Interval, Natural, NaturalPos)\n",
+    "                             Interval, Natural, NaturalPos, Rational, Real)\n",
     "%begin demonstrations"
    ]
   },
@@ -803,6 +803,24 @@
     "InSet(x, Integer).prove(assumptions=[InSet(x, IntegerEven)])"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(x, Rational).prove(assumptions=[InSet(x, IntegerEven)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(x, Real).prove(assumptions=[InSet(x, IntegerEven)])"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -812,6 +830,161 @@
     "Exists(z, Equals(x, Mult(two, z)), domain = Integer).prove(assumptions=[InSet(x, IntegerEven)])"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(x, IntegerEven).prove(assumptions = [Exists(z, Equals(x, Mult(two, z)), domain = Integer)])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "If we know that $2$ can be expressed as $2\\cdot 1$:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Equals(Mult(two, one), two).prove()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "then we can prove that there exists an integer z such that $2 = 2z$:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Exists(z, Equals(two, Mult(two, z)), domain = Integer).conclude_via_example(one)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "And once that existential is established, we can prove that $2$ is in the even integers:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(two, IntegerEven).prove()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A similar example, now wanting to show that $4$ is an even integer:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from proveit.numbers import four\n",
+    "Equals(four, Mult(two, two)).prove()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Exists(z, Equals(four, Mult(two, z)), domain = Integer).conclude_via_example(two)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(four, IntegerEven).prove()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "More generally? YES! Well, sort of …\n",
+    "\n",
+    "Let's assume that $k = 2z$ for some integer $z$, without explicitly specifying the value of $z$:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from proveit import k\n",
+    "assumption_about_k = Equals(k, Mult(two, z))\n",
+    "assumption_about_z = InSet(z, Integer)\n",
+    "display(assumption_about_k)\n",
+    "display(assumption_about_z)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Then we can derive the existential claim:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Exists(z, Equals(k, Mult(two, z)), domain = Integer).conclude_via_example(z, assumptions = [assumption_about_k, assumption_about_z])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "After which, we can prove the set membership:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(k, IntegerEven).prove(assumptions = [assumption_about_k, assumption_about_z])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "assert False"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From 54f3781826b53a8de9e59f87c9140ebd002c58cb Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 4 Jun 2025 15:50:33 -0500
Subject: [PATCH 084/159] Establish IntegerOddSet number set class

Establish the IntegerOddSet number set class to represent the odd integers. Also assumes the establishment of the IntegerOddMembership class, in a separate (later) commit.
---
 .../numbers/number_sets/integers/integer.py       | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/packages/proveit/numbers/number_sets/integers/integer.py b/packages/proveit/numbers/number_sets/integers/integer.py
index 7da87db1fb2c..cd18ecd261da 100644
--- a/packages/proveit/numbers/number_sets/integers/integer.py
+++ b/packages/proveit/numbers/number_sets/integers/integer.py
@@ -288,6 +288,21 @@ def membership_object(self, element):
         from .integer_membership import IntegerEvenMembership    
         return IntegerEvenMembership(element)
 
+class IntegerOddSet(NumberSet):
+    '''
+    Class to represent the odd integers {..., -3, -1, 1, 3, ...}
+    and provide related methods. The odd integer set appears as
+    'IntegerOdd' in string output and as mathbb 'O' in LaTeX output.
+    '''
+    def __init__(self, *, styles=None):
+        NumberSet.__init__(self, 'IntegerOdd', r'\mathbb{O}',
+                           theory=__file__, styles=styles,
+                           fence_when_forced=True)
+
+    def membership_object(self, element):
+        from .integer_membership import IntegerOddMembership    
+        return IntegerOddMembership(element)
+
 
 if proveit.defaults.running_theory_notebook is None:
     # Import some fundamental theorems without quantifiers when not 

From 5a109b6509ba27338df45ac3558ecb238814214e Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 4 Jun 2025 15:52:05 -0500
Subject: [PATCH 085/159] Establish axiomatic def of IntegerOdd number set

Establish the axiomatic def of IntegerOdd number set (i.e. the odd integers) as {2z+1}_{z in Integer}.
---
 .../number_sets/integers/_theory_nbs_/axioms.ipynb    | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/axioms.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/axioms.ipynb
index 9cf588a7227f..9d2de612f28c 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/axioms.ipynb
@@ -18,7 +18,7 @@
     "# Prepare this notebook for defining the axioms of a theory:\n",
     "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
     "from proveit.logic import And, Equals, Forall, Iff, Implies, InSet, SetEquiv, SetOfAll, SubsetProper, Union\n",
-    "from proveit.numbers import Complex, Integer, IntegerEven, Interval, Natural, NaturalPos, Neg\n",
+    "from proveit.numbers import Complex, Integer, IntegerEven, IntegerOdd, Interval, Natural, NaturalPos, Neg\n",
     "from proveit.numbers import Add, greater, Less, LessEq, Mult, number_ordering\n",
     "from proveit.numbers import zero, one, two, num\n",
     "from proveit import a, b, n, m, x, y, z, S\n",
@@ -96,6 +96,15 @@
     "even_integers_def = Equals(IntegerEven, SetOfAll(z, Mult(two, z), domain = Integer))"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "odd_integers_def = Equals(IntegerOdd, SetOfAll(z, Add(Mult(two, z), one), domain = Integer))"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},

From bb0e81a914f43bfc1908f9456b07c0fe74fb8d6c Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 4 Jun 2025 15:53:18 -0500
Subject: [PATCH 086/159] Establish IntegerOdd notation for IntegerOddSet()

Establish IntegerOdd notation for IntegerOddSet().
---
 .../number_sets/integers/_theory_nbs_/common.ipynb    | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/common.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/common.ipynb
index c655860c9966..4c5ad859eb51 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/common.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/common.ipynb
@@ -19,7 +19,7 @@
     "%common_expressions_notebook # Keep this at the top following 'import proveit'.\n",
     "from proveit import Literal\n",
     "from proveit.numbers.number_sets.integers.integer import (\n",
-    "        IntegerSet, IntegerEvenSet, IntegerNegSet, IntegerNonZeroSet, IntegerNonPosSet)\n",
+    "        IntegerSet, IntegerEvenSet, IntegerNegSet, IntegerNonZeroSet, IntegerNonPosSet, IntegerOddSet)\n",
     "%begin common"
    ]
   },
@@ -68,6 +68,15 @@
     "IntegerNonPos = IntegerNonPosSet()"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "IntegerOdd = IntegerOddSet()"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From 993f6e18cbf5cc5b99f8aa6e227d8711edca33c7 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 4 Jun 2025 15:58:15 -0500
Subject: [PATCH 087/159] Establish basic theorems for IntegerOdd number set

Establish some basic theorems for IntegerOdd number set (i.e. the odd integers):
odd_int_membership_is_bool (membership in odd integers is a boolean),
odd_int_within_int (an odd integer is an integer),
odd_int_is_double_int_plus_one (odd int looks like 2z+1 for some integer z),
double_int_plus_one_is_odd (if z is an int then 2z+1 is an odd integer).
These are then actively used in the methods for the IntegerOddMembership class.
---
 .../thm_proof.ipynb                           | 47 +++++++++++++++++++
 .../thm_proof.ipynb                           | 47 +++++++++++++++++++
 .../thm_proof.ipynb                           | 47 +++++++++++++++++++
 .../proofs/odd_int_within_int/thm_proof.ipynb | 47 +++++++++++++++++++
 .../integers/_theory_nbs_/theorems.ipynb      | 45 +++++++++++++++++-
 5 files changed, 232 insertions(+), 1 deletion(-)
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/double_int_plus_one_is_odd/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/odd_int_is_double_int_plus_one/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/odd_int_membership_is_bool/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/odd_int_within_int/thm_proof.ipynb

diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/double_int_plus_one_is_odd/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/double_int_plus_one_is_odd/thm_proof.ipynb
new file mode 100644
index 000000000000..be9e27ac560e
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/double_int_plus_one_is_odd/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#double_int_plus_one_is_odd\">double_int_plus_one_is_odd</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving double_int_plus_one_is_odd"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/odd_int_is_double_int_plus_one/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/odd_int_is_double_int_plus_one/thm_proof.ipynb
new file mode 100644
index 000000000000..f0b6cbc6ef4b
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/odd_int_is_double_int_plus_one/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#odd_int_is_double_int_plus_one\">odd_int_is_double_int_plus_one</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving odd_int_is_double_int_plus_one"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/odd_int_membership_is_bool/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/odd_int_membership_is_bool/thm_proof.ipynb
new file mode 100644
index 000000000000..40e9291592b2
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/odd_int_membership_is_bool/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#odd_int_membership_is_bool\">odd_int_membership_is_bool</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving odd_int_membership_is_bool"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/odd_int_within_int/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/odd_int_within_int/thm_proof.ipynb
new file mode 100644
index 000000000000..a2c95c83fbbd
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/odd_int_within_int/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#odd_int_within_int\">odd_int_within_int</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving odd_int_within_int"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
index 9d41912b032f..8cd631ae08c1 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
@@ -26,7 +26,7 @@
     "from proveit.numbers import zero, one, two, num, frac, Neg\n",
     "from proveit.numbers import (ZeroSet, Natural, NaturalPos, \n",
     "                             Integer, IntegerEven, IntegerNeg, IntegerNonZero, IntegerNonPos,\n",
-    "                             Interval, Complex)\n",
+    "                             IntegerOdd, Interval, Complex)\n",
     "from proveit.numbers import Add, subtract, greater, greater_eq, Less, LessEq, Mult, number_ordering\n",
     "from proveit.numbers import Pzero, Pone, Pm, P_mAddOne, Pn"
    ]
@@ -389,6 +389,15 @@
     "even_int_within_int = ProperSubset(IntegerEven, Integer)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "odd_int_within_int = ProperSubset(IntegerOdd, Integer)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -485,6 +494,31 @@
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "odd_int_is_double_int_plus_one = Forall(\n",
+    "        a, Exists(z, Equals(a, Add(Mult(two, z), one)), domain = Integer),\n",
+    "        domain = IntegerOdd\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "double_int_plus_one_is_odd = Forall(\n",
+    "        a,\n",
+    "        InSet(a, IntegerOdd),\n",
+    "        condition = Exists(z, Equals(a, Add(Mult(two, z), one)), domain = Integer)\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -538,6 +572,15 @@
     "even_int_membership_is_bool = Forall(x, in_bool(InSet(x, IntegerEven)))"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "odd_int_membership_is_bool = Forall(x, in_bool(InSet(x, IntegerOdd)))"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From 18d6e8c8a42baeaf9ed4e73ca2e77d7e28f52ca1 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 4 Jun 2025 15:59:28 -0500
Subject: [PATCH 088/159] Establish the pkg-level imports for IntegerOdd number
 set

Establish the package-level imports for IntegerOdd number set.
---
 packages/proveit/numbers/__init__.py             | 4 ++--
 packages/proveit/numbers/number_sets/__init__.py | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/packages/proveit/numbers/__init__.py b/packages/proveit/numbers/__init__.py
index 944600976136..8b67b59c7467 100644
--- a/packages/proveit/numbers/__init__.py
+++ b/packages/proveit/numbers/__init__.py
@@ -3,8 +3,8 @@
 from .number_sets import (
     ZeroSet, Natural, NaturalPos,
     Integer, IntegerEven, IntegerNonZero, IntegerNeg, IntegerNonPos,
-    Rational, RationalNonZero, RationalPos, RationalNeg, RationalNonNeg,
-    RationalNonPos,
+    IntegerOdd, Rational, RationalNonZero, RationalPos, RationalNeg,
+    RationalNonNeg, RationalNonPos,
     Real, RealNonZero, RealNeg, RealPos, RealNonNeg, RealNonPos,
     Complex, ComplexNonZero, Conjugate,
     complex_polar_coordinates, 
diff --git a/packages/proveit/numbers/number_sets/__init__.py b/packages/proveit/numbers/number_sets/__init__.py
index 57d50c6bcf0e..ab18fc7b3c39 100644
--- a/packages/proveit/numbers/number_sets/__init__.py
+++ b/packages/proveit/numbers/number_sets/__init__.py
@@ -1,6 +1,6 @@
 from .integers import (
         Integer, IntegerEven, IntegerNeg, IntegerNonZero,
-        IntegerNonPos, Interval, infinity)
+        IntegerNonPos, IntegerOdd, Interval, infinity)
 from .natural_numbers import ZeroSet, Natural, NaturalPos
 from .rational_numbers import (Rational, RationalNonZero,
                                RationalPos, RationalNeg,

From d6f8291fee051d4a05a284b7d84bde4f1bf8733b Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 4 Jun 2025 16:01:09 -0500
Subject: [PATCH 089/159] Establish odd_within_rational theorem for IntegerOdd
 number set

Establish the odd_within_rational theorem (odd numbers are rational numbers) for IntegerOdd number set.
---
 .../odd_int_within_rational/thm_proof.ipynb   | 47 +++++++++++++++++++
 .../_theory_nbs_/theorems.ipynb               | 11 ++++-
 2 files changed, 57 insertions(+), 1 deletion(-)
 create mode 100644 packages/proveit/numbers/number_sets/rational_numbers/_theory_nbs_/proofs/odd_int_within_rational/thm_proof.ipynb

diff --git a/packages/proveit/numbers/number_sets/rational_numbers/_theory_nbs_/proofs/odd_int_within_rational/thm_proof.ipynb b/packages/proveit/numbers/number_sets/rational_numbers/_theory_nbs_/proofs/odd_int_within_rational/thm_proof.ipynb
new file mode 100644
index 000000000000..4266dabafde3
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/rational_numbers/_theory_nbs_/proofs/odd_int_within_rational/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">rational_numbers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#odd_int_within_rational\">odd_int_within_rational</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving odd_int_within_rational"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/rational_numbers/_theory_nbs_/theorems.ipynb b/packages/proveit/numbers/number_sets/rational_numbers/_theory_nbs_/theorems.ipynb
index 507f1ff3fe7a..9eb2bcff3e62 100644
--- a/packages/proveit/numbers/number_sets/rational_numbers/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/numbers/number_sets/rational_numbers/_theory_nbs_/theorems.ipynb
@@ -22,7 +22,7 @@
     "from proveit.numbers import frac, GCD, Less, LessEq, greater, greater_eq\n",
     "from proveit.numbers import one, zero\n",
     "from proveit.numbers import (ZeroSet, Natural, NaturalPos, Integer, IntegerNonZero, IntegerNeg, IntegerNonPos,\n",
-    "                             IntegerEven, Rational, RationalPos, RationalNeg,\n",
+    "                             IntegerEven, IntegerOdd, Rational, RationalPos, RationalNeg,\n",
     "                             RationalNonNeg, RationalNonPos, RationalNonZero, NaturalPos)"
    ]
   },
@@ -170,6 +170,15 @@
     "even_int_within_rational = ProperSubset(IntegerEven, Rational)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "odd_int_within_rational = ProperSubset(IntegerOdd, Rational)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From 52db69c665b295e1ea97172d19cffebcfbbb6cfd Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 4 Jun 2025 16:02:33 -0500
Subject: [PATCH 090/159] Establish odd_int_within_real theorem for the
 IntegerOdd number set

Establish the odd_int_within_real theorem (odd integers are real numbers) for the IntegerOdd number set.
---
 .../odd_int_within_real/thm_proof.ipynb       | 47 +++++++++++++++++++
 .../real_numbers/_theory_nbs_/theorems.ipynb  | 11 ++++-
 2 files changed, 57 insertions(+), 1 deletion(-)
 create mode 100644 packages/proveit/numbers/number_sets/real_numbers/_theory_nbs_/proofs/odd_int_within_real/thm_proof.ipynb

diff --git a/packages/proveit/numbers/number_sets/real_numbers/_theory_nbs_/proofs/odd_int_within_real/thm_proof.ipynb b/packages/proveit/numbers/number_sets/real_numbers/_theory_nbs_/proofs/odd_int_within_real/thm_proof.ipynb
new file mode 100644
index 000000000000..40da1542a0dd
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/real_numbers/_theory_nbs_/proofs/odd_int_within_real/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">real_numbers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#odd_int_within_real\">odd_int_within_real</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving odd_int_within_real"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/real_numbers/_theory_nbs_/theorems.ipynb b/packages/proveit/numbers/number_sets/real_numbers/_theory_nbs_/theorems.ipynb
index 419b38f29099..87f90a4ffcfc 100644
--- a/packages/proveit/numbers/number_sets/real_numbers/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/numbers/number_sets/real_numbers/_theory_nbs_/theorems.ipynb
@@ -26,7 +26,7 @@
     "from proveit.numbers import (\n",
     "    zero, one, two, e, pi, ZeroSet, Complex, \n",
     "    Integer, Natural, NaturalPos, IntegerEven, IntegerNeg, IntegerNonPos, IntegerNonZero,\n",
-    "    Rational, RationalNonZero, RationalPos, RationalNeg, RationalNonNeg, RationalNonPos, \n",
+    "    IntegerOdd, Rational, RationalNonZero, RationalPos, RationalNeg, RationalNonNeg, RationalNonPos, \n",
     "    Real, RealNonNeg, RealPos, RealNeg, RealNonPos, RealNonZero)\n"
    ]
   },
@@ -183,6 +183,15 @@
     "even_int_within_real = ProperSubset(IntegerEven, Real)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "odd_int_within_real = ProperSubset(IntegerOdd, Real)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From ff9f14602d66f5cdfa052b5ed57021c4fb171e11 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 4 Jun 2025 16:04:06 -0500
Subject: [PATCH 091/159] Establish IntegerOddMembership class and methods

Establish the IntegerOddMembership class (i.e. membership in the odd integers) and related methods. Depends on several previous commits of related theorems and package imports.
---
 .../integers/integer_membership.py            | 93 ++++++++++++++++++-
 1 file changed, 89 insertions(+), 4 deletions(-)

diff --git a/packages/proveit/numbers/number_sets/integers/integer_membership.py b/packages/proveit/numbers/number_sets/integers/integer_membership.py
index c013ff39523e..e7d570f69cc7 100644
--- a/packages/proveit/numbers/number_sets/integers/integer_membership.py
+++ b/packages/proveit/numbers/number_sets/integers/integer_membership.py
@@ -1,9 +1,10 @@
 from proveit import prover, relation_prover
 from proveit import a, x, z
 from proveit.logic import Equals, Exists, InSet, NotEquals
-from proveit.numbers import Less, LessEq, Mult
-from proveit.numbers import (zero, two, Integer, IntegerEven, IntegerNeg,
-                             IntegerNonPos, IntegerNonZero)
+from proveit.numbers import Add, Less, LessEq, Mult
+from proveit.numbers import (
+        zero, one, two, Integer, IntegerEven, IntegerNeg,
+        IntegerNonPos, IntegerNonZero, IntegerOdd)
 from proveit.numbers.number_sets.number_set import NumberMembership
 
 
@@ -294,7 +295,7 @@ def conclude_as_last_resort(self, **defaults_config):
         '''
         Conclude element in IntegerEven using the fact that the
         element can be expressed as 2z for some Integer z.
-        This is called via NumberMembership.conclude
+        This method is called via NumberMembership.conclude()
         if the 'deduce_in_number_set' method of the element raises
         a NotImplementedError.
         '''
@@ -348,3 +349,87 @@ def derive_element_as_double_int(self, **defaults_config):
         from . import even_int_is_double_int
         _a_sub = self.element
         return even_int_is_double_int.instantiate({a:_a_sub})
+
+class IntegerOddMembership(NumberMembership):
+    '''
+    Defines methods that apply to membership in IntegerOdd (the
+    set of odd integers, O = {..., -3, -1, 1, 3, ...}).
+    '''
+
+    def __init__(self, element):
+        NumberMembership.__init__(self, element, IntegerOdd)
+
+    def _readily_provable(self):
+        return NumberMembership._readily_provable(self)
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Conclude element in IntegerOdd using the fact that the
+        element can be expressed as (2z + 1) for some z in Integer.
+        '''
+        # Use proven, not readily provable here:
+        if Exists(z, Equals(self.element, Add(Mult(two, z), one)),
+                  domain=Integer).proven():
+            return self.conclude_as_last_resort()
+        return NumberMembership.conclude(self)
+
+    @prover
+    def conclude_as_last_resort(self, **defaults_config):
+        '''
+        Conclude element in IntegerEven using the fact that the
+        element can be expressed as (2z + 1) for some Integer z.
+        This method is called via NumberMembership.conclude()
+        if the 'deduce_in_number_set' method of the element raises
+        a NotImplementedError.
+        '''
+        from . import double_int_plus_one_is_odd
+        _a_sub = self.element
+        return double_int_plus_one_is_odd.instantiate({a:_a_sub})
+
+    def side_effects(self, judgment):
+        '''
+        Yield side-effects when proving 'n in IntegerEven' for 
+        # a given n:
+        (1) An odd integer n is an integer;
+        (2) An odd integer n is a rational number;
+        (3) An odd integer n is a real number;
+        (4) An odd integer n can be expressed as 2z+1 for some
+            integer z.
+        '''
+        yield self.derive_element_in_integer
+        yield self.derive_element_in_rational
+        yield self.derive_element_in_real
+        yield self.derive_element_as_double_int_plus_one
+
+    @relation_prover
+    def deduce_in_bool(self, **defaults_config):
+        from . import odd_int_membership_is_bool
+        return odd_int_membership_is_bool.instantiate(
+            {x: self.element}, auto_simplify=False)
+
+    @prover
+    def derive_element_in_integer(self, **defaults_config):
+        from . import odd_int_within_int
+        return odd_int_within_int.derive_superset_membership(
+            self.element, auto_simplify=False)
+
+    @prover
+    def derive_element_in_rational(self, **defaults_config):
+        from proveit.numbers.number_sets.rational_numbers import (
+                odd_int_within_rational)
+        return odd_int_within_rational.derive_superset_membership(
+                self.element, auto_simplify=False)
+
+    @prover
+    def derive_element_in_real(self, **defaults_config):
+        from proveit.numbers.number_sets.real_numbers import (
+                odd_int_within_real)
+        return odd_int_within_real.derive_superset_membership(
+                self.element, auto_simplify=False)
+
+    @prover
+    def derive_element_as_double_int_plus_one(self, **defaults_config):
+        from . import odd_int_is_double_int_plus_one
+        _a_sub = self.element
+        return odd_int_is_double_int_plus_one.instantiate({a:_a_sub})

From 8813ffb36cf8610e5c5e34281bcda47e3093a050 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 4 Jun 2025 16:05:18 -0500
Subject: [PATCH 092/159] Update number_sets/integers/demonstrations.ipynb

Update number_sets/integers/demonstrations.ipynb to demonstrate and test the IntegerOdd number set and the IntegerOddMembership class and related methods.
---
 .../_theory_nbs_/demonstrations.ipynb         | 103 +++++++++++++++++-
 1 file changed, 100 insertions(+), 3 deletions(-)

diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
index 977092dfd808..2e428f820c67 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
@@ -15,12 +15,12 @@
    "outputs": [],
    "source": [
     "import proveit\n",
-    "from proveit import a, b, c, d, n, x, z, ProofFailure\n",
+    "from proveit import a, b, c, d, n, x, y, z, ProofFailure\n",
     "from proveit.logic import Boolean, Equals, Exists, NotEquals, InSet, NotInSet, Or\n",
-    "from proveit.numbers import Neg, Less, LessEq, greater, greater_eq, number_ordering, Mult\n",
+    "from proveit.numbers import Add, Neg, Less, LessEq, greater, greater_eq, number_ordering, Mult\n",
     "from proveit.numbers import (zero, one, two, three, four, five, six, seven,\n",
     "                             eight, nine, Integer, IntegerEven, IntegerNonZero, IntegerNeg, IntegerNonPos,\n",
-    "                             Interval, Natural, NaturalPos, Rational, Real)\n",
+    "                             IntegerOdd, Interval, Natural, NaturalPos, Rational, Real)\n",
     "%begin demonstrations"
    ]
   },
@@ -976,6 +976,103 @@
     "InSet(k, IntegerEven).prove(assumptions = [assumption_about_k, assumption_about_z])"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Odd Integers (`IntegerOdd`), Odd Integer Membership (`IntegerOddMembership`), and subsets of odd integers"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(y, IntegerOdd)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(InSet(y, IntegerOdd), Boolean).prove()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(y, Integer).prove(assumptions=[InSet(y, IntegerOdd)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(y, Rational).prove(assumptions=[InSet(y, IntegerOdd)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(y, Real).prove(assumptions=[InSet(y, IntegerOdd)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from proveit import k\n",
+    "assumption_about_k = Equals(k, Add(Mult(two, z), one))\n",
+    "assumption_about_z = InSet(z, Integer)\n",
+    "display(assumption_about_k)\n",
+    "display(assumption_about_z)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Then we can derive the existential claim:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Exists(z, Equals(k, Add(Mult(two, z), one)), domain = Integer).conclude_via_example(z, assumptions = [assumption_about_k, assumption_about_z])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "After which, we can prove the set membership:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(k, IntegerOdd).prove(assumptions = [assumption_about_k, assumption_about_z])"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From 88f50ffee5fc6ceec8b059b646ec7627caa465c2 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 4 Jun 2025 16:40:37 -0500
Subject: [PATCH 093/159] Update numbers/number_set/integers demos nb

Update numbers/number_set/integers demos nb to remove a temporary `assert False` cell and allow nb to run to completion.
---
 .../integers/_theory_nbs_/demonstrations.ipynb           | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
index 2e428f820c67..9a704e799523 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
@@ -1073,15 +1073,6 @@
     "InSet(k, IntegerOdd).prove(assumptions = [assumption_about_k, assumption_about_z])"
    ]
   },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "assert False"
-   ]
-  },
   {
    "cell_type": "code",
    "execution_count": null,

From a056f3fe182cef5f9c3cc480d1414a5fd23bbf47 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 4 Jun 2025 17:51:29 -0500
Subject: [PATCH 094/159] Modify def of IntegerOdd to be (Z - E)

Modify the axiomatic definition of IntegerOdd (the set of odd integers) to be (Z - E) (i.e., the set of integers without the set of even integers). Suggested by @wwitzel and seconded by Bob.
---
 .../numbers/number_sets/integers/_theory_nbs_/axioms.ipynb    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/axioms.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/axioms.ipynb
index 9d2de612f28c..d9470e34406b 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/axioms.ipynb
@@ -17,7 +17,7 @@
     "import proveit\n",
     "# Prepare this notebook for defining the axioms of a theory:\n",
     "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
-    "from proveit.logic import And, Equals, Forall, Iff, Implies, InSet, SetEquiv, SetOfAll, SubsetProper, Union\n",
+    "from proveit.logic import And, Difference, Equals, Forall, Iff, Implies, InSet, SetEquiv, SetOfAll, SubsetProper, Union\n",
     "from proveit.numbers import Complex, Integer, IntegerEven, IntegerOdd, Interval, Natural, NaturalPos, Neg\n",
     "from proveit.numbers import Add, greater, Less, LessEq, Mult, number_ordering\n",
     "from proveit.numbers import zero, one, two, num\n",
@@ -102,7 +102,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "odd_integers_def = Equals(IntegerOdd, SetOfAll(z, Add(Mult(two, z), one), domain = Integer))"
+    "odd_integers_def = Equals(IntegerOdd, Difference(Integer, IntegerEven))"
    ]
   },
   {

From dd6bc998c4b169537c4f44d91c8d3dcb81cd4b38 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Fri, 6 Jun 2025 14:59:58 -0500
Subject: [PATCH 095/159] Add IntegerEven and IntegerOdd theorems to
 numbers/addition pkg
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Add several theorems to the numbers/addition package related to the IntegerEven (even integers) and IntegerOdd (odd integers) number sets. These are then utilized in the Add.deduce_in_number_set() method:
• add_int_even_closure (adding even integers gives another even integer)
• add_int_even_closure_bin (sum of two even integers is an even integer)
• add_int_even_from_even_odd (the sum of an even number of odd integers is an even integer)
• add_int_even_from_odd_bin (the sum of two odd integers is an even integer)
• add_int_odd_from_even_and_and_odd (sum of an even and an odd integer is an odd integer)
• add_int_odd_from_odd_odd (the sum of an odd number of odd integers is an odd integer)
---
 .../add_int_even_closure/thm_proof.ipynb      | 47 +++++++++++++
 .../add_int_even_closure_bin/thm_proof.ipynb  | 47 +++++++++++++
 .../thm_proof.ipynb                           | 47 +++++++++++++
 .../add_int_even_from_odd_bin/thm_proof.ipynb | 47 +++++++++++++
 .../thm_proof.ipynb                           | 47 +++++++++++++
 .../add_int_odd_from_odd_odd/thm_proof.ipynb  | 47 +++++++++++++
 .../addition/_theory_nbs_/theorems.ipynb      | 66 ++++++++++++++++++-
 7 files changed, 347 insertions(+), 1 deletion(-)
 create mode 100644 packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_even_closure/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_even_closure_bin/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_even_from_even_odd/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_even_from_odd_bin/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_odd_from_even_and_odd_bin/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_odd_from_odd_odd/thm_proof.ipynb

diff --git a/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_even_closure/thm_proof.ipynb b/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_even_closure/thm_proof.ipynb
new file mode 100644
index 000000000000..ade3c3a62f17
--- /dev/null
+++ b/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_even_closure/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">addition</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#add_int_even_closure\">add_int_even_closure</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving add_int_even_closure"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_even_closure_bin/thm_proof.ipynb b/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_even_closure_bin/thm_proof.ipynb
new file mode 100644
index 000000000000..6667c22293e4
--- /dev/null
+++ b/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_even_closure_bin/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">addition</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#add_int_even_closure_bin\">add_int_even_closure_bin</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving add_int_even_closure_bin"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_even_from_even_odd/thm_proof.ipynb b/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_even_from_even_odd/thm_proof.ipynb
new file mode 100644
index 000000000000..68f60b241c7f
--- /dev/null
+++ b/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_even_from_even_odd/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">addition</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#add_int_even_from_even_odd\">add_int_even_from_even_odd</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving add_int_even_from_even_odd"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_even_from_odd_bin/thm_proof.ipynb b/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_even_from_odd_bin/thm_proof.ipynb
new file mode 100644
index 000000000000..c797ce4185e1
--- /dev/null
+++ b/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_even_from_odd_bin/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">addition</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#add_int_even_from_odd_bin\">add_int_even_from_odd_bin</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving add_int_even_from_odd_bin"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_odd_from_even_and_odd_bin/thm_proof.ipynb b/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_odd_from_even_and_odd_bin/thm_proof.ipynb
new file mode 100644
index 000000000000..aa302d8c17f0
--- /dev/null
+++ b/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_odd_from_even_and_odd_bin/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">addition</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#add_int_odd_from_even_and_odd_bin\">add_int_odd_from_even_and_odd_bin</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving add_int_odd_from_even_and_odd_bin"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_odd_from_odd_odd/thm_proof.ipynb b/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_odd_from_odd_odd/thm_proof.ipynb
new file mode 100644
index 000000000000..982f25fbee7c
--- /dev/null
+++ b/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_odd_from_odd_odd/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">addition</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#add_int_odd_from_odd_odd\">add_int_odd_from_odd_odd</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving add_int_odd_from_odd_odd"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/addition/_theory_nbs_/theorems.ipynb b/packages/proveit/numbers/addition/_theory_nbs_/theorems.ipynb
index 9407d00b593d..8eff28928ef2 100644
--- a/packages/proveit/numbers/addition/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/numbers/addition/_theory_nbs_/theorems.ipynb
@@ -28,7 +28,7 @@
     "    Add, Neg, Mult, frac, Exp, \n",
     "    Less, LessEq, greater, greater_eq,\n",
     "    ZeroSet, Natural, NaturalPos,\n",
-    "    Integer, IntegerNonZero, IntegerNeg, IntegerNonPos,\n",
+    "    Integer, IntegerEven, IntegerNonZero, IntegerNeg, IntegerNonPos, IntegerOdd,\n",
     "    Rational, RationalNonZero, RationalPos, RationalNeg,\n",
     "    RationalNonNeg, RationalNonPos,\n",
     "    Real, RealNonZero, RealPos, RealNeg, RealNonNeg, RealNonPos,\n",
@@ -162,6 +162,24 @@
     "add_int_nonpos_closure = Forall(i, Forall(a_1_to_i, InSet(Add(a_1_to_i), IntegerNonPos), domain=IntegerNonPos), domain = Natural)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "add_int_even_closure_bin = Forall((a, b), InSet(Add(a, b), IntegerEven), domain = IntegerEven)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "add_int_even_closure = Forall(i, Forall(a_1_to_i, InSet(Add(a_1_to_i), IntegerEven), domain = IntegerEven), domain = NaturalPos)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -188,6 +206,52 @@
     "                             domain=Natural)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "add_int_even_from_odd_bin = Forall((a, b), InSet(Add(a, b), IntegerEven), domain = IntegerOdd)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "add_int_even_from_even_odd = (\n",
+    "    Forall(i,\n",
+    "           Forall(a_1_to_i, InSet(Add(a_1_to_i), IntegerEven), domain = IntegerOdd),\n",
+    "    condition=greater(i, zero),\n",
+    "    domain=IntegerEven)\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "add_int_odd_from_even_and_odd_bin = Forall((a, b), InSet(Add(a, b), IntegerOdd), domains = [IntegerEven, IntegerOdd])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "add_int_odd_from_odd_odd = (\n",
+    "    Forall(i,\n",
+    "           Forall(a_1_to_i, InSet(Add(a_1_to_i), IntegerOdd), domain = IntegerOdd),\n",
+    "    condition=greater(i, zero),\n",
+    "    domain=IntegerOdd)\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From c1ac10ec25d370b893f70c589a63bbab4bcdc58a Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Fri, 6 Jun 2025 15:02:36 -0500
Subject: [PATCH 096/159] Update Add.deduce_in_number_set() method to use
 related even/odd addition theorems

Update the Add.deduce_in_number_set() method to use related even/odd addition theorems in previous commit, for things like the sum of an even and an odd is an odd, and the sum of an odd number of odd integers is odd, etc.
---
 packages/proveit/numbers/addition/add.py | 48 +++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/packages/proveit/numbers/addition/add.py b/packages/proveit/numbers/addition/add.py
index 424a080ff231..54e75778e2bd 100644
--- a/packages/proveit/numbers/addition/add.py
+++ b/packages/proveit/numbers/addition/add.py
@@ -29,7 +29,8 @@
         sorting_operands, sorting_and_combining_like_operands,
         common_likeness_key)
 from proveit import TransRelUpdater
-from proveit.numbers import (ZeroSet, Integer, IntegerNeg, IntegerNonPos,
+from proveit.numbers import (ZeroSet, Integer, IntegerEven,
+                             IntegerNeg, IntegerNonPos, IntegerOdd,
                              Natural, NaturalPos, IntegerNonZero,
                              Rational, RationalPos, RationalNonZero,
                              RationalNeg, RationalNonNeg,
@@ -1195,6 +1196,20 @@ def deduce_in_number_set(self, number_set, **defaults_config):
                 _a = self.operands
                 _i = _a.num_elements()                
                 add_pkg.add_int_nonpos_closure.instantiate({i: _i, a: _a})
+            if number_set == IntegerEven:
+                if self.operands.is_double():
+                    return add_pkg.add_int_even_closure_bin.instantiate(
+                        {a: self.operands[0], b: self.operands[1]})
+                _a = self.operands
+                _i = _a.num_elements()
+                return add_pkg.add_int_even_closure.instantiate({i: _i, a: _a})
+            if number_set == IntegerOdd:
+                if (InSet(self.operands.num_elements(), IntegerOdd)
+                        .readily_provable()):
+                    _a =  self.operands
+                    _i = _a.num_elements()
+                    return (add_pkg.add_int_odd_from_odd_odd
+                            .instantiate({i: _i, a: _a}))
             if number_set == RationalPos:
                 if self.operands.is_double():
                     return add_pkg.add_rational_pos_closure_bin.instantiate(
@@ -1252,6 +1267,37 @@ def deduce_in_number_set(self, number_set, **defaults_config):
                 _i = _a.num_elements()
                 return add_pkg.add_real_nonpos_closure.instantiate({i:_i, a: _a})
 
+        # Handle special even/odd integer cases:
+        # (1) even + odd = odd
+        # (2) sum of even number of odds is even
+        # Note: the sum of odd number of odds is odd handled earlier.
+        if number_set == IntegerOdd:
+            if self.operands.is_double():
+                if (InSet(self.operands[0], IntegerEven).readily_provable()
+                    and InSet(self.operands[1], IntegerOdd).readily_provable()):
+                    _a = self.operands[0]
+                    _b = self.operands[1]
+                    return (add_pkg.add_int_odd_from_even_and_odd_bin
+                            .instantiate({a: _a, b: _b}))
+                if (InSet(self.operands[0], IntegerOdd).readily_provable()
+                    and InSet(self.operands[1], IntegerEven).readily_provable()):
+                    _a = self.operands[1]
+                    _b = self.operands[0]
+                    temp_inst = (
+                            add_pkg.add_int_odd_from_even_and_odd_bin
+                            .instantiate({a: _a, b: _b}))
+                    return temp_inst.inner_expr().element.commute()
+        if number_set == IntegerEven:
+            if (all(InSet(operand, IntegerOdd).proven() for
+                    operand in self.operands)
+                and InSet(self.operands.num_elements(), IntegerEven)
+                    .readily_provable()): 
+                _a = self.operands
+                _i = self.operands.num_elements()
+                return (add_pkg.add_int_even_from_even_odd
+                        .instantiate({i:_i, a:_a}))
+
+
         # Try special case where one term is positive and the
         # rest are non-negative.
         if number_set in {NaturalPos, RationalPos, RealPos}:

From 7254bbe9b0ce9c43111d25bcec74641352f1fab5 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Fri, 6 Jun 2025 15:04:05 -0500
Subject: [PATCH 097/159] Correct some typos in comments in
 integers/integer_membership.py

Correct some typos in comments in integers/integer_membership.py (changing some instances of IntegerEven to IntegerOdd).
---
 .../numbers/number_sets/integers/integer_membership.py        | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/proveit/numbers/number_sets/integers/integer_membership.py b/packages/proveit/numbers/number_sets/integers/integer_membership.py
index e7d570f69cc7..dda5ed905b71 100644
--- a/packages/proveit/numbers/number_sets/integers/integer_membership.py
+++ b/packages/proveit/numbers/number_sets/integers/integer_membership.py
@@ -377,7 +377,7 @@ def conclude(self, **defaults_config):
     @prover
     def conclude_as_last_resort(self, **defaults_config):
         '''
-        Conclude element in IntegerEven using the fact that the
+        Conclude element in IntegerOdd using the fact that the
         element can be expressed as (2z + 1) for some Integer z.
         This method is called via NumberMembership.conclude()
         if the 'deduce_in_number_set' method of the element raises
@@ -389,7 +389,7 @@ def conclude_as_last_resort(self, **defaults_config):
 
     def side_effects(self, judgment):
         '''
-        Yield side-effects when proving 'n in IntegerEven' for 
+        Yield side-effects when proving 'n in IntegerOdd' for 
         # a given n:
         (1) An odd integer n is an integer;
         (2) An odd integer n is a rational number;

From 2c0caab1bb184d72111a14c7c31f565dcb91d43e Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Fri, 6 Jun 2025 15:06:10 -0500
Subject: [PATCH 098/159] Update number_sets/integers demos nb for more
 even/odd addition thms

Update the numbers/number_sets/integers demonstration.ipynb notebook to include additional tests and demonstrations of the Add.deduce_in_number_set() method for more cases of even and odd integer sets.
---
 .../_theory_nbs_/demonstrations.ipynb         | 93 +++++++++++++++++++
 1 file changed, 93 insertions(+)

diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
index 9a704e799523..059c115a67fa 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
@@ -976,6 +976,32 @@
     "InSet(k, IntegerEven).prove(assumptions = [assumption_about_k, assumption_about_z])"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Closure of the even integers under addition."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Add(a, b).deduce_in_number_set(IntegerEven, assumptions = [InSet(a, IntegerEven), InSet(b, IntegerEven)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Add(a, b, c).deduce_in_number_set(\n",
+    "    IntegerEven, assumptions = [InSet(a, IntegerEven), InSet(b, IntegerEven), InSet(c, IntegerEven)])"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -1073,6 +1099,73 @@
     "InSet(k, IntegerOdd).prove(assumptions = [assumption_about_k, assumption_about_z])"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Even + Odd should be Odd, and Odd + Even should be Odd"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "temp_assumptions = [InSet(a, IntegerEven), InSet(b, IntegerOdd)]\n",
+    "Add(a, b).deduce_in_number_set(IntegerOdd, assumptions=temp_assumptions)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "temp_assumptions = [InSet(a, IntegerEven), InSet(b, IntegerOdd)]\n",
+    "Add(b, a).deduce_in_number_set(IntegerOdd, assumptions=temp_assumptions)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The sum of an even number of odd integers should be even. For example:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from proveit import a, b, c, d, e, f \n",
+    "from proveit.numbers import six\n",
+    "temp_assumptions = [InSet(a, IntegerOdd), InSet(b, IntegerOdd), InSet(c, IntegerOdd),\n",
+    "                    InSet(d, IntegerOdd), InSet(e, IntegerOdd), InSet(f, IntegerOdd), InSet(six, IntegerEven)]\n",
+    "Add(a, b, c, d, e, f).deduce_in_number_set(IntegerEven, assumptions = temp_assumptions)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The sum of an odd number of odd integers should be odd. For example:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from proveit import a, b, c, d, e \n",
+    "from proveit.numbers import five\n",
+    "temp_assumptions = [InSet(a, IntegerOdd), InSet(b, IntegerOdd), InSet(c, IntegerOdd),\n",
+    "                    InSet(d, IntegerOdd), InSet(e, IntegerOdd), InSet(five, IntegerOdd)]\n",
+    "Add(a, b, c, d, e).deduce_in_number_set(IntegerOdd, assumptions = temp_assumptions)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From ed1ea8130f8837fce658001c4cac1da81844ad59 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sat, 7 Jun 2025 12:36:28 -0500
Subject: [PATCH 099/159] Add simple even/odd theorems to numbers_sets/integers

Add some simple even/odd theorems to numbers_sets/integers: claiming that 2, 4, 6, 8 are each even (i.e. in IntegerEven), that 1, 3, 5, 7, 9 are each odd (i.e. in IntegerOdd), and that the negative of an even (or odd) is still an even (or odd). Also added the single-digit claims to the numbers.__initi__.py for automatic loading.
---
 packages/proveit/numbers/__init__.py          |   7 +-
 .../proofs/eight_is_even/thm_proof.ipynb      |  47 ++++++++
 .../proofs/five_is_odd/thm_proof.ipynb        |  47 ++++++++
 .../proofs/four_is_even/thm_proof.ipynb       |  47 ++++++++
 .../proofs/neg_even_is_even/thm_proof.ipynb   |  47 ++++++++
 .../proofs/neg_odd_is_odd/thm_proof.ipynb     |  47 ++++++++
 .../proofs/nine_is_odd/thm_proof.ipynb        |  47 ++++++++
 .../proofs/one_is_odd/thm_proof.ipynb         |  47 ++++++++
 .../proofs/seven_is_odd/thm_proof.ipynb       |  47 ++++++++
 .../proofs/six_is_even/thm_proof.ipynb        |  47 ++++++++
 .../proofs/three_is_odd/thm_proof.ipynb       |  47 ++++++++
 .../proofs/two_is_even/thm_proof.ipynb        |  47 ++++++++
 .../proofs/zero_is_even/thm_proof.ipynb       |  47 ++++++++
 .../integers/_theory_nbs_/theorems.ipynb      | 113 +++++++++++++++++-
 14 files changed, 681 insertions(+), 3 deletions(-)
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/eight_is_even/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/five_is_odd/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/four_is_even/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/neg_even_is_even/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/neg_odd_is_odd/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/nine_is_odd/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/one_is_odd/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/seven_is_odd/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/six_is_even/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/three_is_odd/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/two_is_even/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/zero_is_even/thm_proof.ipynb

diff --git a/packages/proveit/numbers/__init__.py b/packages/proveit/numbers/__init__.py
index 8b67b59c7467..4c25a2184db5 100644
--- a/packages/proveit/numbers/__init__.py
+++ b/packages/proveit/numbers/__init__.py
@@ -57,11 +57,14 @@
 import proveit
 
 
-if proveit.defaults.running_theory_notebook is None:
+if proveit.defaults.running_theory_notebook is None: # might include here 2 is even, 4 is even, etc
     # Import some fundamental theorems without quantifiers when not 
     # running an common/axioms/theorems theory notebook.
     from .number_sets.natural_numbers import zero_in_nats
-    from .number_sets.integers import zero_is_int, zero_is_nonpos_int
+    from .number_sets.integers import (zero_is_int, zero_is_nonpos_int,
+            zero_is_even, two_is_even, four_is_even, six_is_even,
+            eight_is_even, one_is_odd, three_is_odd, five_is_odd,
+            seven_is_odd, nine_is_odd)
     from .number_sets.rational_numbers import (
             zero_is_rational, zero_is_nonneg_rational, 
             zero_is_nonpos_rational)
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/eight_is_even/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/eight_is_even/thm_proof.ipynb
new file mode 100644
index 000000000000..8e906ba6d186
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/eight_is_even/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#eight_is_even\">eight_is_even</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving eight_is_even"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/five_is_odd/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/five_is_odd/thm_proof.ipynb
new file mode 100644
index 000000000000..b03edac2c6f5
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/five_is_odd/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#five_is_odd\">five_is_odd</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving five_is_odd"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/four_is_even/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/four_is_even/thm_proof.ipynb
new file mode 100644
index 000000000000..26a5884916b8
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/four_is_even/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#four_is_even\">four_is_even</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving four_is_even"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/neg_even_is_even/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/neg_even_is_even/thm_proof.ipynb
new file mode 100644
index 000000000000..8cb86bc1ab89
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/neg_even_is_even/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#neg_even_is_even\">neg_even_is_even</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving neg_even_is_even"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/neg_odd_is_odd/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/neg_odd_is_odd/thm_proof.ipynb
new file mode 100644
index 000000000000..ea90a58b0284
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/neg_odd_is_odd/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#neg_odd_is_odd\">neg_odd_is_odd</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving neg_odd_is_odd"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/nine_is_odd/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/nine_is_odd/thm_proof.ipynb
new file mode 100644
index 000000000000..314d7970b4ed
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/nine_is_odd/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nine_is_odd\">nine_is_odd</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving nine_is_odd"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/one_is_odd/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/one_is_odd/thm_proof.ipynb
new file mode 100644
index 000000000000..c226f3910cee
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/one_is_odd/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#one_is_odd\">one_is_odd</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving one_is_odd"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/seven_is_odd/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/seven_is_odd/thm_proof.ipynb
new file mode 100644
index 000000000000..c3a71d258963
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/seven_is_odd/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#seven_is_odd\">seven_is_odd</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving seven_is_odd"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/six_is_even/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/six_is_even/thm_proof.ipynb
new file mode 100644
index 000000000000..99e21ba6c537
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/six_is_even/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#six_is_even\">six_is_even</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving six_is_even"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/three_is_odd/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/three_is_odd/thm_proof.ipynb
new file mode 100644
index 000000000000..5ed81344e29c
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/three_is_odd/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#three_is_odd\">three_is_odd</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving three_is_odd"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/two_is_even/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/two_is_even/thm_proof.ipynb
new file mode 100644
index 000000000000..57fd79adb17d
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/two_is_even/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#two_is_even\">two_is_even</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving two_is_even"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/zero_is_even/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/zero_is_even/thm_proof.ipynb
new file mode 100644
index 000000000000..89eba4e7ee9a
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/zero_is_even/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#zero_is_even\">zero_is_even</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving zero_is_even"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
index 8cd631ae08c1..1bb13ccd83c6 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
@@ -23,7 +23,8 @@
     "from proveit.logic import (And, Equals, Exists, Forall, Implies, in_bool, InSet, NotInSet, Set,\n",
     "                           NotEquals, Or, ProperSubset, SubsetEq, SetEquiv, EmptySet)\n",
     "from proveit.logic.sets import Card, Disjoint, x_equals_any_y\n",
-    "from proveit.numbers import zero, one, two, num, frac, Neg\n",
+    "from proveit.numbers import (zero, one, two, three, four, five, six, seven, eight, nine,\n",
+    "        num, frac, Neg)\n",
     "from proveit.numbers import (ZeroSet, Natural, NaturalPos, \n",
     "                             Integer, IntegerEven, IntegerNeg, IntegerNonZero, IntegerNonPos,\n",
     "                             IntegerOdd, Interval, Complex)\n",
@@ -76,6 +77,96 @@
     "zero_set_within_nonpos_int = ProperSubset(ZeroSet, IntegerNonPos)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "zero_is_even = InSet(zero, IntegerEven)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "two_is_even = InSet(two, IntegerEven)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "four_is_even = InSet(four, IntegerEven)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "six_is_even = InSet(six, IntegerEven)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "eight_is_even = InSet(eight, IntegerEven)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "one_is_odd = InSet(one, IntegerOdd)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "three_is_odd = InSet(three, IntegerOdd)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "five_is_odd = InSet(five, IntegerOdd)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "seven_is_odd = InSet(seven, IntegerOdd)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "nine_is_odd = InSet(nine, IntegerOdd)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -469,6 +560,16 @@
     "        domain=Integer)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "neg_even_is_even = Forall(\n",
+    "        a, InSet(Neg(a), IntegerEven), domain = IntegerEven)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -494,6 +595,16 @@
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "neg_odd_is_odd = Forall(\n",
+    "        a, InSet(Neg(a), IntegerOdd), domain = IntegerOdd)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From dfcf063881a73c9697bb5392c20537e1d20269c3 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sat, 7 Jun 2025 12:43:11 -0500
Subject: [PATCH 100/159] Add several even/odd theorems to
 numbers/multiplication

Add several even-integer and odd-integer theorems to numbers/multiplication package, which will then be utilized in the IntegerEven.conclude() and IntegerOdd.conclude() methods:
mult_int_even_from_ints_with_any_even (product of integers is even if any operand is even)
mult_int_even_from_left_even_bin, mult_int_even_from_right_even_bin (binary product of integers is even if one of the operands is even)
mult_int_odd_from_all_odd (product of odd integers is odd)
---
 .../thm_proof.ipynb                           | 47 ++++++++++++++
 .../thm_proof.ipynb                           | 47 ++++++++++++++
 .../thm_proof.ipynb                           | 47 ++++++++++++++
 .../mult_int_odd_from_all_odd/thm_proof.ipynb | 47 ++++++++++++++
 .../_theory_nbs_/theorems.ipynb               | 64 +++++++++++++++++--
 5 files changed, 247 insertions(+), 5 deletions(-)
 create mode 100644 packages/proveit/numbers/multiplication/_theory_nbs_/proofs/mult_int_even_from_ints_with_any_even/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/multiplication/_theory_nbs_/proofs/mult_int_even_from_left_even_bin/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/multiplication/_theory_nbs_/proofs/mult_int_even_from_right_even_bin/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/multiplication/_theory_nbs_/proofs/mult_int_odd_from_all_odd/thm_proof.ipynb

diff --git a/packages/proveit/numbers/multiplication/_theory_nbs_/proofs/mult_int_even_from_ints_with_any_even/thm_proof.ipynb b/packages/proveit/numbers/multiplication/_theory_nbs_/proofs/mult_int_even_from_ints_with_any_even/thm_proof.ipynb
new file mode 100644
index 000000000000..3d6b481f29bd
--- /dev/null
+++ b/packages/proveit/numbers/multiplication/_theory_nbs_/proofs/mult_int_even_from_ints_with_any_even/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">multiplication</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#mult_int_even_from_ints_with_any_even\">mult_int_even_from_ints_with_any_even</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving mult_int_even_from_ints_with_any_even"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/multiplication/_theory_nbs_/proofs/mult_int_even_from_left_even_bin/thm_proof.ipynb b/packages/proveit/numbers/multiplication/_theory_nbs_/proofs/mult_int_even_from_left_even_bin/thm_proof.ipynb
new file mode 100644
index 000000000000..9e76d8fc8e1c
--- /dev/null
+++ b/packages/proveit/numbers/multiplication/_theory_nbs_/proofs/mult_int_even_from_left_even_bin/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">multiplication</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#mult_int_even_from_left_even_bin\">mult_int_even_from_left_even_bin</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving mult_int_even_from_left_even_bin"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/multiplication/_theory_nbs_/proofs/mult_int_even_from_right_even_bin/thm_proof.ipynb b/packages/proveit/numbers/multiplication/_theory_nbs_/proofs/mult_int_even_from_right_even_bin/thm_proof.ipynb
new file mode 100644
index 000000000000..8ef661ba851e
--- /dev/null
+++ b/packages/proveit/numbers/multiplication/_theory_nbs_/proofs/mult_int_even_from_right_even_bin/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">multiplication</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#mult_int_even_from_right_even_bin\">mult_int_even_from_right_even_bin</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving mult_int_even_from_right_even_bin"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/multiplication/_theory_nbs_/proofs/mult_int_odd_from_all_odd/thm_proof.ipynb b/packages/proveit/numbers/multiplication/_theory_nbs_/proofs/mult_int_odd_from_all_odd/thm_proof.ipynb
new file mode 100644
index 000000000000..6cc62e92dbd7
--- /dev/null
+++ b/packages/proveit/numbers/multiplication/_theory_nbs_/proofs/mult_int_odd_from_all_odd/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">multiplication</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#mult_int_odd_from_all_odd\">mult_int_odd_from_all_odd</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving mult_int_odd_from_all_odd"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/multiplication/_theory_nbs_/theorems.ipynb b/packages/proveit/numbers/multiplication/_theory_nbs_/theorems.ipynb
index b344f8f2f303..e5a79ed62896 100644
--- a/packages/proveit/numbers/multiplication/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/numbers/multiplication/_theory_nbs_/theorems.ipynb
@@ -26,11 +26,12 @@
     "from proveit.core_expr_types import (\n",
     "    a_1_to_i, a_1_to_n, b_1_to_j, c_1_to_j, c_1_to_k, d_1_to_k)\n",
     "\n",
-    "from proveit.logic import Or, Forall, Set, InSet, Equals, NotEquals, Implies, Boolean\n",
-    "from proveit.numbers import (ZeroSet, Natural, NaturalPos, Integer, IntegerNonZero, IntegerNeg, IntegerNonPos,\n",
-    "                             Rational, RationalPos, RationalNeg, RationalNonNeg, RationalNonPos, RationalNonZero,\n",
-    "                             Real, RealPos, RealNeg, RealNonNeg, RealNonPos, RealNonZero,\n",
-    "                             Complex, ComplexNonZero)\n",
+    "from proveit.logic import And, Or, Forall, Set, InSet, Equals, NotEquals, Implies, Boolean\n",
+    "from proveit.numbers import (ZeroSet, Natural, NaturalPos, Integer, IntegerEven,\n",
+    "        IntegerNonZero, IntegerNeg, IntegerNonPos, IntegerOdd,\n",
+    "        Rational, RationalPos, RationalNeg, RationalNonNeg, RationalNonPos, RationalNonZero,\n",
+    "        Real, RealPos, RealNeg, RealNonNeg, RealNonPos, RealNonZero,\n",
+    "        Complex, ComplexNonZero)\n",
     "from proveit.numbers import (Mult, Neg, Add, subtract, Abs, Sum, num, zero, one, two, Exp,\n",
     "                            Less, LessEq, greater, greater_eq)\n",
     "from proveit.numbers.summation import summation_b1toj_fQ\n",
@@ -247,6 +248,59 @@
     "           domain=Natural)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "mult_int_even_from_left_even_bin = (\n",
+    "        Forall((a, b), InSet(Mult(a, b), IntegerEven), domains = [IntegerEven, Integer])\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "mult_int_even_from_right_even_bin = (\n",
+    "        Forall((a, b), InSet(Mult(a, b), IntegerEven), domains = [Integer, IntegerEven])\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "mult_int_even_from_ints_with_any_even = (\n",
+    "    Forall(n, \n",
+    "           Forall(a_1_to_n, InSet(Mult(a_1_to_n), IntegerEven),\n",
+    "                  condition=Or(*ExprTuple(a_1_to_n).map_elements(lambda x : InSet(x, IntegerEven))),\n",
+    "                  domain = Integer),\n",
+    "           domain=NaturalPos)\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from proveit.logic import And\n",
+    "from proveit.numbers import IntegerOdd\n",
+    "mult_int_odd_from_all_odd = (\n",
+    "    Forall(n, \n",
+    "           Forall(a_1_to_n, InSet(Mult(a_1_to_n), IntegerOdd),\n",
+    "                  domain = IntegerOdd),\n",
+    "           domain=Natural)\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From a4f44398cf68c3b265722d61ea826fafb74f6c35 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sat, 7 Jun 2025 12:56:10 -0500
Subject: [PATCH 101/159] Add commuted version of a binary even/odd theorem

Add a commuted version of a binary even/odd theorem claiming that the sum of an odd integer and an even integer is an odd integer. This will then be used to simplify some code in the Add.deduce_in_number_set() method. Also updates the add_int_even_from_even_odd theorem to allow an empty (zero operands) Add, which is axiomatically defined as 0 which is then also even.
---
 .../thm_proof.ipynb                           | 47 +++++++++++++++++++
 .../addition/_theory_nbs_/theorems.ipynb      | 11 ++++-
 2 files changed, 57 insertions(+), 1 deletion(-)
 create mode 100644 packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_odd_from_odd_and_even_bin/thm_proof.ipynb

diff --git a/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_odd_from_odd_and_even_bin/thm_proof.ipynb b/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_odd_from_odd_and_even_bin/thm_proof.ipynb
new file mode 100644
index 000000000000..9ed79aad02c2
--- /dev/null
+++ b/packages/proveit/numbers/addition/_theory_nbs_/proofs/add_int_odd_from_odd_and_even_bin/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">addition</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#add_int_odd_from_odd_and_even_bin\">add_int_odd_from_odd_and_even_bin</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving add_int_odd_from_odd_and_even_bin"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/addition/_theory_nbs_/theorems.ipynb b/packages/proveit/numbers/addition/_theory_nbs_/theorems.ipynb
index 8eff28928ef2..2d416cebab9d 100644
--- a/packages/proveit/numbers/addition/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/numbers/addition/_theory_nbs_/theorems.ipynb
@@ -224,7 +224,7 @@
     "add_int_even_from_even_odd = (\n",
     "    Forall(i,\n",
     "           Forall(a_1_to_i, InSet(Add(a_1_to_i), IntegerEven), domain = IntegerOdd),\n",
-    "    condition=greater(i, zero),\n",
+    "    condition=greater_eq(i, zero),\n",
     "    domain=IntegerEven)\n",
     ")"
    ]
@@ -238,6 +238,15 @@
     "add_int_odd_from_even_and_odd_bin = Forall((a, b), InSet(Add(a, b), IntegerOdd), domains = [IntegerEven, IntegerOdd])"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "add_int_odd_from_odd_and_even_bin = Forall((a, b), InSet(Add(a, b), IntegerOdd), domains = [IntegerOdd, IntegerEven])"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From e3f241ba2c002361bc04251c22a9e77cbaf920db Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 9 Jun 2025 14:52:50 -0500
Subject: [PATCH 102/159] Update IntegerEvenMembership's conclude() and
 side_effects() methods

Update IntegerEvenMembership's conclude() and side_effects() methods, removing some redundant side-effects from side_effects() and adding components in conclude() to take advantage of multiplication (Mult)-related theorems about (for example, if Mult has all integer operands with at least one operand known to be even, then the product is even). A note about including Mult cases in conclude: after discussion with @wwitzel it seemed reasonable consider such cases in conclude() in part because it was difficult to see a good/best way to inject even/odd considerations into the Mult.deduce_in_number_set() method.
---
 .../integers/integer_membership.py            | 69 ++++++++++++++-----
 1 file changed, 51 insertions(+), 18 deletions(-)

diff --git a/packages/proveit/numbers/number_sets/integers/integer_membership.py b/packages/proveit/numbers/number_sets/integers/integer_membership.py
index dda5ed905b71..419853604a0c 100644
--- a/packages/proveit/numbers/number_sets/integers/integer_membership.py
+++ b/packages/proveit/numbers/number_sets/integers/integer_membership.py
@@ -1,7 +1,7 @@
 from proveit import prover, relation_prover
-from proveit import a, x, z
+from proveit import a, b, n, x, z
 from proveit.logic import Equals, Exists, InSet, NotEquals
-from proveit.numbers import Add, Less, LessEq, Mult
+from proveit.numbers import Add, Less, LessEq, Mult, Neg
 from proveit.numbers import (
         zero, one, two, Integer, IntegerEven, IntegerNeg,
         IntegerNonPos, IntegerNonZero, IntegerOdd)
@@ -282,12 +282,51 @@ def _readily_provable(self):
     @prover
     def conclude(self, **defaults_config):
         '''
-        Conclude element in IntegerEven using the fact that the
-        element can be expressed as 2z for some z in Integer.
+        Conclude element in IntegerEven using the fact that
+        (1) the element can be expressed as 2z for some z in Integer,
+        or (2) the element is a product of integers with at least one of
+        the integers being even, or (3) the element is the negation of
+        an even integer. Addition cases are handled mostly through
+        Add.deduce_in_number_set().
         '''
-        # Use proven, not readily provable here:
-        if Exists(z, Equals(self.element, Mult(two, z)), domain=Integer).proven():
+        if (Exists(z, Equals(self.element, Mult(two, z)), domain=Integer)
+                .proven()):
             return self.conclude_as_last_resort()
+
+        if isinstance(self.element, Mult):
+            operands = self.element.operands
+            if operands.is_double():
+                _a = operands[0]
+                _b = operands[1]
+                if (InSet(_a, IntegerEven).proven()
+                        and InSet(_b, Integer).proven()):
+                    from proveit.numbers.multiplication import (
+                            mult_int_even_from_left_even_bin)
+                    return mult_int_even_from_left_even_bin.instantiate(
+                            {a:_a, b:_b})
+                if (InSet(_b, IntegerEven).proven()
+                        and InSet(_a, Integer).proven()):
+                    from proveit.numbers.multiplication import (
+                            mult_int_even_from_right_even_bin)
+                    return mult_int_even_from_right_even_bin.instantiate(
+                            {a:_a, b:_b})
+            if len(operands) > 0: # empty Mult is 1 (odd) by axiom
+                if (all(InSet(a, Integer).proven() for a in operands)
+                    and any(InSet(a, IntegerEven).proven() for a in operands)):
+                    from proveit.numbers.multiplication import (
+                            mult_int_even_from_ints_with_any_even)
+                    _a = operands
+                    _n = operands.num_elements()
+                    return mult_int_even_from_ints_with_any_even.instantiate(
+                            {n:_n, a:_a})
+
+        if (isinstance(self.element, Neg)
+            and InSet(self.element.operand, IntegerEven).proven()):
+            # Neg(even) is even
+            from . import neg_even_is_even
+            _a = self.element.operand
+            return neg_even_is_even.instantiate({a:_a})
+
         return NumberMembership.conclude(self)
 
     @prover
@@ -307,15 +346,12 @@ def side_effects(self, judgment):
         '''
         Yield side-effects when proving 'n in IntegerEven' for 
         # a given n:
-        (1) An even integer n is an integer;
-        (2) An even integer n is a rational number;
-        (3) An even integer is a real number;
-        (4) An even integer n can be expressed as 2z for some
+        (1) An even integer n is an integer (this will then cascade
+            to rationals, reals, and complex numbers);
+        (2) An even integer n can be expressed as 2z for some
             integer z.
         '''
         yield self.derive_element_in_integer
-        yield self.derive_element_in_rational
-        yield self.derive_element_in_real
         yield self.derive_element_as_double_int
 
     @relation_prover
@@ -391,15 +427,12 @@ def side_effects(self, judgment):
         '''
         Yield side-effects when proving 'n in IntegerOdd' for 
         # a given n:
-        (1) An odd integer n is an integer;
-        (2) An odd integer n is a rational number;
-        (3) An odd integer n is a real number;
-        (4) An odd integer n can be expressed as 2z+1 for some
+        (1) An odd integer n is an integer (this will cascade to
+            rationals, reals, and complex numbers);
+        (2) An odd integer n can be expressed as 2z+1 for some
             integer z.
         '''
         yield self.derive_element_in_integer
-        yield self.derive_element_in_rational
-        yield self.derive_element_in_real
         yield self.derive_element_as_double_int_plus_one
 
     @relation_prover

From e68b33e8352c00bfb3474e25a5efce1224bf2721 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 10 Jun 2025 11:09:05 -0500
Subject: [PATCH 103/159] Update Add.deduce_in_number_set() to use two binary
 odd/even theorems

Update Add.deduce_in_number_set() to use two separate binary theorems (odd + even = odd, and even + odd = odd) instead of using a single theorem for both and then commuting the result for one of them.
---
 packages/proveit/numbers/addition/add.py | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/packages/proveit/numbers/addition/add.py b/packages/proveit/numbers/addition/add.py
index 54e75778e2bd..530520d84a33 100644
--- a/packages/proveit/numbers/addition/add.py
+++ b/packages/proveit/numbers/addition/add.py
@@ -1268,25 +1268,25 @@ def deduce_in_number_set(self, number_set, **defaults_config):
                 return add_pkg.add_real_nonpos_closure.instantiate({i:_i, a: _a})
 
         # Handle special even/odd integer cases:
-        # (1) even + odd = odd
+        # (1) even + odd = odd, odd + even = odd
         # (2) sum of even number of odds is even
-        # Note: the sum of odd number of odds is odd handled earlier.
+        # Note: case of odd number of odds (being odd) handled earlier.
         if number_set == IntegerOdd:
             if self.operands.is_double():
                 if (InSet(self.operands[0], IntegerEven).readily_provable()
-                    and InSet(self.operands[1], IntegerOdd).readily_provable()):
+                    and
+                    InSet(self.operands[1], IntegerOdd).readily_provable()):
                     _a = self.operands[0]
                     _b = self.operands[1]
                     return (add_pkg.add_int_odd_from_even_and_odd_bin
                             .instantiate({a: _a, b: _b}))
                 if (InSet(self.operands[0], IntegerOdd).readily_provable()
-                    and InSet(self.operands[1], IntegerEven).readily_provable()):
-                    _a = self.operands[1]
-                    _b = self.operands[0]
-                    temp_inst = (
-                            add_pkg.add_int_odd_from_even_and_odd_bin
+                    and
+                    InSet(self.operands[1], IntegerEven).readily_provable()):
+                    _a = self.operands[0]
+                    _b = self.operands[1]
+                    return (add_pkg.add_int_odd_from_odd_and_even_bin
                             .instantiate({a: _a, b: _b}))
-                    return temp_inst.inner_expr().element.commute()
         if number_set == IntegerEven:
             if (all(InSet(operand, IntegerOdd).proven() for
                     operand in self.operands)

From dce238f7c48e6bef45bd17a3799a4ffbc389ca57 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 10 Jun 2025 11:15:25 -0500
Subject: [PATCH 104/159] Update number_sets/integers demonstrations nb for
 recent even/odd work

Update the demonstrations.ipynb notebook for number_sets/integers for recent developmental work on IntegerEvenSet and IntegerOddSet (and related membership classes), including some (indirect) testing of the IntegerEvenMembership.conclude() method which has been updated with some cases for when the element of a membership is a Mult (product) (see earlier commit).
---
 .../_theory_nbs_/demonstrations.ipynb         | 68 ++++++++++++++++++-
 1 file changed, 67 insertions(+), 1 deletion(-)

diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
index 059c115a67fa..b52d80dcc7e8 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
@@ -794,6 +794,16 @@
     "InSet(InSet(x, IntegerEven), Boolean).prove()"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from proveit.numbers import Complex\n",
+    "InSet(x, Complex).prove(assumptions=[InSet(x, IntegerEven)])"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -1002,6 +1012,61 @@
     "    IntegerEven, assumptions = [InSet(a, IntegerEven), InSet(b, IntegerEven), InSet(c, IntegerEven)])"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Multiplication with even integers.\n",
+    "\n",
+    "In a product of integers, if any of the operands is even, the product is even."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(Mult(a, b), IntegerEven).prove(assumptions = [InSet(a, IntegerEven), InSet(b, Integer)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(Mult(a, b), IntegerEven).prove(assumptions = [InSet(a, Integer), InSet(b, IntegerEven)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from proveit import a, b, c, d, e, f \n",
+    "temp_assumptions = [InSet(a, Integer), InSet(b, Integer), InSet(c, IntegerEven),\n",
+    "                    InSet(d, Integer), InSet(e, Integer), InSet(f, Integer)]\n",
+    "InSet(Mult(a, b, c, d, e, f), IntegerEven).prove(assumptions = temp_assumptions)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The negation of an even is still even."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(Neg(a), IntegerEven).prove(assumptions = [InSet(a, IntegerEven)])"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -1080,7 +1145,8 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Exists(z, Equals(k, Add(Mult(two, z), one)), domain = Integer).conclude_via_example(z, assumptions = [assumption_about_k, assumption_about_z])"
+    "Exists(z, Equals(k, Add(Mult(two, z), one)), domain = Integer).conclude_via_example(\n",
+    "    z, assumptions = [assumption_about_k, assumption_about_z])"
    ]
   },
   {

From 3571c630fe77831cbf7aeaaabdb184c86f6bdbb2 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 10 Jun 2025 12:08:55 -0500
Subject: [PATCH 105/159] Add missing returns in Add.deduce_in_number_set()

Add missing `return` key word to a half-dozen lines in the Add.deduce_in_number_set() method.
---
 packages/proveit/numbers/addition/add.py | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/packages/proveit/numbers/addition/add.py b/packages/proveit/numbers/addition/add.py
index 424a080ff231..ac33034ceb43 100644
--- a/packages/proveit/numbers/addition/add.py
+++ b/packages/proveit/numbers/addition/add.py
@@ -1173,42 +1173,45 @@ def deduce_in_number_set(self, number_set, **defaults_config):
                         {a: self.operands[0], b: self.operands[1]})
                 _a = self.operands
                 _i = _a.num_elements()                
-                add_pkg.add_nat_closure.instantiate({i: _i, a: _a})
+                return add_pkg.add_nat_closure.instantiate({i: _i, a: _a})
             if number_set == NaturalPos:
                 if self.operands.is_double():
                     return add_pkg.add_nat_pos_closure_bin.instantiate(
                         {a: self.operands[0], b: self.operands[1]})
                 _a = self.operands
                 _i = _a.num_elements()                
-                add_pkg.add_nat_pos_closure.instantiate({i: _i, a: _a})
+                return add_pkg.add_nat_pos_closure.instantiate({i: _i, a: _a})
             if number_set == IntegerNeg:
                 if self.operands.is_double():
                     return add_pkg.add_int_neg_closure_bin.instantiate(
                         {a: self.operands[0], b: self.operands[1]})
                 _a = self.operands
                 _i = _a.num_elements()                
-                add_pkg.add_int_neg_closure.instantiate({i: _i, a: _a})
+                return add_pkg.add_int_neg_closure.instantiate({i: _i, a: _a})
             if number_set == IntegerNonPos:
                 if self.operands.is_double():
                     return add_pkg.add_int_nonpos_closure_bin.instantiate(
                         {a: self.operands[0], b: self.operands[1]})
                 _a = self.operands
                 _i = _a.num_elements()                
-                add_pkg.add_int_nonpos_closure.instantiate({i: _i, a: _a})
+                return (add_pkg.add_int_nonpos_closure
+                        .instantiate({i: _i, a: _a}))
             if number_set == RationalPos:
                 if self.operands.is_double():
                     return add_pkg.add_rational_pos_closure_bin.instantiate(
                         {a: self.operands[0], b: self.operands[1]})
                 _a = self.operands
                 _i = _a.num_elements()                
-                add_pkg.add_rational_pos_closure.instantiate({i: _i, a: _a})
+                return (add_pkg.add_rational_pos_closure
+                        .instantiate({i: _i, a: _a}))
             if number_set == RationalNeg:
                 if self.operands.is_double():
                     return add_pkg.add_rational_neg_closure_bin.instantiate(
                         {a: self.operands[0], b: self.operands[1]})
                 _a = self.operands
                 _i = _a.num_elements()                
-                add_pkg.add_rational_neg_closure.instantiate({i: _i, a: _a})
+                return (add_pkg.add_rational_neg_closure
+                        .instantiate({i: _i, a: _a}))
             if number_set == RationalNonNeg:
                 if self.operands.is_double():
                     return add_pkg.add_rational_nonneg_closure_bin.instantiate(

From 70f75b4285d1d8641c22f8df160a69bbf3a062a5 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 10 Jun 2025 14:44:01 -0500
Subject: [PATCH 106/159] Add one more missing `return` in
 Add.deduce_in_number_set()

Add one more missing `return` in Add.deduce_in_number_set(), which was dropped due to a conflict when merging branch 338 into this branch 336.
---
 packages/proveit/numbers/addition/add.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/packages/proveit/numbers/addition/add.py b/packages/proveit/numbers/addition/add.py
index 4164e8372c0d..c57c0a35eeb0 100644
--- a/packages/proveit/numbers/addition/add.py
+++ b/packages/proveit/numbers/addition/add.py
@@ -1195,7 +1195,8 @@ def deduce_in_number_set(self, number_set, **defaults_config):
                         {a: self.operands[0], b: self.operands[1]})
                 _a = self.operands
                 _i = _a.num_elements()
-                add_pkg.add_int_nonpos_closure.instantiate({i: _i, a: _a})
+                return (add_pkg.add_int_nonpos_closure
+                        .instantiate({i: _i, a: _a}))
             if number_set == IntegerEven:
                 if self.operands.is_double():
                     return add_pkg.add_int_even_closure_bin.instantiate(

From ea724ffa9424b880c15db96f6ee26740a5693782 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 11 Jun 2025 16:49:43 -0500
Subject: [PATCH 107/159] Augment IntegerEvenMembership.conclude() method with
 Add case

Augment the IntegerEvenMembership.conclude() method with a case for the element being an instance of Add, in which case we return the element's Add.deduce_in_number_set() method using the IntegerEven number set. Not sure if this is reasonable based on the way @wwitzel likes to think about these things.
---
 .../numbers/number_sets/integers/integer_membership.py    | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/packages/proveit/numbers/number_sets/integers/integer_membership.py b/packages/proveit/numbers/number_sets/integers/integer_membership.py
index 419853604a0c..1409e42bb712 100644
--- a/packages/proveit/numbers/number_sets/integers/integer_membership.py
+++ b/packages/proveit/numbers/number_sets/integers/integer_membership.py
@@ -293,6 +293,9 @@ def conclude(self, **defaults_config):
                 .proven()):
             return self.conclude_as_last_resort()
 
+        if isinstance(self.element, Add):
+            return self.element.deduce_in_number_set(self.number_set)
+
         if isinstance(self.element, Mult):
             operands = self.element.operands
             if operands.is_double():
@@ -334,9 +337,8 @@ def conclude_as_last_resort(self, **defaults_config):
         '''
         Conclude element in IntegerEven using the fact that the
         element can be expressed as 2z for some Integer z.
-        This method is called via NumberMembership.conclude()
-        if the 'deduce_in_number_set' method of the element raises
-        a NotImplementedError.
+        This method is called from NumberMembership.conclude()
+        as an almost-last resort.
         '''
         from . import double_int_is_even
         _a_sub = self.element

From 905080c745f2f099eee791f0b85931d2f6ef6d97 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 11 Jun 2025 21:03:07 -0500
Subject: [PATCH 108/159] Add an observation/comment to NumberSet.conclude()

Add an observation/comment to NumberSet.conclude(), noting that an attempt to include as a step the calling of element.deduce_in_number_set() seems to lead to an infinite loop, where the actual XMembership.conclude() leads to a NumberSet.conclude(), which then leads to an XMembership.conclude, etc.
---
 packages/proveit/numbers/number_sets/number_set.py | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/packages/proveit/numbers/number_sets/number_set.py b/packages/proveit/numbers/number_sets/number_set.py
index 245bdbd7f844..12bef92aadfb 100644
--- a/packages/proveit/numbers/number_sets/number_set.py
+++ b/packages/proveit/numbers/number_sets/number_set.py
@@ -324,6 +324,10 @@ def conclude(self, **defaults_config):
 
         """
         # Try the 'deduce_in_number_set' method.
+        # The 'element.deduce_in_number_set()'' attempt (often?) leads
+        # to infinite loop of some sort, where a membership.conclude()
+        # leads to a NumberSet.conclude(), which then leads to a
+        # membership.conclude(), ad infinitum.
         if hasattr(element, 'deduce_in_number_set'):
             # Try to deduce membership directly in the desired number
             # set via 'deduce_in_number_set'.
@@ -346,6 +350,7 @@ def conclude(self, **defaults_config):
                 return membership.inner_expr().element.substitute(
                         element)
         """
+
         if hasattr(self, 'conclude_as_last_resort'):
             return self.conclude_as_last_resort()
         if hasattr(element, 'readily_provable_number_set'):

From e705fcc75268c583c71d4172a8b353b6d290592b Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 11 Jun 2025 21:07:30 -0500
Subject: [PATCH 109/159] Augment IntegerOddMembership.conclude() method with
 Add case

Analogous to what we did in the IntegerEvenMembership.conclude() method, augment the IntegerOddMembership.conclude() method with a case for the element being an instance of Add, in which case we return the element's Add.deduce_in_number_set() method using the IntegerOdd number set.
---
 .../numbers/number_sets/integers/integer_membership.py        | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/packages/proveit/numbers/number_sets/integers/integer_membership.py b/packages/proveit/numbers/number_sets/integers/integer_membership.py
index 1409e42bb712..8c7bbe2ef8d2 100644
--- a/packages/proveit/numbers/number_sets/integers/integer_membership.py
+++ b/packages/proveit/numbers/number_sets/integers/integer_membership.py
@@ -410,6 +410,10 @@ def conclude(self, **defaults_config):
         if Exists(z, Equals(self.element, Add(Mult(two, z), one)),
                   domain=Integer).proven():
             return self.conclude_as_last_resort()
+
+        if isinstance(self.element, Add):
+            return self.element.deduce_in_number_set(self.number_set)
+
         return NumberMembership.conclude(self)
 
     @prover

From c863af6741f6b94907b191d0c93881a91bd1c1f3 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 11 Jun 2025 21:13:30 -0500
Subject: [PATCH 110/159] Augment IntegerOddMembership.conclude() method with
 Neg() element case

Analogous to what we did in the IntegerEvenMembership.conclude() method, augment the IntegerOddMembership.conclude() method with a case for the element being an instance of Neg(a) with 'a' itself being odd, in which case we the element is also odd (i.e. the negation of an odd is an odd).
---
 .../numbers/number_sets/integers/integer_membership.py     | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/packages/proveit/numbers/number_sets/integers/integer_membership.py b/packages/proveit/numbers/number_sets/integers/integer_membership.py
index 8c7bbe2ef8d2..27d828702b1f 100644
--- a/packages/proveit/numbers/number_sets/integers/integer_membership.py
+++ b/packages/proveit/numbers/number_sets/integers/integer_membership.py
@@ -414,6 +414,13 @@ def conclude(self, **defaults_config):
         if isinstance(self.element, Add):
             return self.element.deduce_in_number_set(self.number_set)
 
+        if (isinstance(self.element, Neg)
+            and InSet(self.element.operand, IntegerOdd).proven()):
+            # Neg(odd) is odd
+            from . import neg_odd_is_odd
+            _a = self.element.operand
+            return neg_odd_is_odd.instantiate({a:_a})
+
         return NumberMembership.conclude(self)
 
     @prover

From 0e7912dbe081458d2d94b8fb2af0053a71901362 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 12 Jun 2025 08:44:41 -0500
Subject: [PATCH 111/159] Augment IntegerOddMembership.conclude() to include
 Mult() element case

Augment the IntegerOddMembership.conclude() to include the case where the membership element is a Mult() with all multiplicands odd, in which case the product should be odd. Analogous to Mult case(s) introduced into the IntegerEvenMembership.conclude() method.
---
 .../integers/integer_membership.py            | 27 +++++++++++++------
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/packages/proveit/numbers/number_sets/integers/integer_membership.py b/packages/proveit/numbers/number_sets/integers/integer_membership.py
index 27d828702b1f..11905ae8b0bf 100644
--- a/packages/proveit/numbers/number_sets/integers/integer_membership.py
+++ b/packages/proveit/numbers/number_sets/integers/integer_membership.py
@@ -283,11 +283,11 @@ def _readily_provable(self):
     def conclude(self, **defaults_config):
         '''
         Conclude element in IntegerEven using the fact that
-        (1) the element can be expressed as 2z for some z in Integer,
-        or (2) the element is a product of integers with at least one of
-        the integers being even, or (3) the element is the negation of
-        an even integer. Addition cases are handled mostly through
-        Add.deduce_in_number_set().
+        (1) the element can be expressed as 2z for some z in Integer;
+        (2) the element is an instance of Add();
+        (3) the element is a product of integers with at least one of
+        the integers being even; or
+        (4) the element is the negation of an even integer.
         '''
         if (Exists(z, Equals(self.element, Mult(two, z)), domain=Integer)
                 .proven()):
@@ -403,10 +403,12 @@ def _readily_provable(self):
     @prover
     def conclude(self, **defaults_config):
         '''
-        Conclude element in IntegerOdd using the fact that the
-        element can be expressed as (2z + 1) for some z in Integer.
+        Conclude element in IntegerOdd using the fact that the element:
+        (1) can be expressed as (2z + 1) for some z in Integer;
+        (2) is an instance of Add();
+        (3) is a product of all odd integers; or
+        (4) the element is the negation of an odd integer.
         '''
-        # Use proven, not readily provable here:
         if Exists(z, Equals(self.element, Add(Mult(two, z), one)),
                   domain=Integer).proven():
             return self.conclude_as_last_resort()
@@ -414,6 +416,15 @@ def conclude(self, **defaults_config):
         if isinstance(self.element, Add):
             return self.element.deduce_in_number_set(self.number_set)
 
+        if isinstance(self.element, Mult):
+            operands = self.element.operands
+            if all(InSet(a, IntegerOdd).proven() for a in operands):
+                from proveit.numbers.multiplication import (
+                        mult_int_odd_from_all_odd)
+                _a = operands
+                _n = operands.num_elements()
+                return mult_int_odd_from_all_odd.instantiate({n:_n, a:_a})
+
         if (isinstance(self.element, Neg)
             and InSet(self.element.operand, IntegerOdd).proven()):
             # Neg(odd) is odd

From 04a8941633f5eb40a876404fd5ed8ec331ae2bbd Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 12 Jun 2025 16:47:21 -0500
Subject: [PATCH 112/159] Add two thms to number_sets/integers package for
 even/odd ints

Add two theorems to the number_sets/integers package for even and odd integers:
odd_int_has_even_successor (an odd integer has an even integer successor)
even_int_has_odd_successor (an even integer has an odd integer successor).
These are then utilized in the IntegerEvenMembership.conclude() and IntegerOddMembership.conclude() methods (a separate later commit).
---
 .../thm_proof.ipynb                           | 47 +++++++++++++++++++
 .../thm_proof.ipynb                           | 47 +++++++++++++++++++
 .../integers/_theory_nbs_/theorems.ipynb      | 18 +++++++
 3 files changed, 112 insertions(+)
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_has_odd_successor/thm_proof.ipynb
 create mode 100644 packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/odd_int_has_even_successor/thm_proof.ipynb

diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_has_odd_successor/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_has_odd_successor/thm_proof.ipynb
new file mode 100644
index 000000000000..cc1fd516d193
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/even_int_has_odd_successor/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#even_int_has_odd_successor\">even_int_has_odd_successor</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving even_int_has_odd_successor"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/odd_int_has_even_successor/thm_proof.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/odd_int_has_even_successor/thm_proof.ipynb
new file mode 100644
index 000000000000..83569f095c00
--- /dev/null
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/proofs/odd_int_has_even_successor/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">numbers</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">number_sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">integers</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#odd_int_has_even_successor\">odd_int_has_even_successor</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving odd_int_has_even_successor"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
index 1bb13ccd83c6..82e4f81c9cbe 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/theorems.ipynb
@@ -630,6 +630,24 @@
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "even_int_has_odd_successor = Forall(a, InSet(a, IntegerOdd), conditions = [InSet(subtract(a, one), IntegerEven)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "odd_int_has_even_successor = Forall(a, InSet(a, IntegerEven), conditions = [InSet(subtract(a, one), IntegerOdd)])"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},

From 1b8a452ba272a3e84296959c319902118849e20d Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 12 Jun 2025 16:53:56 -0500
Subject: [PATCH 113/159] Update even/odd membership conclude() to use
 successor theorems

Update the IntegerEvenMembership.conclude() and IntegerOddMembership.conclude() methods to use recently created integer package theorems about successors of even and odd integers (see recent previous commit). Related Issue: #336.
---
 .../integers/integer_membership.py            | 25 +++++++++++++++----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/packages/proveit/numbers/number_sets/integers/integer_membership.py b/packages/proveit/numbers/number_sets/integers/integer_membership.py
index 11905ae8b0bf..15bd5c452f78 100644
--- a/packages/proveit/numbers/number_sets/integers/integer_membership.py
+++ b/packages/proveit/numbers/number_sets/integers/integer_membership.py
@@ -1,7 +1,7 @@
 from proveit import prover, relation_prover
 from proveit import a, b, n, x, z
 from proveit.logic import Equals, Exists, InSet, NotEquals
-from proveit.numbers import Add, Less, LessEq, Mult, Neg
+from proveit.numbers import Add, Less, LessEq, Mult, Neg, subtract
 from proveit.numbers import (
         zero, one, two, Integer, IntegerEven, IntegerNeg,
         IntegerNonPos, IntegerNonZero, IntegerOdd)
@@ -286,9 +286,11 @@ def conclude(self, **defaults_config):
         (1) the element can be expressed as 2z for some z in Integer;
         (2) the element is an instance of Add();
         (3) the element is a product of integers with at least one of
-        the integers being even; or
-        (4) the element is the negation of an even integer.
+        the integers being even;
+        (4) the element is the negation of an even integer; or
+        (5) the element is the successor of an odd integer.
         '''
+        print("Entering the IntegerEvenMembership.conclude() method.")
         if (Exists(z, Equals(self.element, Mult(two, z)), domain=Integer)
                 .proven()):
             return self.conclude_as_last_resort()
@@ -330,6 +332,11 @@ def conclude(self, **defaults_config):
             _a = self.element.operand
             return neg_even_is_even.instantiate({a:_a})
 
+        if InSet(subtract(self.element, one), IntegerOdd).readily_provable():
+            from . import odd_int_has_even_successor
+            _a = self.element
+            return odd_int_has_even_successor.instantiate({a: _a})
+
         return NumberMembership.conclude(self)
 
     @prover
@@ -406,9 +413,11 @@ def conclude(self, **defaults_config):
         Conclude element in IntegerOdd using the fact that the element:
         (1) can be expressed as (2z + 1) for some z in Integer;
         (2) is an instance of Add();
-        (3) is a product of all odd integers; or
-        (4) the element is the negation of an odd integer.
+        (3) is a product of all odd integers;
+        (4) the element is the negation of an odd integer; or
+        (5) the element is the successor of an even integer.
         '''
+        print("Entering IntegerOddMembership.conclude() method.")
         if Exists(z, Equals(self.element, Add(Mult(two, z), one)),
                   domain=Integer).proven():
             return self.conclude_as_last_resort()
@@ -432,6 +441,12 @@ def conclude(self, **defaults_config):
             _a = self.element.operand
             return neg_odd_is_odd.instantiate({a:_a})
 
+        if (InSet(subtract(self.element, one), IntegerEven)
+            .readily_provable()):
+            from . import even_int_has_odd_successor
+            _a = self.element
+            return even_int_has_odd_successor.instantiate({a: _a})
+
         return NumberMembership.conclude(self)
 
     @prover

From 690eac6cc197212d442d1ff1be810386633e3c10 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 12 Jun 2025 17:01:29 -0500
Subject: [PATCH 114/159] Remove some obsolete print() statements from
 conclude() methods

Remove some obsolete print() statements (used for testing) from the IntegerEvenMembership.conclude() and IntegerOddMembership.conclude() methods.
---
 .../proveit/numbers/number_sets/integers/integer_membership.py  | 2 --
 1 file changed, 2 deletions(-)

diff --git a/packages/proveit/numbers/number_sets/integers/integer_membership.py b/packages/proveit/numbers/number_sets/integers/integer_membership.py
index 15bd5c452f78..50447269c7ef 100644
--- a/packages/proveit/numbers/number_sets/integers/integer_membership.py
+++ b/packages/proveit/numbers/number_sets/integers/integer_membership.py
@@ -290,7 +290,6 @@ def conclude(self, **defaults_config):
         (4) the element is the negation of an even integer; or
         (5) the element is the successor of an odd integer.
         '''
-        print("Entering the IntegerEvenMembership.conclude() method.")
         if (Exists(z, Equals(self.element, Mult(two, z)), domain=Integer)
                 .proven()):
             return self.conclude_as_last_resort()
@@ -417,7 +416,6 @@ def conclude(self, **defaults_config):
         (4) the element is the negation of an odd integer; or
         (5) the element is the successor of an even integer.
         '''
-        print("Entering IntegerOddMembership.conclude() method.")
         if Exists(z, Equals(self.element, Add(Mult(two, z), one)),
                   domain=Integer).proven():
             return self.conclude_as_last_resort()

From aa4d09b7720424974a40c03636174573a699e0c5 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 12 Jun 2025 18:14:34 -0500
Subject: [PATCH 115/159] Update number_sets/integers/demonstrations.ipynb
 w/recent mods

Update number_sets/integers/demonstrations.ipynb notebook with demonstrations of recent modifications, especially recent modifications to the IntegerEvenMembership.conclude() and IntegerOddMembership.conclude() methods.
---
 .../_theory_nbs_/demonstrations.ipynb         | 290 ++++++++++++++++--
 1 file changed, 268 insertions(+), 22 deletions(-)

diff --git a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
index b52d80dcc7e8..8955e4f9810a 100644
--- a/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/numbers/number_sets/integers/_theory_nbs_/demonstrations.ipynb
@@ -17,7 +17,8 @@
     "import proveit\n",
     "from proveit import a, b, c, d, n, x, y, z, ProofFailure\n",
     "from proveit.logic import Boolean, Equals, Exists, NotEquals, InSet, NotInSet, Or\n",
-    "from proveit.numbers import Add, Neg, Less, LessEq, greater, greater_eq, number_ordering, Mult\n",
+    "from proveit.numbers import (Add, Neg, Less, LessEq, greater, greater_eq,\n",
+    "        number_ordering, Mult, num, subtract)\n",
     "from proveit.numbers import (zero, one, two, three, four, five, six, seven,\n",
     "                             eight, nine, Integer, IntegerEven, IntegerNonZero, IntegerNeg, IntegerNonPos,\n",
     "                             IntegerOdd, Interval, Natural, NaturalPos, Rational, Real)\n",
@@ -773,7 +774,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "#### Even Integers (`IntegerEven`), Even Integer Membership (`IntegerEvenMembership`), and subsets of even integers"
+    "#### Even Integers (`IntegerEven`), Even Integer Membership (`IntegerEvenMembership`), and superset/subsets of even integers"
    ]
   },
   {
@@ -831,13 +832,20 @@
     "InSet(x, Real).prove(assumptions=[InSet(x, IntegerEven)])"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The positive single-digit even integers are “known” (as automatically imported theorems) to be members of the IntegerEven set:"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
    "source": [
-    "Exists(z, Equals(x, Mult(two, z)), domain = Integer).prove(assumptions=[InSet(x, IntegerEven)])"
+    "InSet(zero, IntegerEven).prove()"
    ]
   },
   {
@@ -846,14 +854,50 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(x, IntegerEven).prove(assumptions = [Exists(z, Equals(x, Mult(two, z)), domain = Integer)])"
+    "InSet(two, IntegerEven).prove()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(four, IntegerEven).prove()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(six, IntegerEven).prove()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(eight, IntegerEven).prove()"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "If we know that $2$ can be expressed as $2\\cdot 1$:"
+    "More generally, $x$ is an even integer if and only if there exists an integer $z$ such that $x = 2z$:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Exists(z, Equals(x, Mult(two, z)), domain = Integer).prove(assumptions=[InSet(x, IntegerEven)])"
    ]
   },
   {
@@ -862,14 +906,14 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Equals(Mult(two, one), two).prove()"
+    "InSet(x, IntegerEven).prove(assumptions = [Exists(z, Equals(x, Mult(two, z)), domain = Integer)])"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "then we can prove that there exists an integer z such that $2 = 2z$:"
+    "If we know that $10$ can be expressed as $2\\cdot 5$:"
    ]
   },
   {
@@ -878,14 +922,14 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Exists(z, Equals(two, Mult(two, z)), domain = Integer).conclude_via_example(one)"
+    "Equals(Mult(two, five), num(10)).prove()"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "And once that existential is established, we can prove that $2$ is in the even integers:"
+    "that isn't quite enough by itself in the current system to prove automatically that $10$ is an even integer:"
    ]
   },
   {
@@ -894,14 +938,17 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(two, IntegerEven).prove()"
+    "try:\n",
+    "    InSet(num(10), IntegerEven).prove()\n",
+    "except Exception as the_exception:\n",
+    "    print(f\"Exception: {the_exception}\")"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "A similar example, now wanting to show that $4$ is an even integer:"
+    "and we cannot even jump to automatically proving that there then exists an integer $z$ such that $10 = 2z$:"
    ]
   },
   {
@@ -910,8 +957,17 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "from proveit.numbers import four\n",
-    "Equals(four, Mult(two, two)).prove()"
+    "try:\n",
+    "    Exists(z, Equals(num(10), Mult(two, z)), domain = Integer).prove()\n",
+    "except Exception as the_exception:\n",
+    "    print(f\"Exception: {the_exception}\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "but we can manually prompt Prove-It to prove that there exists an integer z such that $10 = 2z$, using the `conclude_via_example()` method:"
    ]
   },
   {
@@ -920,7 +976,14 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Exists(z, Equals(four, Mult(two, z)), domain = Integer).conclude_via_example(two)"
+    "Exists(z, Equals(num(10), Mult(two, z)), domain = Integer).conclude_via_example(five)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "after which we can automatically prove that $10$ is even:"
    ]
   },
   {
@@ -929,16 +992,14 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(four, IntegerEven).prove()"
+    "InSet(num(10), IntegerEven).prove()"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "More generally? YES! Well, sort of …\n",
-    "\n",
-    "Let's assume that $k = 2z$ for some integer $z$, without explicitly specifying the value of $z$:"
+    "We can do this more generally as well. Let's assume that $k = 2z$ for some integer $z$, without explicitly specifying the value of $z$:"
    ]
   },
   {
@@ -958,7 +1019,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Then we can derive the existential claim:"
+    "Then we can derive the existential claim, using `conclude_by_example`::"
    ]
   },
   {
@@ -990,7 +1051,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Closure of the even integers under addition."
+    "##### Closure of the even integers under addition."
    ]
   },
   {
@@ -1012,6 +1073,25 @@
     "    IntegerEven, assumptions = [InSet(a, IntegerEven), InSet(b, IntegerEven), InSet(c, IntegerEven)])"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "We cannot yet automatically and directly prove that the sum of evens is even"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from proveit import d, e\n",
+    "assumption_about_d = InSet(d, IntegerEven)\n",
+    "assumption_about_e = InSet(e, IntegerEven)\n",
+    "InSet(Add(d, e), IntegerEven).prove(assumptions = [assumption_about_d, assumption_about_e])"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -1067,6 +1147,15 @@
     "InSet(Neg(a), IntegerEven).prove(assumptions = [InSet(a, IntegerEven)])"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(Neg(six), IntegerEven).prove()"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -1119,6 +1208,58 @@
     "InSet(y, Real).prove(assumptions=[InSet(y, IntegerOdd)])"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The positive single-digit odd integers are “known” (as automatically imported theorems) to be members of the IntegerOdd set:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(one, IntegerOdd).prove()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(three, IntegerOdd).prove()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(five, IntegerOdd).prove()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(seven, IntegerOdd).prove()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(nine, IntegerOdd).prove()"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -1232,13 +1373,20 @@
     "Add(a, b, c, d, e).deduce_in_number_set(IntegerOdd, assumptions = temp_assumptions)"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The negation of an odd is still odd:"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
    "source": [
-    "%end demonstrations"
+    "InSet(Neg(a), IntegerOdd).prove(assumptions = [InSet(a, IntegerOdd)])"
    ]
   },
   {
@@ -1246,7 +1394,105 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "InSet(Neg(five), IntegerOdd).prove()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "And a product of all odd integers is odd:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from proveit import a, b, c, d, e\n",
+    "temp_assumptions = [InSet(a, IntegerOdd), InSet(b, IntegerOdd), InSet(c, IntegerOdd),\n",
+    "                    InSet(d, IntegerOdd), InSet(e, IntegerOdd)]\n",
+    "InSet(Mult(a, b, c, d, e), IntegerOdd).prove(assumptions = temp_assumptions)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Odds and Evens: Alternations and Successors"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The successor of an even integer is always an odd integer. The successor of an odd integer is always even. Earlier we proved that $10 \\in \\mathbb{E}$. If we know or can establish that  $11 = 10 + 1$, we can prove automatically that $11 \\in \\mathbb{O}$. And once $11$ is known to be odd, we can establish that $12 = 11 + 1$ and that $12 \\in \\mathbb{E}$, _etc._:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Equals(num(11), Add(num(10), one)).prove()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(num(11), IntegerOdd).prove()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Equals(num(12), Add(num(11), one)).prove()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(num(12), IntegerEven).prove()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Equals(num(13), Add(num(12), one)).prove()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(num(13), IntegerOdd).prove()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end demonstrations"
+   ]
   }
  ],
  "metadata": {

From 79999e431a66b7c2bf40031909e0a1a5a36b0b7e Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 18 Jun 2025 18:14:19 -0500
Subject: [PATCH 116/159] Shift vertices & edges sub-theory content into more
 general graphs folder; establish walks sub-theory pkg

Remove the individual vertices and edges sub-theory packages, shifting the vertices & edges sub-theory content into the more general graphs folder. This reorganization includes a transfer of the sub-theory packages' axioms and theorems into the axioms and theorems for graphs (often with necessary name changes), and updating the graphs/demonstrations.ipynb to include testing and demonstrations that were present in the sub-theory packages' demonstrations notebooks. This commit also includes the establishment of the graphs/walks sub-theory package (essentially an empty package right now, but to be used for walks, trails, paths, circuits, and cycles, all conceptualized in terms of sequences of vertices).
---
 .../proveit/graphs/_brief_description_.txt    |   2 +-
 packages/proveit/graphs/_sub_theories_.txt    |   3 +-
 .../proveit/graphs/_theory_nbs_/axioms.ipynb  |  70 ++-
 .../graphs/_theory_nbs_/demonstrations.ipynb  | 485 +++++++++++++++++-
 .../edges_membership_def/thm_proof.ipynb      |  47 ++
 .../edges_membership_folding/thm_proof.ipynb  |  47 ++
 .../thm_proof.ipynb                           |  47 ++
 .../edges_nonmembership_def/thm_proof.ipynb   |  47 ++
 .../thm_proof.ipynb                           |  47 ++
 .../thm_proof.ipynb                           |  47 ++
 .../thm_proof.ipynb                           |  47 ++
 .../proofs/total_deg_is_even/thm_proof.ipynb  |  47 ++
 .../thm_proof.ipynb                           |  47 ++
 .../vertices_membership_def/thm_proof.ipynb   |  47 ++
 .../thm_proof.ipynb                           |  47 ++
 .../thm_proof.ipynb                           |  47 ++
 .../thm_proof.ipynb                           |  47 ++
 .../thm_proof.ipynb                           |  47 ++
 .../thm_proof.ipynb                           |  47 ++
 .../graphs/_theory_nbs_/theorems.ipynb        | 243 ++++++++-
 .../proveit/graphs/_theory_nbs_/theory.ipynb  |   2 +-
 packages/proveit/graphs/{edges => }/edges.py  |  10 +-
 .../graphs/edges/_brief_description_.txt      |   1 -
 .../graphs/edges/_theory_nbs_/axioms.ipynb    |  69 ---
 .../edges/_theory_nbs_/demonstrations.ipynb   | 245 ---------
 .../membership_def/allowed_presumptions.txt   |   0
 .../disallowed_presumptions.txt               |   0
 .../proofs/membership_def/thm_proof.ipynb     |  98 ----
 .../allowed_presumptions.txt                  |   2 -
 .../disallowed_presumptions.txt               |   0
 .../proofs/membership_folding/thm_proof.ipynb |  88 ----
 .../allowed_presumptions.txt                  |   2 -
 .../disallowed_presumptions.txt               |   0
 .../membership_unfolding/thm_proof.ipynb      |  88 ----
 .../allowed_presumptions.txt                  |   0
 .../disallowed_presumptions.txt               |   0
 .../allowed_presumptions.txt                  |   2 -
 .../disallowed_presumptions.txt               |   0
 .../nonmembership_folding/thm_proof.ipynb     |  88 ----
 .../allowed_presumptions.txt                  |   2 -
 .../disallowed_presumptions.txt               |   0
 .../nonmembership_unfolding/thm_proof.ipynb   |  88 ----
 .../graphs/edges/_theory_nbs_/theorems.ipynb  | 139 -----
 .../graphs/edges/_theory_nbs_/theory.ipynb    |  33 --
 .../graphs/{edges => }/edges_membership.py    |  58 ++-
 .../proveit/graphs/{vertices => }/vertices.py |   0
 packages/proveit/graphs/vertices/__init__.py  |   9 -
 .../graphs/vertices/_brief_description_.txt   |   1 -
 .../graphs/vertices/_sub_theories_.txt        |   0
 .../graphs/vertices/_theory_nbs_/__init__.py  |   0
 .../graphs/vertices/_theory_nbs_/axioms.ipynb |  69 ---
 .../_theory_nbs_/demonstrations.ipynb         | 308 -----------
 .../membership_def/allowed_presumptions.txt   |   0
 .../disallowed_presumptions.txt               |   0
 .../proofs/membership_def/thm_proof.ipynb     | 105 ----
 .../allowed_presumptions.txt                  |   2 -
 .../disallowed_presumptions.txt               |   0
 .../proofs/membership_folding/thm_proof.ipynb |  95 ----
 .../allowed_presumptions.txt                  |   2 -
 .../disallowed_presumptions.txt               |   0
 .../membership_unfolding/thm_proof.ipynb      |  95 ----
 .../allowed_presumptions.txt                  |   0
 .../disallowed_presumptions.txt               |   0
 .../proofs/nonmembership_def/thm_proof.ipynb  | 105 ----
 .../allowed_presumptions.txt                  |   2 -
 .../disallowed_presumptions.txt               |   0
 .../nonmembership_folding/thm_proof.ipynb     |  95 ----
 .../allowed_presumptions.txt                  |   2 -
 .../disallowed_presumptions.txt               |   0
 .../nonmembership_unfolding/thm_proof.ipynb   |  95 ----
 .../vertices/_theory_nbs_/theorems.ipynb      | 139 -----
 .../{vertices => }/vertices_membership.py     |  38 +-
 .../graphs/{edges => walks}/__init__.py       |   2 +-
 .../graphs/walks/_brief_description_.txt      |   1 +
 .../{edges => walks}/_sub_theories_.txt       |   0
 .../{edges => walks}/_theory_nbs_/__init__.py |   0
 .../_theory_nbs_/axioms.ipynb}                |  10 +-
 .../_theory_nbs_/common.ipynb                 |   2 +-
 .../walks/_theory_nbs_/demonstrations.ipynb   |  47 ++
 .../_theory_nbs_/theorems.ipynb}              |  18 +-
 .../_theory_nbs_/theory.ipynb                 |   4 +-
 81 files changed, 1622 insertions(+), 2147 deletions(-)
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/edges_membership_def/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/edges_membership_folding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/edges_membership_unfolding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/edges_nonmembership_def/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/edges_nonmembership_folding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/edges_nonmembership_unfolding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/even_number_of_odd_vertices/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/total_deg_is_even/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/total_deg_is_twice_num_of_edges/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/vertices_membership_def/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/vertices_membership_folding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/vertices_membership_unfolding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/vertices_nonmembership_def/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/vertices_nonmembership_folding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/vertices_nonmembership_unfolding/thm_proof.ipynb
 rename packages/proveit/graphs/{edges => }/edges.py (71%)
 delete mode 100644 packages/proveit/graphs/edges/_brief_description_.txt
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/axioms.ipynb
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/demonstrations.ipynb
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/allowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/disallowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/thm_proof.ipynb
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/disallowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/disallowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_def/allowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_def/disallowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/disallowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/disallowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/theorems.ipynb
 delete mode 100644 packages/proveit/graphs/edges/_theory_nbs_/theory.ipynb
 rename packages/proveit/graphs/{edges => }/edges_membership.py (67%)
 rename packages/proveit/graphs/{vertices => }/vertices.py (100%)
 delete mode 100644 packages/proveit/graphs/vertices/__init__.py
 delete mode 100644 packages/proveit/graphs/vertices/_brief_description_.txt
 delete mode 100644 packages/proveit/graphs/vertices/_sub_theories_.txt
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/__init__.py
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/axioms.ipynb
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/allowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/disallowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/thm_proof.ipynb
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/disallowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/disallowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/allowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/disallowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/disallowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/disallowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb
 delete mode 100644 packages/proveit/graphs/vertices/_theory_nbs_/theorems.ipynb
 rename packages/proveit/graphs/{vertices => }/vertices_membership.py (82%)
 rename packages/proveit/graphs/{edges => walks}/__init__.py (93%)
 create mode 100644 packages/proveit/graphs/walks/_brief_description_.txt
 rename packages/proveit/graphs/{edges => walks}/_sub_theories_.txt (100%)
 rename packages/proveit/graphs/{edges => walks}/_theory_nbs_/__init__.py (100%)
 rename packages/proveit/graphs/{vertices/_theory_nbs_/common.ipynb => walks/_theory_nbs_/axioms.ipynb} (70%)
 rename packages/proveit/graphs/{edges => walks}/_theory_nbs_/common.ipynb (95%)
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
 rename packages/proveit/graphs/{edges/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb => walks/_theory_nbs_/theorems.ipynb} (58%)
 rename packages/proveit/graphs/{vertices => walks}/_theory_nbs_/theory.ipynb (74%)

diff --git a/packages/proveit/graphs/_brief_description_.txt b/packages/proveit/graphs/_brief_description_.txt
index 3209d67f8161..976dda64228c 100644
--- a/packages/proveit/graphs/_brief_description_.txt
+++ b/packages/proveit/graphs/_brief_description_.txt
@@ -1 +1 @@
-basic graph theory concepts
+basic graph theory concepts for simple graphs
diff --git a/packages/proveit/graphs/_sub_theories_.txt b/packages/proveit/graphs/_sub_theories_.txt
index 29648cf9807e..cf87643d997a 100644
--- a/packages/proveit/graphs/_sub_theories_.txt
+++ b/packages/proveit/graphs/_sub_theories_.txt
@@ -1,8 +1,7 @@
-vertices
-edges
 inclusion
 union
 membership
 paths
 paths_of
 endpoints
+walks
diff --git a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
index 2b7f642ce1bf..6d5e9304870f 100644
--- a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
@@ -18,11 +18,11 @@
     "# Prepare this notebook for defining the axioms of a theory:\n",
     "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "from proveit import E, V\n",
+    "from proveit import v, E, G, V\n",
     "from proveit.logic import Equals, Forall, InClass, InSet\n",
-    "from proveit.logic.sets import CartProd, KPowerSet, SubsetEq\n",
+    "from proveit.logic.sets import Card, KPowerSet, SetOfAll, SubsetEq\n",
     "from proveit.numbers import two\n",
-    "from proveit.graphs import Edges, Graph, Graphs, Vertices\n"
+    "from proveit.graphs import Degree, Edges, Graph, Graphs, Vertices\n"
    ]
   },
   {
@@ -47,6 +47,70 @@
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "vertices_def = (\n",
+    "    Forall(V,\n",
+    "    Forall(E, Equals(Vertices(Graph(V, E)), V), conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "edges_def = (\n",
+    "    Forall(V,\n",
+    "    Forall(E, Equals(Edges(Graph(V, E)), E), conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "##### Characterizing an edge: An edge in a graph $G(V, E)$ is a 2-element subset of the vertex set $V$. The set of 2-element subsets of $V$ is denoted by $[V]^{2}$."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Forall(G, SubsetEq(Edges(G), KPowerSet(Vertices(G), two)), domain = Graphs())"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "##### The _degree_ of a vertex $v$ in a graph $G$, denoted $\\text{deg}_{G}(v)$, is defined as the number of edges incident with the vertex $v$. We can formulate this in different ways, but one fairly efficient formulation looks like this:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "vertex_deg_def = (\n",
+    "        Forall(G, Forall(v,\n",
+    "                    Equals(\n",
+    "                        Degree(v, G),\n",
+    "                        Card(SetOfAll(E, E, condition = InSet(v, E), domain = Edges(G)))),\n",
+    "        domain = Vertices(G)), domain = Graphs())\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
index 66649c3a4757..24e8bf2d1fde 100644
--- a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
@@ -15,9 +15,10 @@
    "outputs": [],
    "source": [
     "import proveit\n",
-    "from proveit import x, E, G, V\n",
-    "from proveit.logic import InClass\n",
-    "from proveit.graphs import Endpoints, Graph, Graphs, Path\n",
+    "from proveit import e, v, x, E, G, P, V\n",
+    "from proveit.logic import InClass, InSet, KPowerSet, NotInSet, SubsetEq\n",
+    "from proveit.numbers import two\n",
+    "from proveit.graphs import Degree, Edges, Endpoints, Graph, Graphs, Path, Vertices\n",
     "%begin demonstrations"
    ]
   },
@@ -25,7 +26,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "## Graphs and Related Constructions & Methods $G = \\textrm{Graph}(V, E)$"
+    "## Graphs, Vertices, Edges, and Related Constructions & Methods $G = \\textrm{Graph}(V, E)$"
    ]
   },
   {
@@ -60,7 +61,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "example_path = Path(V, E)"
+    "P = Path(V, E)"
    ]
   },
   {
@@ -69,7 +70,479 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "example_endpts = Endpoints(example_path)"
+    "example_endpts = Endpoints(P)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Vertices of a Graph $G$: $\\mathrm{Vertices}(\\mathrm{Graph}(V, E)) = V$"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### General Constructions"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G = Graph(V, E)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Vertices(G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Vertices(G))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(v, Vertices(G))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Degree(v, G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Vertices(P)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Vertices(P))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### VerticesMembership methods"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`VerticesMembership.definition()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Vertices(Graph(V, E))).definition(assumptions = [SubsetEq(E, KPowerSet(V, two))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Vertices(G)).definition(assumptions = [SubsetEq(E, KPowerSet(V, two))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`VerticesMembership.as_defined()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Vertices(G)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# the domain's argument must be an explicit Graph with specified vertex set\n",
+    "from proveit import H\n",
+    "try:\n",
+    "    InSet(v, Vertices(H)).as_defined()\n",
+    "except Exception as the_exception:\n",
+    "    print(f\"Exception: {the_exception}\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`VerticesMembership.unfold()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Vertices(G)).unfold(assumptions = [SubsetEq(E, KPowerSet(V, two)), InSet(v, Vertices(G))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`VerticesMembership.conclude()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(v, Vertices(G)).conclude(assumptions = [SubsetEq(E, KPowerSet(V, two)), InSet(v, V)])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Vertices Nonmembership methods"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`VerticesNonmembership.definition()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(v, Vertices(G)).definition(assumptions = [SubsetEq(E, KPowerSet(V, two))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`VerticesNonmembership.as_defined()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(v, Vertices(G)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# the domain's argument must be an explicit Graph with specified vertex set\n",
+    "from proveit import H\n",
+    "try:\n",
+    "    NotInSet(v, Vertices(H)).as_defined()\n",
+    "except Exception as the_exception:\n",
+    "    print(f\"Exception: {the_exception}\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`VerticesNonmembership.unfold()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(v, Vertices(G)).unfold(assumptions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(v, Vertices(G))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`VerticesNonmembership.conclude()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(v, Vertices(G)).conclude(assumptions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(v, V)])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Edges of a Graph $G$: $\\mathrm{Edges}(\\mathrm{G}(V, E)) = E$"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Basic Constructions"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "G = Graph(V, E)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Edges(G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(e, Edges(G))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(e, Edges(G))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### EdgesMembership methods"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EdgesMembership.definition()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(e, Edges(G)).definition(assumptions = [SubsetEq(E, KPowerSet(V, two))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EdgesMembership.as_defined()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(e, Edges(G)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "try:\n",
+    "    InSet(e, Edges(H)).as_defined()\n",
+    "except Exception as the_exception:\n",
+    "    print(f\"Exception: {the_exception}\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EdgesMembership.unfold()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(e, Edges(G)).unfold(assumptions = [SubsetEq(E, KPowerSet(V, two)), InSet(e, Edges(G))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EdgesMembership.conclude()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(e, Edges(G)).conclude(assumptions = [SubsetEq(E, KPowerSet(V, two)), InSet(e, E)])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Nonmembership methods"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EdgesNonmembership.definition()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(e, Edges(G)).definition(assumptions = [SubsetEq(E, KPowerSet(V, two))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EdgesNonmembership.as_defined()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(e, Edges(G)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "try:\n",
+    "    NotInSet(e, Edges(H)).as_defined()\n",
+    "except Exception as the_exception:\n",
+    "    print(f\"Exception: {the_exception}\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EdgesNonmembership.unfold()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(e, Edges(G)).unfold(assumptions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(e, Edges(G))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`EdgesNonmembership.conclude()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NotInSet(e, Edges(G)).conclude(assumptions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(e, E)])"
    ]
   },
   {
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/edges_membership_def/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/edges_membership_def/thm_proof.ipynb
new file mode 100644
index 000000000000..25120d639192
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/edges_membership_def/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#edges_membership_def\">edges_membership_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving edges_membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/edges_membership_folding/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/edges_membership_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..2047bcc97c7e
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/edges_membership_folding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#edges_membership_folding\">edges_membership_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving edges_membership_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/edges_membership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/edges_membership_unfolding/thm_proof.ipynb
new file mode 100644
index 000000000000..80df877c10b8
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/edges_membership_unfolding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#edges_membership_unfolding\">edges_membership_unfolding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving edges_membership_unfolding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/edges_nonmembership_def/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/edges_nonmembership_def/thm_proof.ipynb
new file mode 100644
index 000000000000..e2668d8490a7
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/edges_nonmembership_def/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#edges_nonmembership_def\">edges_nonmembership_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving edges_nonmembership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/edges_nonmembership_folding/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/edges_nonmembership_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..6a0e43aa29db
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/edges_nonmembership_folding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#edges_nonmembership_folding\">edges_nonmembership_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving edges_nonmembership_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/edges_nonmembership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/edges_nonmembership_unfolding/thm_proof.ipynb
new file mode 100644
index 000000000000..24900f7ddd6a
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/edges_nonmembership_unfolding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#edges_nonmembership_unfolding\">edges_nonmembership_unfolding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving edges_nonmembership_unfolding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/even_number_of_odd_vertices/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/even_number_of_odd_vertices/thm_proof.ipynb
new file mode 100644
index 000000000000..f92a06557af2
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/even_number_of_odd_vertices/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#even_number_of_odd_vertices\">even_number_of_odd_vertices</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving even_number_of_odd_vertices"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/total_deg_is_even/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/total_deg_is_even/thm_proof.ipynb
new file mode 100644
index 000000000000..cc93b5b2c789
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/total_deg_is_even/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#total_deg_is_even\">total_deg_is_even</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving total_deg_is_even"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/total_deg_is_twice_num_of_edges/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/total_deg_is_twice_num_of_edges/thm_proof.ipynb
new file mode 100644
index 000000000000..99fc3622f1b4
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/total_deg_is_twice_num_of_edges/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#total_deg_is_twice_num_of_edges\">total_deg_is_twice_num_of_edges</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving total_deg_is_twice_num_of_edges"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/vertices_membership_def/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/vertices_membership_def/thm_proof.ipynb
new file mode 100644
index 000000000000..445e5a13ce5d
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/vertices_membership_def/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#vertices_membership_def\">vertices_membership_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving vertices_membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/vertices_membership_folding/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/vertices_membership_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..3beb72dc1de4
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/vertices_membership_folding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#vertices_membership_folding\">vertices_membership_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving vertices_membership_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/vertices_membership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/vertices_membership_unfolding/thm_proof.ipynb
new file mode 100644
index 000000000000..280371a5d8f4
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/vertices_membership_unfolding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#vertices_membership_unfolding\">vertices_membership_unfolding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving vertices_membership_unfolding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/vertices_nonmembership_def/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/vertices_nonmembership_def/thm_proof.ipynb
new file mode 100644
index 000000000000..eae92b761ae7
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/vertices_nonmembership_def/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#vertices_nonmembership_def\">vertices_nonmembership_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving vertices_nonmembership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/vertices_nonmembership_folding/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/vertices_nonmembership_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..fa0c232fbc7a
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/vertices_nonmembership_folding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#vertices_nonmembership_folding\">vertices_nonmembership_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving vertices_nonmembership_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/vertices_nonmembership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/vertices_nonmembership_unfolding/thm_proof.ipynb
new file mode 100644
index 000000000000..30759e7d2b3f
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/vertices_nonmembership_unfolding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#vertices_nonmembership_unfolding\">vertices_nonmembership_unfolding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving vertices_nonmembership_unfolding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
index 21d1714cea56..7e73feae3130 100644
--- a/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
@@ -18,7 +18,12 @@
     "# Prepare this notebook for defining the theorems of a theory:\n",
     "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "# from ... import ..."
+    "# from ... import ...\n",
+    "from proveit import e, v, E, G, V\n",
+    "from proveit.logic import Equals, Forall, InSet, InClass, NotInSet\n",
+    "from proveit.logic.sets import Card, KPowerSet, SetOfAll, SubsetEq\n",
+    "from proveit.numbers import two, IntegerEven, IntegerOdd, Mult, Sum\n",
+    "from proveit.graphs import Degree, Edges, Graph, Graphs, Vertices"
    ]
   },
   {
@@ -30,6 +35,242 @@
     "%begin theorems"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Total Degree of Graph $G$.\n",
+    "##### The _total degree_ of a graph $G$ is twice the number of edges in $G$ (this is what Chartrand & Zhang (2012, pg 32) call “The First Theorem of Graph Theory”). "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "total_deg_is_twice_num_of_edges = (\n",
+    "        Forall(G, Equals(Sum(v, Degree(v, G), domain = Vertices(G)),\n",
+    "                         Mult(two, Card(Edges(G)))),\n",
+    "        domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "##### An immediate corollary to the First Theorem is that the total degree is alway even."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "total_deg_is_even = (\n",
+    "        Forall(G, InSet(Sum(v, Degree(v, G), domain = Vertices(G)),\n",
+    "                         IntegerEven),\n",
+    "        domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "##### And because the total degree is always even, there must be an even number of odd-degree vertices."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "even_number_of_odd_vertices = (\n",
+    "        Forall(G,\n",
+    "        InSet(Card(SetOfAll(v, v, condition = InSet(Degree(v, G), IntegerOdd), domain = Vertices(G))),\n",
+    "              IntegerEven),\n",
+    "        domain = Graphs()\n",
+    "        )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Membership Theorems for Vertex and Edge sets $V$ and $E$"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "vertices_membership_def = (\n",
+    "    Forall((v, V),\n",
+    "    Forall(E, Equals(InSet(v, Vertices(Graph(V, E))), InSet(v, V)), conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "vertices_membership_unfolding = (\n",
+    "    Forall(V,\n",
+    "        Forall((v, E), InSet(v, V),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two)), InSet(v, Vertices(Graph(V, E)))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "vertices_membership_folding = (\n",
+    "    Forall(V,\n",
+    "        Forall((v, E), InSet(v, Vertices(Graph(V, E))),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two)), InSet(v, V)])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "vertices_nonmembership_def = (\n",
+    "    Forall(V,\n",
+    "        Forall((v, E), Equals(NotInSet(v, Vertices(Graph(V, E))), NotInSet(v, V)),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "vertices_nonmembership_unfolding = (\n",
+    "    Forall(V,\n",
+    "        Forall((v, E), NotInSet(v, V),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(v, Vertices(Graph(V, E)))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "vertices_nonmembership_folding = (\n",
+    "    Forall(V,\n",
+    "        Forall((v, E), NotInSet(v, Vertices(Graph(V, E))),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(v, V)])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "edges_membership_def = (\n",
+    "    Forall(V,\n",
+    "    Forall((e, E), Equals(InSet(e, Edges(Graph(V, E))), InSet(e, E)), conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "edges_membership_unfolding = (\n",
+    "    Forall(V,\n",
+    "        Forall((e, E), InSet(e, E),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two)), InSet(e, Edges(Graph(V, E)))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "edges_membership_folding = (\n",
+    "    Forall(V,\n",
+    "        Forall((e, E), InSet(e, Edges(Graph(V, E))),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two)), InSet(e, E)])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "edges_nonmembership_def = (\n",
+    "    Forall(V,\n",
+    "        Forall((e, E), Equals(NotInSet(e, Edges(Graph(V, E))), NotInSet(e, E)),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "edges_nonmembership_unfolding = (\n",
+    "    Forall(V,\n",
+    "        Forall((e, E), NotInSet(e, E),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(e, Edges(Graph(V, E)))])\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "edges_nonmembership_folding = (\n",
+    "    Forall(V,\n",
+    "        Forall((e, E), NotInSet(e, Edges(Graph(V, E))),\n",
+    "               conditions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(e, E)])\n",
+    "    )\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/_theory_nbs_/theory.ipynb b/packages/proveit/graphs/_theory_nbs_/theory.ipynb
index 8357d51ace91..116597aac7d5 100644
--- a/packages/proveit/graphs/_theory_nbs_/theory.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/theory.ipynb
@@ -7,7 +7,7 @@
     "Theory of <a class=\"ProveItLink\" href=\"../../_theory_nbs_/theory.ipynb\">proveit</a>.graphs\n",
     "========\n",
     "\n",
-    "Basic concepts in graph theory."
+    "Basic concepts in graph theory for undirected simple graphs (undirected graphs without loops and without parallel edges)."
    ]
   },
   {
diff --git a/packages/proveit/graphs/edges/edges.py b/packages/proveit/graphs/edges.py
similarity index 71%
rename from packages/proveit/graphs/edges/edges.py
rename to packages/proveit/graphs/edges.py
index b43bf03db4c3..36c7d1b8d0a3 100644
--- a/packages/proveit/graphs/edges/edges.py
+++ b/packages/proveit/graphs/edges.py
@@ -3,11 +3,9 @@
 class Edges(Function):
     '''
     Given a graph G(V, E) with vertex set V and edge set E,
-    Edges(G(V, E)) represents the set E of vertices ---
-    that is, Edges(G(V,E)) = E. The notation will use E(G),
-    in which case we might see things like E(G) = E, but the operator
-    E will appear in mathrm to distinguish it from the set E in
-    italics.
+    Edges(G(V, E)) represents the set E of edges ---
+    that is, Edges(G(V,E)) = E. The notation will use Edges(G),
+    in which case we might see things like Edges(G) = E.
     '''
 
     # the literal operator of the Vertices operation
@@ -17,7 +15,7 @@ class Edges(Function):
 
     def __init__(self, G, *, styles=None):
         '''
-        Given a graph G(V,E) = (V,E), represent the edge set of G.
+        Given a graph G = Graph(V,E), represent the edge set of G.
         '''
         self.graph = G
         Function.__init__(
diff --git a/packages/proveit/graphs/edges/_brief_description_.txt b/packages/proveit/graphs/edges/_brief_description_.txt
deleted file mode 100644
index f030605d7a3d..000000000000
--- a/packages/proveit/graphs/edges/_brief_description_.txt
+++ /dev/null
@@ -1 +0,0 @@
-basic concepts involving edges in a graph
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/axioms.ipynb
deleted file mode 100644
index 4a6c2b0f6c5f..000000000000
--- a/packages/proveit/graphs/edges/_theory_nbs_/axioms.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Axioms for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.edges</a>\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "# Prepare this notebook for defining the axioms of a theory:\n",
-    "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
-    "\n",
-    "from proveit import E, V\n",
-    "from proveit.logic import Equals, Forall\n",
-    "from proveit.logic.sets import KPowerSet, SubsetEq\n",
-    "from proveit.numbers import two\n",
-    "from proveit.graphs import Graph, Edges"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%begin axioms"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "edges_def = (\n",
-    "    Forall(V,\n",
-    "    Forall(E, Equals(Edges(Graph(V, E)), E), conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
-    "    )\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%end axioms"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/demonstrations.ipynb
deleted file mode 100644
index 48c3570a2a63..000000000000
--- a/packages/proveit/graphs/edges/_theory_nbs_/demonstrations.ipynb
+++ /dev/null
@@ -1,245 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Demonstrations for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.edges</a>\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "%begin demonstrations\n",
-    "\n",
-    "from proveit import e, E, G, P, V\n",
-    "from proveit.logic import InSet, NotInSet, SubsetEq\n",
-    "from proveit.logic.sets import KPowerSet\n",
-    "from proveit.numbers import two\n",
-    "from proveit.graphs import Graph, Edges"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "### Edges of Graph $G$: $\\mathrm{E}(\\mathrm{G}(V, E)) = E$"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "#### MISC. TESTING"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "#### Basic Constructions"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "G = Graph(V, E)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "Edges(G)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(e, Edges(G))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "NotInSet(e, Edges(G))"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "#### Testing Membership methods"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`EdgesMembership.definition()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(e, Edges(G)).definition(assumptions = [SubsetEq(E, KPowerSet(V, two))])"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`EdgesMembership.as_defined()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(e, Edges(G)).as_defined()"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`EdgesMembership.unfold()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(e, Edges(G)).unfold(assumptions = [SubsetEq(E, KPowerSet(V, two)), InSet(e, Edges(G))])"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`EdgesMembership.conclude()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(e, Edges(G)).conclude(assumptions = [SubsetEq(E, KPowerSet(V, two)), InSet(e, E)])"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "#### Testing Nonmembership methods"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`EdgesNonmembership.definition()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "NotInSet(e, Edges(G)).definition(assumptions = [SubsetEq(E, KPowerSet(V, two))])"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`EdgesNonmembership.as_defined()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "NotInSet(e, Edges(G)).as_defined()"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`EdgesNonmembership.unfold()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "NotInSet(e, Edges(G)).unfold(assumptions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(e, Edges(G))])"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`EdgesNonmembership.conclude()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "NotInSet(e, Edges(G)).conclude(assumptions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(e, E)])"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%end demonstrations"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/allowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/allowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/disallowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/disallowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/thm_proof.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/thm_proof.ipynb
deleted file mode 100644
index 37b6eac26709..000000000000
--- a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_def/thm_proof.ipynb
+++ /dev/null
@@ -1,98 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">edges</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_def\">membership_def</a> theorem\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "theory = proveit.Theory() # the theorem's theory\n",
-    "\n",
-    "from proveit import e, X, defaults, Lambda\n",
-    "from proveit.logic.sets import InSet\n",
-    "from proveit.graphs.edges import edges_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%proving membership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "defaults.assumptions = membership_def.all_conditions()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "edges_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "edges_def_inst = edges_def.instantiate().instantiate()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "subst_lambda = Lambda(X, InSet(e, X))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "edges_def_inst.substitution(subst_lambda)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%qed"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
deleted file mode 100644
index ddeb342add31..000000000000
--- a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-proveit.graphs.edges.membership_def
-proveit.logic.equality.lhs_via_equality
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/disallowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/disallowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
deleted file mode 100644
index 97b9992173ac..000000000000
--- a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
+++ /dev/null
@@ -1,88 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">edges</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_folding\">membership_folding</a> theorem\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "theory = proveit.Theory() # the theorem's theory\n",
-    "\n",
-    "from proveit import defaults\n",
-    "from proveit.graphs.edges import membership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%proving membership_folding"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "defaults.assumptions = membership_folding.all_conditions()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_def_inst = membership_def.instantiate().instantiate()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_def_inst.derive_left_via_equality()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%qed"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
deleted file mode 100644
index b4418331dce4..000000000000
--- a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-proveit.graphs.edges.membership_def
-proveit.logic.equality.rhs_via_equality
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/disallowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/disallowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
deleted file mode 100644
index 78ebf51d0369..000000000000
--- a/packages/proveit/graphs/edges/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
+++ /dev/null
@@ -1,88 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">edges</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_unfolding\">membership_unfolding</a> theorem\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "theory = proveit.Theory() # the theorem's theory\n",
-    "\n",
-    "from proveit import defaults\n",
-    "from proveit.graphs.edges import membership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%proving membership_unfolding"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "defaults.assumptions = membership_unfolding.all_conditions()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_def_inst = membership_def.instantiate().instantiate()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_def_inst.derive_right_via_equality()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%qed"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_def/allowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_def/allowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_def/disallowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_def/disallowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt
deleted file mode 100644
index 4ca789ee9bbd..000000000000
--- a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-proveit.graphs.edges.nonmembership_def
-proveit.logic.equality.lhs_via_equality
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/disallowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/disallowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
deleted file mode 100644
index 88409bd17ede..000000000000
--- a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
+++ /dev/null
@@ -1,88 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">edges</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_folding\">nonmembership_folding</a> theorem\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "theory = proveit.Theory() # the theorem's theory\n",
-    "\n",
-    "from proveit import defaults\n",
-    "from proveit.graphs.edges import nonmembership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%proving nonmembership_folding"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "defaults.assumptions = nonmembership_folding.all_conditions()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def_inst = nonmembership_def.instantiate().instantiate()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def_inst.derive_left_via_equality()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%qed"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt
deleted file mode 100644
index 6a5ce129b5ee..000000000000
--- a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-proveit.graphs.edges.nonmembership_def
-proveit.logic.equality.rhs_via_equality
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/disallowed_presumptions.txt b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/disallowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb
deleted file mode 100644
index 58493897d840..000000000000
--- a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb
+++ /dev/null
@@ -1,88 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">edges</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_unfolding\">nonmembership_unfolding</a> theorem\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "theory = proveit.Theory() # the theorem's theory\n",
-    "\n",
-    "from proveit import defaults\n",
-    "from proveit.graphs.edges import nonmembership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%proving nonmembership_unfolding"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "defaults.assumptions = nonmembership_unfolding.all_conditions()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def_inst = nonmembership_def.instantiate().instantiate()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def_inst.derive_right_via_equality()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%qed"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/theorems.ipynb
deleted file mode 100644
index 1ccf7057fd79..000000000000
--- a/packages/proveit/graphs/edges/_theory_nbs_/theorems.ipynb
+++ /dev/null
@@ -1,139 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Theorems (or conjectures) for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.edges</a>\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "# Prepare this notebook for defining the theorems of a theory:\n",
-    "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
-    "\n",
-    "from proveit import e, E, V\n",
-    "from proveit.logic import Equals, Forall\n",
-    "from proveit.logic.sets import InSet, KPowerSet, NotInSet, SubsetEq\n",
-    "from proveit.numbers import two\n",
-    "from proveit.graphs import Graph, Edges"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%begin theorems"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_def = (\n",
-    "    Forall(V,\n",
-    "    Forall((e, E), Equals(InSet(e, Edges(Graph(V, E))), InSet(e, E)), conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
-    "    )\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_unfolding = (\n",
-    "    Forall(V,\n",
-    "        Forall((e, E), InSet(e, E),\n",
-    "               conditions = [SubsetEq(E, KPowerSet(V, two)), InSet(e, Edges(Graph(V, E)))])\n",
-    "    )\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_folding = (\n",
-    "    Forall(V,\n",
-    "        Forall((e, E), InSet(e, Edges(Graph(V, E))),\n",
-    "               conditions = [SubsetEq(E, KPowerSet(V, two)), InSet(e, E)])\n",
-    "    )\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def = (\n",
-    "    Forall(V,\n",
-    "        Forall((e, E), Equals(NotInSet(e, Edges(Graph(V, E))), NotInSet(e, E)),\n",
-    "               conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
-    "    )\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_unfolding = (\n",
-    "    Forall(V,\n",
-    "        Forall((e, E), NotInSet(e, E),\n",
-    "               conditions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(e, Edges(Graph(V, E)))])\n",
-    "    )\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_folding = (\n",
-    "    Forall(V,\n",
-    "        Forall((e, E), NotInSet(e, Edges(Graph(V, E))),\n",
-    "               conditions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(e, E)])\n",
-    "    )\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%end theorems"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/theory.ipynb b/packages/proveit/graphs/edges/_theory_nbs_/theory.ipynb
deleted file mode 100644
index 9f2732a2722c..000000000000
--- a/packages/proveit/graphs/edges/_theory_nbs_/theory.ipynb
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Theory of <a class=\"ProveItLink\" href=\"../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../_theory_nbs_/theory.ipynb\">graphs</a>.edges\n",
-    "========\n",
-    "\n",
-    "Provide description here."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "%theory # toggles between interactive and static modes"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/edges/edges_membership.py b/packages/proveit/graphs/edges_membership.py
similarity index 67%
rename from packages/proveit/graphs/edges/edges_membership.py
rename to packages/proveit/graphs/edges_membership.py
index 2df527078327..634c32fbea31 100644
--- a/packages/proveit/graphs/edges/edges_membership.py
+++ b/packages/proveit/graphs/edges_membership.py
@@ -1,5 +1,6 @@
 from proveit import e, E, V, equality_prover, prover
 from proveit.logic import SetMembership, SetNonmembership
+from proveit.graphs import Graph
 
 
 class EdgesMembership(SetMembership):
@@ -17,12 +18,11 @@ def definition(self, **defaults_config):
         From self = [elem in Edges(Graph(V,E))], deduce and return:
             [elem in Edges(Graph(V,E))] = [elem in E]
         '''
-
-        from . import membership_def
+        from . import edges_membership_def
         element = self.element
         _V_sub  = self.domain.graph.vertex_set
         _E_sub  = self.domain.graph.edge_set
-        return membership_def.instantiate(
+        return edges_membership_def.instantiate(
                 {e:element, V:_V_sub, E:_E_sub },auto_simplify=False)
 
     def as_defined(self):
@@ -30,10 +30,18 @@ def as_defined(self):
         From self = [elem in Edges(Graph(V,E))], return: [elem in E]
         (i.e. an expression, not a Judgment)
         '''
-        from proveit.logic import InSet
-        element = self.element
-        _E = self.domain.graph.edge_set
-        return InSet(element, _E)
+        if isinstance(self.domain.operand, Graph):
+            from proveit.logic import InSet
+            element = self.element
+            _E = self.domain.graph.edge_set
+            return InSet(element, _E)
+        else:
+            raise NotImplementedError(
+                "EdgesMembership.as_defined() was called on "
+                f"self = {self.expr} with domain = {self.expr.domain}, "
+                "but the method is implemented only for domains of the "
+                "form Edges(G) where G is an explicit Graph object "
+                "of the form G = Graph(V,E) with a named edge set E.")
 
     @prover
     def unfold(self, **defaults_config):
@@ -41,11 +49,11 @@ def unfold(self, **defaults_config):
         From self = [elem in Edges(Graph(V,E))],
         derive and return [elem in E], knowing or assuming self.
         '''
-        from . import membership_unfolding
+        from . import edges_membership_unfolding
         element = self.element
         _V_sub  = self.domain.graph.vertex_set
         _E_sub  = self.domain.graph.edge_set
-        return membership_unfolding.instantiate(
+        return edges_membership_unfolding.instantiate(
             {e:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
 
     @prover
@@ -56,11 +64,11 @@ def conclude(self, **defaults_config):
         of [V]^2, a subset of the set of 2-element subsets of V)
         derive and return self.
         '''
-        from . import membership_folding
+        from . import edges_membership_folding
         element = self.element
         _V_sub  = self.domain.graph.vertex_set
         _E_sub  = self.domain.graph.edge_set
-        return membership_folding.instantiate(
+        return edges_membership_folding.instantiate(
             {e:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
 
 
@@ -87,11 +95,11 @@ def definition(self, **defaults_config):
         return: [elem not in Edges(Graph(V,E))] = [elem not in E].
         '''
 
-        from . import nonmembership_def
+        from . import edges_nonmembership_def
         element = self.element
         _V_sub  = self.domain.graph.vertex_set
         _E_sub  = self.domain.graph.edge_set
-        return nonmembership_def.instantiate(
+        return edges_nonmembership_def.instantiate(
                 {e:element, V:_V_sub, E:_E_sub },auto_simplify=False)
 
     def as_defined(self):
@@ -99,10 +107,18 @@ def as_defined(self):
         From self = [elem not in Edges(Graph(V,E))],
         return: [elem not in E] (i.e. an expression, not a Judgment)
         '''
-        from proveit.logic import NotInSet
-        element = self.element
-        _E = self.domain.graph.edge_set
-        return NotInSet(element, _E)
+        if isinstance(self.domain.operand, Graph):
+            from proveit.logic import NotInSet
+            element = self.element
+            _E = self.domain.graph.edge_set
+            return NotInSet(element, _E)
+        else:
+            raise NotImplementedError(
+                "EdgesNonmembership.as_defined() was called on "
+                f"self = {self.expr} with domain = {self.expr.domain}, "
+                "but the method is implemented only for domains of the "
+                "form Edges(G) where G is an explicit Graph object "
+                "of the form G = Graph(V,E) with a named edge set E.")
 
     @prover
     def unfold(self, **defaults_config):
@@ -112,11 +128,11 @@ def unfold(self, **defaults_config):
         (and that E is a subset of [V]^2, i.e., a subset of the set
         of 2-element subsets of V).
         '''
-        from . import nonmembership_unfolding
+        from . import edges_nonmembership_unfolding
         element = self.element
         _V_sub  = self.domain.graph.vertex_set
         _E_sub  = self.domain.graph.edge_set
-        return nonmembership_unfolding.instantiate(
+        return edges_nonmembership_unfolding.instantiate(
             {e:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
 
     @prover
@@ -127,10 +143,10 @@ def conclude(self, **defaults_config):
         of [V]^2, a subset of the set of 2-element subsets of V)
         derive and return self.
         '''
-        from . import nonmembership_folding
+        from . import edges_nonmembership_folding
         element = self.element
         _V_sub  = self.domain.graph.vertex_set
         _E_sub  = self.domain.graph.edge_set
-        return nonmembership_folding.instantiate(
+        return edges_nonmembership_folding.instantiate(
             {e:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
 
diff --git a/packages/proveit/graphs/vertices/vertices.py b/packages/proveit/graphs/vertices.py
similarity index 100%
rename from packages/proveit/graphs/vertices/vertices.py
rename to packages/proveit/graphs/vertices.py
diff --git a/packages/proveit/graphs/vertices/__init__.py b/packages/proveit/graphs/vertices/__init__.py
deleted file mode 100644
index b79b83996227..000000000000
--- a/packages/proveit/graphs/vertices/__init__.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from .vertices import Degree, Vertices
-
-# KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
-#  Make additions above, or add to sys.modules[__name__].__dict__ below.
-# This allows us to import common expression, axioms, and theorems of
-# the theory package directly from the package.
-import sys
-from proveit._core_.theory import TheoryPackage
-sys.modules[__name__] = TheoryPackage(__name__, __file__, locals())
diff --git a/packages/proveit/graphs/vertices/_brief_description_.txt b/packages/proveit/graphs/vertices/_brief_description_.txt
deleted file mode 100644
index b7e26aef2066..000000000000
--- a/packages/proveit/graphs/vertices/_brief_description_.txt
+++ /dev/null
@@ -1 +0,0 @@
-basic concepts involving vertices in a graph
diff --git a/packages/proveit/graphs/vertices/_sub_theories_.txt b/packages/proveit/graphs/vertices/_sub_theories_.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/__init__.py b/packages/proveit/graphs/vertices/_theory_nbs_/__init__.py
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/axioms.ipynb
deleted file mode 100644
index 99f37e6de565..000000000000
--- a/packages/proveit/graphs/vertices/_theory_nbs_/axioms.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Axioms for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.vertices</a>\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "# Prepare this notebook for defining the axioms of a theory:\n",
-    "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
-    "\n",
-    "from proveit import E, V\n",
-    "from proveit.logic import Equals, Forall\n",
-    "from proveit.logic.sets import KPowerSet, SubsetEq\n",
-    "from proveit.numbers import two\n",
-    "from proveit.graphs import Graph, Vertices"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%begin axioms"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "vertices_def = (\n",
-    "    Forall(V,\n",
-    "    Forall(E, Equals(Vertices(Graph(V, E)), V), conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
-    "    )\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%end axioms"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
deleted file mode 100644
index e0a009279c08..000000000000
--- a/packages/proveit/graphs/vertices/_theory_nbs_/demonstrations.ipynb
+++ /dev/null
@@ -1,308 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Demonstrations for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.vertices</a>\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "%begin demonstrations\n",
-    "\n",
-    "from proveit import v, E, G, P, V\n",
-    "from proveit.logic.sets import NotInSet, InSet, KPowerSet, SubsetEq\n",
-    "from proveit.numbers import two\n",
-    "from proveit.graphs import Degree, Graph, Vertices"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "### Vertices of Graph $G$: $\\mathrm{Vertices}(\\mathrm{Graph}(V, E)) = V$"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "#### MISC. TESTING"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "#### Basic Constructions"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "G = Graph(V, E)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "Vertices(G)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(v, Vertices(G))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "NotInSet(v, Vertices(G))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "Degree(v, G)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "Vertices(P)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(v, Vertices(P))"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "#### Testing Membership methods"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`VerticesMembership.definition()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(v, Vertices(Graph(V, E))).definition(assumptions = [SubsetEq(E, KPowerSet(V, two))])"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(v, Vertices(G)).definition(assumptions = [SubsetEq(E, KPowerSet(V, two))])"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`VerticesMembership.as_defined()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(v, Vertices(G)).as_defined()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# the domain's argument must be an explicit Graph with specified vertex set\n",
-    "from proveit import H\n",
-    "try:\n",
-    "    InSet(v, Vertices(H)).as_defined()\n",
-    "except Exception as the_exception:\n",
-    "    print(f\"Exception: {the_exception}\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`VerticesMembership.unfold()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(v, Vertices(G)).unfold(assumptions = [SubsetEq(E, KPowerSet(V, two)), InSet(v, Vertices(G))])"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`VerticesMembership.conclude()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(v, Vertices(G)).conclude(assumptions = [SubsetEq(E, KPowerSet(V, two)), InSet(v, V)])"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "#### Testing Nonmembership methods"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`VerticesNonmembership.definition()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "NotInSet(v, Vertices(G)).definition(assumptions = [SubsetEq(E, KPowerSet(V, two))])"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`VerticesNonmembership.as_defined()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "NotInSet(v, Vertices(G)).as_defined()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# the domain's argument must be an explicit Graph with specified vertex set\n",
-    "from proveit import H\n",
-    "try:\n",
-    "    NotInSet(v, Vertices(H)).as_defined()\n",
-    "except Exception as the_exception:\n",
-    "    print(f\"Exception: {the_exception}\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`VerticesNonmembership.unfold()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "NotInSet(v, Vertices(G)).unfold(assumptions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(v, Vertices(G))])"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`VerticesNonmembership.conclude()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "NotInSet(v, Vertices(G)).conclude(assumptions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(v, V)])"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%end demonstrations"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/allowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/allowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/disallowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/disallowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/thm_proof.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/thm_proof.ipynb
deleted file mode 100644
index 81c3a941bace..000000000000
--- a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_def/thm_proof.ipynb
+++ /dev/null
@@ -1,105 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">vertices</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_def\">membership_def</a> theorem\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "theory = proveit.Theory() # the theorem's theory\n",
-    "\n",
-    "from proveit import v, X, V, defaults, Lambda\n",
-    "from proveit.logic import InSet\n",
-    "from proveit.graphs.vertices import vertices_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%proving membership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "defaults.assumptions = membership_def.all_conditions()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "vertices_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "vertices_def_inst = vertices_def.instantiate().instantiate()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "subst_lambda = Lambda(X, InSet(v, X))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "vertices_def_inst.substitution(subst_lambda)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%qed"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
deleted file mode 100644
index ba8ca63a6c5a..000000000000
--- a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-proveit.graphs.vertices.membership_def
-proveit.logic.equality.lhs_via_equality
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/disallowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/disallowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
deleted file mode 100644
index 3230ad107abf..000000000000
--- a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
+++ /dev/null
@@ -1,95 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">vertices</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_folding\">membership_folding</a> theorem\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "theory = proveit.Theory() # the theorem's theory\n",
-    "\n",
-    "from proveit import defaults\n",
-    "from proveit.graphs.vertices import membership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%proving membership_folding"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "defaults.assumptions = membership_folding.all_conditions()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_def_inst =  membership_def.instantiate().instantiate()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_def_inst.derive_left_via_equality()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%qed"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
deleted file mode 100644
index d592d98ccdde..000000000000
--- a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-proveit.graphs.vertices.membership_def
-proveit.logic.equality.rhs_via_equality
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/disallowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/disallowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
deleted file mode 100644
index 42aedaa25511..000000000000
--- a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
+++ /dev/null
@@ -1,95 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">vertices</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_unfolding\">membership_unfolding</a> theorem\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "theory = proveit.Theory() # the theorem's theory\n",
-    "\n",
-    "from proveit import defaults\n",
-    "from proveit.graphs.vertices import membership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%proving membership_unfolding"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "defaults.assumptions = membership_unfolding.all_conditions()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_def_inst = membership_def.instantiate().instantiate()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_def_inst.derive_right_via_equality()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%qed"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/allowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/allowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/disallowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/disallowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb
deleted file mode 100644
index 8513092bd187..000000000000
--- a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb
+++ /dev/null
@@ -1,105 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">vertices</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_def\">nonmembership_def</a> theorem\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "theory = proveit.Theory() # the theorem's theory\n",
-    "\n",
-    "from proveit import v, X, defaults, Lambda\n",
-    "from proveit.logic import NotInSet\n",
-    "from proveit.graphs.vertices import vertices_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%proving nonmembership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "defaults.assumptions = nonmembership_def.all_conditions()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "vertices_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "vertices_def_inst = vertices_def.instantiate().instantiate()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "subst_lambda = Lambda(X, NotInSet(v, X))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "vertices_def_inst.substitution(subst_lambda)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%qed"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt
deleted file mode 100644
index 5855e4ad2662..000000000000
--- a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-proveit.graphs.vertices.nonmembership_def
-proveit.logic.equality.lhs_via_equality
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/disallowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/disallowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
deleted file mode 100644
index f05907202e77..000000000000
--- a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
+++ /dev/null
@@ -1,95 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">vertices</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_folding\">nonmembership_folding</a> theorem\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "theory = proveit.Theory() # the theorem's theory\n",
-    "\n",
-    "from proveit import defaults\n",
-    "from proveit.graphs.vertices import nonmembership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%proving nonmembership_folding"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "defaults.assumptions = nonmembership_folding.all_conditions()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def_inst = nonmembership_def.instantiate().instantiate()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def_inst.derive_left_via_equality()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%qed"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt
deleted file mode 100644
index 9ccaf2367b89..000000000000
--- a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-proveit.graphs.vertices.nonmembership_def
-proveit.logic.equality.rhs_via_equality
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/disallowed_presumptions.txt b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/disallowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb
deleted file mode 100644
index 47539825822e..000000000000
--- a/packages/proveit/graphs/vertices/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb
+++ /dev/null
@@ -1,95 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">vertices</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_unfolding\">nonmembership_unfolding</a> theorem\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "theory = proveit.Theory() # the theorem's theory\n",
-    "\n",
-    "from proveit import defaults\n",
-    "from proveit.graphs.vertices import nonmembership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%proving nonmembership_unfolding"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "defaults.assumptions = nonmembership_unfolding.all_conditions()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def_inst = nonmembership_def.instantiate().instantiate()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def_inst.derive_right_via_equality()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%qed"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/vertices/_theory_nbs_/theorems.ipynb
deleted file mode 100644
index e4c7f0620414..000000000000
--- a/packages/proveit/graphs/vertices/_theory_nbs_/theorems.ipynb
+++ /dev/null
@@ -1,139 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Theorems (or conjectures) for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.vertices</a>\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "# Prepare this notebook for defining the theorems of a theory:\n",
-    "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
-    "\n",
-    "from proveit import v, E, V\n",
-    "from proveit.logic import Equals, Forall\n",
-    "from proveit.logic.sets import InSet, KPowerSet, NotInSet, SubsetEq\n",
-    "from proveit.numbers import two\n",
-    "from proveit.graphs import Graph, Vertices"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%begin theorems"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_def = (\n",
-    "    Forall((v, V),\n",
-    "    Forall(E, Equals(InSet(v, Vertices(Graph(V, E))), InSet(v, V)), conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
-    "    )\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_unfolding = (\n",
-    "    Forall(V,\n",
-    "        Forall((v, E), InSet(v, V),\n",
-    "               conditions = [SubsetEq(E, KPowerSet(V, two)), InSet(v, Vertices(Graph(V, E)))])\n",
-    "    )\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_folding = (\n",
-    "    Forall(V,\n",
-    "        Forall((v, E), InSet(v, Vertices(Graph(V, E))),\n",
-    "               conditions = [SubsetEq(E, KPowerSet(V, two)), InSet(v, V)])\n",
-    "    )\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def = (\n",
-    "    Forall(V,\n",
-    "        Forall((v, E), Equals(NotInSet(v, Vertices(Graph(V, E))), NotInSet(v, V)),\n",
-    "               conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
-    "    )\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_unfolding = (\n",
-    "    Forall(V,\n",
-    "        Forall((v, E), NotInSet(v, V),\n",
-    "               conditions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(v, Vertices(Graph(V, E)))])\n",
-    "    )\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_folding = (\n",
-    "    Forall(V,\n",
-    "        Forall((v, E), NotInSet(v, Vertices(Graph(V, E))),\n",
-    "               conditions = [SubsetEq(E, KPowerSet(V, two)), NotInSet(v, V)])\n",
-    "    )\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%end theorems"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/vertices/vertices_membership.py b/packages/proveit/graphs/vertices_membership.py
similarity index 82%
rename from packages/proveit/graphs/vertices/vertices_membership.py
rename to packages/proveit/graphs/vertices_membership.py
index 0b9308f3c5ea..172555a414cd 100644
--- a/packages/proveit/graphs/vertices/vertices_membership.py
+++ b/packages/proveit/graphs/vertices_membership.py
@@ -19,11 +19,11 @@ def definition(self, **defaults_config):
             [elem in Vertices(Graph(V,E))] = [elem in V]
         '''
 
-        from . import membership_def
+        from . import vertices_membership_def
         element = self.element
         _V_sub  = self.domain.graph.vertex_set
         _E_sub  = self.domain.graph.edge_set
-        return membership_def.instantiate(
+        return vertices_membership_def.instantiate(
                 {v:element, V:_V_sub, E:_E_sub },auto_simplify=False)
 
     def as_defined(self):
@@ -40,11 +40,11 @@ def as_defined(self):
             return InSet(element, _V)
         else:
             raise NotImplementedError(
-                "VerticesMembership.as_defined() called on "
+                "VerticesMembership.as_defined() was called on "
                 f"self = {self.expr} with domain = {self.expr.domain}, "
-                "but the method is implemented only for domains of "
-                "the form Vertices(G) where G is an explicit Graph "
-                "object of the form Graph(V,E) with a named vertex set.")
+                "but the method is implemented only for domains of the "
+                "form Vertices(G) where G is an explicit Graph object "
+                "of the form G = Graph(V,E) with a named vertex set V.")
 
     @prover
     def unfold(self, **defaults_config):
@@ -52,11 +52,11 @@ def unfold(self, **defaults_config):
         From self = [elem in Vertices(Graph(V,E))],
         derive and return [elem in V], knowing or assuming self.
         '''
-        from . import membership_unfolding
+        from . import vertices_membership_unfolding
         element = self.element
         _V_sub  = self.domain.graph.vertex_set
         _E_sub  = self.domain.graph.edge_set
-        return membership_unfolding.instantiate(
+        return vertices_membership_unfolding.instantiate(
             {v:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
 
     @prover
@@ -67,11 +67,11 @@ def conclude(self, **defaults_config):
         of [V]^2, a subset of the set of 2-element subsets of V)
         derive and return self.
         '''
-        from . import membership_folding
+        from . import vertices_membership_folding
         element = self.element
         _V_sub  = self.domain.graph.vertex_set
         _E_sub  = self.domain.graph.edge_set
-        return membership_folding.instantiate(
+        return vertices_membership_folding.instantiate(
             {v:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
 
 
@@ -99,11 +99,11 @@ def definition(self, **defaults_config):
         return: [elem not in Vertices(Graph(V,E))] = [elem not in V].
         '''
 
-        from . import nonmembership_def
+        from . import vertices_nonmembership_def
         element = self.element
         _V_sub  = self.domain.graph.vertex_set
         _E_sub  = self.domain.graph.edge_set
-        return nonmembership_def.instantiate(
+        return vertices_nonmembership_def.instantiate(
                 {v:element, V:_V_sub, E:_E_sub },auto_simplify=False)
 
     def as_defined(self):
@@ -120,9 +120,9 @@ def as_defined(self):
             raise NotImplementedError(
                 "VerticesNonmembership.as_defined() called on "
                 f"self = {self.expr} with domain = {self.expr.domain}, "
-                "but the method is implemented only for domains of "
-                "the form Vertices(G) where G is an explicit Graph "
-                "object of the form Graph(V,E) with a named vertex set.")
+                "but the method is implemented only for domains of the "
+                "form Vertices(G) where G is an explicit Graph object "
+                "of the form G = Graph(V,E) with a named vertex set V.")
 
     @prover
     def unfold(self, **defaults_config):
@@ -132,11 +132,11 @@ def unfold(self, **defaults_config):
         (and that E is a subset of [V]^2, i.e., a subset of the set
         of 2-element subsets of V).
         '''
-        from . import nonmembership_unfolding
+        from . import vertices_nonmembership_unfolding
         element = self.element
         _V_sub  = self.domain.graph.vertex_set
         _E_sub  = self.domain.graph.edge_set
-        return nonmembership_unfolding.instantiate(
+        return vertices_nonmembership_unfolding.instantiate(
             {v:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
 
     @prover
@@ -147,10 +147,10 @@ def conclude(self, **defaults_config):
         of [V]^2, a subset of the set of 2-element subsets of V)
         derive and return self.
         '''
-        from . import nonmembership_folding
+        from . import vertices_nonmembership_folding
         element = self.element
         _V_sub  = self.domain.graph.vertex_set
         _E_sub  = self.domain.graph.edge_set
-        return nonmembership_folding.instantiate(
+        return vertices_nonmembership_folding.instantiate(
             {v:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
 
diff --git a/packages/proveit/graphs/edges/__init__.py b/packages/proveit/graphs/walks/__init__.py
similarity index 93%
rename from packages/proveit/graphs/edges/__init__.py
rename to packages/proveit/graphs/walks/__init__.py
index 744731235907..dba3de849ed8 100644
--- a/packages/proveit/graphs/edges/__init__.py
+++ b/packages/proveit/graphs/walks/__init__.py
@@ -1,4 +1,4 @@
-from .edges import Edges
+
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
 #  Make additions above, or add to sys.modules[__name__].__dict__ below.
diff --git a/packages/proveit/graphs/walks/_brief_description_.txt b/packages/proveit/graphs/walks/_brief_description_.txt
new file mode 100644
index 000000000000..189a5f032a8a
--- /dev/null
+++ b/packages/proveit/graphs/walks/_brief_description_.txt
@@ -0,0 +1 @@
+walks, trails, paths, circuits, and cycles, as sequences of vertices within a graph
diff --git a/packages/proveit/graphs/edges/_sub_theories_.txt b/packages/proveit/graphs/walks/_sub_theories_.txt
similarity index 100%
rename from packages/proveit/graphs/edges/_sub_theories_.txt
rename to packages/proveit/graphs/walks/_sub_theories_.txt
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/__init__.py b/packages/proveit/graphs/walks/_theory_nbs_/__init__.py
similarity index 100%
rename from packages/proveit/graphs/edges/_theory_nbs_/__init__.py
rename to packages/proveit/graphs/walks/_theory_nbs_/__init__.py
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/common.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
similarity index 70%
rename from packages/proveit/graphs/vertices/_theory_nbs_/common.ipynb
rename to packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
index d47aa5e24580..c6faf0a6d859 100644
--- a/packages/proveit/graphs/vertices/_theory_nbs_/common.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
@@ -4,7 +4,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Common expressions for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.vertices</a>\n",
+    "Axioms for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.walks</a>\n",
     "========"
    ]
   },
@@ -15,8 +15,8 @@
    "outputs": [],
    "source": [
     "import proveit\n",
-    "# Prepare this notebook for defining the common expressions of a theory:\n",
-    "%common_expressions_notebook # Keep this at the top following 'import proveit'.\n",
+    "# Prepare this notebook for defining the axioms of a theory:\n",
+    "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
     "# from ... import ..."
    ]
@@ -27,7 +27,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "%begin common"
+    "%begin axioms"
    ]
   },
   {
@@ -43,7 +43,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "%end common"
+    "%end axioms"
    ]
   }
  ],
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/common.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/common.ipynb
similarity index 95%
rename from packages/proveit/graphs/edges/_theory_nbs_/common.ipynb
rename to packages/proveit/graphs/walks/_theory_nbs_/common.ipynb
index 4f5cd0d8325c..22e8ac141800 100644
--- a/packages/proveit/graphs/edges/_theory_nbs_/common.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/common.ipynb
@@ -4,7 +4,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Common expressions for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.edges</a>\n",
+    "Common expressions for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.walks</a>\n",
     "========"
    ]
   },
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
new file mode 100644
index 000000000000..6991c8b4f211
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Demonstrations for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.walks</a>\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "%begin demonstrations"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%end demonstrations"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
similarity index 58%
rename from packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb
rename to packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
index 10d8e2f1a3c6..5260797e5412 100644
--- a/packages/proveit/graphs/edges/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
@@ -4,7 +4,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">edges</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_def\">nonmembership_def</a> theorem\n",
+    "Theorems (or conjectures) for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.walks</a>\n",
     "========"
    ]
   },
@@ -15,10 +15,10 @@
    "outputs": [],
    "source": [
     "import proveit\n",
-    "theory = proveit.Theory() # the theorem's theory\n",
+    "# Prepare this notebook for defining the theorems of a theory:\n",
+    "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "from proveit import defaults\n",
-    "from proveit.graphs.edges import edges_def"
+    "# from ... import ..."
    ]
   },
   {
@@ -27,7 +27,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "%proving nonmembership_def"
+    "%begin theorems"
    ]
   },
   {
@@ -35,16 +35,16 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": [
-    "%qed"
-   ]
+   "source": []
   },
   {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "%end theorems"
+   ]
   }
  ],
  "metadata": {
diff --git a/packages/proveit/graphs/vertices/_theory_nbs_/theory.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/theory.ipynb
similarity index 74%
rename from packages/proveit/graphs/vertices/_theory_nbs_/theory.ipynb
rename to packages/proveit/graphs/walks/_theory_nbs_/theory.ipynb
index c47105a3cb48..b37d9d15045d 100644
--- a/packages/proveit/graphs/vertices/_theory_nbs_/theory.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/theory.ipynb
@@ -4,10 +4,10 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Theory of <a class=\"ProveItLink\" href=\"../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../_theory_nbs_/theory.ipynb\">graphs</a>.vertices\n",
+    "Theory of <a class=\"ProveItLink\" href=\"../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../_theory_nbs_/theory.ipynb\">graphs</a>.walks\n",
     "========\n",
     "\n",
-    "Provide description here."
+    "Walks within graphs, conceptualized as sequences of vertices (in a simple graph), including special walks called trails, paths, circuits, and cycles."
    ]
   },
   {

From c9cdfae9c4e062d1a68a040b6060a25e7b072825 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 18 Jun 2025 18:16:51 -0500
Subject: [PATCH 117/159] Update logic/sets/common.ipyn with missing expr
 each_y_in_S_in_bool

Update logic/sets/common.ipyn with missing expr each_y_in_S_in_bool, which was causing problems in essential builds. Not clear how or why this ended up missing or necessary in this branch, but doesn't hurt to include it. Might create a conflict later when merging with other branches, but the conflict should be easy to resolve.
---
 packages/proveit/logic/sets/_theory_nbs_/common.ipynb | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/packages/proveit/logic/sets/_theory_nbs_/common.ipynb b/packages/proveit/logic/sets/_theory_nbs_/common.ipynb
index 5b79f873edc2..fe94d670e47f 100644
--- a/packages/proveit/logic/sets/_theory_nbs_/common.ipynb
+++ b/packages/proveit/logic/sets/_theory_nbs_/common.ipynb
@@ -21,7 +21,7 @@
     "from proveit import i, l, m, n, x, y, A, S, fy, Qy\n",
     "from proveit.core_expr_types import y_1_to_n, f__y_1_to_n, Q__y_1_to_n, S_1_to_n, R__y_1_to_n\n",
     "from proveit.logic import (And, Or, Equals, NotEquals, Set, InSet, NotInSet, SubsetEq,\n",
-    "                           SetOfAll, UnionAll, IntersectAll)\n",
+    "                           SetOfAll, UnionAll, IntersectAll, in_bool)\n",
     "from proveit.numbers import one\n",
     "from proveit.logic.sets.empty_set import EmptySetLiteral\n",
     "%begin common"
@@ -165,6 +165,15 @@
     "                                        conditions=[Q__y_1_to_n])"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "each_y_in_S_in_bool = ExprRange(i, in_bool(InSet(IndexedVar(y, i), IndexedVar(S, i))), one, n)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From bf6f3b1f53620d4ef95ce9cf710c959cb5fea5c3 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 18 Jun 2025 18:18:01 -0500
Subject: [PATCH 118/159] Comment out some broken, incomplete code in
 graphs/membership/axioms

Comment out some broken, incomplete code in graphs/membership/axioms. This sub-theory package will likely by deleted in a future commit.
---
 .../membership/_theory_nbs_/axioms.ipynb      | 23 ++++++++++---------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/packages/proveit/graphs/membership/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/membership/_theory_nbs_/axioms.ipynb
index 5769bbdac1e7..54a89dddf1df 100644
--- a/packages/proveit/graphs/membership/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/membership/_theory_nbs_/axioms.ipynb
@@ -46,11 +46,12 @@
    "outputs": [],
    "source": [
     "# this should eventually use an exclusive or (XOR) instead of simple disjunction (OR)\n",
-    "in_graph_def = (\n",
-    "    Forall((E, V),\n",
-    "    Forall((x, G,\n",
-    "           Equals(InGraph(x, G), Or(InSet(x, V), InSet(x, E))))\n",
-    "    ))"
+    "# in_graph_def = (\n",
+    "#     Forall((E, V),\n",
+    "#     Forall((x, G,\n",
+    "#            Equals(InGraph(x, G), Or(InSet(x, V), InSet(x, E))))\n",
+    "#     ))\n",
+    "# )"
    ]
   },
   {
@@ -60,11 +61,11 @@
    "outputs": [],
    "source": [
     "# this should eventually use an exclusive or (XOR) instead of simple disjunction (OR)\n",
-    "(\n",
-    "    Forall((E, V),\n",
-    "    Forall(x,\n",
-    "           Equals(InGraph(x, Graph(V,E)), Or(InSet(x, V), InSet(x, E))))\n",
-    "    ))"
+    "# (\n",
+    "#     Forall((E, V),\n",
+    "#     Forall(x,\n",
+    "#            Equals(InGraph(x, Graph(V,E)), Or(InSet(x, V), InSet(x, E))))\n",
+    "#     ))"
    ]
   },
   {
@@ -96,7 +97,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "not_in_graph_def = Forall((x, G), Equals(NotInGraph(x, G), Not(InGraph(x, G))))"
+    "# not_in_graph_def = Forall((x, G), Equals(NotInGraph(x, G), Not(InGraph(x, G))))"
    ]
   },
   {

From 9c0ba9af51c23dbed26e903dba376d7fa78ae8c9 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 23 Jun 2025 12:18:33 -0500
Subject: [PATCH 119/159] Add Connected(G) predicate class to graphs pkg

Add Connected(G) predicate class to graphs package to represent the claim that a graph G is connected. This is then used in one of Euler's theorems (a later commit) about a connected graph G having an Eulerian circuit if and only if G has all even vertices.
---
 packages/proveit/graphs/graph.py | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/packages/proveit/graphs/graph.py b/packages/proveit/graphs/graph.py
index 15007061564c..6c7e963069a7 100644
--- a/packages/proveit/graphs/graph.py
+++ b/packages/proveit/graphs/graph.py
@@ -66,4 +66,27 @@ def __init__(self, V, E, *, styles=None):
                 self, Graph._operator_, (V, E), styles=styles)
 
 
+class Connected(Function):
+    '''
+    Connected(G) is a propositional function (or predicate)
+    representing the claim that graph G is connected (i.e., that
+    for every pair (u, v) of vertices in G, there exists a u-v path
+    in G).
+    '''
+
+    # the literal operator of the Connected operation
+    _operator_ = Literal(string_format='Connected',
+                         latex_format=r'\textrm{Connected}',
+                         theory=__file__)
+
+    def __init__(self, G, *, styles=None):
+        '''
+        Represent the propositional function Connected(G),
+        claiming graph G is connected.
+        '''
+        self.graph = G
+        Function.__init__(
+                self, Connected._operator_, G, styles=styles)
+
+
 

From aa7544986755d97b28adff898ef69d39b9fd6895 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 23 Jun 2025 12:31:44 -0500
Subject: [PATCH 120/159] Establish walks.py and related classes of walks

Establish walks.py and a number of related walk types and predicates, including:
Walks(G) (representing the set of all walks in the simple graph G)
Walk(S, G) (representing specific walk consisting of a sequence S of vertices in graph G)
Trail(S, G) (representing a trail in G)
Path(S, G) (representing a path in G, which will replace the previous code establishing a path as a subgraph of G)
WalkLength(W) (representing the length of a walk W)
EndVertices(W) (representing the set of endvertices of walk W)
HasEulerTrail(G) (representing the claim that graph G has an Eulerian trail)
HasEulerCircuit (representing the claim that graph G has an Eulerian circuit).
Also update related __init__.py files and the walks/demonstrations.ipynb notebook.
---
 packages/proveit/graphs/__init__.py           |   4 +-
 packages/proveit/graphs/walks/__init__.py     |   3 +-
 .../walks/_theory_nbs_/demonstrations.ipynb   | 167 +++++++++++
 packages/proveit/graphs/walks/walks.py        | 278 ++++++++++++++++++
 4 files changed, 450 insertions(+), 2 deletions(-)
 create mode 100644 packages/proveit/graphs/walks/walks.py

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index 2aec5e84fd40..4402f63c8d97 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -1,4 +1,4 @@
-from .graph import Graph, Graphs
+from .graph import Connected, Graph, Graphs
 from .edges import Edges
 from .endpoints import Endpoints
 from .inclusion import NotSubgraph, Subgraph
@@ -8,6 +8,8 @@
 from .paths_of import PathsOf
 from .union import GraphUnion
 from .vertices import Degree, Vertices
+from .walks import (EndVertices, HasEulerCircuit, HasEulerTrail,
+          Path, Trail, Walk, WalkLength, Walks)
 
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
diff --git a/packages/proveit/graphs/walks/__init__.py b/packages/proveit/graphs/walks/__init__.py
index dba3de849ed8..d223cbd447bf 100644
--- a/packages/proveit/graphs/walks/__init__.py
+++ b/packages/proveit/graphs/walks/__init__.py
@@ -1,4 +1,5 @@
-
+from .walks import (EndVertices, HasEulerCircuit, HasEulerTrail,
+        Path, Trail, Walk, WalkLength, Walks)
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
 #  Make additions above, or add to sys.modules[__name__].__dict__ below.
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
index 6991c8b4f211..709463a31274 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
@@ -15,6 +15,9 @@
    "outputs": [],
    "source": [
     "import proveit\n",
+    "from proveit import G, S, W\n",
+    "from proveit.graphs import (EndVertices, Graph, HasEulerCircuit, HasEulerTrail, Path, Trail,\n",
+    "        Walk, WalkLength, Walks)\n",
     "%begin demonstrations"
    ]
   },
@@ -25,6 +28,170 @@
    "outputs": [],
    "source": []
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Walks of Various Kinds\n",
+    "### Including: Walks, Trails, Paths, Circuits, & Cycles"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Miscellaneous Testing\n",
+    "Testing various classes and methods related to walks in an undirected simple graph. Some of this material could eventually be integrated into the `_demonstrations_` page and/or deleted as development continues."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`Walks(G)` represents the set of all walks in the simple undirected graph $G$. \n",
+    "\n",
+    "A __walk__ $W$ in a simple undirected graph $G$ is a sequence\n",
+    "    $(u = v_0, v_1, ..., v = v_k)$ of vertices of $G$ such that consecutive\n",
+    "    vertices in the sequence are adjacent in $G$ --- in other words,\n",
+    "    every pair $\\{v_{i}, v_{i+1}\\}$ of vertices (for $i \\in \\{0, 1, ..., k-1\\}$)\n",
+    "    corresponds to an edge in $G$. $u$ and $v$ are called the endvertices\n",
+    "    or endpoints of the walk, and a walk from $u$ to $v$ is often referred\n",
+    "    to as a $u$-$v$ walk. The vertices $v_1, v_2, ..., v_{k-1}$ are called\n",
+    "    _internal vertices_. The number of edges in the walk $W$, denoted\n",
+    "    by $||W||$, is the length of the walk (in this example, $||W|| = k$).\n",
+    "    The number of vertices in walk $W$, including\n",
+    "    multiplicities of repeated vertices, is denoted $|W|$, analogous\n",
+    "    to the notation for the order of a graph, $|G|$."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Walks(G)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A specific walk in graph $G$ consisting of a sequence $S$ of vertices in $G$:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Walk(S, G)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The length (_i.e._, number of edges) in a walk $W$, denoted by $\\|W\\|$:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "WalkLength(W)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A trail in graph G, consisting of a sequence $S$ of vertices in $G$. A trail is a walk in which no edge is repeated."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Trail(S, G)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A path in graph $G$, consisting of a sequence $S$ of vertices in $G$. A path is a walk in which no vertices (and thus no edges) are repeated."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Path(S, G)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The endvertices (or endpoints) of a walk $W$ is denoted $\\texttt{EndVertices}(W)$:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "EndVertices(W)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Propositional function $\\texttt{HasEulerTrail}(G)$, claiming graph $G$ has an Eulerian trail."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "HasEulerTrail(G)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Propositional function $\\texttt{HasEulerCircuit}(G)$, claiming graph $G$ has an Eulerian circuit."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "HasEulerCircuit(G)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/walks/walks.py b/packages/proveit/graphs/walks/walks.py
new file mode 100644
index 000000000000..9278d9998987
--- /dev/null
+++ b/packages/proveit/graphs/walks/walks.py
@@ -0,0 +1,278 @@
+from proveit import Function, Literal
+from proveit.logic import ClassMembership
+from proveit.graphs import Graph
+
+class Walks(Function):
+    '''
+    Walks(G) represents the set of walks in the simple undirected
+    graph G. A walk W in a simple undirected graph G is a sequence
+    (u = v0, v1, ..., v = vk) of vertices of G such that consecutive
+    vertices in the sequence are adjacent in G --- in other words,
+    every pair {v_{i}, v_{i+1}} of vertices (for i in {0, 1, ..., k-1})
+    corresponds to an edge in G. u and v are called the endvertices
+    or endpoints of the walk, and a walk from u to v is often referred
+    to as a u-v walk. The vertices v1, v2, ..., v_{k-1} are called
+    internal vertices. The number of edges in the walk W, denoted
+    by ||W||, is the length of the walk (in this example, ||W|| = k).
+    The number of vertices in the Walk sequence W, including
+    multiplicities of repeated vertices, is denoted |W|, analogous
+    to the notation for the order of a graph, |G|.
+    '''
+
+    # the literal operator of the Walks operation
+    _operator_ = Literal(string_format='Walks',
+                         latex_format=r'\textrm{Walks}',
+                         theory=__file__)
+
+    def __init__(self, G, *, styles=None):
+        '''
+        Represent the set Walks(G) of all walks in graph G.
+        '''
+        self.graph = G
+        Function.__init__(
+                self, Walks._operator_, G, styles=styles)
+
+class Walk(Function):
+    '''
+    Walk(S, G) represents a walk in the simple undirected graph G
+    with vertex sequence S. See the description above under Walks(G)
+    for a definition of a walk in graph G.
+    '''
+
+    # the literal operator of the Walk(S,G) operation
+    _operator_ = Literal(string_format='Walk',
+                         latex_format=r'\textrm{Walk}',
+                         theory=__file__)
+
+    def __init__(self, S, G, *, styles=None):
+        '''
+        Represent Walk(S, G), the walk in G consisting of vertex
+        sequence S in the simple undirected graph G.
+        '''
+        self.graph = G
+        self.vertex_sequence = S
+        Function.__init__(
+                self, Walk._operator_, (S, G), styles=styles)
+
+class WalkLength(Function):
+    '''
+    WalkLength(W), denoted ||W||, represents the length of walk W
+    (where W could be a walk or one of the special cases of a
+    trail, path, circuit, etc., all of which area also walks)
+    equivalent to the number of edges crossed during the walk
+    (including multiplicities). For example, given a walk
+    W = Walk(S, G) in graph G with vertex sequence
+        S = (a, b, c, b, d, e),
+    we have WalkLength(W) = ||W|| = 5. Notice that ||W|| is always
+    equal to len(S) - 1, where len(S) is the length of sequence S.
+    '''
+
+    # literal operator of the WalkLength operation.
+    _operator_ = Literal(string_format='Len', theory=__file__)
+
+    def __init__(self, W, *, styles=None):
+        '''
+        Represent WalkLength(W), the length of walk W, equivalent
+        to the number of edges traveled during walk W.
+        '''
+        self.walk = W
+        Function.__init__(
+                self, WalkLength._operator_, W, styles=styles)
+
+    def string(self, **kwargs):
+        return '||' + self.operand.string() + '||'
+
+    def latex(self, **kwargs):
+        return r'\left\|' + self.operand.latex() + r'\right\|'
+
+
+class Trail(Function):
+    '''
+    Trail(S, G) represents a trail in the simple undirected graph G
+    with vertex sequence S. A trail is a walk (see the description
+    above in the Walks(G) class) in which no edge is repeated.
+    '''
+
+    # the literal operator of the Trail(S,G) operation
+    _operator_ = Literal(string_format='Trail',
+                         latex_format=r'\textrm{Trail}',
+                         theory=__file__)
+
+    def __init__(self, S, G, *, styles=None):
+        '''
+        Represent Trail(S, G), the trail in G consisting of vertex
+        sequence S in the simple undirected graph G.
+        '''
+        self.graph = G
+        self.vertex_sequence = S
+        Function.__init__(
+                self, Trail._operator_, (S, G), styles=styles)
+
+
+class Path(Function):
+    '''
+    Path(S, G) represents a path in the simple undirected graph G
+    with vertex sequence S. A path is a walk (see the description
+    above in the Walks(G) class) in which no vertex (and thus no edge)
+    is repeated.
+    '''
+
+    # the literal operator of the Path(S,G) operation
+    _operator_ = Literal(string_format='Path',
+                         latex_format=r'\textrm{Path}',
+                         theory=__file__)
+
+    def __init__(self, S, G, *, styles=None):
+        '''
+        Represent Path(S, G), the path in G consisting of vertex
+        sequence S in the simple undirected graph G.
+        '''
+        self.graph = G
+        self.vertex_sequence = S
+        Function.__init__(
+                self, Path._operator_, (S, G), styles=styles)
+
+
+class EndVertices(Function):
+    '''
+    EndVertices(W) represent the set of endvertices or endpoints of
+    the walk W (and recall that trails, paths, circuits, and cycles
+    are special cases of walks). For example, given a walk
+    W = Walk(S, G) in graph G with vertex sequence
+        S = (a, b, c, b, d, e),
+    we have EndVertices(W) = {a, e}. Notice that EndVertices(W) will
+    have a single element when W is a circuit or a cycle.
+    '''
+
+    # the literal operator of the EndVertices(W) operation
+    _operator_ = Literal(string_format='EndVertices',
+                         latex_format=r'\textrm{EndVertices}',
+                         theory=__file__)
+
+    def __init__(self, W, *, styles=None):
+        '''
+        Represent EndVertices(W), the set of endvertices of walk W.
+        '''
+        self.walk = W
+        Function.__init__(
+                self, EndVertices._operator_, W, styles=styles)
+
+
+class HasEulerTrail(Function):
+    '''
+    HasEulerTrail(G) is a propositional function (or predicate)
+    claiming that graph G has an Eulerian trail (i.e., G has a
+    walk that uses each and every edge of G exactly once).
+    '''
+
+    # the literal operator of the HasEulerTrail operation
+    _operator_ = Literal(string_format='HasEulerTrail',
+                         latex_format=r'\textrm{HasEulerTrail}',
+                         theory=__file__)
+
+    def __init__(self, G, *, styles=None):
+        '''
+        Represent the propositional function HasEulerTrail(G),
+        claiming graph G has an Eulerian trail.
+        '''
+        self.graph = G
+        Function.__init__(
+                self, HasEulerTrail._operator_, G, styles=styles)
+
+
+class HasEulerCircuit(Function):
+    '''
+    HasEulerCircuit(G) is a propositional function (or predicate)
+    claiming that graph G has an Eulerian circuit (i.e., G has a
+    closed walk that uses each and every edge of G exactly once).
+    '''
+
+    # the literal operator of the HasEulerCircuit operation
+    _operator_ = Literal(string_format='HasEulerCircuit',
+                         latex_format=r'\textrm{HasEulerCircuit}',
+                         theory=__file__)
+
+    def __init__(self, G, *, styles=None):
+        '''
+        Represent the propositional function HasEulerCircuit(G),
+        claiming graph G has an Eulerian circuit.
+        '''
+        self.graph = G
+        Function.__init__(
+                self, HasEulerCircuit._operator_, G, styles=styles)
+
+
+# class Paths(Literal):
+#     '''
+#     Paths() represents the set of all graphs that are (undirected)
+#     paths. A undirected path is a non-empty graph P = (V,E)
+#     with non-empty vertex set V and (possibly empty) edge set E such
+#     that:
+#             V = {x0, x1, ..., xk},
+#             E = {{x0,x1}, {x1,x2}, ..., {x_{k-1},x_{k}},
+
+#     where the x_{i} are all distinct. The vertices x0 and xk are said
+#     to be linked by the path P and are called its endvertices, or
+#     endpoints, or simply its ends. The vertices x1, ..., x_{k-1} are
+#     the inner vertices of P. The number of edges in the path P,
+#     denoted ||P||, is its length (in this example, ||P|| = k).
+#     '''
+
+#     # the literal string for representing the class of Paths
+#     def __init__(self, *, styles=None):
+#         Literal.__init__(self, string_format='Paths', 
+#                          latex_format=r'\textrm{Paths}',
+#                          styles=styles)
+
+#     @property
+#     def is_proper_class(self):
+#         '''
+#         Paths consitute a proper class (i.e. instead of a set).
+#         This indicates that InClass() should be used instead of
+#         InSet() when this is a domain.
+#         '''
+#         return True
+
+#     def membership_object(self, element):
+#         from .paths_membership import PathsMembership
+#         return PathsMembership(element, self)
+
+#     def nonmembership_object(self, element):
+#         from .paths_membership import PathsNonmembership
+#         return PathsNonmembership(element, self)
+
+
+# class Path(Graph):
+#     '''
+#     Path(V,E) represents the special type of graph called a path,
+#     with vertex set V and edge set E. A path is a non-empty graph
+#     P = (V,E) with vertex set V and (possibly empty) edge set E such
+#     that:
+
+#         V = {x0, x1, ..., xk}, E = {x0x1, x1x2, ..., x_{k-1}x_{k}},
+
+#     where the x_{i} are all distinct. The vertices x0 and xk are said
+#     to be linked by the path P and are called its endvertices, or
+#     endpoints, or simply its ends. The vertices x1, ..., x_{k-1} are
+#     the inner vertices of P. The number of edges in the path P,
+#     denoted ||P||, is its length (in this example, ||P|| = k).
+#     '''
+
+#     # the literal operator of the Path operator
+#     _operator_ = Literal(string_format='Path',
+#                          latex_format=r'\text{Path}',
+#                          theory=__file__)
+
+#     def __init__(self, V, E, *, styles=None):
+#         '''
+#         Create or represent a path, Path(V,E), with vertex set V
+#         and edge set E. If explicit sets of vertices and edges are
+#         provided, they are NOT currently verified to represent a
+#         valid path.
+#         '''
+#         self.vertex_set = V
+#         self.edge_set   = E
+#         Function.__init__(self, Path._operator_, (V, E), styles=styles)
+
+
+

From 19d0b4f7dd973ca2dd1a0d2364892aae79e98114 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 23 Jun 2025 12:33:13 -0500
Subject: [PATCH 121/159] Update graphs/demonstrations.ipynb with Connected(G)

Update graphs/demonstrations.ipynb notebook to test the Connected(G) predicate construction (created in earlier commit).
---
 .../proveit/graphs/_theory_nbs_/demonstrations.ipynb | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
index 24e8bf2d1fde..87e2c6e50521 100644
--- a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
@@ -18,7 +18,7 @@
     "from proveit import e, v, x, E, G, P, V\n",
     "from proveit.logic import InClass, InSet, KPowerSet, NotInSet, SubsetEq\n",
     "from proveit.numbers import two\n",
-    "from proveit.graphs import Degree, Edges, Endpoints, Graph, Graphs, Path, Vertices\n",
+    "from proveit.graphs import Connected, Degree, Edges, Endpoints, Graph, Graphs, Path, Vertices\n",
     "%begin demonstrations"
    ]
   },
@@ -55,6 +55,16 @@
     "InClass(example_graph, Graphs())"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# assert that the example graph is connected\n",
+    "Connected(example_graph)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From 6606b5dc43a3d61198e8067b5573a969ddc0e59e Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 23 Jun 2025 12:35:03 -0500
Subject: [PATCH 122/159] Establish initial attempt at Euler thm for Euler
 circuit in connected graph

Establish initial attempt at an Euler's theorem for a connected graph G having an Euler circuit if and only if G has all even vertices.
---
 .../thm_proof.ipynb                           | 47 +++++++++++++++++++
 .../graphs/_theory_nbs_/theorems.ipynb        | 27 ++++++++++-
 2 files changed, 72 insertions(+), 2 deletions(-)
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/euler_circuit_iff_all_even_vertices/thm_proof.ipynb

diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/euler_circuit_iff_all_even_vertices/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/euler_circuit_iff_all_even_vertices/thm_proof.ipynb
new file mode 100644
index 000000000000..bcad989b0c12
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/euler_circuit_iff_all_even_vertices/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#euler_circuit_iff_all_even_vertices\">euler_circuit_iff_all_even_vertices</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving euler_circuit_iff_all_even_vertices"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
index 7e73feae3130..8e04f16f08ec 100644
--- a/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
@@ -20,10 +20,10 @@
     "\n",
     "# from ... import ...\n",
     "from proveit import e, v, E, G, V\n",
-    "from proveit.logic import Equals, Forall, InSet, InClass, NotInSet\n",
+    "from proveit.logic import Equals, Forall, Iff, InSet, InClass, NotInSet\n",
     "from proveit.logic.sets import Card, KPowerSet, SetOfAll, SubsetEq\n",
     "from proveit.numbers import two, IntegerEven, IntegerOdd, Mult, Sum\n",
-    "from proveit.graphs import Degree, Edges, Graph, Graphs, Vertices"
+    "from proveit.graphs import Connected, Degree, Edges, Graph, Graphs, HasEulerCircuit, Vertices"
    ]
   },
   {
@@ -271,6 +271,29 @@
     ")"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### One of Euler's theorems: a connected simple graph $G$ has an Eulerian circuit if and only if $G$ has all even vertices."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "euler_circuit_iff_all_even_vertices = (\n",
+    "    Forall(G,\n",
+    "           Iff(HasEulerCircuit(G),\n",
+    "               Forall(v, InSet(Degree(v, G), IntegerEven), domain = Vertices(G))),\n",
+    "    conditions = [Connected(G)],\n",
+    "    domain = Graphs()\n",
+    "    )\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From f6ed102c80b0ddc8573000c5ace717b1f55766f3 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 26 Jun 2025 16:21:31 -0500
Subject: [PATCH 123/159] Add Closed(), EdgeSequence(), EdgeSet(),
 EulerianTrails() classes to graphs/walks

Add the Closed(), EdgeSequence(), EdgeSet(), EulerianTrails() classes to graphs/walks, and remove the HasEulerianTrail(G) and HasEulerianCircuit(G) (shifting them to graphs.py in next commit). Closed(W) represents the claim that the walk W is closed (i.e. its endvertices are the same). EdgeSequence(W) and EdgeSet(W) represent the edges of a walk W either as the original sequence (which might contain repeated edges) or as a set. EulerianTrails(G) represents the set of all Eulerian trails in graph G.
---
 packages/proveit/graphs/walks/__init__.py     |   4 +-
 .../walks/_theory_nbs_/demonstrations.ipynb   |  52 ++++++--
 packages/proveit/graphs/walks/walks.py        | 119 +++++++++++++-----
 3 files changed, 127 insertions(+), 48 deletions(-)

diff --git a/packages/proveit/graphs/walks/__init__.py b/packages/proveit/graphs/walks/__init__.py
index d223cbd447bf..a73801c603b0 100644
--- a/packages/proveit/graphs/walks/__init__.py
+++ b/packages/proveit/graphs/walks/__init__.py
@@ -1,5 +1,5 @@
-from .walks import (EndVertices, HasEulerCircuit, HasEulerTrail,
-        Path, Trail, Walk, WalkLength, Walks)
+from .walks import (Closed, EdgeSequence, EdgeSet, EndVertices,
+        EulerianTrails, Path, Trail, Walk, WalkLength, Walks)
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
 #  Make additions above, or add to sys.modules[__name__].__dict__ below.
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
index 709463a31274..b19e2309185e 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
@@ -16,8 +16,9 @@
    "source": [
     "import proveit\n",
     "from proveit import G, S, W\n",
-    "from proveit.graphs import (EndVertices, Graph, HasEulerCircuit, HasEulerTrail, Path, Trail,\n",
-    "        Walk, WalkLength, Walks)\n",
+    "from proveit.graphs import (\n",
+    "        Closed, EdgeSequence, EdgeSet, EndVertices, EulerianTrails, Graph,\n",
+    "        Path, Trail, Walk, WalkLength, Walks)\n",
     "%begin demonstrations"
    ]
   },
@@ -109,7 +110,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "A trail in graph G, consisting of a sequence $S$ of vertices in $G$. A trail is a walk in which no edge is repeated."
+    "Assert that walk $W$ is a closed walk:"
    ]
   },
   {
@@ -118,14 +119,14 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Trail(S, G)"
+    "Closed(W)"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "A path in graph $G$, consisting of a sequence $S$ of vertices in $G$. A path is a walk in which no vertices (and thus no edges) are repeated."
+    "The sequence of edges traveled during a walk $W$ is denoted by $\\texttt{EdgeSeq}(W)$:"
    ]
   },
   {
@@ -134,14 +135,14 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Path(S, G)"
+    "EdgeSequence(W)"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "The endvertices (or endpoints) of a walk $W$ is denoted $\\texttt{EndVertices}(W)$:"
+    "The set (not the sequence) of edges traveled during a walk $W$ is denoted by $\\texttt{EdgeSet}(W)$:"
    ]
   },
   {
@@ -150,7 +151,14 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "EndVertices(W)"
+    "EdgeSet(W)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A trail in graph G, consisting of a sequence $S$ of vertices in $G$. A trail is a walk in which no edge is repeated."
    ]
   },
   {
@@ -158,13 +166,15 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "Trail(S, G)"
+   ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Propositional function $\\texttt{HasEulerTrail}(G)$, claiming graph $G$ has an Eulerian trail."
+    "A path in graph $G$, consisting of a sequence $S$ of vertices in $G$. A path is a walk in which no vertices (and thus no edges) are repeated."
    ]
   },
   {
@@ -173,14 +183,30 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "HasEulerTrail(G)"
+    "Path(S, G)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The set of endvertices (or endpoints) of a walk $W$ is denoted $\\texttt{EndVertices}(W)$:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "EndVertices(W)"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Propositional function $\\texttt{HasEulerCircuit}(G)$, claiming graph $G$ has an Eulerian circuit."
+    "The set of all Eulerian trails in graph $G$:"
    ]
   },
   {
@@ -189,7 +215,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "HasEulerCircuit(G)"
+    "EulerianTrails(G)"
    ]
   },
   {
diff --git a/packages/proveit/graphs/walks/walks.py b/packages/proveit/graphs/walks/walks.py
index 9278d9998987..1e8e070bb1b7 100644
--- a/packages/proveit/graphs/walks/walks.py
+++ b/packages/proveit/graphs/walks/walks.py
@@ -86,6 +86,78 @@ def latex(self, **kwargs):
         return r'\left\|' + self.operand.latex() + r'\right\|'
 
 
+class Closed(Function):
+    '''
+    Closed(W) is a propositional function (or predicate)
+    claiming that walk W is closed (i.e., that the endvertices of
+    walk W are equal).
+    '''
+
+    # the literal operator of the Closed operation
+    _operator_ = Literal(string_format='Closed',
+                         latex_format=r'\textrm{Closed}',
+                         theory=__file__)
+
+    def __init__(self, W, *, styles=None):
+        '''
+        Represent the propositional function Closed(G),
+        claiming walk W is closed.
+        '''
+        self.walk = W
+        Function.__init__(
+                self, Closed._operator_, W, styles=styles)
+
+class EdgeSequence(Function):
+    '''
+    Given a walk W = Walk(S, G) consisting of vertex sequence S in
+    graph G, EdgeSeq(W) represents the sequence of edges traveled
+    along the walk, which for a simple graph is completely
+    determined by the vertex sequence S. The number of edges in
+    EdgeSequence(W) is the length of the walk W, represented with
+    WalkLength(W).
+    '''
+
+    # the literal operator of the EdgeSequence operation
+    _operator_ = Literal(string_format='EdgeSeq',
+                         latex_format=r'\mathrm{EdgeSeq}',
+                         theory=__file__)
+
+    def __init__(self, W, *, styles=None):
+        '''
+        Given a walk W = Walk(S, G) in graph G, represent the
+        sequence of edges traveled during the walk.
+        '''
+        self.walk = W
+        Function.__init__(
+                self, EdgeSequence._operator_, W, styles=styles)
+
+
+class EdgeSet(Function):
+    '''
+    Given a walk W = Walk(S, G) consisting of vertex sequence S in
+    graph G, EdgeSet(W) represents the set (not the sequence) of edges
+    traveled along the walk, which for a simple graph is completely
+    determined by the vertex sequence S. The sequence of edges traveled
+    in the walk W, represented by EdgeSequence(W), will have the same
+    edges as EdgeSet(W), but EdgeSequence(W) might have repeated
+    edges.
+    '''
+
+    # the literal operator of the EdgeSet operation
+    _operator_ = Literal(string_format='EdgeSet',
+                         latex_format=r'\mathrm{EdgeSet}',
+                         theory=__file__)
+
+    def __init__(self, W, *, styles=None):
+        '''
+        Given a walk W = Walk(S, G) in graph G, represent the
+        set of edges traveled during the walk.
+        '''
+        self.walk = W
+        Function.__init__(
+                self, EdgeSet._operator_, W, styles=styles)
+
+
 class Trail(Function):
     '''
     Trail(S, G) represents a trail in the simple undirected graph G
@@ -135,7 +207,7 @@ def __init__(self, S, G, *, styles=None):
 
 class EndVertices(Function):
     '''
-    EndVertices(W) represent the set of endvertices or endpoints of
+    EndVertices(W) represents the set of endvertices or endpoints of
     the walk W (and recall that trails, paths, circuits, and cycles
     are special cases of walks). For example, given a walk
     W = Walk(S, G) in graph G with vertex sequence
@@ -158,48 +230,29 @@ def __init__(self, W, *, styles=None):
                 self, EndVertices._operator_, W, styles=styles)
 
 
-class HasEulerTrail(Function):
-    '''
-    HasEulerTrail(G) is a propositional function (or predicate)
-    claiming that graph G has an Eulerian trail (i.e., G has a
-    walk that uses each and every edge of G exactly once).
-    '''
-
-    # the literal operator of the HasEulerTrail operation
-    _operator_ = Literal(string_format='HasEulerTrail',
-                         latex_format=r'\textrm{HasEulerTrail}',
-                         theory=__file__)
-
-    def __init__(self, G, *, styles=None):
-        '''
-        Represent the propositional function HasEulerTrail(G),
-        claiming graph G has an Eulerian trail.
-        '''
-        self.graph = G
-        Function.__init__(
-                self, HasEulerTrail._operator_, G, styles=styles)
-
-
-class HasEulerCircuit(Function):
+class EulerianTrails(Function):
     '''
-    HasEulerCircuit(G) is a propositional function (or predicate)
-    claiming that graph G has an Eulerian circuit (i.e., G has a
-    closed walk that uses each and every edge of G exactly once).
+    EulerianTrails(G) represents the set of Eulerian trails in the
+    simple undirected graph G. An Eulerian trail in graph G is a u-v
+    walk that uses each and every edge of G exactly once, and such
+    an Eulerian trail will exist in G if and only if G is connected
+    with exactly two vertices of odd degree. The odd degree vertices
+    will then also be the u and v of the u-v walk.
     '''
 
-    # the literal operator of the HasEulerCircuit operation
-    _operator_ = Literal(string_format='HasEulerCircuit',
-                         latex_format=r'\textrm{HasEulerCircuit}',
+    # the literal operator of the EulerianTrails operation
+    _operator_ = Literal(string_format='EulerianTrails',
+                         latex_format=r'\textrm{EulerianTrails}',
                          theory=__file__)
 
     def __init__(self, G, *, styles=None):
         '''
-        Represent the propositional function HasEulerCircuit(G),
-        claiming graph G has an Eulerian circuit.
+        Represent the set EulerianTrails(G) of all Eulerian trails
+        in graph G.
         '''
         self.graph = G
         Function.__init__(
-                self, HasEulerCircuit._operator_, G, styles=styles)
+                self, EulerianTrails._operator_, G, styles=styles)
 
 
 # class Paths(Literal):

From 70bf30317696108f23311bf9bf56fec067a89905 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 26 Jun 2025 16:23:18 -0500
Subject: [PATCH 124/159] Add Order(), Size(), HasEulerianTrail(), &
 HasEulerianCircuit() classes to graphs pkg

Add the Order(), Size(), HasEulerianTrail(), & HasEulerianCircuit() classes to the graphs package. Order(G) represents the number of vertices in graph G. Size(G) represents the number of edges in graph G. And the HasEulerianTrail/Circuit(G) classes represent the claim that graph G has an Eulerian trail/circuit (these Eulerian trail/circuit predicate classes were moved from the graphs/walks subtheory package). Associated axiomatic definitions for Eulerian trails/circuits are included, as are some basic theorems about the Eulerian trails and circuits, and an update to the graphs/demonstrations.ipynb notebook.
---
 packages/proveit/graphs/__init__.py           |   7 +-
 .../proveit/graphs/_theory_nbs_/axioms.ipynb  |  55 ++++++++-
 .../graphs/_theory_nbs_/demonstrations.ipynb  |  44 ++++++-
 .../thm_proof.ipynb                           |  47 ++++++++
 .../thm_proof.ipynb                           |  47 ++++++++
 .../thm_proof.ipynb                           |  47 ++++++++
 .../euler_trail_guarantee/thm_proof.ipynb     |  47 ++++++++
 .../thm_proof.ipynb                           |  47 ++++++++
 .../thm_proof.ipynb                           |  47 ++++++++
 .../graphs/_theory_nbs_/theorems.ipynb        | 113 ++++++++++++++++--
 packages/proveit/graphs/graph.py              |  92 ++++++++++++++
 11 files changed, 577 insertions(+), 16 deletions(-)
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/all_even_vertices_imp_euler_circuit/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/euler_circuit_imp_all_even_vertices/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/euler_trail_between_odd_vertices/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/euler_trail_guarantee/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/euler_trail_imp_two_odd_vertices/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/two_odd_vertices_imp_euler_trail/thm_proof.ipynb

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index 4402f63c8d97..707fcd27e1a5 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -1,4 +1,5 @@
-from .graph import Connected, Graph, Graphs
+from .graph import (Connected, Graph, Graphs, HasEulerianCircuit,
+          HasEulerianTrail, Order, Size)
 from .edges import Edges
 from .endpoints import Endpoints
 from .inclusion import NotSubgraph, Subgraph
@@ -8,8 +9,8 @@
 from .paths_of import PathsOf
 from .union import GraphUnion
 from .vertices import Degree, Vertices
-from .walks import (EndVertices, HasEulerCircuit, HasEulerTrail,
-          Path, Trail, Walk, WalkLength, Walks)
+from .walks import (Closed, EdgeSequence, EdgeSet, EndVertices,
+          EulerianTrails, Path, Trail, Walk, WalkLength, Walks)
 
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
diff --git a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
index 6d5e9304870f..cfa7d3a360c9 100644
--- a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
@@ -18,11 +18,12 @@
     "# Prepare this notebook for defining the axioms of a theory:\n",
     "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "from proveit import v, E, G, V\n",
-    "from proveit.logic import Equals, Forall, InClass, InSet\n",
+    "from proveit import v, E, G, V, W\n",
+    "from proveit.logic import And, Equals, Exists, Forall, InClass, InSet\n",
     "from proveit.logic.sets import Card, KPowerSet, SetOfAll, SubsetEq\n",
     "from proveit.numbers import two\n",
-    "from proveit.graphs import Degree, Edges, Graph, Graphs, Vertices\n"
+    "from proveit.graphs import (Closed, Connected, Degree, EdgeSequence, EdgeSet, Edges, Graph, Graphs,\n",
+    "        HasEulerianCircuit, HasEulerianTrail, Size, Vertices, WalkLength, Walks)\n"
    ]
   },
   {
@@ -111,6 +112,54 @@
     ")"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Characterizing what it means for a graph $G$ to have an Eulerian circuit: this means that there exists a closed walk $W$ in graph $G$ such that $W$ uses each and every edge of $G$ exactly once. That can be awkward to express literally in _Prove-It_, but an equivalent definition involves a walk whose edge set is the same as the graph's edge set (capturing the idea that we use all of the edges of $G$), while the length of the walk (i.e. the number of edges) is the same as the cardinality of the graph's edge set (_i.e._, the “size” of the graph) (capturing the idea that we have no repeated edges)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "has_eulerian_circuit_def = Forall(G,\n",
+    "    Equals(\n",
+    "    HasEulerianCircuit(G),\n",
+    "    Exists(W, And(Equals(EdgeSet(W), Edges(G)), Equals(WalkLength(W), Size(G))),\n",
+    "       conditions = [Closed(W)], domain = Walks(G))\n",
+    "    ),\n",
+    "conditions = [Connected(G)],\n",
+    "domain = Graphs()\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Characterizing what it means for a graph $G$ to have an Eulerian trail: this means that there exists a walk $W$ in graph $G$ such that $W$ uses each and every edge of $G$ exactly once. If the walk is closed, then the Eulerian trail is an Eulerian circuit. As in the case of the Eulerian circuit, the definition can be awkward to express literally in _Prove-It_, but an equivalent definition involves a walk whose edge set is the same as the graph's edge set (capturing the idea that we use all of the edges of $G$), while the length of the walk (i.e. the number of edges) is the same as the cardinality of the graph's edge set (_i.e._, the “size” of the graph) (capturing the idea that we have no repeated edges)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "has_eulerian_trail_def = Forall(G,\n",
+    "    Equals(\n",
+    "    HasEulerianTrail(G),\n",
+    "    Exists(W, And(Equals(EdgeSet(W), Edges(G)), Equals(WalkLength(W), Size(G))),\n",
+    "       domain = Walks(G))\n",
+    "    ),\n",
+    "conditions = [Connected(G)],\n",
+    "domain = Graphs()\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
index 87e2c6e50521..0f58239cb344 100644
--- a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
@@ -18,7 +18,9 @@
     "from proveit import e, v, x, E, G, P, V\n",
     "from proveit.logic import InClass, InSet, KPowerSet, NotInSet, SubsetEq\n",
     "from proveit.numbers import two\n",
-    "from proveit.graphs import Connected, Degree, Edges, Endpoints, Graph, Graphs, Path, Vertices\n",
+    "from proveit.graphs import (\n",
+    "        Connected, Degree, Edges, Endpoints, Graph, Graphs,\n",
+    "        HasEulerianCircuit, HasEulerianTrail, Order, Path, Size, Vertices)\n",
     "%begin demonstrations"
    ]
   },
@@ -65,6 +67,46 @@
     "Connected(example_graph)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# the order of a graph G is the number of vertices in G\n",
+    "Order(G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# the size of a graph G is the number of edges in G\n",
+    "Size(G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# assert that G has an Eulerian trail\n",
+    "HasEulerianTrail(G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# assert that G has an Eulerian circuit\n",
+    "HasEulerianCircuit(G)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/all_even_vertices_imp_euler_circuit/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/all_even_vertices_imp_euler_circuit/thm_proof.ipynb
new file mode 100644
index 000000000000..9540934f9311
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/all_even_vertices_imp_euler_circuit/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#all_even_vertices_imp_euler_circuit\">all_even_vertices_imp_euler_circuit</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving all_even_vertices_imp_euler_circuit"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/euler_circuit_imp_all_even_vertices/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/euler_circuit_imp_all_even_vertices/thm_proof.ipynb
new file mode 100644
index 000000000000..d76f11d6c5ae
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/euler_circuit_imp_all_even_vertices/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#euler_circuit_imp_all_even_vertices\">euler_circuit_imp_all_even_vertices</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving euler_circuit_imp_all_even_vertices"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/euler_trail_between_odd_vertices/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/euler_trail_between_odd_vertices/thm_proof.ipynb
new file mode 100644
index 000000000000..0a5d84a88929
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/euler_trail_between_odd_vertices/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#euler_trail_between_odd_vertices\">euler_trail_between_odd_vertices</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving euler_trail_between_odd_vertices"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/euler_trail_guarantee/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/euler_trail_guarantee/thm_proof.ipynb
new file mode 100644
index 000000000000..dc957abbb4b2
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/euler_trail_guarantee/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#euler_trail_guarantee\">euler_trail_guarantee</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving euler_trail_guarantee"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/euler_trail_imp_two_odd_vertices/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/euler_trail_imp_two_odd_vertices/thm_proof.ipynb
new file mode 100644
index 000000000000..c027d60ffb47
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/euler_trail_imp_two_odd_vertices/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#euler_trail_imp_two_odd_vertices\">euler_trail_imp_two_odd_vertices</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving euler_trail_imp_two_odd_vertices"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/two_odd_vertices_imp_euler_trail/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/two_odd_vertices_imp_euler_trail/thm_proof.ipynb
new file mode 100644
index 000000000000..d191dd692b5c
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/two_odd_vertices_imp_euler_trail/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#two_odd_vertices_imp_euler_trail\">two_odd_vertices_imp_euler_trail</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving two_odd_vertices_imp_euler_trail"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
index 8e04f16f08ec..069f9ce0003f 100644
--- a/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
@@ -18,12 +18,13 @@
     "# Prepare this notebook for defining the theorems of a theory:\n",
     "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "# from ... import ...\n",
-    "from proveit import e, v, E, G, V\n",
-    "from proveit.logic import Equals, Forall, Iff, InSet, InClass, NotInSet\n",
+    "from proveit import e, v, E, G, V, W\n",
+    "from proveit.logic import Equals, Forall, Iff, Implies, InSet, InClass, NotInSet\n",
     "from proveit.logic.sets import Card, KPowerSet, SetOfAll, SubsetEq\n",
     "from proveit.numbers import two, IntegerEven, IntegerOdd, Mult, Sum\n",
-    "from proveit.graphs import Connected, Degree, Edges, Graph, Graphs, HasEulerCircuit, Vertices"
+    "from proveit.graphs import (\n",
+    "        Connected, Degree, Edges, EndVertices, EulerianTrails, Graph, Graphs,\n",
+    "        HasEulerianCircuit, HasEulerianTrail, Vertices)"
    ]
   },
   {
@@ -40,7 +41,7 @@
    "metadata": {},
    "source": [
     "#### Total Degree of Graph $G$.\n",
-    "##### The _total degree_ of a graph $G$ is twice the number of edges in $G$ (this is what Chartrand & Zhang (2012, pg 32) call “The First Theorem of Graph Theory”). "
+    "##### The _total degree_ of a graph $G$ is twice the number of edges in $G$ (this is what Chartrand & Zhang (2012, pg 32) call “The First Theorem of Graph Theory” and what is more generally called the “degree sum formula”) . "
    ]
   },
   {
@@ -60,7 +61,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "##### An immediate corollary to the First Theorem is that the total degree is alway even."
+    "##### An immediate corollary to the First Theorem is that the total degree is alway even. This is often referred to as the “Handshake Lemma” or “Handshaking Lemma” (although that name is sometimes applied to the degree sum formula above, and sometimes even to the next theorem about there being an even number of odd vertices)."
    ]
   },
   {
@@ -275,7 +276,11 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "#### One of Euler's theorems: a connected simple graph $G$ has an Eulerian circuit if and only if $G$ has all even vertices."
+    "#### Theorems about the existence of an Euler circuit or Euler trail in a simple connected graph $G$:\n",
+    "\n",
+    "(1) a connected simple graph $G$ has an Eulerian circuit if and only if $G$ has all even vertices;\n",
+    "\n",
+    "(2) a connected simple graph $G$ has an Eulerian trail if and only if $G$ has exactly 2 odd vertices (and every Eulerian trail in $G$ will start at one of the odd vertices and end at the other odd vertex)."
    ]
   },
   {
@@ -286,7 +291,7 @@
    "source": [
     "euler_circuit_iff_all_even_vertices = (\n",
     "    Forall(G,\n",
-    "           Iff(HasEulerCircuit(G),\n",
+    "           Iff(HasEulerianCircuit(G),\n",
     "               Forall(v, InSet(Degree(v, G), IntegerEven), domain = Vertices(G))),\n",
     "    conditions = [Connected(G)],\n",
     "    domain = Graphs()\n",
@@ -299,7 +304,97 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "euler_circuit_imp_all_even_vertices = (\n",
+    "    Forall(G,\n",
+    "           Forall(v, InSet(Degree(v, G), IntegerEven), domain = Vertices(G)),\n",
+    "    conditions = [HasEulerianCircuit(G)],\n",
+    "    domain = Graphs()\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "all_even_vertices_imp_euler_circuit = (\n",
+    "    Forall(G,\n",
+    "           HasEulerianCircuit(G),\n",
+    "    conditions = [Connected(G), Forall(v, InSet(Degree(v, G), IntegerEven), domain = Vertices(G))],\n",
+    "    domain = Graphs()\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "euler_trail_guarantee = (\n",
+    "Forall(G,\n",
+    "    Iff(\n",
+    "    HasEulerianTrail(G),\n",
+    "    Equals(Card(SetOfAll(v, v, condition = InSet(Degree(v, G), IntegerOdd), domain = Vertices(G))), two)\n",
+    "    ),\n",
+    "conditions = [Connected(G)],\n",
+    "domain = Graphs()\n",
+    ")\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "euler_trail_imp_two_odd_vertices = (\n",
+    "Forall(G,\n",
+    "    Equals(Card(SetOfAll(v, v, condition = InSet(Degree(v, G), IntegerOdd), domain = Vertices(G))), two),\n",
+    "conditions = [HasEulerianTrail(G)],\n",
+    "domain = Graphs()\n",
+    ")\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "two_odd_vertices_imp_euler_trail = (\n",
+    "Forall(G,\n",
+    "    HasEulerianTrail(G),\n",
+    "conditions = [Connected(G), Equals(Card(SetOfAll(v, v, condition = InSet(Degree(v, G), IntegerOdd), domain = Vertices(G))), two)],\n",
+    "domain = Graphs()\n",
+    ")\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "euler_trail_between_odd_vertices = (\n",
+    "Forall(G,\n",
+    "    Forall(W,\n",
+    "           Equals(EndVertices(W),\n",
+    "                  SetOfAll(v, v, condition = InSet(Degree(v, G), IntegerOdd),\n",
+    "                           domain = Vertices(G))),\n",
+    "           domain = EulerianTrails(G)),\n",
+    "conditions = [Connected(G), HasEulerianTrail(G)],\n",
+    "domain = Graphs()\n",
+    ")\n",
+    ")"
+   ]
   },
   {
    "cell_type": "code",
diff --git a/packages/proveit/graphs/graph.py b/packages/proveit/graphs/graph.py
index 6c7e963069a7..55fa4b227dcf 100644
--- a/packages/proveit/graphs/graph.py
+++ b/packages/proveit/graphs/graph.py
@@ -66,6 +66,56 @@ def __init__(self, V, E, *, styles=None):
                 self, Graph._operator_, (V, E), styles=styles)
 
 
+class Order(Function):
+    '''
+    Order(G), denoted |G|, represents the order of graph G, giving
+    the number of vertices in graph G. This will be equivalent to
+    |Vertices(G)|.
+    '''
+    # literal operator of the Order operation.
+    _operator_ = Literal(string_format='Order', theory=__file__)
+
+    def __init__(self, G, *, styles=None):
+        '''
+        Represent Order(G), the order of graph G, equivalent
+        to the number of vertices in G.
+        '''
+        self.graph = G
+        Function.__init__(
+                self, Order._operator_, G, styles=styles)
+
+    def string(self, **kwargs):
+        return '|' + self.operand.string() + '|'
+
+    def latex(self, **kwargs):
+        return r'\left|' + self.operand.latex() + r'\right|'
+
+
+class Size(Function):
+    '''
+    Size(G), denoted ||G||, represents the size of graph G, meaning
+    the number of edges in graph G. This will be equivalent to
+    |Edges(G)|.
+    '''
+    # literal operator of the Size operation.
+    _operator_ = Literal(string_format='Size', theory=__file__)
+
+    def __init__(self, G, *, styles=None):
+        '''
+        Represent Size(G), the size of graph G, equivalent
+        to the number of edges in G.
+        '''
+        self.graph = G
+        Function.__init__(
+                self, Size._operator_, G, styles=styles)
+
+    def string(self, **kwargs):
+        return '||' + self.operand.string() + '||'
+
+    def latex(self, **kwargs):
+        return r'\left\|' + self.operand.latex() + r'\right\|'
+
+
 class Connected(Function):
     '''
     Connected(G) is a propositional function (or predicate)
@@ -89,4 +139,46 @@ def __init__(self, G, *, styles=None):
                 self, Connected._operator_, G, styles=styles)
 
 
+class HasEulerianTrail(Function):
+    '''
+    HasEulerTrail(G) is a propositional function (or predicate)
+    claiming that graph G has an Eulerian trail (i.e., G has a
+    walk that uses each and every edge of G exactly once).
+    '''
+
+    # the literal operator of the HasEulerTrail operation
+    _operator_ = Literal(string_format='HasEulerianTrail',
+                         latex_format=r'\textrm{HasEulerianTrail}',
+                         theory=__file__)
+
+    def __init__(self, G, *, styles=None):
+        '''
+        Represent the propositional function HasEulerianTrail(G),
+        claiming graph G has an Eulerian trail.
+        '''
+        self.graph = G
+        Function.__init__(
+                self, HasEulerianTrail._operator_, G, styles=styles)
+
+
+class HasEulerianCircuit(Function):
+    '''
+    HasEulerCircuit(G) is a propositional function (or predicate)
+    claiming that graph G has an Eulerian circuit (i.e., G has a
+    closed walk that uses each and every edge of G exactly once).
+    '''
+
+    # the literal operator of the HasEulerCircuit operation
+    _operator_ = Literal(string_format='HasEulerianCircuit',
+                         latex_format=r'\textrm{HasEulerianCircuit}',
+                         theory=__file__)
+
+    def __init__(self, G, *, styles=None):
+        '''
+        Represent the propositional function HasEulerianCircuit(G),
+        claiming graph G has an Eulerian circuit.
+        '''
+        self.graph = G
+        Function.__init__(
+                self, HasEulerianCircuit._operator_, G, styles=styles)
 

From 81fde461d1ac817f3a9f7ed7d4e6f20005573266 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 26 Jun 2025 16:49:21 -0500
Subject: [PATCH 125/159] Add axiomatic defs for Order(G) and Size(G) for graph
 G

Add axiomatic definitions for Order(G) and Size(G) for graph G, along with Order().definition() and Size().definition() methods and related update of the graphs.demonstrations.ipynb notebook.
---
 .../proveit/graphs/_theory_nbs_/axioms.ipynb  | 26 ++++++++++++++++++-
 .../graphs/_theory_nbs_/demonstrations.ipynb  | 18 +++++++++++++
 packages/proveit/graphs/graph.py              | 24 +++++++++++++++--
 3 files changed, 65 insertions(+), 3 deletions(-)

diff --git a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
index cfa7d3a360c9..5ce5a08c5ec9 100644
--- a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
@@ -23,7 +23,7 @@
     "from proveit.logic.sets import Card, KPowerSet, SetOfAll, SubsetEq\n",
     "from proveit.numbers import two\n",
     "from proveit.graphs import (Closed, Connected, Degree, EdgeSequence, EdgeSet, Edges, Graph, Graphs,\n",
-    "        HasEulerianCircuit, HasEulerianTrail, Size, Vertices, WalkLength, Walks)\n"
+    "        HasEulerianCircuit, HasEulerianTrail, Order, Size, Vertices, WalkLength, Walks)\n"
    ]
   },
   {
@@ -48,6 +48,30 @@
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "graph_order_def = Forall(G, \n",
+    "       Equals(Order(G), Card(Vertices(G))),\n",
+    "       domain = Graphs()\n",
+    "      )"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "graph_size_def = Forall(G, \n",
+    "       Equals(Size(G), Card(Edges(G))),\n",
+    "       domain = Graphs()\n",
+    "      )"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
index 0f58239cb344..937ed8a5ce82 100644
--- a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
@@ -77,6 +77,15 @@
     "Order(G)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Order(G).definition(assumptions = [InClass(G, Graphs())])"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -87,6 +96,15 @@
     "Size(G)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Size(G).definition(assumptions = [InClass(G, Graphs())])"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/graph.py b/packages/proveit/graphs/graph.py
index 55fa4b227dcf..939bb8391265 100644
--- a/packages/proveit/graphs/graph.py
+++ b/packages/proveit/graphs/graph.py
@@ -1,5 +1,5 @@
-from proveit import Function, Literal
-from proveit import E, V
+from proveit import equality_prover, Function, Literal
+from proveit import E, G, V
 from proveit.logic import ClassMembership
 
 class Graphs(Literal):
@@ -90,6 +90,16 @@ def string(self, **kwargs):
     def latex(self, **kwargs):
         return r'\left|' + self.operand.latex() + r'\right|'
 
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self = |G|, deduce and return the equality:
+        |G| = |Vertices(G)|.
+        '''
+        from . import graph_order_def
+        _G_sub = self.operand
+        return graph_order_def.instantiate({G:_G_sub}, auto_simplify=False)
+
 
 class Size(Function):
     '''
@@ -115,6 +125,16 @@ def string(self, **kwargs):
     def latex(self, **kwargs):
         return r'\left\|' + self.operand.latex() + r'\right\|'
 
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self = ||G||, deduce and return the equality:
+        ||G|| = |Edges(G)|.
+        '''
+        from . import graph_size_def
+        _G_sub = self.operand
+        return graph_size_def.instantiate({G:_G_sub}, auto_simplify=False)
+
 
 class Connected(Function):
     '''

From 5ed06e9277cf988075ab0c74a0e250244dacc1c7 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 26 Jun 2025 19:47:40 -0500
Subject: [PATCH 126/159] Add AdjacentVertices() class and update Connected
 class

Add AdjacentVertices() class to graphs/vertices sub-theory package to represent adjacency of two vertices in a graph and add related axiomatic definition of such adjacency, as well as a definition() method. Also add Connected() axiomatic definition and update Connected class with a definition() method. Also update graphs/demonstrations.ipynb notebook with related demos.
---
 packages/proveit/graphs/__init__.py           |  6 +--
 .../proveit/graphs/_theory_nbs_/axioms.ipynb  | 50 +++++++++++++++++--
 .../graphs/_theory_nbs_/demonstrations.ipynb  | 47 +++++++++++++----
 packages/proveit/graphs/graph.py              | 11 ++++
 packages/proveit/graphs/vertices.py           | 39 ++++++++++++++-
 5 files changed, 135 insertions(+), 18 deletions(-)

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index 707fcd27e1a5..c2d71955b02f 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -5,12 +5,12 @@
 from .inclusion import NotSubgraph, Subgraph
 from .membership import (
       GraphMembership, GraphNonmembership, InGraph, NotInGraph)
-from .paths import Path, Paths
+# from .paths import Path, Paths
 from .paths_of import PathsOf
 from .union import GraphUnion
-from .vertices import Degree, Vertices
+from .vertices import AdjacentVertices, Degree, Vertices
 from .walks import (Closed, EdgeSequence, EdgeSet, EndVertices,
-          EulerianTrails, Path, Trail, Walk, WalkLength, Walks)
+          EulerianTrails, Path, Paths, Trail, Walk, WalkLength, Walks)
 
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
diff --git a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
index 5ce5a08c5ec9..f3ebc34317e0 100644
--- a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
@@ -18,12 +18,13 @@
     "# Prepare this notebook for defining the axioms of a theory:\n",
     "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "from proveit import v, E, G, V, W\n",
+    "from proveit import u, v, E, G, P, V, W\n",
     "from proveit.logic import And, Equals, Exists, Forall, InClass, InSet\n",
-    "from proveit.logic.sets import Card, KPowerSet, SetOfAll, SubsetEq\n",
+    "from proveit.logic.sets import Card, Set, KPowerSet, SetOfAll, SubsetEq\n",
     "from proveit.numbers import two\n",
-    "from proveit.graphs import (Closed, Connected, Degree, EdgeSequence, EdgeSet, Edges, Graph, Graphs,\n",
-    "        HasEulerianCircuit, HasEulerianTrail, Order, Size, Vertices, WalkLength, Walks)\n"
+    "from proveit.graphs import (AdjacentVertices, Closed, Connected, Degree, EdgeSequence, EdgeSet, Edges,\n",
+    "        EndVertices, Graph, Graphs, HasEulerianCircuit, HasEulerianTrail, Order, Path,\n",
+    "        Paths, Size, Vertices, WalkLength, Walks)\n"
    ]
   },
   {
@@ -72,6 +73,23 @@
     "      )"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "connected_def = (\n",
+    "    Forall(G,\n",
+    "          Equals(Connected(G),\n",
+    "                 Forall((u, v),\n",
+    "                         Exists(P, Equals(EndVertices(P), Set(u, v)), domain = Paths(G)),\n",
+    "                         domain = Vertices(G))),\n",
+    "          domain = Graphs()\n",
+    "    )\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -111,6 +129,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
+    "# needs a name!\n",
     "Forall(G, SubsetEq(Edges(G), KPowerSet(Vertices(G), two)), domain = Graphs())"
    ]
   },
@@ -136,6 +155,29 @@
     ")"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Two vertices $u$ and $v$ in a graph $G$ are __adjacent__ if there is an edge directly connecting them — _i.e._, $u$ and $v$ are adjacent in graph G if $\\{u, v\\}$ is an edge of $G$."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "adjacent_vertices_def = (\n",
+    "    Forall(G,\n",
+    "           Forall((u, v),\n",
+    "                  Equals(AdjacentVertices(u, v, G), InSet(Set(u, v), Edges(G))),\n",
+    "                  domain = Vertices(G)),\n",
+    "           domain = Graphs()\n",
+    "    )\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
diff --git a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
index 937ed8a5ce82..994cd0d40d42 100644
--- a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
@@ -15,11 +15,11 @@
    "outputs": [],
    "source": [
     "import proveit\n",
-    "from proveit import e, v, x, E, G, P, V\n",
+    "from proveit import e, u, v, x, E, G, P, V\n",
     "from proveit.logic import InClass, InSet, KPowerSet, NotInSet, SubsetEq\n",
     "from proveit.numbers import two\n",
     "from proveit.graphs import (\n",
-    "        Connected, Degree, Edges, Endpoints, Graph, Graphs,\n",
+    "        AdjacentVertices, Connected, Degree, Edges, Endpoints, Graph, Graphs,\n",
     "        HasEulerianCircuit, HasEulerianTrail, Order, Path, Size, Vertices)\n",
     "%begin demonstrations"
    ]
@@ -63,8 +63,8 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "# assert that the example graph is connected\n",
-    "Connected(example_graph)"
+    "# the order of a graph G is the number of vertices in G\n",
+    "Order(G)"
    ]
   },
   {
@@ -73,8 +73,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "# the order of a graph G is the number of vertices in G\n",
-    "Order(G)"
+    "Order(G).definition(assumptions = [InClass(G, Graphs())])"
    ]
   },
   {
@@ -83,7 +82,8 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Order(G).definition(assumptions = [InClass(G, Graphs())])"
+    "# the size of a graph G is the number of edges in G\n",
+    "Size(G)"
    ]
   },
   {
@@ -92,8 +92,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "# the size of a graph G is the number of edges in G\n",
-    "Size(G)"
+    "Size(G).definition(assumptions = [InClass(G, Graphs())])"
    ]
   },
   {
@@ -102,7 +101,17 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Size(G).definition(assumptions = [InClass(G, Graphs())])"
+    "# assert that the example graph is connected\n",
+    "Connected(G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Connected(G).definition(assumptions = [InClass(G, Graphs())])"
    ]
   },
   {
@@ -220,6 +229,24 @@
     "InSet(v, Vertices(P))"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "AdjacentVertices(u, v, G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "AdjacentVertices(u, v, G).definition(assumptions = [InClass(G, Graphs()), InSet(u, Vertices(G)), InSet(v, Vertices(G))])"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
diff --git a/packages/proveit/graphs/graph.py b/packages/proveit/graphs/graph.py
index 939bb8391265..a4532036be37 100644
--- a/packages/proveit/graphs/graph.py
+++ b/packages/proveit/graphs/graph.py
@@ -157,6 +157,17 @@ def __init__(self, G, *, styles=None):
         self.graph = G
         Function.__init__(
                 self, Connected._operator_, G, styles=styles)
+    
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self = Connected(G), deduce and return the equality:
+        Connected(G) = A, where A represents the statement that,
+        for all vertices u, v in G, there exists a u-v path in G.
+        '''
+        from . import connected_def
+        _G_sub = self.operand
+        return connected_def.instantiate({G:_G_sub}, auto_simplify=False)
 
 
 class HasEulerianTrail(Function):
diff --git a/packages/proveit/graphs/vertices.py b/packages/proveit/graphs/vertices.py
index 608f91581899..f184809a1fc1 100644
--- a/packages/proveit/graphs/vertices.py
+++ b/packages/proveit/graphs/vertices.py
@@ -1,4 +1,4 @@
-from proveit import Function, Literal
+from proveit import u, v, G, equality_prover, Function, Literal
 
 class Vertices(Function):
     '''
@@ -51,3 +51,40 @@ def __init__(self, v, G, *, styles=None):
         Function.__init__(
                 self, Degree._operator_, (v, G), styles=styles)
 
+
+class AdjacentVertices(Function):
+    '''
+    For vertices u, v in graph G, AdjacentVertices(u, v, G) denotes
+    the claim that vertices u and v are adjacent in graph G (i.e., 
+    AdjacentVertices(u, v, G) means that {u, v} is an edge in graph G).
+    We use the full 'AdjacentVertices()' for naming and calling the
+    class to distinguish the situation from adjacent edges.
+    '''
+    # the literal operator of the Adjacent operation
+    _operator_ = Literal(string_format='Adjacent',
+                         latex_format=r'\mathrm{Adjacent}',
+                         theory=__file__)
+
+    def __init__(self, u, v, G, *, styles=None):
+        '''
+        Given vertices u, v in graph G, represent the claim that
+        vertices u and v are adjacent in G.
+        '''
+        self.graph = G
+        self.vertices = (u, v)
+        Function.__init__(
+                self, AdjacentVertices._operator_, (u, v, G), styles=styles)
+
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self = AdjacentVertices(u, v, G), deduce and return the
+        equality: AdjacentVertices(u, v, G) = {u, v} in Edges(G).
+        '''
+        from . import adjacent_vertices_def
+        _u_sub = self.operands[0]
+        _v_sub = self.operands[1]
+        _G_sub = self.operands[2]
+        return adjacent_vertices_def.instantiate(
+            {u:_u_sub, v:_v_sub, G:_G_sub}, auto_simplify=False)
+

From 50d561428c398e2dd3aadcf7916257b2091aa218 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 1 Jul 2025 20:06:47 -0500
Subject: [PATCH 127/159] Update walks subtheory pkg with new Walks(k, G) class

Update the graphs/walks subtheory package with new Walks(k, G), Trails(k, G), and Paths(k, G) classes; establish axiomatic definitions for those classes; and update the related walks/demonstrations.ipynb notebook. Just beginning the development of the related membership classes.
---
 packages/proveit/graphs/walks/__init__.py     |   2 +-
 .../graphs/walks/_theory_nbs_/axioms.ipynb    |  85 +++++-
 .../walks/_theory_nbs_/demonstrations.ipynb   | 164 ++++++++++--
 packages/proveit/graphs/walks/walks.py        | 248 +++++++-----------
 .../proveit/graphs/walks/walks_membership.py  | 154 +++++++++++
 5 files changed, 474 insertions(+), 179 deletions(-)
 create mode 100644 packages/proveit/graphs/walks/walks_membership.py

diff --git a/packages/proveit/graphs/walks/__init__.py b/packages/proveit/graphs/walks/__init__.py
index a73801c603b0..b7e856e1eb89 100644
--- a/packages/proveit/graphs/walks/__init__.py
+++ b/packages/proveit/graphs/walks/__init__.py
@@ -1,5 +1,5 @@
 from .walks import (Closed, EdgeSequence, EdgeSet, EndVertices,
-        EulerianTrails, Path, Trail, Walk, WalkLength, Walks)
+        EulerianTrails, Paths, Trails, WalkLength, Walks)
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
 #  Make additions above, or add to sys.modules[__name__].__dict__ below.
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
index c6faf0a6d859..22f493741c97 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
@@ -18,7 +18,13 @@
     "# Prepare this notebook for defining the axioms of a theory:\n",
     "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "# from ... import ..."
+    "# from ... import ...\n",
+    "from proveit import i, k, G, S, T, W, X, Function\n",
+    "from proveit.logic import Card, Equals, Forall, Functions, Injections, InSet, SetOfAll\n",
+    "from proveit.numbers import zero, one, Add, Interval, Natural, subtract\n",
+    "from proveit.graphs import (\n",
+    "        AdjacentVertices, Edges, EdgeSequence, Graphs, Paths,\n",
+    "        Trails, Vertices, Walks)"
    ]
   },
   {
@@ -30,12 +36,87 @@
     "%begin axioms"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A walk $W$ of length $k$ in a simple graph $G$, denoted using $W \\in \\texttt{Walks}(k, G)$, is essentially a sequence of vertices of $G$ such that whenever two vertices $u$ and $v$ are consecutive in the sequence, $u$ and $v$ are also adjacent in $G$."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "walks_k_G_def = (\n",
+    "    Forall(G,\n",
+    "    Forall(k,\n",
+    "    Equals(\n",
+    "        Walks(k, G),\n",
+    "        SetOfAll(S,\n",
+    "             S,\n",
+    "             conditions = [Forall(i, AdjacentVertices(Function(S, i), Function(S, Add(i, one)), G),\n",
+    "                                  domain = Interval(zero, subtract(k, one)))],\n",
+    "             domain = Functions(Interval(zero, k), Vertices(G)))\n",
+    "    ),\n",
+    "    domain = Natural),\n",
+    "    domain = Graphs()\n",
+    "    )\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A trail $T$ of length $k$ in a simple graph $G$, denoted using $T \\in \\texttt{Trails}(k, G)$, is a walk in which no edge is repeated."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "trails_k_G_def = (\n",
+    "    Forall(G, Forall(k,\n",
+    "        Equals(\n",
+    "            Trails(k, G),\n",
+    "            SetOfAll(W,\n",
+    "                 W,\n",
+    "                 conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
+    "                 domain = Walks(k, G), )\n",
+    "        ),\n",
+    "    domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A path $P$ of length $k$ in a simple graph $G$, denoted using $P \\in \\texttt{Paths}(k, G)$, is a walk in which no vertex (and thus no edge) is repeated. This means that the vertex sequence is a one-to-one function."
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "paths_k_G_def = (\n",
+    "    Forall(G, Forall(k,\n",
+    "        Equals(\n",
+    "            Paths(k, G),\n",
+    "            SetOfAll(W,\n",
+    "                 W,\n",
+    "                 conditions = [InSet(W, Injections(Interval(zero, subtract(k, one)), Vertices(G)))],\n",
+    "                 domain = Walks(k, G), )\n",
+    "        ),\n",
+    "    domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
   },
   {
    "cell_type": "code",
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
index b19e2309185e..ed367c0675c2 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
@@ -15,10 +15,11 @@
    "outputs": [],
    "source": [
     "import proveit\n",
-    "from proveit import G, S, W\n",
+    "from proveit import a, b, k, G, P, S, T, W\n",
+    "from proveit.logic import Equals, InSet, Set\n",
     "from proveit.graphs import (\n",
     "        Closed, EdgeSequence, EdgeSet, EndVertices, EulerianTrails, Graph,\n",
-    "        Path, Trail, Walk, WalkLength, Walks)\n",
+    "        Paths, Trails, WalkLength, Walks)\n",
     "%begin demonstrations"
    ]
   },
@@ -49,20 +50,9 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "`Walks(G)` represents the set of all walks in the simple undirected graph $G$. \n",
+    "`Walks(k, G)` represents the set of all walks of length $k$ in the simple undirected graph $G$. \n",
     "\n",
-    "A __walk__ $W$ in a simple undirected graph $G$ is a sequence\n",
-    "    $(u = v_0, v_1, ..., v = v_k)$ of vertices of $G$ such that consecutive\n",
-    "    vertices in the sequence are adjacent in $G$ --- in other words,\n",
-    "    every pair $\\{v_{i}, v_{i+1}\\}$ of vertices (for $i \\in \\{0, 1, ..., k-1\\}$)\n",
-    "    corresponds to an edge in $G$. $u$ and $v$ are called the endvertices\n",
-    "    or endpoints of the walk, and a walk from $u$ to $v$ is often referred\n",
-    "    to as a $u$-$v$ walk. The vertices $v_1, v_2, ..., v_{k-1}$ are called\n",
-    "    _internal vertices_. The number of edges in the walk $W$, denoted\n",
-    "    by $||W||$, is the length of the walk (in this example, $||W|| = k$).\n",
-    "    The number of vertices in walk $W$, including\n",
-    "    multiplicities of repeated vertices, is denoted $|W|$, analogous\n",
-    "    to the notation for the order of a graph, $|G|$."
+    "A __walk__ $W$ in a simple undirected graph $G$ is a sequence $(u = v_0, v_1, ..., v = v_k)$ of vertices of $G$ such that consecutive vertices in the sequence are adjacent in $G$ --- in other words, every pair $\\{v_{i}, v_{i+1}\\}$ of vertices (for $i \\in \\{0, 1, ..., k-1\\}$) corresponds to an edge in $G$. $u$ and $v$ are called the endvertices or endpoints of the walk, and a walk from $u$ to $v$ is often referred to as a $u$-$v$ walk. The vertices $v_1, v_2, ..., v_{k-1}$ are called _internal vertices_. The number of edges in the walk $W$, denoted by $||W||$, is the length of the walk (in this example, $||W|| = k$). The number of vertices in walk $W$, including multiplicities of repeated vertices, is denoted $|W|$, analogous to the notation for the order of a graph, $|G|$."
    ]
   },
   {
@@ -71,14 +61,14 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Walks(G)"
+    "Walks(k, G)"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "A specific walk in graph $G$ consisting of a sequence $S$ of vertices in $G$:"
+    "We can claim that $W$ is a length-$k$ walk in $G$ by claiming $W$ is a member of the set of all such length-$k$ walks:"
    ]
   },
   {
@@ -87,7 +77,23 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Walk(S, G)"
+    "InSet(W, Walks(k, G))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "And we could make more specific assumptions about a walk $W$, for example claiming or assuming that $W$ is a length-$k$ _u_,_v_-walk in $G$ “connecting” vertices $u$ and $v$, using the following:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "temp_assumptions = [InSet(W, Walks(k, G)), Equals(EndVertices(W), Set(a, b))]"
    ]
   },
   {
@@ -158,7 +164,18 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "A trail in graph G, consisting of a sequence $S$ of vertices in $G$. A trail is a walk in which no edge is repeated."
+    "`Trails(k, G)` represents the set of all trails of length $k$ in the simple graph $G$. \n",
+    "\n",
+    "A __trail__ $T$ in a simple graph $G$ is a walk in which no edge is repeated."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Trails(k, G)"
    ]
   },
   {
@@ -167,14 +184,16 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Trail(S, G)"
+    "InSet(T, Trails(k, G))"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "A path in graph $G$, consisting of a sequence $S$ of vertices in $G$. A path is a walk in which no vertices (and thus no edges) are repeated."
+    "`Paths(k, G)` represents the set of all paths of length $k$ in the simple graph $G$. \n",
+    "\n",
+    "A __path__ $P$ in a simple graph $G$ is a walk in which no vertex (and thus no edge) is repeated."
    ]
   },
   {
@@ -183,7 +202,16 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Path(S, G)"
+    "Paths(k, G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(P, Paths(k, G))"
    ]
   },
   {
@@ -218,6 +246,98 @@
     "EulerianTrails(G)"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Defining a walk $W \\in \\texttt{Walks}(G)$ in the simple graph $G$."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A __walk__ $W$ in a simple graph $G$ is a sequence $ S = (v_{0}, v_{1}, \\ldots, v_{k})$ of vertices of $G$ such that two vertices are consecutive in sequence $S$ only if they are adjacent in $G$. We might formulate the constraint like this:\n",
+    "\n",
+    "$$\\texttt{Consecutive}(u, v, S) \\Rightarrow \\texttt{Adjacent}(u, v, G).$$"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A sequence $S$ can be conceptualized as a function $S: \\mathbb{N} \\rightarrow X$, from the natural numbers to some set $X$, where $S(0)$ is the first element of the sequence, $S(1)$ the second, and so on."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    " A $(k+1)$-vertex walk $W \\in \\texttt{Walks}(G)$ would then be a sequence $S: \\{0, 1, \\ldots, k\\} \\rightarrow \\texttt{Vertices}(G)$ such that $\\texttt{Adjacent}(S(i), S(i+1), G)$ for $i \\in \\{0, 1, \\ldots, k-1\\}$. In this approach, $S(0) = s_{0}$ and $S(k) = s_{k}$ are the two endvertices of the walk $W$."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A __path__ $P$ in a simple graph $G$ is a walk in $G$ such that no vertices (and thus no edges) are repeated. If we think of the path/walk as a literal sequence $S = (v_0, v_1, \\ldots, v_k)$, then the non-repetition of vertices might be formulated using a predicate such as $\\texttt{Unique}(S)$ or $\\texttt{NonRepeating}(S)$, or, if we can index the elements of the sequence $S$, we might claim that $\\forall_{v_{i}, v_{j} \\in S} \\big(v_{i} = v_{j} \\Leftrightarrow i = j\\big)$.\n",
+    "\n",
+    "If we think of the path/walk sequence as a function $S: \\{0, 1, \\ldots, k\\} \\rightarrow \\texttt{Vertices}(G)$, a path would be a walk where the sequence (function) $S$ is one-to-one (_i.e._, $S(i) = S(j) \\Rightarrow i = j$).\n",
+    "\n",
+    "domain?\n",
+    "\n",
+    "$W \\in \\texttt{Functions}(\\{0, 1, \\ldots, k\\}, \\texttt{Vertices}(G))$\n",
+    "\n",
+    "$W \\in \\texttt{Walks}(G) := W \\in \\texttt{Functions}(\\{0, 1, \\ldots, k\\}, \\texttt{Vertices}(G))$\n",
+    "\n",
+    "$\\forall_{G \\in \\texttt{Graphs}}\\forall_{k \\in \\mathbb{N}}\\big[\\texttt{Walks}(G, k) := \\texttt{Functions}(\\{0, 1, \\ldots, k\\}, \\texttt{Vertices}(G))\\big]$\n",
+    "\n",
+    "By the end of our discussion on Fri 6/27, generally thinking that we'd represent walks in $G$ as $\\texttt{Walks}(G, k)$ or walks of a specific length $k$ in graph $G$, and those can be represented as special functions (equivalent to a sequence), as written above. And despite the annoyance of using $0$-based indexing, such indexing can be useful since we then talk about lengths of walks as the number of edges, which will be one less than the number of vertices in the sequence. Paths of length $k$ can then be defined in terms of injective walks. And Trails can be defined in terms of injective functions into the edges — to be more clear, WW suggested we might have something like a claim that the EdgeSequence(Trail) is an injective function."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A $(k+1)$-vertex __trail__ $T$ in a simple graph $G$ is a $(k+1)$-vertex walk in $G$ such that no edges are repeated. This would mean that in the walk's vertex sequence $S = \\{v_0, v_1, \\ldots, v_k\\}$, no consecutive pair $(v_{i}, v_{i+1})$ is repeated. Without invoking a function-based definition of the sequence $S$, we might formulate the constraint like this:\n",
+    "\n",
+    "$$ |S| - 1 = |\\{(s_i, s_{i+1}) \\,|\\, i \\in \\{0, 1, \\ldots, k-1\\})\\}|,$$\n",
+    "\n",
+    "where we have a slight abuse of notation using $|S|$ to denote the length of sequence $S$. Using a function-based definition of the sequence $S$, we could say\n",
+    "$$\\forall_{i, j \\in\\{0, 1, \\ldots, k-1\\}} \\big[ (S(i), S(i+1)) = (S(j), S(j+1)) \\Rightarrow i = j \\big]$$\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "If we represent a sequence of elements of set $X$ by $\\texttt{Sequence}(X)$, then it's not clear if there is any utility in having both:\n",
+    "\n",
+    "$\\texttt{Walks}(G)$ and $\\texttt{Walk}(S, G)$ (_e.g._, we just say that $W \\in \\texttt{Walks}(G)$ instead of $W = \\texttt{Walk}(S, G)$?)\n",
+    "\n",
+    "$\\texttt{Trails}(G)$ and $\\texttt{Trail}(S, G)$ (_e.g._, we just say that $T \\in \\texttt{Trails}(G)$ instead of $T = \\texttt{Trail}(S, G)$?)\n",
+    "\n",
+    "$\\texttt{Paths}(G)$ and $\\texttt{Path}(S, G)$ (_e.g._, we just say that $P \\in \\texttt{Paths}(G)$ instead of $P = \\texttt{Path}(S, G)$)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "$\\forall_{x_1, \\ldots, x_n}\\big(P(x_1, x_2, \\ldots, x_n)\\big)$\n",
+    "\n",
+    "WW is leaning toward something like this: the above would be a “style”\n",
+    "but now internally\n",
+    "\n",
+    "$\\forall_x \\big(P(x(1), x(2), \\ldots, x(n))\\big)$\n",
+    "\n",
+    "where $x$ is now a function. \n",
+    "\n",
+    "Defining an existential:\n",
+    "\n",
+    "$[\\exists] = P \\mapsto \\lnot(\\forall_{x} (\\lnot P(x)))$"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/walks/walks.py b/packages/proveit/graphs/walks/walks.py
index 1e8e070bb1b7..c466df730aa3 100644
--- a/packages/proveit/graphs/walks/walks.py
+++ b/packages/proveit/graphs/walks/walks.py
@@ -4,19 +4,25 @@
 
 class Walks(Function):
     '''
-    Walks(G) represents the set of walks in the simple undirected
-    graph G. A walk W in a simple undirected graph G is a sequence
-    (u = v0, v1, ..., v = vk) of vertices of G such that consecutive
-    vertices in the sequence are adjacent in G --- in other words,
-    every pair {v_{i}, v_{i+1}} of vertices (for i in {0, 1, ..., k-1})
-    corresponds to an edge in G. u and v are called the endvertices
-    or endpoints of the walk, and a walk from u to v is often referred
-    to as a u-v walk. The vertices v1, v2, ..., v_{k-1} are called
-    internal vertices. The number of edges in the walk W, denoted
-    by ||W||, is the length of the walk (in this example, ||W|| = k).
-    The number of vertices in the Walk sequence W, including
-    multiplicities of repeated vertices, is denoted |W|, analogous
-    to the notation for the order of a graph, |G|.
+    Walks(k, G) represents the set of walks of length k in the simple
+    undirected graph G. A walk W in a simple undirected graph G is a
+    sequence (u = v0, v1, ..., v = vk) of vertices of G such that
+    consecutive vertices in the sequence are adjacent in G ---
+    in other words, every pair {v_{i}, v_{i+1}} of vertices
+    (for i in {0, 1, ..., k-1}) corresponds to an edge in G.
+    u and v are called the endvertices or endpoints of the walk, and
+    a walk from u to v is often referred to as a u-v walk.
+    The vertices v1, v2, ..., v_{k-1} are called internal vertices.
+    The number of edges in the walk W, denoted by ||W||, is the
+    length of the walk (in this example, ||W|| = k).
+    The number of vertices in the walk W, including multiplicities
+    of repeated vertices, is denoted |W|, analogous to the notation
+    for the order of a graph, |G|.
+    Ultimately, the vertex sequence characterizing a walk W is
+    conceptualized as a function, S: {0, 1, ..., k} -> Vertices(G),
+    and thus a walk is itself conceptualized as a special kind of
+    function.
+    Trails, paths, circuits, and cycles are all special cases of walks.
     '''
 
     # the literal operator of the Walks operation
@@ -24,44 +30,100 @@ class Walks(Function):
                          latex_format=r'\textrm{Walks}',
                          theory=__file__)
 
-    def __init__(self, G, *, styles=None):
+    def __init__(self, k, G, *, styles=None):
         '''
-        Represent the set Walks(G) of all walks in graph G.
+        Represent Walks(k, G), the set of all walks of
+        length k in graph G.
         '''
         self.graph = G
+        self.length = k
         Function.__init__(
-                self, Walks._operator_, G, styles=styles)
+                self, Walks._operator_, (k, G), styles=styles)
+
+#   membership objects/development under construction
+#     def membership_object(self, element):
+#         from .walks_membership import WalksMembership
+#         return WalksMembership(element, self)
+
+#     def nonmembership_object(self, element):
+#         from .walks_membership import WalksNonmembership
+#         return WalksNonmembership(element, self)
 
-class Walk(Function):
+
+class Trails(Function):
     '''
-    Walk(S, G) represents a walk in the simple undirected graph G
-    with vertex sequence S. See the description above under Walks(G)
-    for a definition of a walk in graph G.
+    Trails(k, G) represents the set of trails of length k in the
+    simple graph G. A trail is a walk in which no edge is repeated.
+    See the Walks() class above for a definition of walk.
+    A trail with endvertices u and v is often called a u-v trail.
     '''
 
-    # the literal operator of the Walk(S,G) operation
-    _operator_ = Literal(string_format='Walk',
-                         latex_format=r'\textrm{Walk}',
+    # the literal operator of the Walks operation
+    _operator_ = Literal(string_format='Trails',
+                         latex_format=r'\textrm{Trails}',
                          theory=__file__)
 
-    def __init__(self, S, G, *, styles=None):
+    def __init__(self, k, G, *, styles=None):
         '''
-        Represent Walk(S, G), the walk in G consisting of vertex
-        sequence S in the simple undirected graph G.
+        Represent Trails(k, G), the set of all trails of
+        length k in graph G.
         '''
         self.graph = G
-        self.vertex_sequence = S
+        self.length = k
         Function.__init__(
-                self, Walk._operator_, (S, G), styles=styles)
+                self, Trails._operator_, (k, G), styles=styles)
+
+#   membership objects/development under construction
+#     def membership_object(self, element):
+#         from .walks_membership import WalksMembership
+#         return WalksMembership(element, self)
+
+#     def nonmembership_object(self, element):
+#         from .walks_membership import WalksNonmembership
+#         return WalksNonmembership(element, self)
+
+
+class Paths(Function):
+    '''
+    Paths(k, G) represents the set of paths of length k in the simple
+    graph G. A path is a walk in which no vertex (and thus no edge)
+    is repeated. See the Walks() class above for a definition of walk.
+    A path with endvertices u and v is often called a u-v path.
+    '''
+
+    # the literal operator of the Walks operation
+    _operator_ = Literal(string_format='Paths',
+                         latex_format=r'\textrm{Paths}',
+                         theory=__file__)
+
+    def __init__(self, k, G, *, styles=None):
+        '''
+        Represent Paths(k, G), the set of all paths of
+        length k in graph G.
+        '''
+        self.graph = G
+        self.length = k
+        Function.__init__(
+                self, Paths._operator_, (k, G), styles=styles)
+
+#   membership objects/development under construction
+#     def membership_object(self, element):
+#         from .walks_membership import WalksMembership
+#         return WalksMembership(element, self)
+
+#     def nonmembership_object(self, element):
+#         from .walks_membership import WalksNonmembership
+#         return WalksNonmembership(element, self)
+
 
 class WalkLength(Function):
     '''
     WalkLength(W), denoted ||W||, represents the length of walk W
     (where W could be a walk or one of the special cases of a
-    trail, path, circuit, etc., all of which area also walks)
+    trail, path, circuit, etc., all of which area also walks),
     equivalent to the number of edges crossed during the walk
     (including multiplicities). For example, given a walk
-    W = Walk(S, G) in graph G with vertex sequence
+    W in Walks(5, G) in graph G with vertex sequence
         S = (a, b, c, b, d, e),
     we have WalkLength(W) = ||W|| = 5. Notice that ||W|| is always
     equal to len(S) - 1, where len(S) is the length of sequence S.
@@ -109,7 +171,7 @@ def __init__(self, W, *, styles=None):
 
 class EdgeSequence(Function):
     '''
-    Given a walk W = Walk(S, G) consisting of vertex sequence S in
+    Given a walk W in Walks(k, G) consisting of vertex sequence S in
     graph G, EdgeSeq(W) represents the sequence of edges traveled
     along the walk, which for a simple graph is completely
     determined by the vertex sequence S. The number of edges in
@@ -134,7 +196,7 @@ def __init__(self, W, *, styles=None):
 
 class EdgeSet(Function):
     '''
-    Given a walk W = Walk(S, G) consisting of vertex sequence S in
+    Given a walk W in Walks(k, G) consisting of vertex sequence S in
     graph G, EdgeSet(W) represents the set (not the sequence) of edges
     traveled along the walk, which for a simple graph is completely
     determined by the vertex sequence S. The sequence of edges traveled
@@ -158,52 +220,6 @@ def __init__(self, W, *, styles=None):
                 self, EdgeSet._operator_, W, styles=styles)
 
 
-class Trail(Function):
-    '''
-    Trail(S, G) represents a trail in the simple undirected graph G
-    with vertex sequence S. A trail is a walk (see the description
-    above in the Walks(G) class) in which no edge is repeated.
-    '''
-
-    # the literal operator of the Trail(S,G) operation
-    _operator_ = Literal(string_format='Trail',
-                         latex_format=r'\textrm{Trail}',
-                         theory=__file__)
-
-    def __init__(self, S, G, *, styles=None):
-        '''
-        Represent Trail(S, G), the trail in G consisting of vertex
-        sequence S in the simple undirected graph G.
-        '''
-        self.graph = G
-        self.vertex_sequence = S
-        Function.__init__(
-                self, Trail._operator_, (S, G), styles=styles)
-
-
-class Path(Function):
-    '''
-    Path(S, G) represents a path in the simple undirected graph G
-    with vertex sequence S. A path is a walk (see the description
-    above in the Walks(G) class) in which no vertex (and thus no edge)
-    is repeated.
-    '''
-
-    # the literal operator of the Path(S,G) operation
-    _operator_ = Literal(string_format='Path',
-                         latex_format=r'\textrm{Path}',
-                         theory=__file__)
-
-    def __init__(self, S, G, *, styles=None):
-        '''
-        Represent Path(S, G), the path in G consisting of vertex
-        sequence S in the simple undirected graph G.
-        '''
-        self.graph = G
-        self.vertex_sequence = S
-        Function.__init__(
-                self, Path._operator_, (S, G), styles=styles)
-
 
 class EndVertices(Function):
     '''
@@ -253,79 +269,3 @@ def __init__(self, G, *, styles=None):
         self.graph = G
         Function.__init__(
                 self, EulerianTrails._operator_, G, styles=styles)
-
-
-# class Paths(Literal):
-#     '''
-#     Paths() represents the set of all graphs that are (undirected)
-#     paths. A undirected path is a non-empty graph P = (V,E)
-#     with non-empty vertex set V and (possibly empty) edge set E such
-#     that:
-#             V = {x0, x1, ..., xk},
-#             E = {{x0,x1}, {x1,x2}, ..., {x_{k-1},x_{k}},
-
-#     where the x_{i} are all distinct. The vertices x0 and xk are said
-#     to be linked by the path P and are called its endvertices, or
-#     endpoints, or simply its ends. The vertices x1, ..., x_{k-1} are
-#     the inner vertices of P. The number of edges in the path P,
-#     denoted ||P||, is its length (in this example, ||P|| = k).
-#     '''
-
-#     # the literal string for representing the class of Paths
-#     def __init__(self, *, styles=None):
-#         Literal.__init__(self, string_format='Paths', 
-#                          latex_format=r'\textrm{Paths}',
-#                          styles=styles)
-
-#     @property
-#     def is_proper_class(self):
-#         '''
-#         Paths consitute a proper class (i.e. instead of a set).
-#         This indicates that InClass() should be used instead of
-#         InSet() when this is a domain.
-#         '''
-#         return True
-
-#     def membership_object(self, element):
-#         from .paths_membership import PathsMembership
-#         return PathsMembership(element, self)
-
-#     def nonmembership_object(self, element):
-#         from .paths_membership import PathsNonmembership
-#         return PathsNonmembership(element, self)
-
-
-# class Path(Graph):
-#     '''
-#     Path(V,E) represents the special type of graph called a path,
-#     with vertex set V and edge set E. A path is a non-empty graph
-#     P = (V,E) with vertex set V and (possibly empty) edge set E such
-#     that:
-
-#         V = {x0, x1, ..., xk}, E = {x0x1, x1x2, ..., x_{k-1}x_{k}},
-
-#     where the x_{i} are all distinct. The vertices x0 and xk are said
-#     to be linked by the path P and are called its endvertices, or
-#     endpoints, or simply its ends. The vertices x1, ..., x_{k-1} are
-#     the inner vertices of P. The number of edges in the path P,
-#     denoted ||P||, is its length (in this example, ||P|| = k).
-#     '''
-
-#     # the literal operator of the Path operator
-#     _operator_ = Literal(string_format='Path',
-#                          latex_format=r'\text{Path}',
-#                          theory=__file__)
-
-#     def __init__(self, V, E, *, styles=None):
-#         '''
-#         Create or represent a path, Path(V,E), with vertex set V
-#         and edge set E. If explicit sets of vertices and edges are
-#         provided, they are NOT currently verified to represent a
-#         valid path.
-#         '''
-#         self.vertex_set = V
-#         self.edge_set   = E
-#         Function.__init__(self, Path._operator_, (V, E), styles=styles)
-
-
-
diff --git a/packages/proveit/graphs/walks/walks_membership.py b/packages/proveit/graphs/walks/walks_membership.py
new file mode 100644
index 000000000000..6e32e76e4471
--- /dev/null
+++ b/packages/proveit/graphs/walks/walks_membership.py
@@ -0,0 +1,154 @@
+from proveit import e, E, V, equality_prover, prover
+from proveit.logic import SetMembership, SetNonmembership
+from proveit.graphs import Graph
+
+
+class WalksMembership(SetMembership):
+    '''
+    Defines methods that apply to membership in the set
+    of walks in the simple graph G, denoted Walks(G).
+
+    UNDER CONSTRUCTION
+    '''
+
+    def __init__(self, element, domain):
+        SetMembership.__init__(self, element, domain)
+
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self = [elem in Edges(Graph(V,E))], deduce and return:
+            [elem in Edges(Graph(V,E))] = [elem in E]
+        '''
+        from . import edges_membership_def
+        element = self.element
+        _V_sub  = self.domain.graph.vertex_set
+        _E_sub  = self.domain.graph.edge_set
+        return edges_membership_def.instantiate(
+                {e:element, V:_V_sub, E:_E_sub },auto_simplify=False)
+
+    def as_defined(self):
+        '''
+        From self = [elem in Edges(Graph(V,E))], return: [elem in E]
+        (i.e. an expression, not a Judgment)
+        '''
+        if isinstance(self.domain.operand, Graph):
+            from proveit.logic import InSet
+            element = self.element
+            _E = self.domain.graph.edge_set
+            return InSet(element, _E)
+        else:
+            raise NotImplementedError(
+                "EdgesMembership.as_defined() was called on "
+                f"self = {self.expr} with domain = {self.expr.domain}, "
+                "but the method is implemented only for domains of the "
+                "form Edges(G) where G is an explicit Graph object "
+                "of the form G = Graph(V,E) with a named edge set E.")
+
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        From self = [elem in Edges(Graph(V,E))],
+        derive and return [elem in E], knowing or assuming self.
+        '''
+        from . import edges_membership_unfolding
+        element = self.element
+        _V_sub  = self.domain.graph.vertex_set
+        _E_sub  = self.domain.graph.edge_set
+        return edges_membership_unfolding.instantiate(
+            {e:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Called on self = [elem in Edges(Graph(V,E))], and
+        knowing or assuming [elem in E] (and that E is a subset
+        of [V]^2, a subset of the set of 2-element subsets of V)
+        derive and return self.
+        '''
+        from . import edges_membership_folding
+        element = self.element
+        _V_sub  = self.domain.graph.vertex_set
+        _E_sub  = self.domain.graph.edge_set
+        return edges_membership_folding.instantiate(
+            {e:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
+
+
+class EdgesNonmembership(SetNonmembership):
+    '''
+    Defines methods that apply to non-membership in the set
+    Edges(G(V,E)) of the edges E of graph G.
+    '''
+
+    def __init__(self, element, domain):
+        SetNonmembership.__init__(self, element, domain)
+
+    def side_effects(self, judgment):
+        '''
+        Currently no side-effects for EdgesNonmembership.
+        '''
+        return
+        yield
+
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self = [elem not in Edges(Graph(V,E))], deduce and
+        return: [elem not in Edges(Graph(V,E))] = [elem not in E].
+        '''
+
+        from . import edges_nonmembership_def
+        element = self.element
+        _V_sub  = self.domain.graph.vertex_set
+        _E_sub  = self.domain.graph.edge_set
+        return edges_nonmembership_def.instantiate(
+                {e:element, V:_V_sub, E:_E_sub },auto_simplify=False)
+
+    def as_defined(self):
+        '''
+        From self = [elem not in Edges(Graph(V,E))],
+        return: [elem not in E] (i.e. an expression, not a Judgment)
+        '''
+        if isinstance(self.domain.operand, Graph):
+            from proveit.logic import NotInSet
+            element = self.element
+            _E = self.domain.graph.edge_set
+            return NotInSet(element, _E)
+        else:
+            raise NotImplementedError(
+                "EdgesNonmembership.as_defined() was called on "
+                f"self = {self.expr} with domain = {self.expr.domain}, "
+                "but the method is implemented only for domains of the "
+                "form Edges(G) where G is an explicit Graph object "
+                "of the form G = Graph(V,E) with a named edge set E.")
+
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        From self = [elem not in Edges(Graph(V,E))],
+        derive and return [elem not in E], knowing or assuming self,
+        (and that E is a subset of [V]^2, i.e., a subset of the set
+        of 2-element subsets of V).
+        '''
+        from . import edges_nonmembership_unfolding
+        element = self.element
+        _V_sub  = self.domain.graph.vertex_set
+        _E_sub  = self.domain.graph.edge_set
+        return edges_nonmembership_unfolding.instantiate(
+            {e:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Called on self = [elem not in Edges(Graph(V,E))], and
+        knowing or assuming [elem not in E] (and that E is a subset
+        of [V]^2, a subset of the set of 2-element subsets of V)
+        derive and return self.
+        '''
+        from . import edges_nonmembership_folding
+        element = self.element
+        _V_sub  = self.domain.graph.vertex_set
+        _E_sub  = self.domain.graph.edge_set
+        return edges_nonmembership_folding.instantiate(
+            {e:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
+

From 9cc45a840a1063fe4fdfe79204b8050548df85cb Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 1 Jul 2025 20:08:21 -0500
Subject: [PATCH 128/159] Update graphs pkg to incorporate recent Walks(k, G)
 updates

Update graphs package to incorporate recent Walks(k, G), Trails(k, G), and Paths(k, G) updates (see earlier commit).
---
 packages/proveit/graphs/__init__.py           |  2 +-
 .../proveit/graphs/_theory_nbs_/axioms.ipynb  | 67 ++++++++++++++++---
 .../graphs/_theory_nbs_/demonstrations.ipynb  | 20 +-----
 3 files changed, 60 insertions(+), 29 deletions(-)

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index c2d71955b02f..bf19a2283ee6 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -10,7 +10,7 @@
 from .union import GraphUnion
 from .vertices import AdjacentVertices, Degree, Vertices
 from .walks import (Closed, EdgeSequence, EdgeSet, EndVertices,
-          EulerianTrails, Path, Paths, Trail, Walk, WalkLength, Walks)
+          EulerianTrails, Paths, Trails, WalkLength, Walks)
 
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
diff --git a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
index f3ebc34317e0..79e074bb369b 100644
--- a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
@@ -18,10 +18,10 @@
     "# Prepare this notebook for defining the axioms of a theory:\n",
     "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "from proveit import u, v, E, G, P, V, W\n",
+    "from proveit import k, u, v, E, G, P, V, W\n",
     "from proveit.logic import And, Equals, Exists, Forall, InClass, InSet\n",
     "from proveit.logic.sets import Card, Set, KPowerSet, SetOfAll, SubsetEq\n",
-    "from proveit.numbers import two\n",
+    "from proveit.numbers import two, Natural\n",
     "from proveit.graphs import (AdjacentVertices, Closed, Connected, Degree, EdgeSequence, EdgeSet, Edges,\n",
     "        EndVertices, Graph, Graphs, HasEulerianCircuit, HasEulerianTrail, Order, Path,\n",
     "        Paths, Size, Vertices, WalkLength, Walks)\n"
@@ -83,7 +83,7 @@
     "    Forall(G,\n",
     "          Equals(Connected(G),\n",
     "                 Forall((u, v),\n",
-    "                         Exists(P, Equals(EndVertices(P), Set(u, v)), domain = Paths(G)),\n",
+    "                         Exists((P, k), Equals(EndVertices(P), Set(u, v)), domains = [Paths(k, G), Natural]),\n",
     "                         domain = Vertices(G))),\n",
     "          domain = Graphs()\n",
     "    )\n",
@@ -182,7 +182,56 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Characterizing what it means for a graph $G$ to have an Eulerian circuit: this means that there exists a closed walk $W$ in graph $G$ such that $W$ uses each and every edge of $G$ exactly once. That can be awkward to express literally in _Prove-It_, but an equivalent definition involves a walk whose edge set is the same as the graph's edge set (capturing the idea that we use all of the edges of $G$), while the length of the walk (i.e. the number of edges) is the same as the cardinality of the graph's edge set (_i.e._, the “size” of the graph) (capturing the idea that we have no repeated edges)."
+    "The following three items might be an elegant way to simply use a broader class called Adjacent, which then is axiomatically defined to Or or XOr over the AdjacentVertices and AdjacentEdges classes (discussed w/WW on 20250627):"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Forall(G,\n",
+    "#            Forall((u, v),\n",
+    "#                   Equals(AdjacentVertices(u, v, G), InSet(Set(u, v), Edges(G))),\n",
+    "#                   ),\n",
+    "#            domain = Graphs()\n",
+    "#     )"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Forall(G,\n",
+    "#            Forall((u, v),\n",
+    "#                   Equals(Adjacent(u, v, G), Or(AdjacentVertices(u, v, G), AdjacentEdges(u, v, G))),\n",
+    "#                   ),\n",
+    "#            domain = Graphs()\n",
+    "#     )"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# class Adjacent(x, y, G):\n",
+    "#     '''\n",
+    "#     Adjacent(x, y, G) is the claim that x and y are adjacent in G.\n",
+    "#     x, y could be vertices, or they could be edges ...\n",
+    "#     '''\n",
+    "#     then define the operator, etc"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Characterizing what it means for a graph $G$ to have an Eulerian circuit: this means that there exists a closed walk $W$ in graph $G$ such that $W$ uses each and every edge of $G$ exactly once. That can be challenging to express literally in _Prove-It_, but an equivalent definition involves a walk whose edge set is the same as the graph's edge set (capturing the idea that we use all of the edges of $G$), while the length of the walk (i.e. the number of edges) is the same as the cardinality of the graph's edge set (_i.e._, the “size” of the graph) (capturing the idea that we have no repeated edges). The cardinality constraint is captured by taking $W$ to be in the set of $\\texttt{Walks}(||G||, G)$, _i.e._ walks of exactly the desired length $||G||$. "
    ]
   },
   {
@@ -194,8 +243,8 @@
     "has_eulerian_circuit_def = Forall(G,\n",
     "    Equals(\n",
     "    HasEulerianCircuit(G),\n",
-    "    Exists(W, And(Equals(EdgeSet(W), Edges(G)), Equals(WalkLength(W), Size(G))),\n",
-    "       conditions = [Closed(W)], domain = Walks(G))\n",
+    "    Exists(W, Equals(EdgeSet(W), Edges(G)),\n",
+    "       conditions = [Closed(W)], domain = Walks(Size(G), G))\n",
     "    ),\n",
     "conditions = [Connected(G)],\n",
     "domain = Graphs()\n",
@@ -206,7 +255,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Characterizing what it means for a graph $G$ to have an Eulerian trail: this means that there exists a walk $W$ in graph $G$ such that $W$ uses each and every edge of $G$ exactly once. If the walk is closed, then the Eulerian trail is an Eulerian circuit. As in the case of the Eulerian circuit, the definition can be awkward to express literally in _Prove-It_, but an equivalent definition involves a walk whose edge set is the same as the graph's edge set (capturing the idea that we use all of the edges of $G$), while the length of the walk (i.e. the number of edges) is the same as the cardinality of the graph's edge set (_i.e._, the “size” of the graph) (capturing the idea that we have no repeated edges)."
+    "Characterizing what it means for a graph $G$ to have an Eulerian trail: this means that there exists a walk $W$ in graph $G$ such that $W$ uses each and every edge of $G$ exactly once. If the walk is closed, then the Eulerian trail is an Eulerian circuit (see above). As in the case of the Eulerian circuit, the definition can be difficult to express literally in _Prove-It_, but an equivalent definition involves a walk whose edge set is the same as the graph's edge set (capturing the idea that we use all of the edges of $G$), while the length of the walk (i.e. the number of edges) is the same as the cardinality of the graph's edge set (_i.e._, the “size” of the graph) (capturing the idea that we have no repeated edges)."
    ]
   },
   {
@@ -218,8 +267,8 @@
     "has_eulerian_trail_def = Forall(G,\n",
     "    Equals(\n",
     "    HasEulerianTrail(G),\n",
-    "    Exists(W, And(Equals(EdgeSet(W), Edges(G)), Equals(WalkLength(W), Size(G))),\n",
-    "       domain = Walks(G))\n",
+    "    Exists(W, Equals(EdgeSet(W), Edges(G)),\n",
+    "       domain = Walks(Size(G), G))\n",
     "    ),\n",
     "conditions = [Connected(G)],\n",
     "domain = Graphs()\n",
diff --git a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
index 994cd0d40d42..1d3516bdec3a 100644
--- a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
@@ -20,7 +20,7 @@
     "from proveit.numbers import two\n",
     "from proveit.graphs import (\n",
     "        AdjacentVertices, Connected, Degree, Edges, Endpoints, Graph, Graphs,\n",
-    "        HasEulerianCircuit, HasEulerianTrail, Order, Path, Size, Vertices)\n",
+    "        HasEulerianCircuit, HasEulerianTrail, Order, Size, Vertices)\n",
     "%begin demonstrations"
    ]
   },
@@ -134,24 +134,6 @@
     "HasEulerianCircuit(G)"
    ]
   },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "P = Path(V, E)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "example_endpts = Endpoints(P)"
-   ]
-  },
   {
    "cell_type": "markdown",
    "metadata": {},

From ef281a5352ea7928cb7039fc65ed72034f07f3c9 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 3 Jul 2025 17:01:11 -0500
Subject: [PATCH 129/159] Minor cleanup of graphs/walks axioms

Minor cleanup of graphs/walks axioms, mainly some elaboration and editing of comments.
---
 packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
index 22f493741c97..5b080dd46349 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
@@ -70,7 +70,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "A trail $T$ of length $k$ in a simple graph $G$, denoted using $T \\in \\texttt{Trails}(k, G)$, is a walk in which no edge is repeated."
+    "A trail $T$ of length $k$ in a simple graph $G$, denoted using $T \\in \\texttt{Trails}(k, G)$, is a walk in which no edge is repeated. This means that the _edge_ sequence is a one-to-one (injective) function $S: [0, 1, \\ldots, k] \\rightarrow \\texttt{Edges}(G)$."
    ]
   },
   {
@@ -84,9 +84,9 @@
     "        Equals(\n",
     "            Trails(k, G),\n",
     "            SetOfAll(W,\n",
-    "                 W,\n",
+    "                 W\n",
     "                 conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
-    "                 domain = Walks(k, G), )\n",
+    "                 domain = Walks(k, G) )\n",
     "        ),\n",
     "    domain = Natural), domain = Graphs())\n",
     ")"
@@ -96,7 +96,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "A path $P$ of length $k$ in a simple graph $G$, denoted using $P \\in \\texttt{Paths}(k, G)$, is a walk in which no vertex (and thus no edge) is repeated. This means that the vertex sequence is a one-to-one function."
+    "A path $P$ of length $k$ in a simple graph $G$, denoted using $P \\in \\texttt{Paths}(k, G)$, is a walk in which no vertex (and thus no edge) is repeated. This means that the vertex sequence is a one-to-one (injective) function $S: [0, 1, \\ldots, k] \\rightarrow \\texttt{Vertices}(G)$."
    ]
   },
   {

From 5d188c6650a2aa3fac091f5ea466745e1025cdf1 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 3 Jul 2025 17:07:17 -0500
Subject: [PATCH 130/159] Add several thms to graphs/walks subtheory pkg
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Add several theorems to the graphs/walks sub-theory package, mostly for WalksMembership(), TrailsMembership(), and PathsMembership() classes, but also a “walk implies path” theorem. See later commit for related updates to the walks.py and walks_membership.py code.
---
 .../paths_membership_def/thm_proof.ipynb      |  47 +++
 .../paths_membership_folding/thm_proof.ipynb  |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../paths_membership_is_bool/thm_proof.ipynb  |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../trails_membership_def/thm_proof.ipynb     |  47 +++
 .../trails_membership_folding/thm_proof.ipynb |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../trails_membership_is_bool/thm_proof.ipynb |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../proofs/walk_implies_path/thm_proof.ipynb  |  47 +++
 .../walks_membership_def/thm_proof.ipynb      |  47 +++
 .../walks_membership_folding/thm_proof.ipynb  |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../walks_membership_is_bool/thm_proof.ipynb  |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../graphs/walks/_theory_nbs_/theorems.ipynb  | 322 +++++++++++++++++-
 20 files changed, 1213 insertions(+), 2 deletions(-)
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_def/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_folding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_folding_components/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_is_bool/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_unfolding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_unfolding_components/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_def/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_folding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_folding_components/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_is_bool/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_unfolding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_unfolding_components/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/walk_implies_path/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_def/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_folding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_folding_components/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_is_bool/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_unfolding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_unfolding_components/thm_proof.ipynb

diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_def/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_def/thm_proof.ipynb
new file mode 100644
index 000000000000..4f89f9bb9b07
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_def/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#paths_membership_def\">paths_membership_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving paths_membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_folding/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..aa97f27f9ae2
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_folding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#paths_membership_folding\">paths_membership_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving paths_membership_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_folding_components/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_folding_components/thm_proof.ipynb
new file mode 100644
index 000000000000..485fc4f37b43
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_folding_components/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#paths_membership_folding_components\">paths_membership_folding_components</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving paths_membership_folding_components"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_is_bool/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_is_bool/thm_proof.ipynb
new file mode 100644
index 000000000000..81dd8f5c7340
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_is_bool/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#paths_membership_is_bool\">paths_membership_is_bool</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving paths_membership_is_bool"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_unfolding/thm_proof.ipynb
new file mode 100644
index 000000000000..571ac57c2409
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_unfolding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#paths_membership_unfolding\">paths_membership_unfolding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving paths_membership_unfolding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_unfolding_components/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_unfolding_components/thm_proof.ipynb
new file mode 100644
index 000000000000..ba73c5d6dbb3
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_membership_unfolding_components/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#paths_membership_unfolding_components\">paths_membership_unfolding_components</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving paths_membership_unfolding_components"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_def/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_def/thm_proof.ipynb
new file mode 100644
index 000000000000..7da8c3d9327c
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_def/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#trails_membership_def\">trails_membership_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving trails_membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_folding/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..26bc0eedcc20
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_folding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#trails_membership_folding\">trails_membership_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving trails_membership_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_folding_components/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_folding_components/thm_proof.ipynb
new file mode 100644
index 000000000000..ff8250a587d6
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_folding_components/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#trails_membership_folding_components\">trails_membership_folding_components</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving trails_membership_folding_components"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_is_bool/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_is_bool/thm_proof.ipynb
new file mode 100644
index 000000000000..6d32c3646aca
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_is_bool/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#trails_membership_is_bool\">trails_membership_is_bool</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving trails_membership_is_bool"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_unfolding/thm_proof.ipynb
new file mode 100644
index 000000000000..0425ae0ee59c
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_unfolding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#trails_membership_unfolding\">trails_membership_unfolding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving trails_membership_unfolding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_unfolding_components/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_unfolding_components/thm_proof.ipynb
new file mode 100644
index 000000000000..9e80a53288b4
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_membership_unfolding_components/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#trails_membership_unfolding_components\">trails_membership_unfolding_components</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving trails_membership_unfolding_components"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/walk_implies_path/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/walk_implies_path/thm_proof.ipynb
new file mode 100644
index 000000000000..a6a181e40212
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/walk_implies_path/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#walk_implies_path\">walk_implies_path</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving walk_implies_path"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_def/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_def/thm_proof.ipynb
new file mode 100644
index 000000000000..c2948433cf01
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_def/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#walks_membership_def\">walks_membership_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving walks_membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_folding/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..5046e5b6c9ff
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_folding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#walks_membership_folding\">walks_membership_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving walks_membership_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_folding_components/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_folding_components/thm_proof.ipynb
new file mode 100644
index 000000000000..6b1c36224bf5
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_folding_components/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#walks_membership_folding_components\">walks_membership_folding_components</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving walks_membership_folding_components"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_is_bool/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_is_bool/thm_proof.ipynb
new file mode 100644
index 000000000000..04ebad452e92
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_is_bool/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#walks_membership_is_bool\">walks_membership_is_bool</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving walks_membership_is_bool"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_unfolding/thm_proof.ipynb
new file mode 100644
index 000000000000..5745cc1ef142
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_unfolding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#walks_membership_unfolding\">walks_membership_unfolding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving walks_membership_unfolding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_unfolding_components/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_unfolding_components/thm_proof.ipynb
new file mode 100644
index 000000000000..c7cdf25a6807
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/walks_membership_unfolding_components/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#walks_membership_unfolding_components\">walks_membership_unfolding_components</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving walks_membership_unfolding_components"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
index 5260797e5412..c8fadc8605d6 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
@@ -18,7 +18,12 @@
     "# Prepare this notebook for defining the theorems of a theory:\n",
     "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "# from ... import ..."
+    "from proveit import i, j, k, u, v, G, P, S, T, W, Function\n",
+    "from proveit.logic import And, Equals, Exists, Forall, in_bool\n",
+    "from proveit.logic.sets import Functions, Injections, InSet, Set, SetOfAll\n",
+    "from proveit.numbers import zero, one, Add, Interval, LessEq, Natural, subtract\n",
+    "from proveit.graphs import (AdjacentVertices, Edges, EdgeSequence, EndVertices, Graphs,\n",
+    "        Paths, Trails, Vertices, Walks)\n"
    ]
   },
   {
@@ -35,7 +40,320 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "walks_membership_def = (\n",
+    "    Forall(G, Forall(k, Forall(W,\n",
+    "    Equals(\n",
+    "        InSet(W, Walks(k, G)),\n",
+    "        InSet(W,\n",
+    "        SetOfAll(S,\n",
+    "             S,\n",
+    "             conditions = [Forall(i, AdjacentVertices(Function(S, i), Function(S, Add(i, one)), G),\n",
+    "                                  domain = Interval(zero, subtract(k, one)))],\n",
+    "             domain = Functions(Interval(zero, k), Vertices(G))))\n",
+    "    )), domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "walks_membership_unfolding = (\n",
+    "    Forall(G, Forall(k, Forall(W,\n",
+    "    InSet(W,\n",
+    "          SetOfAll(S, S,\n",
+    "              conditions = [Forall(i, AdjacentVertices(Function(S, i), Function(S, Add(i, one)), G),\n",
+    "                                  domain = Interval(zero, subtract(k, one)))],\n",
+    "          domain = Functions(Interval(zero, k), Vertices(G)))),\n",
+    "    conditions = [InSet(W, Walks(k, G))]), domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "walks_membership_folding = (\n",
+    "    Forall(G, Forall(k, Forall(W,\n",
+    "    InSet(W, Walks(k, G)),\n",
+    "    conditions = [InSet(W,\n",
+    "          SetOfAll(S, S,\n",
+    "              conditions = [Forall(i, AdjacentVertices(Function(S, i), Function(S, Add(i, one)), G),\n",
+    "                                  domain = Interval(zero, subtract(k, one)))],\n",
+    "          domain = Functions(Interval(zero, k), Vertices(G))))]), domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "walks_membership_unfolding_components = (\n",
+    "    Forall(G, Forall(k, Forall(W,\n",
+    "    And(InSet(W, Functions(Interval(zero, k), Vertices(G))),\n",
+    "        Forall(i, AdjacentVertices(Function(W, i), Function(W, Add(i, one)), G), domain = Interval(zero, subtract(k, one)))),\n",
+    "    conditions = [InSet(W, Walks(k, G))]), domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "walks_membership_folding_components = (\n",
+    "    Forall(G, Forall(k, Forall(W,\n",
+    "    InSet(W, Walks(k, G)),\n",
+    "    conditions = [Forall(i, AdjacentVertices(Function(W, i), Function(W, Add(i, one)), G),\n",
+    "        domain = Interval(zero, subtract(k, one)))],\n",
+    "    domain = Functions(Interval(zero, k), Vertices(G))),\n",
+    "    domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "trails_membership_def = (\n",
+    "    Forall(G, Forall(k, Forall(T,\n",
+    "    Equals(\n",
+    "        InSet(T, Trails(k, G)),\n",
+    "        InSet(T,\n",
+    "        SetOfAll(W,\n",
+    "                 W,\n",
+    "                 conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
+    "                 domain = Walks(k, G) ))\n",
+    "    )), domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "trails_membership_unfolding = (\n",
+    "    Forall(G, Forall(k, Forall(T,\n",
+    "    InSet(T,\n",
+    "        SetOfAll(W,\n",
+    "        W,\n",
+    "        conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
+    "        domain = Walks(k, G) )),\n",
+    "    domain = Trails(k, G)), domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "trails_membership_folding = (\n",
+    "    Forall(G, Forall(k, Forall(T,\n",
+    "    InSet(T, Trails(k, G)),\n",
+    "    conditions = [],\n",
+    "    domain = SetOfAll(W,\n",
+    "        W,\n",
+    "        conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
+    "        domain = Walks(k, G) )), domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "trails_membership_unfolding_components = (\n",
+    "    Forall(G, Forall(k, Forall(T,\n",
+    "    And(InSet(T, Walks(k, G)),\n",
+    "        InSet(EdgeSequence(T), Injections(Interval(zero, subtract(k, one)), Edges(G)))),\n",
+    "    domain = Trails(k, G)), domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "trails_membership_folding_components = (\n",
+    "    Forall(G, Forall(k, Forall(W,\n",
+    "    InSet(W, Trails(k, G)),\n",
+    "    conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
+    "    domain = Walks(k, G)), domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "paths_membership_def = (\n",
+    "    Forall(G, Forall(k, Forall(P,\n",
+    "    Equals(\n",
+    "        InSet(P, Paths(k, G)),\n",
+    "        InSet(P,\n",
+    "        SetOfAll(W,\n",
+    "             W,\n",
+    "             conditions = [InSet(W, Injections(Interval(zero, k), Vertices(G)))],\n",
+    "             domain = Walks(k, G)))\n",
+    "    )), domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "paths_membership_unfolding = (\n",
+    "    Forall(G, Forall(k, Forall(P,\n",
+    "        InSet(P,\n",
+    "        SetOfAll(W,\n",
+    "             W,\n",
+    "             conditions = [InSet(W, Injections(Interval(zero, k), Vertices(G)))],\n",
+    "             domain = Walks(k, G))),\n",
+    "    conditions = [InSet(P, Paths(k, G))]),\n",
+    "    domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "paths_membership_folding = (\n",
+    "    Forall(G, Forall(k, Forall(P,\n",
+    "        InSet(P, Paths(k, G)),\n",
+    "        domain = SetOfAll(W, W,\n",
+    "             conditions = [InSet(W, Injections(Interval(zero, k), Vertices(G)))],\n",
+    "             domain = Walks(k, G))),\n",
+    "    domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "paths_membership_unfolding_components = (\n",
+    "    Forall(G, Forall(k, Forall(P,\n",
+    "        And(InSet(P, Walks(k, G)),\n",
+    "        InSet(P, Injections(Interval(zero, k), Vertices(G)))),\n",
+    "    conditions = [InSet(P, Paths(k, G))]),\n",
+    "    domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "paths_membership_folding_components = (\n",
+    "    Forall(G, Forall(k, Forall(W,\n",
+    "        InSet(W, Paths(k, G)),\n",
+    "    conditions = [InSet(W, Injections(Interval(zero, k), Vertices(G)))], domain = Walks(k, G)),\n",
+    "    domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### The existence of a $u$-$v$ walk implies the existence of a $u$-$v$ path:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "walk_implies_path = Forall(G,\n",
+    "Forall((u, v),\n",
+    "Forall((j, W),\n",
+    "Exists((k, P), Equals(EndVertices(P), Set(u, v)),\n",
+    "       conditions = [LessEq(k, j)], domains = [Natural, Paths(k, G)]),\n",
+    "conditions = [Equals(EndVertices(W), Set(u, v))],\n",
+    "domains = [Natural, Walks(j, G)]),\n",
+    "domain = Vertices(G)),\n",
+    "domain = Graphs())"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Some standard membership boolean claims"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "walks_membership_is_bool = Forall(G,\n",
+    "Forall(k,\n",
+    "Forall(W, in_bool(InSet(W, Walks(k, G)))),\n",
+    "domain = Natural),\n",
+    "domain = Graphs()\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "trails_membership_is_bool = Forall(G,\n",
+    "Forall(k,\n",
+    "Forall(T, in_bool(InSet(T, Trails(k, G)))),\n",
+    "domain = Natural),\n",
+    "domain = Graphs()\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "paths_membership_is_bool = Forall(G,\n",
+    "Forall(k,\n",
+    "Forall(P, in_bool(InSet(P, Paths(k, G)))),\n",
+    "domain = Natural),\n",
+    "domain = Graphs()\n",
+    ")"
+   ]
   },
   {
    "cell_type": "code",

From e8e4abdcc8c0e6ea9f833310f4d582dbabac6d33 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 3 Jul 2025 17:09:30 -0500
Subject: [PATCH 131/159] Update walks.py and walks_membership.py for
 membership methods

Update the walks.py and walks_membership.py for membership classes and methods related to membership in Walks(k, G), Trails(k, G), and Paths(k, G). Also update the graphs/walks/demonstrations.ipynb notebook to test the new classes and methods.
---
 .../walks/_theory_nbs_/demonstrations.ipynb   | 262 +++++++++++++-
 packages/proveit/graphs/walks/walks.py        |  27 +-
 .../proveit/graphs/walks/walks_membership.py  | 339 +++++++++++++-----
 3 files changed, 512 insertions(+), 116 deletions(-)

diff --git a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
index ed367c0675c2..986164e5f8cd 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
@@ -15,12 +15,14 @@
    "outputs": [],
    "source": [
     "import proveit\n",
-    "from proveit import a, b, k, G, P, S, T, W\n",
-    "from proveit.logic import Equals, InSet, Set\n",
+    "from proveit import a, b, i, k, G, P, S, T, W, Function\n",
+    "from proveit.logic import And, Equals, Forall, InClass, InSet, Set, SetOfAll\n",
+    "from proveit.logic.sets import Functions, Injections\n",
+    "from proveit.numbers import zero, one, Add, Interval, Natural, subtract\n",
     "from proveit.graphs import (\n",
-    "        Closed, EdgeSequence, EdgeSet, EndVertices, EulerianTrails, Graph,\n",
-    "        Paths, Trails, WalkLength, Walks)\n",
-    "%begin demonstrations"
+    "        AdjacentVertices, Closed, Edges, EdgeSequence, EdgeSet, EndVertices,\n",
+    "        EulerianTrails, Graph, Graphs, Paths, Trails, Vertices, WalkLength, Walks)\n",
+    "%begin demonstrations\n"
    ]
   },
   {
@@ -246,6 +248,256 @@
     "EulerianTrails(G)"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Walks Membership and Related Methods"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(W, Walks(k, G))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(W, Walks(k, G)).deduce_in_bool(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(W, Walks(k, G)).definition(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(W, Walks(k, G)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(W, Walks(k, G)).unfold(assumptions = [InSet(W, Walks(k, G)), InClass(G, Graphs()), InSet(k, Natural)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(W, Walks(k, G)).conclude(\n",
+    "    assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "                   InSet(W, SetOfAll(S, S,\n",
+    "                            conditions = [\n",
+    "                                Forall(i, AdjacentVertices(Function(S, i), Function(S, Add(i, one)), G),\n",
+    "                                       domain = Interval(zero, subtract(k, one)))],\n",
+    "                            domain = Functions(Interval(zero, k), Vertices(G))))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(W, Walks(k, G)).conclude(\n",
+    "    assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "                   InSet(W, Functions(Interval(zero, k), Vertices(G))),\n",
+    "                   Forall(i, AdjacentVertices(Function(W, i), Function(W, Add(i, one)), G),\n",
+    "                                       domain = Interval(zero, subtract(k, one)))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Trails Membership and Related Methods"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(T, Trails(k, G))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(T, Trails(k, G)).deduce_in_bool(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(T, Trails(k, G)).definition(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(T, Trails(k, G)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(T, Trails(k, G)).unfold(assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(T, Trails(k, G))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(T, Trails(k, G)).conclude(\n",
+    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "                       InSet(T, SetOfAll(W, W, conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
+    "                                        domain = Walks(k, G)))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(T, Trails(k, G)).conclude(\n",
+    "        assumptions = [\n",
+    "            InClass(G, Graphs()), InSet(k, Natural),\n",
+    "            And(InSet(T, Walks(k, G)),\n",
+    "            InSet(EdgeSequence(T), Injections(Interval(zero, subtract(k, one)), Edges(G))))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Paths Membership and Related Methods"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(P, Paths(k, G))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(P, Paths(k, G)).deduce_in_bool(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(P, Paths(k, G)).definition(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(P, Paths(k, G)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(P, Paths(k, G)).unfold(assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(P, Paths(k, G))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(P, Injections(Interval(zero, k), Vertices(G)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(P, Paths(k, G)).conclude(\n",
+    "    assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "                   InSet(P, Walks(k, G)), InSet(P, Injections(Interval(zero, k), Vertices(G)))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(P, SetOfAll(W, W, conditions =[InSet(W, Injections(Interval(zero, k), Vertices(G)))], domain = Walks(k, G)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(P, Paths(k, G)).conclude(\n",
+    "    assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "                   InSet(P, SetOfAll(W, W, conditions =[InSet(W, Injections(Interval(zero, k), Vertices(G)))],\n",
+    "                                     domain = Walks(k, G)))])"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
diff --git a/packages/proveit/graphs/walks/walks.py b/packages/proveit/graphs/walks/walks.py
index c466df730aa3..7570e79169f9 100644
--- a/packages/proveit/graphs/walks/walks.py
+++ b/packages/proveit/graphs/walks/walks.py
@@ -40,10 +40,9 @@ def __init__(self, k, G, *, styles=None):
         Function.__init__(
                 self, Walks._operator_, (k, G), styles=styles)
 
-#   membership objects/development under construction
-#     def membership_object(self, element):
-#         from .walks_membership import WalksMembership
-#         return WalksMembership(element, self)
+    def membership_object(self, element):
+        from .walks_membership import WalksMembership
+        return WalksMembership(element, self)
 
 #     def nonmembership_object(self, element):
 #         from .walks_membership import WalksNonmembership
@@ -73,14 +72,13 @@ def __init__(self, k, G, *, styles=None):
         Function.__init__(
                 self, Trails._operator_, (k, G), styles=styles)
 
-#   membership objects/development under construction
-#     def membership_object(self, element):
-#         from .walks_membership import WalksMembership
-#         return WalksMembership(element, self)
+    def membership_object(self, element):
+        from .walks_membership import TrailsMembership
+        return TrailsMembership(element, self)
 
-#     def nonmembership_object(self, element):
-#         from .walks_membership import WalksNonmembership
-#         return WalksNonmembership(element, self)
+    # def nonmembership_object(self, element):
+    #     from .walks_membership import WalksNonmembership
+    #     return WalksNonmembership(element, self)
 
 
 class Paths(Function):
@@ -106,10 +104,9 @@ def __init__(self, k, G, *, styles=None):
         Function.__init__(
                 self, Paths._operator_, (k, G), styles=styles)
 
-#   membership objects/development under construction
-#     def membership_object(self, element):
-#         from .walks_membership import WalksMembership
-#         return WalksMembership(element, self)
+    def membership_object(self, element):
+        from .walks_membership import PathsMembership
+        return PathsMembership(element, self)
 
 #     def nonmembership_object(self, element):
 #         from .walks_membership import WalksNonmembership
diff --git a/packages/proveit/graphs/walks/walks_membership.py b/packages/proveit/graphs/walks/walks_membership.py
index 6e32e76e4471..a311ea3213e3 100644
--- a/packages/proveit/graphs/walks/walks_membership.py
+++ b/packages/proveit/graphs/walks/walks_membership.py
@@ -1,14 +1,17 @@
-from proveit import e, E, V, equality_prover, prover
-from proveit.logic import SetMembership, SetNonmembership
-from proveit.graphs import Graph
+from proveit import (i, k, G, P, S, T, W, equality_prover, Function,
+        prover, relation_prover)
+from proveit.logic import Forall, InSet, SetMembership, SetNonmembership
+from proveit.logic.sets import Functions, Injections, SetOfAll
+from proveit.numbers import zero, one, Add, Interval, subtract
+from proveit.graphs import (AdjacentVertices, Edges, EdgeSequence,
+            Graph, Vertices, Walks)
 
 
 class WalksMembership(SetMembership):
     '''
     Defines methods that apply to membership in the set
-    of walks in the simple graph G, denoted Walks(G).
-
-    UNDER CONSTRUCTION
+    of length-k walks in the simple graph G, denoted Walks(k, G).
+    See related membership classes further below for Trails and Paths.
     '''
 
     def __init__(self, element, domain):
@@ -17,138 +20,282 @@ def __init__(self, element, domain):
     @equality_prover('defined', 'define')
     def definition(self, **defaults_config):
         '''
-        From self = [elem in Edges(Graph(V,E))], deduce and return:
-            [elem in Edges(Graph(V,E))] = [elem in E]
+        From self = [elem in Walks(k, G)], deduce and return:
+        [elem in Walks(G)]
+        = elem in {S | Adjacent(S(i), S(i+1))}
+        for {S in Functions([0,...,k], Vertices(G))}
         '''
-        from . import edges_membership_def
+        from . import walks_membership_def
         element = self.element
-        _V_sub  = self.domain.graph.vertex_set
-        _E_sub  = self.domain.graph.edge_set
-        return edges_membership_def.instantiate(
-                {e:element, V:_V_sub, E:_E_sub },auto_simplify=False)
+        _G_sub  = self.domain.graph
+        _k_sub  = self.domain.length
+        return walks_membership_def.instantiate(
+                {G: _G_sub, k: _k_sub, W: element },auto_simplify=False)
 
     def as_defined(self):
         '''
-        From self = [elem in Edges(Graph(V,E))], return: [elem in E]
-        (i.e. an expression, not a Judgment)
-        '''
-        if isinstance(self.domain.operand, Graph):
-            from proveit.logic import InSet
-            element = self.element
-            _E = self.domain.graph.edge_set
-            return InSet(element, _E)
-        else:
-            raise NotImplementedError(
-                "EdgesMembership.as_defined() was called on "
-                f"self = {self.expr} with domain = {self.expr.domain}, "
-                "but the method is implemented only for domains of the "
-                "form Edges(G) where G is an explicit Graph object "
-                "of the form G = Graph(V,E) with a named edge set E.")
+        From self = [elem in Walks(k, G)],
+        return the expression (NOT a judgment):
+        elem in {S | Adjacent(S(i), S(i+1))}
+        for {S in Functions([0,...,k], Vertices(G))}
+        '''
+        element = self.element
+        _G      = self.domain.graph
+        _k      = self.domain.length
+        return InSet(element,
+               SetOfAll(S, S,
+               conditions = [
+                   Forall(i,
+                   AdjacentVertices(
+                           Function(S, i), Function(S, Add(i, one)), _G),
+                   domain = Interval(zero, subtract(_k, one)))],
+               domain = Functions(Interval(zero, _k), Vertices(_G))))
 
     @prover
     def unfold(self, **defaults_config):
         '''
-        From self = [elem in Edges(Graph(V,E))],
-        derive and return [elem in E], knowing or assuming self.
+        From self = [elem in Walks(k, G)], and knowing self,
+        derive and return:
+        elem in {S | Adjacent(S(i), S(i+1))}
+        for {S in Functions([0,...,k], Vertices(G))}.
         '''
-        from . import edges_membership_unfolding
+        from . import walks_membership_unfolding
         element = self.element
-        _V_sub  = self.domain.graph.vertex_set
-        _E_sub  = self.domain.graph.edge_set
-        return edges_membership_unfolding.instantiate(
-            {e:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
+        _G_sub  = self.domain.graph
+        _k_sub  = self.domain.length
+        return walks_membership_unfolding.instantiate(
+            {G: _G_sub, k: _k_sub, W: element}, auto_simplify=False)
 
     @prover
     def conclude(self, **defaults_config):
         '''
-        Called on self = [elem in Edges(Graph(V,E))], and
-        knowing or assuming [elem in E] (and that E is a subset
-        of [V]^2, a subset of the set of 2-element subsets of V)
-        derive and return self.
+        Called on self = [W in Walks(k, G)], derive and return
+        self, knowing or assuming at least one of the following:
+        (1) W in Functions([0,...,k], Vertices(G)) AND
+            forall i in [0,..., k-1][AdjacentVertices(W(i), W(i+1), G)]
+        (2) elem in {S | Adjacent(S(i), S(i+1))}
+            for {S in Functions([0,...,k], Vertices(G))}
         '''
-        from . import edges_membership_folding
-        element = self.element
-        _V_sub  = self.domain.graph.vertex_set
-        _E_sub  = self.domain.graph.edge_set
-        return edges_membership_folding.instantiate(
-            {e:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
+        _W = self.element
+        _G  = self.domain.graph
+        _k  = self.domain.length
+        functions_set = Functions(Interval(zero, _k), Vertices(_G))
+        adj_verts = Forall(
+            i, AdjacentVertices(Function(_W, i),
+                                Function(_W, Add(i, one)), _G),
+            domain = Interval(zero, subtract(_k, one)))
+        if (InSet(_W, functions_set).proven()
+            and adj_verts.proven()):
+            from . import walks_membership_folding_components
+            return walks_membership_folding_components.instantiate(
+                    {G: _G, k: _k, W: _W},
+                    auto_simplify=False)
+        
+        from . import walks_membership_folding
+        return walks_membership_folding.instantiate(
+            {G: _G, k: _k, W: _W}, auto_simplify=False)
+
+    @relation_prover
+    def deduce_in_bool(self, **defaults_config):
+        from . import walks_membership_is_bool
+        _G_sub = self.domain.graph
+        _k_sub = self.domain.length
+        _W_sub = self.element
+        return walks_membership_is_bool.instantiate(
+            {G:_G_sub, k:_k_sub, W:_W_sub}, auto_simplify=False)
 
 
-class EdgesNonmembership(SetNonmembership):
+class TrailsMembership(SetMembership):
     '''
-    Defines methods that apply to non-membership in the set
-    Edges(G(V,E)) of the edges E of graph G.
+    Defines methods that apply to membership in the set
+    of length-k trails in the simple graph G, denoted Trails(k, G).
+    See related membership classes above and below for Walks and Paths.
     '''
 
     def __init__(self, element, domain):
-        SetNonmembership.__init__(self, element, domain)
+        SetMembership.__init__(self, element, domain)
+
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self = [elem in Trails(k, G)], deduce and return:
+        [elem in Trails(k, G)]
+        = elem in {W | EdgeSequence(W) in Injections([0, ..., k-1], Edges(G))}
+        for {W in Walks(k, G)}.
+        W being in Walks(k, G) takes care of the requirement that 
+        consecutive elements of the vertex sequence are adjacent in the
+        graph G.
+        '''
+        from . import trails_membership_def
+        element = self.element
+        _G_sub  = self.domain.graph
+        _k_sub  = self.domain.length
+        return trails_membership_def.instantiate(
+                {G: _G_sub, k: _k_sub, T: element },auto_simplify=False)
+
+    def as_defined(self):
+        '''
+        From self = [elem in Trails(k, G)],
+        return the expression (NOT a judgment):
+        elem in {W | EdgeSequence(W) in
+                 Injections([0, ..., k-1], Edges(G))}
+        for {W in Walks(k, G)}
+        '''
+        element = self.element
+        _G      = self.domain.graph
+        _k      = self.domain.length
+        return InSet(element,
+               SetOfAll(W, W,
+               conditions = [
+                   InSet(EdgeSequence(W),
+                   Injections(Interval(zero, subtract(_k, one)), Edges(_G)))],
+               domain = Walks(_k, _G)))
+
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        From self = [elem in Trails(k, G)], and knowing or assuming
+        self, derive and return:
+        elem in {W | EdgeSequence(W) in
+                 Injections([0, ..., k-1], Edges(G))}
+                 for {W in Walks(k, G)}.
+        '''
+        from . import trails_membership_unfolding
+        element = self.element
+        _G_sub  = self.domain.graph
+        _k_sub  = self.domain.length
+        return trails_membership_unfolding.instantiate(
+            {G: _G_sub, k: _k_sub, T: element}, auto_simplify=False)
 
-    def side_effects(self, judgment):
+    @prover
+    def conclude(self, **defaults_config):
         '''
-        Currently no side-effects for EdgesNonmembership.
+        Called on self = [W in Trails(k, G)], derive and return
+        self, knowing or assuming at least one of the following:
+        (1) W in Walks(k, G) AND
+            EdgeSeq(W) in Injections([0,...,k-1], Edges(G))
+        (2) W in {W | EdgeSequence(W) in
+                 Injections([0, ..., k-1], Edges(G))}
+                 for {W in Walks(k, G)}
         '''
-        return
-        yield
+        _W = self.element
+        _G  = self.domain.graph
+        _k  = self.domain.length
+        injections_set = (
+            Injections(Interval(zero, subtract(_k, one)), Edges(_G)))
+        if (InSet(EdgeSequence(_W), injections_set).proven()
+            and InSet(_W, Walks(_k, _G)).proven()):
+            from . import trails_membership_folding_components
+            return trails_membership_folding_components.instantiate(
+                    {G: _G, k: _k, W: _W},
+                    auto_simplify=False)
+        
+        from . import trails_membership_folding
+        return trails_membership_folding.instantiate(
+            {G: _G, k: _k, W: _W}, auto_simplify=False)
+
+    @relation_prover
+    def deduce_in_bool(self, **defaults_config):
+        from . import trails_membership_is_bool
+        _G_sub = self.domain.graph
+        _k_sub = self.domain.length
+        _T_sub = self.element
+        return trails_membership_is_bool.instantiate(
+            {G:_G_sub, k:_k_sub, T:_T_sub}, auto_simplify=False)
+
+
+class PathsMembership(SetMembership):
+    '''
+    Defines methods that apply to membership in the set of length-k
+    paths in the simple graph G, denoted Paths(k, G). A path in G is
+    a walk in which no vertex (and thus no edge) is repeated.
+    See related membership classes above for Walks and Trails.
+    '''
+
+    def __init__(self, element, domain):
+        SetMembership.__init__(self, element, domain)
 
     @equality_prover('defined', 'define')
     def definition(self, **defaults_config):
         '''
-        From self = [elem not in Edges(Graph(V,E))], deduce and
-        return: [elem not in Edges(Graph(V,E))] = [elem not in E].
+        From self = [elem in Paths(k, G)], deduce and return:
+        [elem in Paths(k, G)]
+        = elem in {W | W in Injections([0, ..., k], Vertices(G))}
+                  for {W in Walks(k, G)}.
+        W being in Walks(k, G) takes care of the requirement that 
+        consecutive elements of the vertex sequence are adjacent in the
+        graph G.
         '''
-
-        from . import edges_nonmembership_def
+        from . import paths_membership_def
         element = self.element
-        _V_sub  = self.domain.graph.vertex_set
-        _E_sub  = self.domain.graph.edge_set
-        return edges_nonmembership_def.instantiate(
-                {e:element, V:_V_sub, E:_E_sub },auto_simplify=False)
+        _G_sub  = self.domain.graph
+        _k_sub  = self.domain.length
+        return paths_membership_def.instantiate(
+                {G: _G_sub, k: _k_sub, P: element },auto_simplify=False)
 
     def as_defined(self):
         '''
-        From self = [elem not in Edges(Graph(V,E))],
-        return: [elem not in E] (i.e. an expression, not a Judgment)
-        '''
-        if isinstance(self.domain.operand, Graph):
-            from proveit.logic import NotInSet
-            element = self.element
-            _E = self.domain.graph.edge_set
-            return NotInSet(element, _E)
-        else:
-            raise NotImplementedError(
-                "EdgesNonmembership.as_defined() was called on "
-                f"self = {self.expr} with domain = {self.expr.domain}, "
-                "but the method is implemented only for domains of the "
-                "form Edges(G) where G is an explicit Graph object "
-                "of the form G = Graph(V,E) with a named edge set E.")
+        From self = [elem in Paths(k, G)],
+        return the expression (NOT a judgment):
+        elem in {W | W in Injections([0, ..., k], Vertices(G))}
+                for {W in Walks(k, G)}.
+        '''
+        element = self.element
+        _G      = self.domain.graph
+        _k      = self.domain.length
+        return InSet(element,
+               SetOfAll(W, W,
+               conditions = [
+                   InSet(W,
+                   Injections(Interval(zero, _k), Vertices(_G)))],
+               domain = Walks(_k, _G)))
 
     @prover
     def unfold(self, **defaults_config):
         '''
-        From self = [elem not in Edges(Graph(V,E))],
-        derive and return [elem not in E], knowing or assuming self,
-        (and that E is a subset of [V]^2, i.e., a subset of the set
-        of 2-element subsets of V).
+        From self = [elem in Paths(k, G)], and knowing or assuming
+        self, derive and return:
+        elem in {W | W in Injections([0, ..., k], Vertices(G))}
+                for {W in Walks(k, G)}.
         '''
-        from . import edges_nonmembership_unfolding
+        from . import paths_membership_unfolding
         element = self.element
-        _V_sub  = self.domain.graph.vertex_set
-        _E_sub  = self.domain.graph.edge_set
-        return edges_nonmembership_unfolding.instantiate(
-            {e:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
+        _G_sub  = self.domain.graph
+        _k_sub  = self.domain.length
+        return paths_membership_unfolding.instantiate(
+            {G: _G_sub, k: _k_sub, P: element}, auto_simplify=False)
 
-    @prover
+    @prover # WORKING HERE
     def conclude(self, **defaults_config):
         '''
-        Called on self = [elem not in Edges(Graph(V,E))], and
-        knowing or assuming [elem not in E] (and that E is a subset
-        of [V]^2, a subset of the set of 2-element subsets of V)
-        derive and return self.
+        Called on self = [P in Paths(k, G)], derive and return
+        self, knowing or assuming at least one of the following:
+        (1) P in Walks(k, G) AND
+            P in Injections([0,...,k], Vertices(G))
+        (2) P in {W | W in Injections([0, ..., k], Vertices(G))}
+                 for {W in Walks(k, G)}
         '''
-        from . import edges_nonmembership_folding
-        element = self.element
-        _V_sub  = self.domain.graph.vertex_set
-        _E_sub  = self.domain.graph.edge_set
-        return edges_nonmembership_folding.instantiate(
-            {e:element, V:_V_sub, E:_E_sub}, auto_simplify=False)
+        _W = self.element
+        _G  = self.domain.graph
+        _k  = self.domain.length
+        injections_set = Injections(Interval(zero, _k), Vertices(_G))
+        if (InSet(_W, injections_set).proven()
+            and InSet(_W, Walks(_k, _G)).proven()):
+            from . import paths_membership_folding_components
+            return paths_membership_folding_components.instantiate(
+                    {G: _G, k: _k, W: _W},
+                    auto_simplify=False)
+        
+        from . import trails_membership_folding
+        return trails_membership_folding.instantiate(
+            {G: _G, k: _k, W: _W}, auto_simplify=False)
+
+    @relation_prover
+    def deduce_in_bool(self, **defaults_config):
+        from . import paths_membership_is_bool
+        _G_sub = self.domain.graph
+        _k_sub = self.domain.length
+        _P_sub = self.element
+        return paths_membership_is_bool.instantiate(
+            {G:_G_sub, k:_k_sub, P:_P_sub}, auto_simplify=False)
 

From 33960f07910342cbd00a183c2628dbee656b8fc5 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Fri, 4 Jul 2025 14:54:07 -0500
Subject: [PATCH 132/159] Correct a few typos and edit comments

Correct a few typos and edit comments in walks_membership.py, most importantly correcting a copy-paste error where a trails-related theorem was being called where we needed the analogous paths-related theorem instead.
---
 packages/proveit/graphs/walks/walks_membership.py | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/packages/proveit/graphs/walks/walks_membership.py b/packages/proveit/graphs/walks/walks_membership.py
index a311ea3213e3..3972d270e2a7 100644
--- a/packages/proveit/graphs/walks/walks_membership.py
+++ b/packages/proveit/graphs/walks/walks_membership.py
@@ -120,11 +120,12 @@ def definition(self, **defaults_config):
         '''
         From self = [elem in Trails(k, G)], deduce and return:
         [elem in Trails(k, G)]
-        = elem in {W | EdgeSequence(W) in Injections([0, ..., k-1], Edges(G))}
+        = elem in
+        {W | EdgeSequence(W) in Injections([0, ..., k-1], Edges(G))}
         for {W in Walks(k, G)}.
         W being in Walks(k, G) takes care of the requirement that 
-        consecutive elements of the vertex sequence are adjacent in the
-        graph G.
+        consecutive elements of the vertex sequence are adjacent in
+        the graph G.
         '''
         from . import trails_membership_def
         element = self.element
@@ -285,9 +286,8 @@ def conclude(self, **defaults_config):
             return paths_membership_folding_components.instantiate(
                     {G: _G, k: _k, W: _W},
                     auto_simplify=False)
-        
-        from . import trails_membership_folding
-        return trails_membership_folding.instantiate(
+        from . import paths_membership_folding
+        return paths_membership_folding.instantiate(
             {G: _G, k: _k, W: _W}, auto_simplify=False)
 
     @relation_prover

From 072f832ed8e4eeb3d50ef67304f8d63e9c70fc6e Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Fri, 4 Jul 2025 14:55:04 -0500
Subject: [PATCH 133/159] Update graphs/walks/demonstrations

Update graphs/walks/demonstrations, mostly cleaning up and editing comments and removing obsolete notes.
---
 .../walks/_theory_nbs_/demonstrations.ipynb   | 80 +++----------------
 1 file changed, 9 insertions(+), 71 deletions(-)

diff --git a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
index 986164e5f8cd..953e52e712db 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
@@ -25,13 +25,6 @@
     "%begin demonstrations\n"
    ]
   },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -44,17 +37,21 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "### Miscellaneous Testing\n",
-    "Testing various classes and methods related to walks in an undirected simple graph. Some of this material could eventually be integrated into the `_demonstrations_` page and/or deleted as development continues."
+    "`Walks(k, G)` represents the set of all walks of length $k$ in the simple undirected graph $G$. \n",
+    "\n",
+    "A __walk__ $W$ in a simple undirected graph $G$ is a sequence $(u = v_0, v_1, ..., v = v_k)$ of vertices of $G$ such that consecutive vertices in the sequence are adjacent in $G$ --- in other words, every pair $\\{v_{i}, v_{i+1}\\}$ of vertices (for $i \\in \\{0, 1, ..., k-1\\}$) in the sequence corresponds to an edge in $G$. We have chosen to embrace a formal definition of a sequence, so a length-$k$ walk in graph $G$ is actually a function, $W:[0, 1, 2, \\ldots, k]\\rightarrow \\texttt{Vertices}(G)$.\n",
+    "\n",
+    "Trails, paths, circuits, and cycles are all special cases of walks.\n",
+    "\n",
+    "In the walk with sequence $(u = v_0, v_1, ..., v = v_k)$, $u$ and $v$ are called the endvertices or endpoints of the walk, and a walk from $u$ to $v$ is often referred to as a $u$-$v$ walk. The vertices $v_1, v_2, ..., v_{k-1}$ are called _internal vertices_. The number of edges in the walk $W$, denoted by $||W||$, is the _length_ of the walk (in this example, $||W|| = k$). The number of vertices in walk $W$, including multiplicities of repeated vertices, is denoted $|W|$, analogous to the notation for the order of a graph, $|G|$. In the example used above, $|W| = k+1$."
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "`Walks(k, G)` represents the set of all walks of length $k$ in the simple undirected graph $G$. \n",
-    "\n",
-    "A __walk__ $W$ in a simple undirected graph $G$ is a sequence $(u = v_0, v_1, ..., v = v_k)$ of vertices of $G$ such that consecutive vertices in the sequence are adjacent in $G$ --- in other words, every pair $\\{v_{i}, v_{i+1}\\}$ of vertices (for $i \\in \\{0, 1, ..., k-1\\}$) corresponds to an edge in $G$. $u$ and $v$ are called the endvertices or endpoints of the walk, and a walk from $u$ to $v$ is often referred to as a $u$-$v$ walk. The vertices $v_1, v_2, ..., v_{k-1}$ are called _internal vertices_. The number of edges in the walk $W$, denoted by $||W||$, is the length of the walk (in this example, $||W|| = k$). The number of vertices in walk $W$, including multiplicities of repeated vertices, is denoted $|W|$, analogous to the notation for the order of a graph, $|G|$."
+    "### Miscellaneous Testing\n",
+    "Testing various classes and methods related to walks in an undirected simple graph. Some of this material could eventually be integrated into the `_demonstrations_` page and/or deleted as development continues."
    ]
   },
   {
@@ -477,15 +474,6 @@
     "                   InSet(P, Walks(k, G)), InSet(P, Injections(Interval(zero, k), Vertices(G)))])"
    ]
   },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(P, SetOfAll(W, W, conditions =[InSet(W, Injections(Interval(zero, k), Vertices(G)))], domain = Walks(k, G)))"
-   ]
-  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -498,13 +486,6 @@
     "                                     domain = Walks(k, G)))])"
    ]
   },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "### Defining a walk $W \\in \\texttt{Walks}(G)$ in the simple graph $G$."
-   ]
-  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -547,49 +528,6 @@
     "By the end of our discussion on Fri 6/27, generally thinking that we'd represent walks in $G$ as $\\texttt{Walks}(G, k)$ or walks of a specific length $k$ in graph $G$, and those can be represented as special functions (equivalent to a sequence), as written above. And despite the annoyance of using $0$-based indexing, such indexing can be useful since we then talk about lengths of walks as the number of edges, which will be one less than the number of vertices in the sequence. Paths of length $k$ can then be defined in terms of injective walks. And Trails can be defined in terms of injective functions into the edges — to be more clear, WW suggested we might have something like a claim that the EdgeSequence(Trail) is an injective function."
    ]
   },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "A $(k+1)$-vertex __trail__ $T$ in a simple graph $G$ is a $(k+1)$-vertex walk in $G$ such that no edges are repeated. This would mean that in the walk's vertex sequence $S = \\{v_0, v_1, \\ldots, v_k\\}$, no consecutive pair $(v_{i}, v_{i+1})$ is repeated. Without invoking a function-based definition of the sequence $S$, we might formulate the constraint like this:\n",
-    "\n",
-    "$$ |S| - 1 = |\\{(s_i, s_{i+1}) \\,|\\, i \\in \\{0, 1, \\ldots, k-1\\})\\}|,$$\n",
-    "\n",
-    "where we have a slight abuse of notation using $|S|$ to denote the length of sequence $S$. Using a function-based definition of the sequence $S$, we could say\n",
-    "$$\\forall_{i, j \\in\\{0, 1, \\ldots, k-1\\}} \\big[ (S(i), S(i+1)) = (S(j), S(j+1)) \\Rightarrow i = j \\big]$$\n"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "If we represent a sequence of elements of set $X$ by $\\texttt{Sequence}(X)$, then it's not clear if there is any utility in having both:\n",
-    "\n",
-    "$\\texttt{Walks}(G)$ and $\\texttt{Walk}(S, G)$ (_e.g._, we just say that $W \\in \\texttt{Walks}(G)$ instead of $W = \\texttt{Walk}(S, G)$?)\n",
-    "\n",
-    "$\\texttt{Trails}(G)$ and $\\texttt{Trail}(S, G)$ (_e.g._, we just say that $T \\in \\texttt{Trails}(G)$ instead of $T = \\texttt{Trail}(S, G)$?)\n",
-    "\n",
-    "$\\texttt{Paths}(G)$ and $\\texttt{Path}(S, G)$ (_e.g._, we just say that $P \\in \\texttt{Paths}(G)$ instead of $P = \\texttt{Path}(S, G)$)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "$\\forall_{x_1, \\ldots, x_n}\\big(P(x_1, x_2, \\ldots, x_n)\\big)$\n",
-    "\n",
-    "WW is leaning toward something like this: the above would be a “style”\n",
-    "but now internally\n",
-    "\n",
-    "$\\forall_x \\big(P(x(1), x(2), \\ldots, x(n))\\big)$\n",
-    "\n",
-    "where $x$ is now a function. \n",
-    "\n",
-    "Defining an existential:\n",
-    "\n",
-    "$[\\exists] = P \\mapsto \\lnot(\\forall_{x} (\\lnot P(x)))$"
-   ]
-  },
   {
    "cell_type": "code",
    "execution_count": null,

From ae2ff9e7d3af586d5f797e3dbd8b34bccd6d3170 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 8 Jul 2025 09:53:04 -0600
Subject: [PATCH 134/159] Add Circuits and Cycles classes to graphs/walks
 theory pkg

Add the Circuits(k, G) and Cycles(k, G) classes to the graphs/walks sub-theory package, along with axiomatic definition for the Circuits class (but not yet for the Cycles class, because that will be easier once we update sets/functions theory package to have function restrictions).
---
 packages/proveit/graphs/__init__.py           |  4 +-
 packages/proveit/graphs/walks/__init__.py     |  4 +-
 .../graphs/walks/_theory_nbs_/axioms.ipynb    | 63 +++++++++++++-
 .../walks/_theory_nbs_/demonstrations.ipynb   | 62 +++++++++++++-
 packages/proveit/graphs/walks/walks.py        | 85 +++++++++++++++++--
 5 files changed, 204 insertions(+), 14 deletions(-)

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index bf19a2283ee6..7a5ba07f9bda 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -9,8 +9,8 @@
 from .paths_of import PathsOf
 from .union import GraphUnion
 from .vertices import AdjacentVertices, Degree, Vertices
-from .walks import (Closed, EdgeSequence, EdgeSet, EndVertices,
-          EulerianTrails, Paths, Trails, WalkLength, Walks)
+from .walks import (Circuits, Closed, Cycles, EdgeSequence, EdgeSet,
+          EndVertices, EulerianTrails, Paths, Trails, WalkLength, Walks)
 
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
diff --git a/packages/proveit/graphs/walks/__init__.py b/packages/proveit/graphs/walks/__init__.py
index b7e856e1eb89..d6deed8c90bc 100644
--- a/packages/proveit/graphs/walks/__init__.py
+++ b/packages/proveit/graphs/walks/__init__.py
@@ -1,5 +1,5 @@
-from .walks import (Closed, EdgeSequence, EdgeSet, EndVertices,
-        EulerianTrails, Paths, Trails, WalkLength, Walks)
+from .walks import (Circuits, Closed, Cycles, EdgeSequence, EdgeSet,
+        EndVertices, EulerianTrails, Paths, Trails, WalkLength, Walks)
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
 #  Make additions above, or add to sys.modules[__name__].__dict__ below.
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
index 5b080dd46349..d2e3af98d67c 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
@@ -23,7 +23,7 @@
     "from proveit.logic import Card, Equals, Forall, Functions, Injections, InSet, SetOfAll\n",
     "from proveit.numbers import zero, one, Add, Interval, Natural, subtract\n",
     "from proveit.graphs import (\n",
-    "        AdjacentVertices, Edges, EdgeSequence, Graphs, Paths,\n",
+    "        AdjacentVertices, Circuits, Closed, Cycles, Edges, EdgeSequence, Graphs, Paths,\n",
     "        Trails, Vertices, Walks)"
    ]
   },
@@ -84,7 +84,7 @@
     "        Equals(\n",
     "            Trails(k, G),\n",
     "            SetOfAll(W,\n",
-    "                 W\n",
+    "                 W,\n",
     "                 conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
     "                 domain = Walks(k, G) )\n",
     "        ),\n",
@@ -118,6 +118,65 @@
     ")"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A circuit $C$ of length $k$ in a simple graph $G$, denoted using $C \\in \\texttt{Circuits}(k, G)$, is a closed trail of length $3$ or more, or a closed walk of length $3$ in which no edge is repeated. This means that the _edge_ sequence associated with $C$ is a one-to-one (injective) function $S: [0, 1, \\ldots, k] \\xrightarrow[]{1:1} \\texttt{Edges}(G)$, and the cardinality of the $\\texttt{EndVertices}(C)$ set is $1$ (since the sequence begins and ends with the same vertex)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "circuits_k_G_def = (\n",
+    "    Forall(G, Forall(k,\n",
+    "        Equals(\n",
+    "            Circuits(k, G),\n",
+    "            SetOfAll(T,\n",
+    "                 T,\n",
+    "                 conditions = [Closed(T)],\n",
+    "                 domain = Trails(k, G) )\n",
+    "        ),\n",
+    "    domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A cycle $C$ of length $k$ in a simple graph $G$, denoted using $C \\in \\texttt{Cycles}(k, G)$, is a circuit in which no vertex is repeated (except the beginning and ending vertices). Another way of saying this is to realize that a cycle is a closed circuit $C \\in \\texttt{Circuits}(k, G)$ such that the restriction $C\\vert_{[0, 1, \\ldots, k-1]}$ is a length-($k$-$1$) path in $G$."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# this doesn't work -- the intersection would be empty\n",
+    "# what we really need is some \"restriction\" on the Circuit, making it a path\n",
+    "from proveit.logic.sets import Intersect\n",
+    "(\n",
+    "    Forall(G, Forall(k,\n",
+    "        Equals(\n",
+    "            Cycles(k, G),\n",
+    "            Intersect(Circuits(k, G), Paths(subtract(k, one), G))\n",
+    "        ),\n",
+    "    domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A __closed__ walk $W$ is a walk whose beginning and ending vertices are the same. We could define such closure using the observation that $|\\texttt{EndVertices}(W)| = 1$ or we can use some classes for beginning and ending vertices, producing $\\texttt{BeginningVertex}(W) = \\texttt{EndingVertex}(W)$."
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
index 953e52e712db..d4285c49ef62 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
@@ -20,8 +20,9 @@
     "from proveit.logic.sets import Functions, Injections\n",
     "from proveit.numbers import zero, one, Add, Interval, Natural, subtract\n",
     "from proveit.graphs import (\n",
-    "        AdjacentVertices, Closed, Edges, EdgeSequence, EdgeSet, EndVertices,\n",
-    "        EulerianTrails, Graph, Graphs, Paths, Trails, Vertices, WalkLength, Walks)\n",
+    "        AdjacentVertices, Circuits, Closed, Cycles, Edges, EdgeSequence,\n",
+    "        EdgeSet, EndVertices, EulerianTrails, Graph, Graphs, Paths, Trails,\n",
+    "        Vertices, WalkLength, Walks)\n",
     "%begin demonstrations\n"
    ]
   },
@@ -213,6 +214,56 @@
     "InSet(P, Paths(k, G))"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A __circuit__ is a closed trail (_i.e._, a closed walk with no repeated edges). A circuit of length $k$ in graph $G$ is denoted by its membership in the class of all such circuits:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Circuits(k, G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# circuit membership under construction"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A __cycle__ is a circuit in which no vertex is repeated, in other words: a closed walk in which no vertex (and thus no edge) is repeated. With some abuse of terminology, one might call a cycle a “closed path.” A cycle of length $k$ (generally referred to as a $k$-cycle) in graph $G$ is denoted by its membership in the class of all such cycles:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Cycles(k, G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# cycle membership under construction"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -486,6 +537,13 @@
     "                                     domain = Walks(k, G)))])"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
diff --git a/packages/proveit/graphs/walks/walks.py b/packages/proveit/graphs/walks/walks.py
index 7570e79169f9..d8949b5b7287 100644
--- a/packages/proveit/graphs/walks/walks.py
+++ b/packages/proveit/graphs/walks/walks.py
@@ -77,8 +77,8 @@ def membership_object(self, element):
         return TrailsMembership(element, self)
 
     # def nonmembership_object(self, element):
-    #     from .walks_membership import WalksNonmembership
-    #     return WalksNonmembership(element, self)
+    #     from .walks_membership import TrailsNonmembership
+    #     return TrailsNonmembership(element, self)
 
 
 class Paths(Function):
@@ -89,7 +89,7 @@ class Paths(Function):
     A path with endvertices u and v is often called a u-v path.
     '''
 
-    # the literal operator of the Walks operation
+    # the literal operator of the Paths operation
     _operator_ = Literal(string_format='Paths',
                          latex_format=r'\textrm{Paths}',
                          theory=__file__)
@@ -109,8 +109,80 @@ def membership_object(self, element):
         return PathsMembership(element, self)
 
 #     def nonmembership_object(self, element):
-#         from .walks_membership import WalksNonmembership
-#         return WalksNonmembership(element, self)
+#         from .walks_membership import PathsNonmembership
+#         return PathsNonmembership(element, self)
+
+
+class Circuits(Function):
+    '''
+    Circuits(k, G) represents the set of circuits of length k in
+    the simple undirected graph G. A circuit in a graph G is a closed
+    trail of length 3 or more in G. Because a circuit is a closed
+    trail, a circuit begins and ends at the same vertex without
+    repeating any edges, and a circuit can be described by choosing
+    any of its vertices as the beginning (and ending) vertex. See the
+    description above in the Walks class for more details about walks.
+    '''
+
+    # the literal operator of the Circuits operation
+    _operator_ = Literal(string_format='Circuits',
+                         latex_format=r'\textrm{Circuits}',
+                         theory=__file__)
+
+    def __init__(self, k, G, *, styles=None):
+        '''
+        Represent Circuits(k, G), the set of all circuits of
+        length k in graph G.
+        '''
+        self.graph = G
+        self.length = k
+        Function.__init__(
+                self, Circuits._operator_, (k, G), styles=styles)
+
+    def membership_object(self, element):
+        from .walks_membership import CircuitsMembership
+        return CircuitsMembership(element, self)
+
+#     def nonmembership_object(self, element):
+#         from .walks_membership import CircuitsNonmembership
+#         return CircuitsNonmembership(element, self)
+
+
+class Cycles(Function):
+    '''
+    Cycles(k, G) represents the set of cycles of length k in
+    the simple undirected graph G. A cycle in a graph G can be
+    thought of as a "closed path": a cycle is a circuit without 
+    repeating any vertices (except for the beginning and ending
+    vertices). A cycle of length k is often referred to as a k-cycle.
+    A 3-cycle is often simply referred to as a triangle. A cycle of
+    odd length is called an odd cycle; a cycle of even length is
+    called an even cycle. See the description above in the Walks
+    class for more details about walks.
+    '''
+
+    # the literal operator of the Cycles operation
+    _operator_ = Literal(string_format='Cycles',
+                         latex_format=r'\textrm{Cycles}',
+                         theory=__file__)
+
+    def __init__(self, k, G, *, styles=None):
+        '''
+        Represent Cycles(k, G), the set of all cycles of
+        length k (also called k-cycles) in graph G.
+        '''
+        self.graph = G
+        self.length = k
+        Function.__init__(
+                self, Cycles._operator_, (k, G), styles=styles)
+
+    def membership_object(self, element):
+        from .walks_membership import CyclesMembership
+        return CyclessMembership(element, self)
+
+#     def nonmembership_object(self, element):
+#         from .walks_membership import CyclesNonmembership
+#         return CyclesNonmembership(element, self)
 
 
 class WalkLength(Function):
@@ -149,7 +221,8 @@ class Closed(Function):
     '''
     Closed(W) is a propositional function (or predicate)
     claiming that walk W is closed (i.e., that the endvertices of
-    walk W are equal).
+    walk W are equal). Recall that trails, paths, circuits, and
+    cycles are all special cases of walks.
     '''
 
     # the literal operator of the Closed operation

From 07e12f248c778b359092a01a2a2c9a7e186766f5 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 8 Jul 2025 10:50:05 -0600
Subject: [PATCH 135/159] Establish BeginningVertex and EndingVertex classes in
 graphs/walks pkg

Establish the BeginningVertex() and EndingVertex() classes in the graphs/walks sub-theory package to represent the beginning and ending vertices of a walk sequence. Also establish the associated axiomatic definitions, as well as an axiomatic definition of the more general EndVertices() class.
---
 packages/proveit/graphs/__init__.py           |  5 +-
 packages/proveit/graphs/walks/__init__.py     |  5 +-
 .../graphs/walks/_theory_nbs_/axioms.ipynb    | 85 +++++++++++++++++--
 .../walks/_theory_nbs_/demonstrations.ipynb   | 33 ++++++-
 packages/proveit/graphs/walks/walks.py        | 49 ++++++++++-
 5 files changed, 163 insertions(+), 14 deletions(-)

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index 7a5ba07f9bda..2268069fb367 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -9,8 +9,9 @@
 from .paths_of import PathsOf
 from .union import GraphUnion
 from .vertices import AdjacentVertices, Degree, Vertices
-from .walks import (Circuits, Closed, Cycles, EdgeSequence, EdgeSet,
-          EndVertices, EulerianTrails, Paths, Trails, WalkLength, Walks)
+from .walks import (BeginningVertex, Circuits, Closed, Cycles,
+          EdgeSequence, EdgeSet, EndingVertex, EndVertices,
+          EulerianTrails, Paths, Trails, WalkLength, Walks)
 
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
diff --git a/packages/proveit/graphs/walks/__init__.py b/packages/proveit/graphs/walks/__init__.py
index d6deed8c90bc..33a2c06db8aa 100644
--- a/packages/proveit/graphs/walks/__init__.py
+++ b/packages/proveit/graphs/walks/__init__.py
@@ -1,5 +1,6 @@
-from .walks import (Circuits, Closed, Cycles, EdgeSequence, EdgeSet,
-        EndVertices, EulerianTrails, Paths, Trails, WalkLength, Walks)
+from .walks import (BeginningVertex, Circuits, Closed, Cycles,
+        EdgeSequence, EdgeSet, EndingVertex, EndVertices,
+        EulerianTrails, Paths, Trails, WalkLength, Walks)
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
 #  Make additions above, or add to sys.modules[__name__].__dict__ below.
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
index d2e3af98d67c..5e27ad7f523c 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
@@ -20,11 +20,11 @@
     "\n",
     "# from ... import ...\n",
     "from proveit import i, k, G, S, T, W, X, Function\n",
-    "from proveit.logic import Card, Equals, Forall, Functions, Injections, InSet, SetOfAll\n",
+    "from proveit.logic import Card, Equals, Forall, Functions, Injections, InSet, Set, SetOfAll\n",
     "from proveit.numbers import zero, one, Add, Interval, Natural, subtract\n",
     "from proveit.graphs import (\n",
-    "        AdjacentVertices, Circuits, Closed, Cycles, Edges, EdgeSequence, Graphs, Paths,\n",
-    "        Trails, Vertices, Walks)"
+    "        AdjacentVertices, BeginningVertex, Circuits, Closed, Cycles, Edges,\n",
+    "        EdgeSequence, EndingVertex, EndVertices, Graphs, Paths, Trails, Vertices, Walks)"
    ]
   },
   {
@@ -40,7 +40,14 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "A walk $W$ of length $k$ in a simple graph $G$, denoted using $W \\in \\texttt{Walks}(k, G)$, is essentially a sequence of vertices of $G$ such that whenever two vertices $u$ and $v$ are consecutive in the sequence, $u$ and $v$ are also adjacent in $G$."
+    "### Walks"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A walk $W$ of length $k$ in a simple graph $G$, denoted using $W \\in \\texttt{Walks}(k, G)$, is essentially a sequence of vertices of $G$ such that whenever two vertices $u$ and $v$ are consecutive in the sequence, $u$ and $v$ are also adjacent in $G$. Notice that trails, paths, circuits, and cycles are all special types of walks."
    ]
   },
   {
@@ -70,7 +77,69 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "A trail $T$ of length $k$ in a simple graph $G$, denoted using $T \\in \\texttt{Trails}(k, G)$, is a walk in which no edge is repeated. This means that the _edge_ sequence is a one-to-one (injective) function $S: [0, 1, \\ldots, k] \\rightarrow \\texttt{Edges}(G)$."
+    "Since a length-$k$ walk $W$ in graph $G$ is a function $W:(0, 1, \\ldots, k)\\rightarrow \\texttt{Vertices}(G)$, the begining vertex is $W(0)$ and the ending vertex is $W(k)$. Sometimes it is useful to consider the _set_ of both endvertices, denoted with $\\texttt{EndVertices}(W)$."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "beginning_vertex_def = (\n",
+    "    Forall(W,\n",
+    "        Equals(BeginningVertex(W), Function(W, zero)),\n",
+    "    domain=Walks(k, G))\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "ending_vertex_def = (\n",
+    "    Forall(W,\n",
+    "        Equals(EndingVertex(W), Function(W, k)),\n",
+    "    domain=Walks(k, G))\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "endvertices_def = (\n",
+    "    Forall(W,\n",
+    "        Equals(EndVertices(W), Set(Function(W, zero), Function(W, k))),\n",
+    "    domain=Walks(k, G))\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A __closed__ walk $W$ is a walk whose beginning and ending vertices are the same. We could define such closure using the observation that $|\\texttt{EndVertices}(W)| = 1$, but it's more straightforward to use our `BeginningVertex` and `EndingVertex` classes:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Trails\n",
+    "\n",
+    "A trail $T$ of length $k$ in a simple graph $G$, denoted using $T \\in \\texttt{Trails}(k, G)$, is a walk in which no edge is repeated. This means that the _edge_ sequence is a one-to-one (injective) function $S: [0, 1, \\ldots, k] \\xrightarrow[]{1:1} \\texttt{Edges}(G)$."
    ]
   },
   {
@@ -96,6 +165,8 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
+    "### Paths\n",
+    "\n",
     "A path $P$ of length $k$ in a simple graph $G$, denoted using $P \\in \\texttt{Paths}(k, G)$, is a walk in which no vertex (and thus no edge) is repeated. This means that the vertex sequence is a one-to-one (injective) function $S: [0, 1, \\ldots, k] \\rightarrow \\texttt{Vertices}(G)$."
    ]
   },
@@ -122,6 +193,8 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
+    "### Circuits\n",
+    "\n",
     "A circuit $C$ of length $k$ in a simple graph $G$, denoted using $C \\in \\texttt{Circuits}(k, G)$, is a closed trail of length $3$ or more, or a closed walk of length $3$ in which no edge is repeated. This means that the _edge_ sequence associated with $C$ is a one-to-one (injective) function $S: [0, 1, \\ldots, k] \\xrightarrow[]{1:1} \\texttt{Edges}(G)$, and the cardinality of the $\\texttt{EndVertices}(C)$ set is $1$ (since the sequence begins and ends with the same vertex)."
    ]
   },
@@ -148,6 +221,8 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
+    "### Cycles\n",
+    "\n",
     "A cycle $C$ of length $k$ in a simple graph $G$, denoted using $C \\in \\texttt{Cycles}(k, G)$, is a circuit in which no vertex is repeated (except the beginning and ending vertices). Another way of saying this is to realize that a cycle is a closed circuit $C \\in \\texttt{Circuits}(k, G)$ such that the restriction $C\\vert_{[0, 1, \\ldots, k-1]}$ is a length-($k$-$1$) path in $G$."
    ]
   },
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
index d4285c49ef62..72d7e0a57a64 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
@@ -20,9 +20,9 @@
     "from proveit.logic.sets import Functions, Injections\n",
     "from proveit.numbers import zero, one, Add, Interval, Natural, subtract\n",
     "from proveit.graphs import (\n",
-    "        AdjacentVertices, Circuits, Closed, Cycles, Edges, EdgeSequence,\n",
-    "        EdgeSet, EndVertices, EulerianTrails, Graph, Graphs, Paths, Trails,\n",
-    "        Vertices, WalkLength, Walks)\n",
+    "        AdjacentVertices, BeginningVertex, Circuits, Closed, Cycles, Edges,\n",
+    "        EdgeSequence, EdgeSet, EndingVertex, EndVertices, EulerianTrails,\n",
+    "        Graph, Graphs, Paths, Trails, Vertices, WalkLength, Walks)\n",
     "%begin demonstrations\n"
    ]
   },
@@ -268,7 +268,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "The set of endvertices (or endpoints) of a walk $W$ is denoted $\\texttt{EndVertices}(W)$:"
+    "The _set_ of endvertices (or endpoints) of a walk $W$ is denoted $\\texttt{EndVertices}(W)$:"
    ]
   },
   {
@@ -280,6 +280,31 @@
     "EndVertices(W)"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Since a length-$k$ walk $W$ in graph $G$ is a function $W:(0, 1, \\ldots, k)\\rightarrow \\texttt{Vertices}(G)$, there is a natural “begining vertex” and “ending vertex,” denoted `BeginningVertex(W)` and `EndingVertex(W)`, respectively."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "BeginningVertex(W)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "EndingVertex(W)"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
diff --git a/packages/proveit/graphs/walks/walks.py b/packages/proveit/graphs/walks/walks.py
index d8949b5b7287..2032d3b86d58 100644
--- a/packages/proveit/graphs/walks/walks.py
+++ b/packages/proveit/graphs/walks/walks.py
@@ -290,7 +290,6 @@ def __init__(self, W, *, styles=None):
                 self, EdgeSet._operator_, W, styles=styles)
 
 
-
 class EndVertices(Function):
     '''
     EndVertices(W) represents the set of endvertices or endpoints of
@@ -316,6 +315,54 @@ def __init__(self, W, *, styles=None):
                 self, EndVertices._operator_, W, styles=styles)
 
 
+class BeginningVertex(Function):
+    '''
+    BeginningVertex(W) represents the beginning vertex of walk W
+    (and recall that trails, paths, circuits, and cycles are all cases
+    of walks). Since a length-k walk W is actually a function:
+        W:[0,1,...,k] -> Vertices(G),
+    BeginningVertex(W) represents the value W(0).
+    '''
+
+    # the literal operator of the BeginningVertex(W) operation
+    _operator_ = Literal(string_format='BeginningVertex',
+                         latex_format=r'\textrm{BeginningVertex}',
+                         theory=__file__)
+
+    def __init__(self, W, *, styles=None):
+        '''
+        Represent BeginningVertex(W), the beginning vertex W(0) of
+        walk W in a graph G.
+        '''
+        self.walk = W
+        Function.__init__(
+                self, BeginningVertex._operator_, W, styles=styles)
+
+
+class EndingVertex(Function):
+    '''
+    EndingVertex(W) represents the ending vertex of walk W (and recall
+    that trails, paths, circuits, and cycles are all cases of walks).
+    Since a length-k walk W is actually a function:
+        W:[0,1,...,k] -> Vertices(G),
+    EndingVertex(W) represents the value W(k).
+    '''
+
+    # the literal operator of the EndingVertex(W) operation
+    _operator_ = Literal(string_format='EndingVertex',
+                         latex_format=r'\textrm{EndingVertex}',
+                         theory=__file__)
+
+    def __init__(self, W, *, styles=None):
+        '''
+        Represent EndingVertex(W), the ending vertex W(k) of length-k
+        walk W in graph G.
+        '''
+        self.walk = W
+        Function.__init__(
+                self, EndingVertex._operator_, W, styles=styles)
+
+
 class EulerianTrails(Function):
     '''
     EulerianTrails(G) represents the set of Eulerian trails in the

From 0b2c5700d5b12efa570e82c54edffa5df488f73f Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 8 Jul 2025 15:58:48 -0600
Subject: [PATCH 136/159] Establish ClosedWalks(k, G) and
 ClosedWalksMembership(k, G) classes

Establish ClosedWalks(k, G) and ClosedWalksMembership(k, G) classes in the graphs/walks sub-theory package. The ClosedWalks(k, G) class is intended to replace the Closed() or ClosedWalk() predicate(s) I (minimally) utilized earlier. Also rework the axiomatic definition of Circuits(k, G) using the class of ClosedWalks(k, G) and establish the ClosedWalksMembership(k, G) class along with basic def/unfolding/folding theorems for ClosedWalksMembership() membership expressions.
---
 packages/proveit/graphs/__init__.py           |  2 +-
 packages/proveit/graphs/walks/__init__.py     |  2 +-
 .../graphs/walks/_theory_nbs_/axioms.ipynb    | 58 +++++++----
 .../walks/_theory_nbs_/demonstrations.ipynb   |  4 +-
 .../closed_walks_folding/thm_proof.ipynb      | 47 +++++++++
 .../thm_proof.ipynb                           | 47 +++++++++
 .../thm_proof.ipynb                           | 47 +++++++++
 .../closed_walks_unfolding/thm_proof.ipynb    | 47 +++++++++
 .../graphs/walks/_theory_nbs_/theorems.ipynb  | 70 ++++++++++++-
 packages/proveit/graphs/walks/walks.py        | 44 ++++++++-
 .../proveit/graphs/walks/walks_membership.py  | 98 +++++++++++++++++++
 11 files changed, 436 insertions(+), 30 deletions(-)
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_folding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_membership_def/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_membership_is_bool/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_unfolding/thm_proof.ipynb

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index 2268069fb367..12c7ba0ff918 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -9,7 +9,7 @@
 from .paths_of import PathsOf
 from .union import GraphUnion
 from .vertices import AdjacentVertices, Degree, Vertices
-from .walks import (BeginningVertex, Circuits, Closed, Cycles,
+from .walks import (BeginningVertex, Circuits, ClosedWalk, ClosedWalks, Cycles,
           EdgeSequence, EdgeSet, EndingVertex, EndVertices,
           EulerianTrails, Paths, Trails, WalkLength, Walks)
 
diff --git a/packages/proveit/graphs/walks/__init__.py b/packages/proveit/graphs/walks/__init__.py
index 33a2c06db8aa..c5871b6e2393 100644
--- a/packages/proveit/graphs/walks/__init__.py
+++ b/packages/proveit/graphs/walks/__init__.py
@@ -1,4 +1,4 @@
-from .walks import (BeginningVertex, Circuits, Closed, Cycles,
+from .walks import (BeginningVertex, Circuits, ClosedWalk, ClosedWalks, Cycles,
         EdgeSequence, EdgeSet, EndingVertex, EndVertices,
         EulerianTrails, Paths, Trails, WalkLength, Walks)
 
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
index 5e27ad7f523c..5aa0ee70fb3b 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
@@ -21,9 +21,9 @@
     "# from ... import ...\n",
     "from proveit import i, k, G, S, T, W, X, Function\n",
     "from proveit.logic import Card, Equals, Forall, Functions, Injections, InSet, Set, SetOfAll\n",
-    "from proveit.numbers import zero, one, Add, Interval, Natural, subtract\n",
+    "from proveit.numbers import zero, one, three, Add, greater_eq, Interval, Natural, subtract\n",
     "from proveit.graphs import (\n",
-    "        AdjacentVertices, BeginningVertex, Circuits, Closed, Cycles, Edges,\n",
+    "        AdjacentVertices, BeginningVertex, Circuits, ClosedWalk, ClosedWalks, Cycles, Edges,\n",
     "        EdgeSequence, EndingVertex, EndVertices, Graphs, Paths, Trails, Vertices, Walks)"
    ]
   },
@@ -40,14 +40,9 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "### Walks"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "A walk $W$ of length $k$ in a simple graph $G$, denoted using $W \\in \\texttt{Walks}(k, G)$, is essentially a sequence of vertices of $G$ such that whenever two vertices $u$ and $v$ are consecutive in the sequence, $u$ and $v$ are also adjacent in $G$. Notice that trails, paths, circuits, and cycles are all special types of walks."
+    "### Walks & Closed Walks\n",
+    "\n",
+    "A walk $W$ of length $k$ in a simple graph $G$, denoted using $W \\in \\texttt{Walks}(k, G)$, is essentially a sequence of vertices of $G$ such that whenever two vertices $u$ and $v$ are consecutive in the sequence, $u$ and $v$ are also adjacent in $G$. A _closed_ walk $W$ of length $k$ in a simple graph $G$, denoted using $W \\in \\texttt{ClosedWalks}(k, G)$, is a walk that begins and ends at the same vertex. Notice that trails, paths, circuits, and cycles are all special types of walks."
    ]
   },
   {
@@ -87,9 +82,13 @@
    "outputs": [],
    "source": [
     "beginning_vertex_def = (\n",
+    "    Forall(G,\n",
+    "    Forall(k,\n",
     "    Forall(W,\n",
     "        Equals(BeginningVertex(W), Function(W, zero)),\n",
-    "    domain=Walks(k, G))\n",
+    "    domain =Walks(k, G)),\n",
+    "    domain = Natural),\n",
+    "    domain = Graphs())\n",
     ")"
    ]
   },
@@ -100,9 +99,13 @@
    "outputs": [],
    "source": [
     "ending_vertex_def = (\n",
+    "    Forall(G,\n",
+    "    Forall(k,\n",
     "    Forall(W,\n",
     "        Equals(EndingVertex(W), Function(W, k)),\n",
-    "    domain=Walks(k, G))\n",
+    "    domain=Walks(k, G)),\n",
+    "    domain = Natural),\n",
+    "    domain = Graphs())\n",
     ")"
    ]
   },
@@ -113,9 +116,13 @@
    "outputs": [],
    "source": [
     "endvertices_def = (\n",
+    "    Forall(G,\n",
+    "    Forall(k,\n",
     "    Forall(W,\n",
     "        Equals(EndVertices(W), Set(Function(W, zero), Function(W, k))),\n",
-    "    domain=Walks(k, G))\n",
+    "    domain=Walks(k, G)),\n",
+    "    domain = Natural),\n",
+    "    domain = Graphs())\n",
     ")"
    ]
   },
@@ -131,7 +138,19 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "closed_walks_k_G_def = (\n",
+    "    Forall(G, Forall(k,\n",
+    "        Equals(\n",
+    "            ClosedWalks(k, G),\n",
+    "            SetOfAll(W,\n",
+    "                 W,\n",
+    "                 conditions = [Equals(BeginningVertex(W), EndingVertex(W))],\n",
+    "                 domain = Walks(k, G) )\n",
+    "        ),\n",
+    "    domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
   },
   {
    "cell_type": "markdown",
@@ -195,7 +214,7 @@
    "source": [
     "### Circuits\n",
     "\n",
-    "A circuit $C$ of length $k$ in a simple graph $G$, denoted using $C \\in \\texttt{Circuits}(k, G)$, is a closed trail of length $3$ or more, or a closed walk of length $3$ in which no edge is repeated. This means that the _edge_ sequence associated with $C$ is a one-to-one (injective) function $S: [0, 1, \\ldots, k] \\xrightarrow[]{1:1} \\texttt{Edges}(G)$, and the cardinality of the $\\texttt{EndVertices}(C)$ set is $1$ (since the sequence begins and ends with the same vertex)."
+    "A circuit $C$ of length $k$ in a simple graph $G$, denoted using $C \\in \\texttt{Circuits}(k, G)$, is a closed trail of length $3$ or more. Instead of defining an intermediate “closed trail” class, we return to the trail definition as a walk with no repeated edges and add the closure constraint to the walk itself. Recall that the requirement that we have no repeated edges means that the edge sequence associated with circuit $C$ is a one-to-one (injective) function $S: [0, 1, \\ldots, k] \\xrightarrow[]{1:1} \\texttt{Edges}(G)$."
    ]
   },
   {
@@ -208,10 +227,11 @@
     "    Forall(G, Forall(k,\n",
     "        Equals(\n",
     "            Circuits(k, G),\n",
-    "            SetOfAll(T,\n",
-    "                 T,\n",
-    "                 conditions = [Closed(T)],\n",
-    "                 domain = Trails(k, G) )\n",
+    "            SetOfAll(W,\n",
+    "                 W,\n",
+    "                 conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G))),\n",
+    "                              greater_eq(k, three)],\n",
+    "                 domain = ClosedWalks(k, G) )\n",
     "        ),\n",
     "    domain = Natural), domain = Graphs())\n",
     ")"
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
index 72d7e0a57a64..70a3dede452f 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
@@ -20,7 +20,7 @@
     "from proveit.logic.sets import Functions, Injections\n",
     "from proveit.numbers import zero, one, Add, Interval, Natural, subtract\n",
     "from proveit.graphs import (\n",
-    "        AdjacentVertices, BeginningVertex, Circuits, Closed, Cycles, Edges,\n",
+    "        AdjacentVertices, BeginningVertex, Circuits, ClosedWalks, Cycles, Edges,\n",
     "        EdgeSequence, EdgeSet, EndingVertex, EndVertices, EulerianTrails,\n",
     "        Graph, Graphs, Paths, Trails, Vertices, WalkLength, Walks)\n",
     "%begin demonstrations\n"
@@ -125,7 +125,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Closed(W)"
+    "InSet(W, ClosedWalks(k, G))"
    ]
   },
   {
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_folding/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..338993633b44
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_folding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#closed_walks_folding\">closed_walks_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving closed_walks_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_membership_def/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_membership_def/thm_proof.ipynb
new file mode 100644
index 000000000000..989e6bbe2065
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_membership_def/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#closed_walks_membership_def\">closed_walks_membership_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving closed_walks_membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_membership_is_bool/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_membership_is_bool/thm_proof.ipynb
new file mode 100644
index 000000000000..c3e9f2bce0d1
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_membership_is_bool/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#closed_walks_membership_is_bool\">closed_walks_membership_is_bool</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving closed_walks_membership_is_bool"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_unfolding/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_unfolding/thm_proof.ipynb
new file mode 100644
index 000000000000..f4c7adccd8a0
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_unfolding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#closed_walks_unfolding\">closed_walks_unfolding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving closed_walks_unfolding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
index c8fadc8605d6..ef42a6ce64cb 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
@@ -22,8 +22,8 @@
     "from proveit.logic import And, Equals, Exists, Forall, in_bool\n",
     "from proveit.logic.sets import Functions, Injections, InSet, Set, SetOfAll\n",
     "from proveit.numbers import zero, one, Add, Interval, LessEq, Natural, subtract\n",
-    "from proveit.graphs import (AdjacentVertices, Edges, EdgeSequence, EndVertices, Graphs,\n",
-    "        Paths, Trails, Vertices, Walks)\n"
+    "from proveit.graphs import (AdjacentVertices, BeginningVertex, ClosedWalks, Edges,\n",
+    "        EdgeSequence, EndingVertex, EndVertices, Graphs, Paths, Trails, Vertices, Walks)\n"
    ]
   },
   {
@@ -119,6 +119,58 @@
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "closed_walks_membership_def = (\n",
+    "Forall(G, Forall(k, Forall(W,\n",
+    "Equals(\n",
+    "    InSet(W, ClosedWalks(k, G)),\n",
+    "    InSet(W,\n",
+    "    SetOfAll(S,\n",
+    "         S,\n",
+    "         conditions = [Equals(BeginningVertex(S), EndingVertex(S))],\n",
+    "         domain = Walks(k, G)))\n",
+    ")), domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "closed_walks_unfolding = (\n",
+    "Forall(G, Forall(k, Forall(W,\n",
+    "InSet(W,\n",
+    "      SetOfAll(S,\n",
+    "               S,\n",
+    "               conditions = [Equals(BeginningVertex(S), EndingVertex(S))],\n",
+    "               domain = Walks(k, G))),\n",
+    "domain = ClosedWalks(k, G)), domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "closed_walks_folding = (\n",
+    "Forall(G, Forall(k, Forall(W,\n",
+    "    InSet(W,ClosedWalks(k, G)),\n",
+    "    domain = SetOfAll(S, S,\n",
+    "                  conditions = [Equals(BeginningVertex(S), EndingVertex(S))],\n",
+    "                  domain = Walks(k, G))),\n",
+    "domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -327,6 +379,20 @@
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "closed_walks_membership_is_bool = Forall(G,\n",
+    "Forall(k,\n",
+    "Forall(W, in_bool(InSet(W, ClosedWalks(k, G)))),\n",
+    "domain = Natural),\n",
+    "domain = Graphs()\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/walks/walks.py b/packages/proveit/graphs/walks/walks.py
index 2032d3b86d58..53270a3db11f 100644
--- a/packages/proveit/graphs/walks/walks.py
+++ b/packages/proveit/graphs/walks/walks.py
@@ -49,6 +49,40 @@ def membership_object(self, element):
 #         return WalksNonmembership(element, self)
 
 
+class ClosedWalks(Function):
+    '''
+    ClosedWalks(k, G) represents the set of closed walks of length k
+    in the simple undirected graph G. See the description in the Walks
+    class for details about walks more generally. A closed walk is a
+    walk in which the first and last vertex are the same. Closed walks
+    are important in part because ClosedWalks(k, G) is a superset for
+    Circuits(k, G) and Cycles(k, G).
+    '''
+
+    # the literal operator of the Walks operation
+    _operator_ = Literal(string_format='ClosedWalks',
+                         latex_format=r'\textrm{ClosedWalks}',
+                         theory=__file__)
+
+    def __init__(self, k, G, *, styles=None):
+        '''
+        Represent ClosedWalks(k, G), the set of all closed walks of
+        length k in graph G.
+        '''
+        self.graph = G
+        self.length = k
+        Function.__init__(
+                self, ClosedWalks._operator_, (k, G), styles=styles)
+
+    def membership_object(self, element):
+        from .walks_membership import ClosedWalksMembership
+        return ClosedWalksMembership(element, self)
+
+#     def nonmembership_object(self, element):
+#         from .walks_membership import WalksNonmembership
+#         return WalksNonmembership(element, self)
+
+
 class Trails(Function):
     '''
     Trails(k, G) represents the set of trails of length k in the
@@ -217,27 +251,27 @@ def latex(self, **kwargs):
         return r'\left\|' + self.operand.latex() + r'\right\|'
 
 
-class Closed(Function):
+class ClosedWalk(Function):
     '''
-    Closed(W) is a propositional function (or predicate)
+    ClosedWalk(W) is a propositional function (or predicate)
     claiming that walk W is closed (i.e., that the endvertices of
     walk W are equal). Recall that trails, paths, circuits, and
     cycles are all special cases of walks.
     '''
 
-    # the literal operator of the Closed operation
+    # the literal operator of the ClosedWalk() operation
     _operator_ = Literal(string_format='Closed',
                          latex_format=r'\textrm{Closed}',
                          theory=__file__)
 
     def __init__(self, W, *, styles=None):
         '''
-        Represent the propositional function Closed(G),
+        Represent the propositional function ClosedWalk(G),
         claiming walk W is closed.
         '''
         self.walk = W
         Function.__init__(
-                self, Closed._operator_, W, styles=styles)
+                self, ClosedWalk._operator_, W, styles=styles)
 
 class EdgeSequence(Function):
     '''
diff --git a/packages/proveit/graphs/walks/walks_membership.py b/packages/proveit/graphs/walks/walks_membership.py
index 3972d270e2a7..26eac841c1f1 100644
--- a/packages/proveit/graphs/walks/walks_membership.py
+++ b/packages/proveit/graphs/walks/walks_membership.py
@@ -105,6 +105,104 @@ def deduce_in_bool(self, **defaults_config):
             {G:_G_sub, k:_k_sub, W:_W_sub}, auto_simplify=False)
 
 
+class ClosedWalksMembership(SetMembership):
+    '''
+    Defines methods that apply to membership in the set
+    of length-k closed walks in the simple graph G, denoted
+    ClosedWalks(k, G).
+    '''
+
+    def __init__(self, element, domain):
+        SetMembership.__init__(self, element, domain)
+
+    # @equality_prover('defined', 'define')
+    # def definition(self, **defaults_config):
+    #     '''
+    #     From self = [elem in Walks(k, G)], deduce and return:
+    #     [elem in Walks(G)]
+    #     = elem in {S | Adjacent(S(i), S(i+1))}
+    #     for {S in Functions([0,...,k], Vertices(G))}
+    #     '''
+    #     from . import walks_membership_def
+    #     element = self.element
+    #     _G_sub  = self.domain.graph
+    #     _k_sub  = self.domain.length
+    #     return walks_membership_def.instantiate(
+    #             {G: _G_sub, k: _k_sub, W: element },auto_simplify=False)
+
+    # def as_defined(self):
+    #     '''
+    #     From self = [elem in Walks(k, G)],
+    #     return the expression (NOT a judgment):
+    #     elem in {S | Adjacent(S(i), S(i+1))}
+    #     for {S in Functions([0,...,k], Vertices(G))}
+    #     '''
+    #     element = self.element
+    #     _G      = self.domain.graph
+    #     _k      = self.domain.length
+    #     return InSet(element,
+    #            SetOfAll(S, S,
+    #            conditions = [
+    #                Forall(i,
+    #                AdjacentVertices(
+    #                        Function(S, i), Function(S, Add(i, one)), _G),
+    #                domain = Interval(zero, subtract(_k, one)))],
+    #            domain = Functions(Interval(zero, _k), Vertices(_G))))
+
+    # @prover
+    # def unfold(self, **defaults_config):
+    #     '''
+    #     From self = [elem in Walks(k, G)], and knowing self,
+    #     derive and return:
+    #     elem in {S | Adjacent(S(i), S(i+1))}
+    #     for {S in Functions([0,...,k], Vertices(G))}.
+    #     '''
+    #     from . import walks_membership_unfolding
+    #     element = self.element
+    #     _G_sub  = self.domain.graph
+    #     _k_sub  = self.domain.length
+    #     return walks_membership_unfolding.instantiate(
+    #         {G: _G_sub, k: _k_sub, W: element}, auto_simplify=False)
+
+    # @prover
+    # def conclude(self, **defaults_config):
+    #     '''
+    #     Called on self = [W in Walks(k, G)], derive and return
+    #     self, knowing or assuming at least one of the following:
+    #     (1) W in Functions([0,...,k], Vertices(G)) AND
+    #         forall i in [0,..., k-1][AdjacentVertices(W(i), W(i+1), G)]
+    #     (2) elem in {S | Adjacent(S(i), S(i+1))}
+    #         for {S in Functions([0,...,k], Vertices(G))}
+    #     '''
+    #     _W = self.element
+    #     _G  = self.domain.graph
+    #     _k  = self.domain.length
+    #     functions_set = Functions(Interval(zero, _k), Vertices(_G))
+    #     adj_verts = Forall(
+    #         i, AdjacentVertices(Function(_W, i),
+    #                             Function(_W, Add(i, one)), _G),
+    #         domain = Interval(zero, subtract(_k, one)))
+    #     if (InSet(_W, functions_set).proven()
+    #         and adj_verts.proven()):
+    #         from . import walks_membership_folding_components
+    #         return walks_membership_folding_components.instantiate(
+    #                 {G: _G, k: _k, W: _W},
+    #                 auto_simplify=False)
+        
+    #     from . import walks_membership_folding
+    #     return walks_membership_folding.instantiate(
+    #         {G: _G, k: _k, W: _W}, auto_simplify=False)
+
+    @relation_prover
+    def deduce_in_bool(self, **defaults_config):
+        from . import walks_membership_is_bool
+        _G_sub = self.domain.graph
+        _k_sub = self.domain.length
+        _W_sub = self.element
+        return walks_membership_is_bool.instantiate(
+            {G:_G_sub, k:_k_sub, W:_W_sub}, auto_simplify=False)
+
+
 class TrailsMembership(SetMembership):
     '''
     Defines methods that apply to membership in the set

From 7e5f859dd290e56f6d578743654d42d6d7852cff Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 8 Jul 2025 16:27:24 -0600
Subject: [PATCH 137/159] Establish the ClosedWalksMembership(k, G) methods

Establish the ClosedWalksMembership(k, G) methods in the graphs/walks sub-theory package (also slightly renaming a couple of the ClosedWalksMembership theorems), and update the graphs/walks/demos notebook to test the new membership methods.
---
 .../walks/_theory_nbs_/demonstrations.ipynb   |  65 ++++++++
 .../thm_proof.ipynb                           |   4 +-
 .../thm_proof.ipynb                           |   4 +-
 .../graphs/walks/_theory_nbs_/theorems.ipynb  |   4 +-
 .../proveit/graphs/walks/walks_membership.py  | 148 ++++++++----------
 5 files changed, 137 insertions(+), 88 deletions(-)
 rename packages/proveit/graphs/walks/_theory_nbs_/proofs/{closed_walks_folding => closed_walks_membership_folding}/thm_proof.ipynb (84%)
 rename packages/proveit/graphs/walks/_theory_nbs_/proofs/{closed_walks_unfolding => closed_walks_membership_unfolding}/thm_proof.ipynb (84%)

diff --git a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
index 70a3dede452f..206894b0fc50 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
@@ -401,6 +401,71 @@
     "                                       domain = Interval(zero, subtract(k, one)))])"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### ClosedWalks Membership and Related Methods"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(W, ClosedWalks(k, G))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(W, ClosedWalks(k, G)).deduce_in_bool(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(W, ClosedWalks(k, G)).definition(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(W, ClosedWalks(k, G)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(W, ClosedWalks(k, G)).unfold(\n",
+    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(W, ClosedWalks(k, G))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(W, ClosedWalks(k, G)).conclude(\n",
+    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "                       InSet(W, SetOfAll(S, S, conditions = [Equals(BeginningVertex(S), EndingVertex(S))],\n",
+    "                                domain = Walks(k, G)))])"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_folding/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_membership_folding/thm_proof.ipynb
similarity index 84%
rename from packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_folding/thm_proof.ipynb
rename to packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_membership_folding/thm_proof.ipynb
index 338993633b44..9297b86f23f1 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_folding/thm_proof.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_membership_folding/thm_proof.ipynb
@@ -4,7 +4,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#closed_walks_folding\">closed_walks_folding</a> theorem\n",
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#closed_walks_membership_folding\">closed_walks_membership_folding</a> theorem\n",
     "========"
    ]
   },
@@ -24,7 +24,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "%proving closed_walks_folding"
+    "%proving closed_walks_membership_folding"
    ]
   },
   {
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_unfolding/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_membership_unfolding/thm_proof.ipynb
similarity index 84%
rename from packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_unfolding/thm_proof.ipynb
rename to packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_membership_unfolding/thm_proof.ipynb
index f4c7adccd8a0..a3a6fd7c37f1 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_unfolding/thm_proof.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_membership_unfolding/thm_proof.ipynb
@@ -4,7 +4,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#closed_walks_unfolding\">closed_walks_unfolding</a> theorem\n",
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#closed_walks_membership_unfolding\">closed_walks_membership_unfolding</a> theorem\n",
     "========"
    ]
   },
@@ -24,7 +24,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "%proving closed_walks_unfolding"
+    "%proving closed_walks_membership_unfolding"
    ]
   },
   {
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
index ef42a6ce64cb..377673bcc7df 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
@@ -144,7 +144,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "closed_walks_unfolding = (\n",
+    "closed_walks_membership_unfolding = (\n",
     "Forall(G, Forall(k, Forall(W,\n",
     "InSet(W,\n",
     "      SetOfAll(S,\n",
@@ -161,7 +161,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "closed_walks_folding = (\n",
+    "closed_walks_membership_folding = (\n",
     "Forall(G, Forall(k, Forall(W,\n",
     "    InSet(W,ClosedWalks(k, G)),\n",
     "    domain = SetOfAll(S, S,\n",
diff --git a/packages/proveit/graphs/walks/walks_membership.py b/packages/proveit/graphs/walks/walks_membership.py
index 26eac841c1f1..6c089b3aac9b 100644
--- a/packages/proveit/graphs/walks/walks_membership.py
+++ b/packages/proveit/graphs/walks/walks_membership.py
@@ -1,10 +1,11 @@
 from proveit import (i, k, G, P, S, T, W, equality_prover, Function,
         prover, relation_prover)
-from proveit.logic import Forall, InSet, SetMembership, SetNonmembership
+from proveit.logic import (Equals, Forall, InSet, SetMembership,
+            SetNonmembership)
 from proveit.logic.sets import Functions, Injections, SetOfAll
 from proveit.numbers import zero, one, Add, Interval, subtract
-from proveit.graphs import (AdjacentVertices, Edges, EdgeSequence,
-            Graph, Vertices, Walks)
+from proveit.graphs import (AdjacentVertices, BeginningVertex, Edges,
+            EdgeSequence, EndingVertex, Graph, Vertices, Walks)
 
 
 class WalksMembership(SetMembership):
@@ -115,91 +116,74 @@ class ClosedWalksMembership(SetMembership):
     def __init__(self, element, domain):
         SetMembership.__init__(self, element, domain)
 
-    # @equality_prover('defined', 'define')
-    # def definition(self, **defaults_config):
-    #     '''
-    #     From self = [elem in Walks(k, G)], deduce and return:
-    #     [elem in Walks(G)]
-    #     = elem in {S | Adjacent(S(i), S(i+1))}
-    #     for {S in Functions([0,...,k], Vertices(G))}
-    #     '''
-    #     from . import walks_membership_def
-    #     element = self.element
-    #     _G_sub  = self.domain.graph
-    #     _k_sub  = self.domain.length
-    #     return walks_membership_def.instantiate(
-    #             {G: _G_sub, k: _k_sub, W: element },auto_simplify=False)
-
-    # def as_defined(self):
-    #     '''
-    #     From self = [elem in Walks(k, G)],
-    #     return the expression (NOT a judgment):
-    #     elem in {S | Adjacent(S(i), S(i+1))}
-    #     for {S in Functions([0,...,k], Vertices(G))}
-    #     '''
-    #     element = self.element
-    #     _G      = self.domain.graph
-    #     _k      = self.domain.length
-    #     return InSet(element,
-    #            SetOfAll(S, S,
-    #            conditions = [
-    #                Forall(i,
-    #                AdjacentVertices(
-    #                        Function(S, i), Function(S, Add(i, one)), _G),
-    #                domain = Interval(zero, subtract(_k, one)))],
-    #            domain = Functions(Interval(zero, _k), Vertices(_G))))
-
-    # @prover
-    # def unfold(self, **defaults_config):
-    #     '''
-    #     From self = [elem in Walks(k, G)], and knowing self,
-    #     derive and return:
-    #     elem in {S | Adjacent(S(i), S(i+1))}
-    #     for {S in Functions([0,...,k], Vertices(G))}.
-    #     '''
-    #     from . import walks_membership_unfolding
-    #     element = self.element
-    #     _G_sub  = self.domain.graph
-    #     _k_sub  = self.domain.length
-    #     return walks_membership_unfolding.instantiate(
-    #         {G: _G_sub, k: _k_sub, W: element}, auto_simplify=False)
-
-    # @prover
-    # def conclude(self, **defaults_config):
-    #     '''
-    #     Called on self = [W in Walks(k, G)], derive and return
-    #     self, knowing or assuming at least one of the following:
-    #     (1) W in Functions([0,...,k], Vertices(G)) AND
-    #         forall i in [0,..., k-1][AdjacentVertices(W(i), W(i+1), G)]
-    #     (2) elem in {S | Adjacent(S(i), S(i+1))}
-    #         for {S in Functions([0,...,k], Vertices(G))}
-    #     '''
-    #     _W = self.element
-    #     _G  = self.domain.graph
-    #     _k  = self.domain.length
-    #     functions_set = Functions(Interval(zero, _k), Vertices(_G))
-    #     adj_verts = Forall(
-    #         i, AdjacentVertices(Function(_W, i),
-    #                             Function(_W, Add(i, one)), _G),
-    #         domain = Interval(zero, subtract(_k, one)))
-    #     if (InSet(_W, functions_set).proven()
-    #         and adj_verts.proven()):
-    #         from . import walks_membership_folding_components
-    #         return walks_membership_folding_components.instantiate(
-    #                 {G: _G, k: _k, W: _W},
-    #                 auto_simplify=False)
-        
-    #     from . import walks_membership_folding
-    #     return walks_membership_folding.instantiate(
-    #         {G: _G, k: _k, W: _W}, auto_simplify=False)
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self = [elem in ClosedWalks(k, G)], deduce and return
+        the equality:
+            [elem in ClosedWalks(k, G)]
+             = elem in {S | BeginningVertex(S) = EndingVertex(S)}
+             for {S in Walks(k, G)}
+        '''
+        from . import closed_walks_membership_def
+        element = self.element
+        _G_sub  = self.domain.graph
+        _k_sub  = self.domain.length
+        return closed_walks_membership_def.instantiate(
+                {G: _G_sub, k: _k_sub, W: element },auto_simplify=False)
+
+    def as_defined(self):
+        '''
+        From self = [elem in ClosedWalks(k, G)],
+        return the expression (NOT a judgment):
+            elem in {S | BeginningVertex(S) = EndingVertex(S)}
+            for {S in Walks(k, G)}
+        '''
+        element = self.element
+        _G      = self.domain.graph
+        _k      = self.domain.length
+        return InSet(element,
+               SetOfAll(S, S,
+               conditions = [Equals(BeginningVertex(S), EndingVertex(S))],
+               domain = Walks(_k, _G)))
+
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        From self = [elem in ClosedWalks(k, G)], and knowing (or
+        (assuming) self, derive and return:
+             elem in {S | BeginningVertex(S) = EndingVertex(S)}
+             for {S in Walks(k, G)}.
+        '''
+        from . import closed_walks_membership_unfolding
+        element = self.element
+        _G_sub  = self.domain.graph
+        _k_sub  = self.domain.length
+        return closed_walks_membership_unfolding.instantiate(
+            {G: _G_sub, k: _k_sub, W: element}, auto_simplify=False)
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Called on self = [W in ClosedWalks(k, G)], derive and return
+        self, knowing or assuming that:
+            W in {S | BeginningVertex(S) = EndingVertex(S)}
+            for {S in Walks(k, G)}
+        '''
+        _W = self.element
+        _G  = self.domain.graph
+        _k  = self.domain.length
+        from . import closed_walks_membership_folding
+        return closed_walks_membership_folding.instantiate(
+            {G: _G, k: _k, W: _W}, auto_simplify=False)
 
     @relation_prover
     def deduce_in_bool(self, **defaults_config):
-        from . import walks_membership_is_bool
+        from . import closed_walks_membership_is_bool
         _G_sub = self.domain.graph
         _k_sub = self.domain.length
         _W_sub = self.element
-        return walks_membership_is_bool.instantiate(
+        return closed_walks_membership_is_bool.instantiate(
             {G:_G_sub, k:_k_sub, W:_W_sub}, auto_simplify=False)
 
 

From 8247cec2dc1d9813a89a3cbac828fb007c4f5d4d Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Wed, 9 Jul 2025 19:46:42 -0600
Subject: [PATCH 138/159] Establish ClosedTrailsMembership(k,G) and
 CircuitsMembership(k,G) classes

Establish the ClosedTrailsMembership(k,G) and CircuitsMembership(k,G) classes in walks_membership.py, along with related theorems and membership methods. Also in this commit: some updates to other walks_membership methods (dealing with side-effects, for example), the axiomatic definition of ClosedTrails(k, G), and related updates to the graphs/walks/demonstrations.ipynb notebook.
---
 packages/proveit/graphs/__init__.py           |   3 +-
 packages/proveit/graphs/walks/__init__.py     |   3 +-
 .../graphs/walks/_theory_nbs_/axioms.ipynb    |  33 +-
 .../walks/_theory_nbs_/demonstrations.ipynb   | 279 +++++++++++++++-
 .../circuits_membership_def/thm_proof.ipynb   |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../closed_walks_within_walks/thm_proof.ipynb |  47 +++
 .../paths_within_trails/thm_proof.ipynb       |  47 +++
 .../trails_within_walks/thm_proof.ipynb       |  47 +++
 .../thm_proof.ipynb                           |  47 +++
 .../graphs/walks/_theory_nbs_/theorems.ipynb  | 306 +++++++++++++++++-
 packages/proveit/graphs/walks/walks.py        |  59 +++-
 .../proveit/graphs/walks/walks_membership.py  | 285 +++++++++++++++-
 23 files changed, 1693 insertions(+), 27 deletions(-)
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_membership_def/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_membership_folding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_membership_is_bool/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_membership_unfolding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_within_closed_trails/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_def/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_folding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_folding_components/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_is_bool/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_unfolding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_unfolding_components/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_within_closed_walks/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_within_walks/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_within_trails/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_within_walks/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/walk_length_from_membership/thm_proof.ipynb

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index 12c7ba0ff918..7b3198083561 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -9,7 +9,8 @@
 from .paths_of import PathsOf
 from .union import GraphUnion
 from .vertices import AdjacentVertices, Degree, Vertices
-from .walks import (BeginningVertex, Circuits, ClosedWalk, ClosedWalks, Cycles,
+from .walks import (BeginningVertex, Circuits, ClosedTrails,
+          ClosedWalk, ClosedWalks, Cycles,
           EdgeSequence, EdgeSet, EndingVertex, EndVertices,
           EulerianTrails, Paths, Trails, WalkLength, Walks)
 
diff --git a/packages/proveit/graphs/walks/__init__.py b/packages/proveit/graphs/walks/__init__.py
index c5871b6e2393..e606ccdaaab1 100644
--- a/packages/proveit/graphs/walks/__init__.py
+++ b/packages/proveit/graphs/walks/__init__.py
@@ -1,4 +1,5 @@
-from .walks import (BeginningVertex, Circuits, ClosedWalk, ClosedWalks, Cycles,
+from .walks import (BeginningVertex, Circuits, ClosedTrails,
+        ClosedWalk, ClosedWalks, Cycles,
         EdgeSequence, EdgeSet, EndingVertex, EndVertices,
         EulerianTrails, Paths, Trails, WalkLength, Walks)
 
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
index 5aa0ee70fb3b..ffb1b3b0fd5a 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
@@ -23,8 +23,9 @@
     "from proveit.logic import Card, Equals, Forall, Functions, Injections, InSet, Set, SetOfAll\n",
     "from proveit.numbers import zero, one, three, Add, greater_eq, Interval, Natural, subtract\n",
     "from proveit.graphs import (\n",
-    "        AdjacentVertices, BeginningVertex, Circuits, ClosedWalk, ClosedWalks, Cycles, Edges,\n",
-    "        EdgeSequence, EndingVertex, EndVertices, Graphs, Paths, Trails, Vertices, Walks)"
+    "        AdjacentVertices, BeginningVertex, Circuits, ClosedTrails,\n",
+    "        ClosedWalk, ClosedWalks, Cycles, Edges, EdgeSequence, EndingVertex,\n",
+    "        EndVertices, Graphs, Paths, Trails, Vertices, Walks)"
    ]
   },
   {
@@ -156,9 +157,9 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "### Trails\n",
+    "### Trails & Closed Trails\n",
     "\n",
-    "A trail $T$ of length $k$ in a simple graph $G$, denoted using $T \\in \\texttt{Trails}(k, G)$, is a walk in which no edge is repeated. This means that the _edge_ sequence is a one-to-one (injective) function $S: [0, 1, \\ldots, k] \\xrightarrow[]{1:1} \\texttt{Edges}(G)$."
+    "A trail $T$ of length $k$ in a simple graph $G$, denoted using $T \\in \\texttt{Trails}(k, G)$, is a walk in which no edge is repeated. This means that the _edge_ sequence is a one-to-one (injective) function $S: [0, 1, \\ldots, k] \\xrightarrow[]{1:1} \\texttt{Edges}(G)$. A _closed_ trail is a trail in which the beginning and ending vertices are the same."
    ]
   },
   {
@@ -180,6 +181,25 @@
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "closed_trails_k_G_def = (\n",
+    "    Forall(G, Forall(k,\n",
+    "        Equals(\n",
+    "            ClosedTrails(k, G),\n",
+    "            SetOfAll(W,\n",
+    "                 W,\n",
+    "                 conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
+    "                 domain = ClosedWalks(k, G) )\n",
+    "        ),\n",
+    "    domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -229,9 +249,8 @@
     "            Circuits(k, G),\n",
     "            SetOfAll(W,\n",
     "                 W,\n",
-    "                 conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G))),\n",
-    "                              greater_eq(k, three)],\n",
-    "                 domain = ClosedWalks(k, G) )\n",
+    "                 conditions = [greater_eq(k, three)],\n",
+    "                 domain = ClosedTrails(k, G) )\n",
     "        ),\n",
     "    domain = Natural), domain = Graphs())\n",
     ")"
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
index 206894b0fc50..cfd4a3f95b28 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
@@ -15,14 +15,15 @@
    "outputs": [],
    "source": [
     "import proveit\n",
-    "from proveit import a, b, i, k, G, P, S, T, W, Function\n",
+    "from proveit import a, b, i, k, C, G, P, S, T, W, Function\n",
     "from proveit.logic import And, Equals, Forall, InClass, InSet, Set, SetOfAll\n",
     "from proveit.logic.sets import Functions, Injections\n",
-    "from proveit.numbers import zero, one, Add, Interval, Natural, subtract\n",
+    "from proveit.numbers import zero, one, three, Add, greater_eq, Interval, Natural, subtract\n",
     "from proveit.graphs import (\n",
-    "        AdjacentVertices, BeginningVertex, Circuits, ClosedWalks, Cycles, Edges,\n",
-    "        EdgeSequence, EdgeSet, EndingVertex, EndVertices, EulerianTrails,\n",
-    "        Graph, Graphs, Paths, Trails, Vertices, WalkLength, Walks)\n",
+    "        AdjacentVertices, BeginningVertex, Circuits, ClosedTrails,\n",
+    "        ClosedWalks, Cycles, Edges, EdgeSequence, EdgeSet, EndingVertex,\n",
+    "        EndVertices, EulerianTrails, Graph, Graphs, Paths, Trails, Vertices,\n",
+    "        WalkLength, Walks)\n",
     "%begin demonstrations\n"
    ]
   },
@@ -166,7 +167,7 @@
    "source": [
     "`Trails(k, G)` represents the set of all trails of length $k$ in the simple graph $G$. \n",
     "\n",
-    "A __trail__ $T$ in a simple graph $G$ is a walk in which no edge is repeated."
+    "A __trail__ $T$ in a simple graph $G$ is a walk in which no edge is repeated. A _closed_ trail is a trail in which the beginning vertex and ending vertex are the same."
    ]
   },
   {
@@ -187,6 +188,24 @@
     "InSet(T, Trails(k, G))"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "ClosedTrails(k, G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(T, ClosedTrails(k, G))"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -280,6 +299,15 @@
     "EndVertices(W)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "EndVertices(W).definition(assumptions = [InClass(G, Graphs()), InSet(WalkLength(W), Natural), InSet(W, Walks(WalkLength(W), G))])"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -364,6 +392,15 @@
     "InSet(W, Walks(k, G)).as_defined()"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(W, Walks(k, G)).element_length_derivation(assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(W, Walks(k, G))])"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -466,6 +503,16 @@
     "                                domain = Walks(k, G)))])"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(W, ClosedWalks(k, G)).derive_element_in_walks(\n",
+    "    assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(W, ClosedWalks(k, G))])"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -543,6 +590,114 @@
     "            InSet(EdgeSequence(T), Injections(Interval(zero, subtract(k, one)), Edges(G))))])"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(T, Trails(k, G)).derive_element_in_walks(\n",
+    "    assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(T, Trails(k, G))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### ClosedTrails Membership and Related Methods"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(T, ClosedTrails(k, G))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(T, ClosedTrails(k, G)).deduce_in_bool(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(T, ClosedTrails(k, G)).definition(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(T, ClosedTrails(k, G)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(T, ClosedTrails(k, G)).unfold(assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(T, ClosedTrails(k, G))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(T, ClosedTrails(k, G)).conclude(\n",
+    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "                       InSet(T, SetOfAll(W, W, conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
+    "                                        domain = ClosedWalks(k, G)))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(T, ClosedTrails(k, G)).conclude(\n",
+    "        assumptions = [\n",
+    "            InClass(G, Graphs()), InSet(k, Natural),\n",
+    "            And(InSet(T, ClosedWalks(k, G)),\n",
+    "            InSet(EdgeSequence(T), Injections(Interval(zero, subtract(k, one)), Edges(G))))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(T, ClosedTrails(k, G)).derive_element_in_closed_walks(\n",
+    "    assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(T, ClosedTrails(k, G))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(T, Walks(k, G)).prove(\n",
+    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(T, ClosedTrails(k, G))]\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -632,7 +787,117 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "InSet(P, Paths(k, G)).derive_element_in_trails(\n",
+    "    assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(P, Paths(k, G))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Because of cascading of side-effects in walk-related memberships, we can automatically prove that $P$ is a walk if we know or assume that $P$ is a path:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(P, Walks(k, G)).prove(\n",
+    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(P, Paths(k, G))]\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Circuits Membership and Related Methods"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, Circuits(k, G))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, Circuits(k, G)).deduce_in_bool(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, Circuits(k, G)).definition(\n",
+    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural), greater_eq(k, three)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, Circuits(k, G)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, Circuits(k, G)).unfold(\n",
+    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "                       greater_eq(k, three), InSet(C, Circuits(k, G))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, Circuits(k, G)).conclude(\n",
+    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "                       greater_eq(k, three), InSet(C, ClosedTrails(k, G))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, Circuits(k, G)).derive_element_in_closed_trails(\n",
+    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "                       greater_eq(k, three), InSet(C, Circuits(k, G))]\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, Walks(k, G)).prove(\n",
+    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "                       greater_eq(k, three), InSet(C, Circuits(k, G))])"
+   ]
   },
   {
    "cell_type": "markdown",
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_membership_def/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_membership_def/thm_proof.ipynb
new file mode 100644
index 000000000000..2725b76f44e6
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_membership_def/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#circuits_membership_def\">circuits_membership_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving circuits_membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_membership_folding/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_membership_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..02d9304aff0a
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_membership_folding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#circuits_membership_folding\">circuits_membership_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving circuits_membership_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_membership_is_bool/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_membership_is_bool/thm_proof.ipynb
new file mode 100644
index 000000000000..dd7bec343a7c
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_membership_is_bool/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#circuits_membership_is_bool\">circuits_membership_is_bool</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving circuits_membership_is_bool"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_membership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_membership_unfolding/thm_proof.ipynb
new file mode 100644
index 000000000000..912c98347f24
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_membership_unfolding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#circuits_membership_unfolding\">circuits_membership_unfolding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving circuits_membership_unfolding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_within_closed_trails/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_within_closed_trails/thm_proof.ipynb
new file mode 100644
index 000000000000..bac75244bb8e
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/circuits_within_closed_trails/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#circuits_within_closed_trails\">circuits_within_closed_trails</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving circuits_within_closed_trails"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_def/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_def/thm_proof.ipynb
new file mode 100644
index 000000000000..4dff0356f014
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_def/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#closed_trails_membership_def\">closed_trails_membership_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving closed_trails_membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_folding/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..e1059f472c5e
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_folding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#closed_trails_membership_folding\">closed_trails_membership_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving closed_trails_membership_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_folding_components/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_folding_components/thm_proof.ipynb
new file mode 100644
index 000000000000..0052e96f6070
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_folding_components/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#closed_trails_membership_folding_components\">closed_trails_membership_folding_components</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving closed_trails_membership_folding_components"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_is_bool/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_is_bool/thm_proof.ipynb
new file mode 100644
index 000000000000..b3ae61176b49
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_is_bool/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#closed_trails_membership_is_bool\">closed_trails_membership_is_bool</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving closed_trails_membership_is_bool"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_unfolding/thm_proof.ipynb
new file mode 100644
index 000000000000..9668ceb55728
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_unfolding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#closed_trails_membership_unfolding\">closed_trails_membership_unfolding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving closed_trails_membership_unfolding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_unfolding_components/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_unfolding_components/thm_proof.ipynb
new file mode 100644
index 000000000000..6c7780c73d25
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_membership_unfolding_components/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#closed_trails_membership_unfolding_components\">closed_trails_membership_unfolding_components</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving closed_trails_membership_unfolding_components"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_within_closed_walks/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_within_closed_walks/thm_proof.ipynb
new file mode 100644
index 000000000000..8208c02eb954
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_trails_within_closed_walks/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#closed_trails_within_closed_walks\">closed_trails_within_closed_walks</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving closed_trails_within_closed_walks"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_within_walks/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_within_walks/thm_proof.ipynb
new file mode 100644
index 000000000000..a373021e68cd
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/closed_walks_within_walks/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#closed_walks_within_walks\">closed_walks_within_walks</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving closed_walks_within_walks"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_within_trails/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_within_trails/thm_proof.ipynb
new file mode 100644
index 000000000000..42c5b466d5aa
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/paths_within_trails/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#paths_within_trails\">paths_within_trails</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving paths_within_trails"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_within_walks/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_within_walks/thm_proof.ipynb
new file mode 100644
index 000000000000..f7b79b90359a
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/trails_within_walks/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#trails_within_walks\">trails_within_walks</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving trails_within_walks"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/walk_length_from_membership/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/walk_length_from_membership/thm_proof.ipynb
new file mode 100644
index 000000000000..f6ab938c5638
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/walk_length_from_membership/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#walk_length_from_membership\">walk_length_from_membership</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving walk_length_from_membership"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
index 377673bcc7df..9ebe09fe908e 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
@@ -18,12 +18,14 @@
     "# Prepare this notebook for defining the theorems of a theory:\n",
     "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "from proveit import i, j, k, u, v, G, P, S, T, W, Function\n",
+    "from proveit import i, j, k, u, v, C, G, P, S, T, W, Function\n",
     "from proveit.logic import And, Equals, Exists, Forall, in_bool\n",
-    "from proveit.logic.sets import Functions, Injections, InSet, Set, SetOfAll\n",
-    "from proveit.numbers import zero, one, Add, Interval, LessEq, Natural, subtract\n",
-    "from proveit.graphs import (AdjacentVertices, BeginningVertex, ClosedWalks, Edges,\n",
-    "        EdgeSequence, EndingVertex, EndVertices, Graphs, Paths, Trails, Vertices, Walks)\n"
+    "from proveit.logic.sets import Functions, Injections, InSet, Set, SetOfAll, SubsetEq\n",
+    "from proveit.numbers import (zero, one, three, Add, greater_eq,\n",
+    "        Interval, LessEq, Natural, subtract)\n",
+    "from proveit.graphs import (AdjacentVertices, BeginningVertex, Circuits,\n",
+    "        ClosedTrails, ClosedWalks, Edges, EdgeSequence, EndingVertex,\n",
+    "        EndVertices, Graphs, Paths, Trails, Vertices, WalkLength, Walks) \n"
    ]
   },
   {
@@ -35,6 +37,13 @@
     "%begin theorems"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### WalksMembership($k$, $G$)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -119,6 +128,30 @@
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "walk_length_from_membership = (\n",
+    "    Forall(G,\n",
+    "    Forall(k,\n",
+    "    Forall(W,\n",
+    "        Equals(WalkLength(W), k),\n",
+    "    domain = Walks(k, G)),\n",
+    "    domain = Natural),\n",
+    "    domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### ClosedWalksMembership($k$, $G$)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -171,6 +204,13 @@
     ")"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### TrailsMembership($k$, $G$)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -252,6 +292,101 @@
     ")"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### ClosedTrailsMembership($k$, $G$)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "closed_trails_membership_def = (\n",
+    "    Forall(G, Forall(k, Forall(T,\n",
+    "    Equals(\n",
+    "        InSet(T, ClosedTrails(k, G)),\n",
+    "        InSet(T,\n",
+    "        SetOfAll(W,\n",
+    "                 W,\n",
+    "                 conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
+    "                 domain = ClosedWalks(k, G) ))\n",
+    "    )), domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "closed_trails_membership_unfolding = (\n",
+    "    Forall(G, Forall(k, Forall(T,\n",
+    "    InSet(T,\n",
+    "        SetOfAll(W,\n",
+    "        W,\n",
+    "        conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
+    "        domain = ClosedWalks(k, G) )),\n",
+    "    domain = ClosedTrails(k, G)), domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "closed_trails_membership_folding = (\n",
+    "    Forall(G, Forall(k, Forall(T,\n",
+    "    InSet(T, ClosedTrails(k, G)),\n",
+    "    conditions = [],\n",
+    "    domain = SetOfAll(W,\n",
+    "        W,\n",
+    "        conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
+    "        domain = ClosedWalks(k, G) )), domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "closed_trails_membership_unfolding_components = (\n",
+    "    Forall(G, Forall(k, Forall(T,\n",
+    "    And(InSet(T, ClosedWalks(k, G)),\n",
+    "        InSet(EdgeSequence(T), Injections(Interval(zero, subtract(k, one)), Edges(G)))),\n",
+    "    domain = ClosedTrails(k, G)), domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "closed_trails_membership_folding_components = (\n",
+    "    Forall(G, Forall(k, Forall(W,\n",
+    "    InSet(W, ClosedTrails(k, G)),\n",
+    "    conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
+    "    domain = ClosedWalks(k, G)), domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### PathsMembership($k$, $G$)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -334,6 +469,56 @@
     ")"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### CircuitsMembership($k$, $G$)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "circuits_membership_def = (\n",
+    "    Forall(G, Forall(k, Forall(C,\n",
+    "    Equals(\n",
+    "        InSet(C, Circuits(k, G)),\n",
+    "        InSet(C, ClosedTrails(k, G))\n",
+    "    )), conditions = [greater_eq(k, three)], domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "circuits_membership_unfolding = (\n",
+    "    Forall(G, Forall(k, Forall(C,\n",
+    "        InSet(C, ClosedTrails(k, G)),\n",
+    "        domain = Circuits(k, G)), conditions = [greater_eq(k, three)], domain = Natural), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "circuits_membership_folding = (\n",
+    "    Forall(G, Forall(k, Forall(C,\n",
+    "        InSet(C, Circuits(k, G)),\n",
+    "        domain = ClosedTrails(k, G)),\n",
+    "    conditions = [greater_eq(k, three)], domain = Natural),\n",
+    "    domain = Graphs())\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -358,6 +543,89 @@
     "domain = Graphs())"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Subset/Superset Relationships Among Various Walks"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "closed_walks_within_walks = (\n",
+    "    Forall(G,\n",
+    "    Forall(k,\n",
+    "        SubsetEq(ClosedWalks(k, G), Walks(k, G)),\n",
+    "    domain = Natural),\n",
+    "    domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "trails_within_walks = (\n",
+    "    Forall(G,\n",
+    "    Forall(k,\n",
+    "        SubsetEq(Trails(k, G), Walks(k, G)),\n",
+    "    domain = Natural),\n",
+    "    domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "closed_trails_within_closed_walks = (\n",
+    "    Forall(G,\n",
+    "    Forall(k,\n",
+    "        SubsetEq(ClosedTrails(k, G), ClosedWalks(k, G)),\n",
+    "    domain = Natural),\n",
+    "    domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "paths_within_trails = (\n",
+    "    Forall(G,\n",
+    "    Forall(k,\n",
+    "        SubsetEq(Paths(k, G), Trails(k, G)),\n",
+    "    domain = Natural),\n",
+    "    domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "circuits_within_closed_trails = (\n",
+    "Forall(G,\n",
+    "Forall(k,\n",
+    "    SubsetEq(Circuits(k, G), ClosedTrails(k, G)),\n",
+    "    conditions = [greater_eq(k, three)],\n",
+    "domain = Natural),\n",
+    "domain = Graphs())\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -407,6 +675,20 @@
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "closed_trails_membership_is_bool = Forall(G,\n",
+    "Forall(k,\n",
+    "Forall(T, in_bool(InSet(T, ClosedTrails(k, G)))),\n",
+    "domain = Natural),\n",
+    "domain = Graphs()\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -421,6 +703,20 @@
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "circuits_membership_is_bool = Forall(G,\n",
+    "Forall(k,\n",
+    "Forall(C, in_bool(InSet(C, Circuits(k, G)))),\n",
+    "domain = Natural),\n",
+    "domain = Graphs()\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/walks/walks.py b/packages/proveit/graphs/walks/walks.py
index 53270a3db11f..6804440a1cc5 100644
--- a/packages/proveit/graphs/walks/walks.py
+++ b/packages/proveit/graphs/walks/walks.py
@@ -1,4 +1,4 @@
-from proveit import Function, Literal
+from proveit import equality_prover, Function, Literal
 from proveit.logic import ClassMembership
 from proveit.graphs import Graph
 
@@ -59,7 +59,7 @@ class for details about walks more generally. A closed walk is a
     Circuits(k, G) and Cycles(k, G).
     '''
 
-    # the literal operator of the Walks operation
+    # the literal operator of the ClosedWalks operation
     _operator_ = Literal(string_format='ClosedWalks',
                          latex_format=r'\textrm{ClosedWalks}',
                          theory=__file__)
@@ -91,7 +91,7 @@ class Trails(Function):
     A trail with endvertices u and v is often called a u-v trail.
     '''
 
-    # the literal operator of the Walks operation
+    # the literal operator of the Trails operation
     _operator_ = Literal(string_format='Trails',
                          latex_format=r'\textrm{Trails}',
                          theory=__file__)
@@ -115,6 +115,39 @@ def membership_object(self, element):
     #     return TrailsNonmembership(element, self)
 
 
+class ClosedTrails(Function):
+    '''
+    ClosedTrails(k, G) represents the set of closed trails of length
+    k in the simple graph G. A trail is a walk in which no edge is
+    repeated; a _closed_ trail is a trail that begins and ends at the
+    same vertex, and can be conceptualized as a special case of a
+    closed walk.
+    '''
+
+    # the literal operator of the ClosedTrails operation
+    _operator_ = Literal(string_format='ClosedTrails',
+                         latex_format=r'\textrm{ClosedTrails}',
+                         theory=__file__)
+
+    def __init__(self, k, G, *, styles=None):
+        '''
+        Represent ClosedTrails(k, G), the set of all closed trails of
+        length k in graph G.
+        '''
+        self.graph = G
+        self.length = k
+        Function.__init__(
+                self, ClosedTrails._operator_, (k, G), styles=styles)
+
+    def membership_object(self, element):
+        from .walks_membership import ClosedTrailsMembership
+        return ClosedTrailsMembership(element, self)
+
+    # def nonmembership_object(self, element):
+    #     from .walks_membership import TrailsNonmembership
+    #     return TrailsNonmembership(element, self)
+
+
 class Paths(Function):
     '''
     Paths(k, G) represents the set of paths of length k in the simple
@@ -149,7 +182,7 @@ def membership_object(self, element):
 
 class Circuits(Function):
     '''
-    Circuits(k, G) represents the set of circuits of length k in
+    Circuits(k, G) represents the set of circuits of length k >= 3 in
     the simple undirected graph G. A circuit in a graph G is a closed
     trail of length 3 or more in G. Because a circuit is a closed
     trail, a circuit begins and ends at the same vertex without
@@ -348,6 +381,24 @@ def __init__(self, W, *, styles=None):
         Function.__init__(
                 self, EndVertices._operator_, W, styles=styles)
 
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self = [EndVertices(W)], deduce and return
+        the equality:
+            [EndVertices(W)]
+             = {BeginningVertex(W) = EndingVertex(W)}
+        '''
+        from . import endvertices_def
+        from proveit import k, G, W
+        from proveit.graphs import WalkLength
+        _W_sub  = self.operand
+        _k_sub  = WalkLength(self.operand)
+        # _G_sub  = _W_sub.graph
+
+        return endvertices_def.instantiate(
+                {k: _k_sub, W: _W_sub, G:G },auto_simplify=False)
+
 
 class BeginningVertex(Function):
     '''
diff --git a/packages/proveit/graphs/walks/walks_membership.py b/packages/proveit/graphs/walks/walks_membership.py
index 6c089b3aac9b..38394216918d 100644
--- a/packages/proveit/graphs/walks/walks_membership.py
+++ b/packages/proveit/graphs/walks/walks_membership.py
@@ -1,10 +1,11 @@
-from proveit import (i, k, G, P, S, T, W, equality_prover, Function,
+from proveit import (i, k, C, G, P, S, T, W, equality_prover, Function,
         prover, relation_prover)
 from proveit.logic import (Equals, Forall, InSet, SetMembership,
             SetNonmembership)
 from proveit.logic.sets import Functions, Injections, SetOfAll
 from proveit.numbers import zero, one, Add, Interval, subtract
-from proveit.graphs import (AdjacentVertices, BeginningVertex, Edges,
+from proveit.graphs import (AdjacentVertices, BeginningVertex,
+            ClosedWalks, Edges,
             EdgeSequence, EndingVertex, Graph, Vertices, Walks)
 
 
@@ -18,6 +19,17 @@ class WalksMembership(SetMembership):
     def __init__(self, element, domain):
         SetMembership.__init__(self, element, domain)
 
+    def side_effects(self, judgment):
+        '''
+        Yield side-effects when proving 'W in Walks(k, G)' for
+        k in Natural and G in Graphs.
+        '''
+        yield self.element_length_derivation
+        
+        # Added but commented the following out while we debate the
+        # wisdom of further side-effects
+        # yield lambda: self.deduce_member_in_real(member)
+
     @equality_prover('defined', 'define')
     def definition(self, **defaults_config):
         '''
@@ -105,6 +117,20 @@ def deduce_in_bool(self, **defaults_config):
         return walks_membership_is_bool.instantiate(
             {G:_G_sub, k:_k_sub, W:_W_sub}, auto_simplify=False)
 
+    @prover
+    def element_length_derivation(self, **defaults_config):
+        '''
+        Can't seem to make this work as an @equality_prover?
+        From self = (element in Walks(k, G)) derive and return that
+        WalkLength(element) = k.
+        '''
+        from . import walk_length_from_membership
+        _G_sub = self.domain.graph
+        _k_sub = self.domain.length
+        _W_sub = self.element
+        return walk_length_from_membership.instantiate(
+                {G: _G_sub, k: _k_sub, W: _W_sub}, auto_simplify=False)
+
 
 class ClosedWalksMembership(SetMembership):
     '''
@@ -116,6 +142,13 @@ class ClosedWalksMembership(SetMembership):
     def __init__(self, element, domain):
         SetMembership.__init__(self, element, domain)
 
+    def side_effects(self, judgment):
+        '''
+        Yield side-effects when proving 'W in ClosedWalks(k, G)' for
+        k in Natural and G in Graphs.
+        '''
+        yield self.derive_element_in_walks
+
     @equality_prover('defined', 'define')
     def definition(self, **defaults_config):
         '''
@@ -186,6 +219,15 @@ def deduce_in_bool(self, **defaults_config):
         return closed_walks_membership_is_bool.instantiate(
             {G:_G_sub, k:_k_sub, W:_W_sub}, auto_simplify=False)
 
+    @prover
+    def derive_element_in_walks(self, **defaults_config):
+        from . import closed_walks_within_walks
+        _G      = self.domain.graph
+        _k      = self.domain.length
+        return (closed_walks_within_walks.instantiate(
+            {G:_G, k:_k}, auto_simplify=False)
+            .derive_superset_membership(self.element, auto_simplify=False))
+
 
 class TrailsMembership(SetMembership):
     '''
@@ -197,6 +239,13 @@ class TrailsMembership(SetMembership):
     def __init__(self, element, domain):
         SetMembership.__init__(self, element, domain)
 
+    def side_effects(self, judgment):
+        '''
+        Yield side-effects when proving 'W in Trails(k, G)' for
+        k in Natural and G in Graphs.
+        '''
+        yield self.derive_element_in_walks
+
     @equality_prover('defined', 'define')
     def definition(self, **defaults_config):
         '''
@@ -286,6 +335,132 @@ def deduce_in_bool(self, **defaults_config):
         return trails_membership_is_bool.instantiate(
             {G:_G_sub, k:_k_sub, T:_T_sub}, auto_simplify=False)
 
+    @prover
+    def derive_element_in_walks(self, **defaults_config):
+        from . import trails_within_walks
+        _G      = self.domain.graph
+        _k      = self.domain.length
+        return (trails_within_walks.instantiate(
+            {G:_G, k:_k}, auto_simplify=False)
+            .derive_superset_membership(self.element, auto_simplify=False))
+
+
+class ClosedTrailsMembership(SetMembership):
+    '''
+    Defines methods that apply to membership in the set of length-k
+    closed trails in the simple graph G, denoted ClosedTrails(k, G).
+    See related membership classes above and below for Trails, Walks,
+    etc.
+    '''
+
+    def __init__(self, element, domain):
+        SetMembership.__init__(self, element, domain)
+
+    def side_effects(self, judgment):
+        '''
+        Yield side-effects when proving 'W in ClosedTrails(k, G)' for
+        k in Natural and G in Graphs.
+        '''
+        yield self.derive_element_in_closed_walks
+
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self = [elem in ClosedTrails(k, G)], deduce and return:
+        [elem in ClosedTrails(k, G)]
+        = elem in
+        {W | EdgeSequence(W) in Injections([0, ..., k-1], Edges(G))}
+        for {W in ClosedWalks(k, G)}.
+        W being in ClosedWalks(k, G) takes care of the requirement that 
+        consecutive elements of the vertex sequence are adjacent in
+        the graph G.
+        '''
+        from . import closed_trails_membership_def
+        element = self.element
+        _G_sub  = self.domain.graph
+        _k_sub  = self.domain.length
+        return closed_trails_membership_def.instantiate(
+                {G: _G_sub, k: _k_sub, T: element },auto_simplify=False)
+
+    def as_defined(self):
+        '''
+        From self = [elem in ClosedTrails(k, G)],
+        return the expression (NOT a judgment):
+        elem in {W | EdgeSequence(W) in
+                 Injections([0, ..., k-1], Edges(G))}
+        for {W in ClosedWalks(k, G)}
+        '''
+        element = self.element
+        _G      = self.domain.graph
+        _k      = self.domain.length
+        return InSet(element,
+               SetOfAll(W, W,
+               conditions = [
+                   InSet(EdgeSequence(W),
+                   Injections(Interval(zero, subtract(_k, one)), Edges(_G)))],
+               domain = ClosedWalks(_k, _G)))
+
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        From self = [elem in ClsoedTrails(k, G)], and knowing or
+        assuming self, derive and return:
+        elem in {W | EdgeSequence(W) in
+                 Injections([0, ..., k-1], Edges(G))}
+                 for {W in ClosedWalks(k, G)}.
+        '''
+        from . import closed_trails_membership_unfolding
+        element = self.element
+        _G_sub  = self.domain.graph
+        _k_sub  = self.domain.length
+        return closed_trails_membership_unfolding.instantiate(
+            {G: _G_sub, k: _k_sub, T: element}, auto_simplify=False)
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Called on self = [W in ClosedTrails(k, G)], derive and return
+        self, knowing or assuming at least one of the following:
+        (1) W in ClosedWalks(k, G) AND
+            EdgeSeq(W) in Injections([0,...,k-1], Edges(G))
+        (2) W in {W | EdgeSequence(W) in
+                 Injections([0, ..., k-1], Edges(G))}
+                 for {W in ClosedWalks(k, G)}
+        '''
+        _W = self.element
+        _G  = self.domain.graph
+        _k  = self.domain.length
+        injections_set = (
+            Injections(Interval(zero, subtract(_k, one)), Edges(_G)))
+        if (InSet(EdgeSequence(_W), injections_set).proven()
+            and InSet(_W, ClosedWalks(_k, _G)).proven()):
+            from . import closed_trails_membership_folding_components
+            return (closed_trails_membership_folding_components
+                    .instantiate({G: _G, k: _k, W: _W},
+                    auto_simplify=False))
+        
+        from . import closed_trails_membership_folding
+        return closed_trails_membership_folding.instantiate(
+            {G: _G, k: _k, W: _W}, auto_simplify=False)
+
+    @relation_prover
+    def deduce_in_bool(self, **defaults_config):
+        from . import closed_trails_membership_is_bool
+        _G_sub = self.domain.graph
+        _k_sub = self.domain.length
+        _T_sub = self.element
+        return closed_trails_membership_is_bool.instantiate(
+            {G:_G_sub, k:_k_sub, T:_T_sub}, auto_simplify=False)
+
+    @prover
+    def derive_element_in_closed_walks(self, **defaults_config):
+        from . import closed_trails_within_closed_walks
+        _G      = self.domain.graph
+        _k      = self.domain.length
+        return (closed_trails_within_closed_walks.instantiate(
+            {G:_G, k:_k}, auto_simplify=False)
+            .derive_superset_membership(self.element, auto_simplify=False))
+
 
 class PathsMembership(SetMembership):
     '''
@@ -298,6 +473,13 @@ class PathsMembership(SetMembership):
     def __init__(self, element, domain):
         SetMembership.__init__(self, element, domain)
 
+    def side_effects(self, judgment):
+        '''
+        Yield side-effects when proving 'W in Paths(k, G)' for
+        k in Natural and G in Graphs.
+        '''
+        yield self.derive_element_in_trails
+
     @equality_prover('defined', 'define')
     def definition(self, **defaults_config):
         '''
@@ -381,3 +563,102 @@ def deduce_in_bool(self, **defaults_config):
         return paths_membership_is_bool.instantiate(
             {G:_G_sub, k:_k_sub, P:_P_sub}, auto_simplify=False)
 
+    @prover
+    def derive_element_in_trails(self, **defaults_config):
+        from . import paths_within_trails
+        _G      = self.domain.graph
+        _k      = self.domain.length
+        return (paths_within_trails.instantiate(
+            {G:_G, k:_k}, auto_simplify=False)
+            .derive_superset_membership(self.element, auto_simplify=False))
+
+
+class CircuitsMembership(SetMembership):
+    '''
+    Defines methods that apply to membership in the set of length-k
+    circuits in the simple graph G, denoted Circuits(k, G). A circuit
+    in G is a closed trail -- i.e., a closed walk in which no edge is
+    repeated.
+    '''
+
+    def __init__(self, element, domain):
+        SetMembership.__init__(self, element, domain)
+
+    def side_effects(self, judgment):
+        '''
+        Yield side-effects when proving 'C in Circuits(k, G)' for
+        Natural k >= 3 and G in Graphs.
+        '''
+        yield self.derive_element_in_closed_trails
+
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self = [elem in Circuits(k, G)], with k >= 3, deduce
+        and return:
+        [elem in Circuits(k, G)] = elem in ClosedWalks(k, G).
+        '''
+        from . import circuits_membership_def
+        element = self.element
+        _G_sub  = self.domain.graph
+        _k_sub  = self.domain.length
+        return circuits_membership_def.instantiate(
+                {G: _G_sub, k: _k_sub, C: element },auto_simplify=False)
+
+    def as_defined(self):
+        '''
+        From self = [elem in Circuits(k, G)], return the expression
+        (NOT a judgment):
+                           elem in ClosedWalks(k, G).
+        '''
+        element = self.element
+        _G      = self.domain.graph
+        _k      = self.domain.length
+        return InSet(element, ClosedWalks(_k, _G))
+
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        From self = [elem in Circuits(k, G)], and knowing or assuming
+        self and k >= 3, derive and return: elem ClosedWalks(k, G).
+        '''
+        from . import circuits_membership_unfolding
+        element = self.element
+        _G_sub  = self.domain.graph
+        _k_sub  = self.domain.length
+        return circuits_membership_unfolding.instantiate(
+            {G: _G_sub, k: _k_sub, C: element}, auto_simplify=False)
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Called on self = [C in Circuits(k, G)], derive and return
+        self, knowing or assuming BOTH of the following:
+        (1) k >= 3
+        (2) C in ClosedTrails(k, G)
+        '''
+        _C = self.element
+        _G  = self.domain.graph
+        _k  = self.domain.length
+        from . import circuits_membership_folding
+        return circuits_membership_folding.instantiate(
+            {G: _G, k: _k, C: _C}, auto_simplify=False)
+
+    @relation_prover
+    def deduce_in_bool(self, **defaults_config):
+        from . import circuits_membership_is_bool
+        _G_sub = self.domain.graph
+        _k_sub = self.domain.length
+        _C_sub = self.element
+        return circuits_membership_is_bool.instantiate(
+            {G:_G_sub, k:_k_sub, C:_C_sub}, auto_simplify=False)
+
+    @prover
+    def derive_element_in_closed_trails(self, **defaults_config):
+        from . import circuits_within_closed_trails
+        _G      = self.domain.graph
+        _k      = self.domain.length
+        return (circuits_within_closed_trails.instantiate(
+            {G:_G, k:_k}, auto_simplify=False)
+            .derive_superset_membership(self.element, auto_simplify=False))
+

From 60586c99fa7bdf7edfd8ef40c9c7fdb02afa82a2 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 10 Jul 2025 09:55:28 -0600
Subject: [PATCH 139/159] Add some minor clean-up of some comments.

Add some minor clean-up of some comments in graphs/walks.py and graphs/walks_membership.py.
---
 packages/proveit/graphs/walks/walks.py            | 2 +-
 packages/proveit/graphs/walks/walks_membership.py | 6 +-----
 2 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/packages/proveit/graphs/walks/walks.py b/packages/proveit/graphs/walks/walks.py
index 6804440a1cc5..ac361c0928b9 100644
--- a/packages/proveit/graphs/walks/walks.py
+++ b/packages/proveit/graphs/walks/walks.py
@@ -465,7 +465,7 @@ class EulerianTrails(Function):
 
     def __init__(self, G, *, styles=None):
         '''
-        Represent the set EulerianTrails(G) of all Eulerian trails
+        Represent EulerianTrails(G), the set of all Eulerian trails
         in graph G.
         '''
         self.graph = G
diff --git a/packages/proveit/graphs/walks/walks_membership.py b/packages/proveit/graphs/walks/walks_membership.py
index 38394216918d..bef9efc7a137 100644
--- a/packages/proveit/graphs/walks/walks_membership.py
+++ b/packages/proveit/graphs/walks/walks_membership.py
@@ -25,10 +25,6 @@ def side_effects(self, judgment):
         k in Natural and G in Graphs.
         '''
         yield self.element_length_derivation
-        
-        # Added but commented the following out while we debate the
-        # wisdom of further side-effects
-        # yield lambda: self.deduce_member_in_real(member)
 
     @equality_prover('defined', 'define')
     def definition(self, **defaults_config):
@@ -530,7 +526,7 @@ def unfold(self, **defaults_config):
         return paths_membership_unfolding.instantiate(
             {G: _G_sub, k: _k_sub, P: element}, auto_simplify=False)
 
-    @prover # WORKING HERE
+    @prover
     def conclude(self, **defaults_config):
         '''
         Called on self = [P in Paths(k, G)], derive and return

From c5f4c09020315d5af878c1906fc690bc95b55f68 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 10 Jul 2025 10:00:20 -0600
Subject: [PATCH 140/159] Add newline to end of file

Add newline to end of graphs/edges.py for standard PEP formatting.
---
 packages/proveit/graphs/edges.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/proveit/graphs/edges.py b/packages/proveit/graphs/edges.py
index 36c7d1b8d0a3..5620d95f9db4 100644
--- a/packages/proveit/graphs/edges.py
+++ b/packages/proveit/graphs/edges.py
@@ -27,4 +27,4 @@ def membership_object(self, element):
 
     def nonmembership_object(self, element):
         from .edges_membership import EdgesNonmembership
-        return EdgesNonmembership(element, self)
\ No newline at end of file
+        return EdgesNonmembership(element, self)

From 629cf96f3d18b79988d92cd99fea1d98f0e20170 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 10 Jul 2025 10:53:13 -0600
Subject: [PATCH 141/159] Update sets/functions_def axiom

Update the functions_def axiom in numbers/sets/functions sub-theory package to more carefully specify functions with domain A and codomain B instead of functions that take A to B but might also have elements outside of A in their domain.
---
 .../proveit/logic/sets/functions/_theory_nbs_/axioms.ipynb   | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/packages/proveit/logic/sets/functions/_theory_nbs_/axioms.ipynb b/packages/proveit/logic/sets/functions/_theory_nbs_/axioms.ipynb
index 6bbc9385e62b..82089ebb803e 100644
--- a/packages/proveit/logic/sets/functions/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/logic/sets/functions/_theory_nbs_/axioms.ipynb
@@ -19,7 +19,7 @@
     "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
     "from proveit import f, x, A, B, fx\n",
-    "from proveit.logic import Forall, Equals, InSet\n",
+    "from proveit.logic import And, Equals, FALSE, Forall, InSet, NotInSet\n",
     "from proveit.logic.sets import Functions"
    ]
   },
@@ -47,7 +47,8 @@
    "source": [
     "functions_def = Forall(\n",
     "    (f, A, B), Equals(InSet(f, Functions(A, B)),\n",
-    "                      Forall(x, InSet(fx, B), domain=A)))"
+    "                      And(Forall(x, InSet(fx, B), domain=A),\n",
+    "    Forall(x, Equals(fx, FALSE), conditions = [NotInSet(x, A)]))))"
    ]
   },
   {

From d19c016820ac511a909a25d234454ef7e61be51a Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sun, 13 Jul 2025 16:16:51 -0600
Subject: [PATCH 142/159] Add UNDEF literal

Add UNDEF literal, a common expression labeled as 'undefined' in logic/sets/functions, most immediately for use in the expression of function-related expressions where the function is not defined for some set of inputs. This is then used in an update to the functions_def axiomatic definition of sets/functions and related theorems.
---
 .../logic/sets/functions/_theory_nbs_/common.ipynb  | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/packages/proveit/logic/sets/functions/_theory_nbs_/common.ipynb b/packages/proveit/logic/sets/functions/_theory_nbs_/common.ipynb
index 8058fa985890..50981aceb5a5 100644
--- a/packages/proveit/logic/sets/functions/_theory_nbs_/common.ipynb
+++ b/packages/proveit/logic/sets/functions/_theory_nbs_/common.ipynb
@@ -18,7 +18,7 @@
     "# Prepare this notebook for defining the common expressions of a theory:\n",
     "%common_expressions_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "# from ... import ..."
+    "from proveit import Literal"
    ]
   },
   {
@@ -30,12 +30,21 @@
     "%begin common"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "An undefined “UNDEF” literal, for use in defining function values for inputs outside the given domain of the function."
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "undefined = Literal('UNDEF', r'\\textrm{UNDEF}')"
+   ]
   },
   {
    "cell_type": "code",

From 20a459cbfaf4958dae4f01332e315e520242a740 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sun, 13 Jul 2025 16:19:44 -0600
Subject: [PATCH 143/159] Update functions_def axiom and establish
 Restriction() class

Update the functions_def axiom in logic/sets/functions to utilize the UNDEF literal for undefined function outputs and establish the Restriction() class in logic/sets/functions along with related axiomatic definition, a related theorem, and some entries in the logic/sets/functions demonstrations notebook.
---
 packages/proveit/logic/sets/__init__.py       |   4 +-
 .../proveit/logic/sets/functions/__init__.py  |   1 +
 .../sets/functions/_theory_nbs_/axioms.ipynb  |  36 +++++-
 .../_theory_nbs_/demonstrations.ipynb         | 106 +++++++++++++++++-
 .../restriction_membership/thm_proof.ipynb    |  47 ++++++++
 .../functions/_theory_nbs_/theorems.ipynb     |  23 +++-
 .../logic/sets/functions/restriction.py       |  37 ++++++
 7 files changed, 243 insertions(+), 11 deletions(-)
 create mode 100644 packages/proveit/logic/sets/functions/_theory_nbs_/proofs/restriction_membership/thm_proof.ipynb
 create mode 100644 packages/proveit/logic/sets/functions/restriction.py

diff --git a/packages/proveit/logic/sets/__init__.py b/packages/proveit/logic/sets/__init__.py
index 1229367f29cf..203c5458e035 100644
--- a/packages/proveit/logic/sets/__init__.py
+++ b/packages/proveit/logic/sets/__init__.py
@@ -15,8 +15,8 @@
 from .cartesian_products import CartProd, CartExp
 from .disjointness import Disjoint, Distinct
 from .cardinality import Card
-from .functions import (Functions, Injections, Surjections, Bijections, 
-                        Image, InvImage)
+from .functions import (Functions, Injections, Restriction, Surjections,
+                        Bijections, Image, InvImage)
 
 def is_infinite_set(expr):
     if hasattr(expr, 'is_infinite_set'):
diff --git a/packages/proveit/logic/sets/functions/__init__.py b/packages/proveit/logic/sets/functions/__init__.py
index b6ceda0a2202..8ff4448a3652 100644
--- a/packages/proveit/logic/sets/functions/__init__.py
+++ b/packages/proveit/logic/sets/functions/__init__.py
@@ -1,4 +1,5 @@
 from .functions import Functions
+from .restriction import Restriction 
 from .images import Image, InvImage
 from .injections import Injections
 from .surjections import Surjections
diff --git a/packages/proveit/logic/sets/functions/_theory_nbs_/axioms.ipynb b/packages/proveit/logic/sets/functions/_theory_nbs_/axioms.ipynb
index 82089ebb803e..7b25c1c1f575 100644
--- a/packages/proveit/logic/sets/functions/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/logic/sets/functions/_theory_nbs_/axioms.ipynb
@@ -18,9 +18,10 @@
     "# Prepare this notebook for defining the axioms of a theory:\n",
     "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "from proveit import f, x, A, B, fx\n",
+    "from proveit import f, x, A, B, R, fx, Conditional, ConditionalSet, Function\n",
     "from proveit.logic import And, Equals, FALSE, Forall, InSet, NotInSet\n",
-    "from proveit.logic.sets import Functions"
+    "from proveit.logic.sets import Functions, Restriction, SubsetEq\n",
+    "from proveit.logic.sets.functions import undefined"
    ]
   },
   {
@@ -36,7 +37,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "A function from a domain $A$ to codomain $B$ must map any element in $A$ to an element in $B$."
+    "Specifying a function $f:A\\rightarrow B$ with domain $A$ and codomain $B$ means two things: (1) for all $x \\in A$ we have $f(x) \\in B$; and (2) if $x \\notin A$, then $f(x)$ is undefined (otherwise we should re-define the domain $A$)."
    ]
   },
   {
@@ -48,7 +49,34 @@
     "functions_def = Forall(\n",
     "    (f, A, B), Equals(InSet(f, Functions(A, B)),\n",
     "                      And(Forall(x, InSet(fx, B), domain=A),\n",
-    "    Forall(x, Equals(fx, FALSE), conditions = [NotInSet(x, A)]))))"
+    "    Forall(x, Equals(fx, undefined), conditions = [NotInSet(x, A)]))))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The restriction of a function $f:A \\rightarrow B$ to some new domain $R \\subseteq A$ creates a new function $f\\vert_{R}:R \\rightarrow B$ whose outputs agree with the original function on the restricted domain:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "restriction_def = (\n",
+    "    Forall((A, B, R),\n",
+    "    Forall(f,\n",
+    "    Forall(x,\n",
+    "           Equals(\n",
+    "           Function(Restriction(f, R), x),\n",
+    "           ConditionalSet(Conditional(fx, InSet(x, R)), Conditional(undefined, NotInSet(x, R)))\n",
+    "           )),\n",
+    "    domain = Functions(A, B)),\n",
+    "    conditions = [SubsetEq(R, A)]\n",
+    "    )\n",
+    ")"
    ]
   },
   {
diff --git a/packages/proveit/logic/sets/functions/_theory_nbs_/demonstrations.ipynb b/packages/proveit/logic/sets/functions/_theory_nbs_/demonstrations.ipynb
index a813f7cdbdf5..afa48194b5e9 100644
--- a/packages/proveit/logic/sets/functions/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/logic/sets/functions/_theory_nbs_/demonstrations.ipynb
@@ -15,15 +15,119 @@
    "outputs": [],
    "source": [
     "import proveit\n",
+    "from proveit import f, x, A, B, C, R, fx\n",
+    "from proveit.logic import Forall, Functions, InSet\n",
+    "from proveit.logic.sets import Restriction\n",
     "%begin demonstrations"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### $\\texttt{Functions}(A, B)$, the set of all functions $f:A \\rightarrow B$ with domain $A$ and codomain $B$"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(f, Functions(A, B))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(f, Functions(A, B)).definition()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(f, Functions(A, B)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(f, Functions(A, B)).conclude(\n",
+    "        assumptions = [Forall(x, InSet(fx, B), domain = A)]\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(f, Functions(A, B)).unfold(\n",
+    "        assumptions = [InSet(f, Functions(A, B))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### $f\\vert_{R}$, the restriction of $f:A \\rightarrow B$ to new domain $R \\subseteq A$."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Restriction(f, R)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from proveit.logic.sets.functions import restriction_def\n",
+    "restriction_def"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "from proveit.logic import SubsetEq\n",
+    "restriction_def_inst = restriction_def.instantiate({A:A, B:B, R:R, f:f},\n",
+    "        assumptions = [SubsetEq(R, A), InSet(f, Functions(A, B))])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "And notice the `known_memberships` dictionary, which might be useful in constructing some Restriction() methods:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet.known_memberships[f]"
+   ]
   },
   {
    "cell_type": "code",
diff --git a/packages/proveit/logic/sets/functions/_theory_nbs_/proofs/restriction_membership/thm_proof.ipynb b/packages/proveit/logic/sets/functions/_theory_nbs_/proofs/restriction_membership/thm_proof.ipynb
new file mode 100644
index 000000000000..f7233f262891
--- /dev/null
+++ b/packages/proveit/logic/sets/functions/_theory_nbs_/proofs/restriction_membership/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">logic</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">sets</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">functions</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#restriction_membership\">restriction_membership</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving restriction_membership"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/logic/sets/functions/_theory_nbs_/theorems.ipynb b/packages/proveit/logic/sets/functions/_theory_nbs_/theorems.ipynb
index f2e38fcd91bd..f6dee8dd4dd0 100644
--- a/packages/proveit/logic/sets/functions/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/logic/sets/functions/_theory_nbs_/theorems.ipynb
@@ -18,10 +18,11 @@
     "# Prepare this notebook for defining the theorems of a theory:\n",
     "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "from proveit import Lambda, Conditional\n",
-    "from proveit import f, x, A, B, fx\n",
-    "from proveit.logic import Forall, Equals, InSet\n",
-    "from proveit.logic.sets import Functions"
+    "from proveit import Lambda, Conditional, ConditionalSet, Function\n",
+    "from proveit import f, x, A, B, R, fx\n",
+    "from proveit.logic import Forall, Equals, InSet, NotInSet, SubsetEq\n",
+    "from proveit.logic.sets import Functions, Restriction\n",
+    "from proveit.logic.sets.functions import undefined"
    ]
   },
   {
@@ -67,6 +68,20 @@
     "                                   Functions(A, B))))"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "restriction_membership = (\n",
+    "    Forall((A, B, R),\n",
+    "    Forall(f, InSet(Restriction(f, R), Functions(R, B)),\n",
+    "           domain = Functions(A, B)),\n",
+    "    conditions = [SubsetEq(R, A)])\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/logic/sets/functions/restriction.py b/packages/proveit/logic/sets/functions/restriction.py
new file mode 100644
index 000000000000..7544afc10ce8
--- /dev/null
+++ b/packages/proveit/logic/sets/functions/restriction.py
@@ -0,0 +1,37 @@
+from proveit import Function, Literal, Operation
+
+class Restriction(Function):
+    '''
+    Given a function f: A -> B, with domain A and co-domain B,
+    and subset S of A, Restriction(f, S) represents the restriction
+    of the function f to domain S --- that is, g = Restriction(f, S)
+    is a new function such that g(x) = f(x) for all x in S and is
+    undefined for x not in S.
+    Restriction(f, S) is an element of the set of Functions(S, B).
+    The axiomatic definition includes the constraint that S be a
+    subset of the original domain A.
+    '''
+
+    # The literal operator for the Restriction function
+    # (see further below for actual latex and string implementations).
+    _operator_ = Literal('Restriction', r'\textrm{Restriction}',
+                         theory=__file__)
+    
+    def __init__(self, f, domain, *, styles=None):
+        # Represent f|_{S}, the restriction of function f: A -> B to
+        # the restricted domain S (where S is a subset of A).
+        Operation.__init__(
+                self, Restriction._operator_, (f, domain), 
+                styles=styles)
+        self.fxn = f
+        self.domain = domain
+    
+    def latex(self, **kwargs):
+        fxn_str = self.fxn.latex(fence=True)
+        domain_str = self.domain.latex(fence=True)
+        return (fxn_str + r'\vert_{'+ domain_str + r'}')
+
+    def string(self, **kwargs):
+        fxn_str    = self.fxn.string(fence=True)
+        domain_str = self.domain.string(fence=True)
+        return (fxn_str + r'_{' + domain_str + r'}')

From 5e6e1a6652c16f2e596b1b35200b806e429f87bd Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 14 Jul 2025 09:53:28 -0600
Subject: [PATCH 144/159] Add comment for future consideration

Add comment in Restriction() class description for future consideration, possibly changing Restriction(f, S) to Restriction(f, A, B, S) to include the original domain and co-domain of the function f (since neither may be easily accessible from the Restriction(f, S) construction itself).
---
 packages/proveit/logic/sets/functions/restriction.py | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/packages/proveit/logic/sets/functions/restriction.py b/packages/proveit/logic/sets/functions/restriction.py
index 7544afc10ce8..ac5d883f51a1 100644
--- a/packages/proveit/logic/sets/functions/restriction.py
+++ b/packages/proveit/logic/sets/functions/restriction.py
@@ -10,6 +10,9 @@ class Restriction(Function):
     Restriction(f, S) is an element of the set of Functions(S, B).
     The axiomatic definition includes the constraint that S be a
     subset of the original domain A.
+    Future work: consider (re-)defining Restriction(f, S) to be
+    Restriction(f, A, B, S) so as to explicitly include the original
+    domain and co-domain of the function f.
     '''
 
     # The literal operator for the Restriction function

From 12538d2c1b3fe734eadf561fcf583115026ec1f4 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 14 Jul 2025 11:25:56 -0600
Subject: [PATCH 145/159] Update HasEulerianCircuit(G) axiom def to use
 ClosedWalks(k, G)

Update the axiomatic definition of HasEulerianCircuit(G) to use ClosedWalks(k, G) instead of the now obsolete Closed() predicate.
---
 packages/proveit/graphs/_theory_nbs_/axioms.ipynb | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
index 79e074bb369b..474591e55ff0 100644
--- a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
@@ -22,9 +22,10 @@
     "from proveit.logic import And, Equals, Exists, Forall, InClass, InSet\n",
     "from proveit.logic.sets import Card, Set, KPowerSet, SetOfAll, SubsetEq\n",
     "from proveit.numbers import two, Natural\n",
-    "from proveit.graphs import (AdjacentVertices, Closed, Connected, Degree, EdgeSequence, EdgeSet, Edges,\n",
-    "        EndVertices, Graph, Graphs, HasEulerianCircuit, HasEulerianTrail, Order, Path,\n",
-    "        Paths, Size, Vertices, WalkLength, Walks)\n"
+    "from proveit.graphs import (AdjacentVertices, ClosedWalks, Connected,\n",
+    "        Degree, EdgeSequence, EdgeSet, Edges, EndVertices, Graph, Graphs,\n",
+    "        HasEulerianCircuit, HasEulerianTrail, Order, Paths, Size, Vertices,\n",
+    "        WalkLength, Walks)\n"
    ]
   },
   {
@@ -244,7 +245,7 @@
     "    Equals(\n",
     "    HasEulerianCircuit(G),\n",
     "    Exists(W, Equals(EdgeSet(W), Edges(G)),\n",
-    "       conditions = [Closed(W)], domain = Walks(Size(G), G))\n",
+    "       domain = ClosedWalks(Size(G), G))\n",
     "    ),\n",
     "conditions = [Connected(G)],\n",
     "domain = Graphs()\n",

From dd45e8578f14b5069910079bd151831c06fb028c Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 14 Jul 2025 11:39:35 -0600
Subject: [PATCH 146/159] Delete graphs/endpoints sub-theory pkg

Delete the graphs/endpoints sub-theory package. The endpoints pkg and related concepts is being replaced by the EndVertices() class now living in the graphs/walks sub-theory package.
---
 packages/proveit/graphs/__init__.py           |   1 -
 packages/proveit/graphs/_sub_theories_.txt    |   1 -
 packages/proveit/graphs/endpoints/__init__.py |   9 -
 .../graphs/endpoints/_brief_description_.txt  |   1 -
 .../graphs/endpoints/_sub_theories_.txt       |   0
 .../graphs/endpoints/_theory_nbs_/__init__.py |   0
 .../endpoints/_theory_nbs_/axioms.ipynb       |  77 -----
 .../endpoints/_theory_nbs_/common.ipynb       |  59 ----
 .../_theory_nbs_/demonstrations.ipynb         | 324 ------------------
 .../membership_def/allowed_presumptions.txt   |   0
 .../disallowed_presumptions.txt               |   0
 .../proofs/membership_def/thm_proof.ipynb     | 105 ------
 .../allowed_presumptions.txt                  |   1 -
 .../disallowed_presumptions.txt               |   0
 .../proofs/membership_folding/thm_proof.ipynb | 114 ------
 .../allowed_presumptions.txt                  |   1 -
 .../disallowed_presumptions.txt               |   0
 .../membership_unfolding/thm_proof.ipynb      |  51 ---
 .../allowed_presumptions.txt                  |   0
 .../disallowed_presumptions.txt               |   0
 .../proofs/nonmembership_def/thm_proof.ipynb  | 105 ------
 .../allowed_presumptions.txt                  |   2 -
 .../disallowed_presumptions.txt               |   0
 .../nonmembership_folding/thm_proof.ipynb     |  95 -----
 .../allowed_presumptions.txt                  |   2 -
 .../disallowed_presumptions.txt               |   0
 .../nonmembership_unfolding/thm_proof.ipynb   |  95 -----
 .../endpoints/_theory_nbs_/theorems.ipynb     | 158 ---------
 .../endpoints/_theory_nbs_/theory.ipynb       |  33 --
 .../proveit/graphs/endpoints/endpoints.py     |  31 --
 .../graphs/endpoints/endpoints_membership.py  | 163 ---------
 31 files changed, 1428 deletions(-)
 delete mode 100644 packages/proveit/graphs/endpoints/__init__.py
 delete mode 100644 packages/proveit/graphs/endpoints/_brief_description_.txt
 delete mode 100644 packages/proveit/graphs/endpoints/_sub_theories_.txt
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/__init__.py
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/axioms.ipynb
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/common.ipynb
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/allowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/disallowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/thm_proof.ipynb
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/disallowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/disallowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/allowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/disallowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/disallowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/disallowed_presumptions.txt
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
 delete mode 100644 packages/proveit/graphs/endpoints/_theory_nbs_/theory.ipynb
 delete mode 100644 packages/proveit/graphs/endpoints/endpoints.py
 delete mode 100644 packages/proveit/graphs/endpoints/endpoints_membership.py

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index 7b3198083561..555a153c7aca 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -1,7 +1,6 @@
 from .graph import (Connected, Graph, Graphs, HasEulerianCircuit,
           HasEulerianTrail, Order, Size)
 from .edges import Edges
-from .endpoints import Endpoints
 from .inclusion import NotSubgraph, Subgraph
 from .membership import (
       GraphMembership, GraphNonmembership, InGraph, NotInGraph)
diff --git a/packages/proveit/graphs/_sub_theories_.txt b/packages/proveit/graphs/_sub_theories_.txt
index cf87643d997a..92fc48186f08 100644
--- a/packages/proveit/graphs/_sub_theories_.txt
+++ b/packages/proveit/graphs/_sub_theories_.txt
@@ -3,5 +3,4 @@ union
 membership
 paths
 paths_of
-endpoints
 walks
diff --git a/packages/proveit/graphs/endpoints/__init__.py b/packages/proveit/graphs/endpoints/__init__.py
deleted file mode 100644
index 76d3d1048bdf..000000000000
--- a/packages/proveit/graphs/endpoints/__init__.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from .endpoints import Endpoints
-
-# KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
-#  Make additions above, or add to sys.modules[__name__].__dict__ below.
-# This allows us to import common expression, axioms, and theorems of
-# the theory package directly from the package.
-import sys
-from proveit._core_.theory import TheoryPackage
-sys.modules[__name__] = TheoryPackage(__name__, __file__, locals())
diff --git a/packages/proveit/graphs/endpoints/_brief_description_.txt b/packages/proveit/graphs/endpoints/_brief_description_.txt
deleted file mode 100644
index 79ae73411a60..000000000000
--- a/packages/proveit/graphs/endpoints/_brief_description_.txt
+++ /dev/null
@@ -1 +0,0 @@
-basic concepts involving the endpoints of paths
diff --git a/packages/proveit/graphs/endpoints/_sub_theories_.txt b/packages/proveit/graphs/endpoints/_sub_theories_.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/__init__.py b/packages/proveit/graphs/endpoints/_theory_nbs_/__init__.py
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/axioms.ipynb
deleted file mode 100644
index 8c1a3ea9f657..000000000000
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/axioms.ipynb
+++ /dev/null
@@ -1,77 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Axioms for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.endpoints</a>\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "# Prepare this notebook for defining the axioms of a theory:\n",
-    "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
-    "\n",
-    "from proveit import v, P\n",
-    "from proveit.logic import Equals, Forall, NotEquals\n",
-    "from proveit.logic.sets import EmptySet, SetOfAll\n",
-    "from proveit.numbers import one, LessEq\n",
-    "from proveit.graphs import Degree, Edges, Endpoints, Paths, Vertices"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%begin axioms"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "#### The following defines endpoints for any path $P$, including a trivial path consisting of just a single isolated vertex."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "endpoints_def = (\n",
-    "    Forall(P,\n",
-    "       Equals(Endpoints(P), SetOfAll(v, v, conditions = [LessEq(Degree(v, P), one)], domain = Vertices(P))),\n",
-    "       domain = Paths()\n",
-    "    )\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%end axioms"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/common.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/common.ipynb
deleted file mode 100644
index 93fb1ef700d5..000000000000
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/common.ipynb
+++ /dev/null
@@ -1,59 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Common expressions for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.endpoints</a>\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "# Prepare this notebook for defining the common expressions of a theory:\n",
-    "%common_expressions_notebook # Keep this at the top following 'import proveit'.\n",
-    "\n",
-    "# from ... import ..."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%begin common"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%end common"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
deleted file mode 100644
index cc1ea82b7857..000000000000
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/demonstrations.ipynb
+++ /dev/null
@@ -1,324 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Demonstrations for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.endpoints</a>\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "%begin demonstrations\n",
-    "\n",
-    "from proveit import e, v, E, G, P, V\n",
-    "from proveit.logic import Equals, InClass\n",
-    "from proveit.logic.sets import NotInSet, InSet, SetOfAll, SubsetEq\n",
-    "from proveit.numbers import one, LessEq\n",
-    "from proveit.graphs import Degree, Endpoints, Graph, Path, Paths, Vertices"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "### Endpoints of a Path $P$ in a Graph $G$: $\\mathrm{Endpts}(P)$"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "#### MISC. TESTING"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "#### Basic Constructions"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "Endpoints(P)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(v, Endpoints(P))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "NotInSet(v, Endpoints(P))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "SubsetEq(Endpoints(P), Vertices(Graph(V, E)))"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "#### Testing Membership methods"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`EndpointsMembership.definition()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(v, Endpoints(P)).definition(assumptions = [InClass(P, Paths())])"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(v, Endpoints(Path(V, E))).definition(assumptions = [InClass(Path(V, E), Paths())])"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`EndpointsMembership.as_defined()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(v, Endpoints(P)).as_defined()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(v, Endpoints(Path(V, E))).as_defined()"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`EndpointsMembership.unfold()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(v, Endpoints(P)).unfold(assumptions = [InClass(P, Paths()), InSet(v, Endpoints(P))])"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(v, Endpoints(Path(V, E))).unfold(assumptions = [InClass(Path(V, E), Paths()), InSet(v, Endpoints(Path(V, E)))])"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`EndpointsMembership.conclude()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "from proveit.logic import And\n",
-    "InSet(v, Endpoints(P)).conclude(\n",
-    "    assumptions = [InClass(P, Paths()), And(InSet(v, Vertices(P)), LessEq(Degree(v, P), one))])"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "InSet(v, Endpoints(P)).conclude(\n",
-    "    assumptions = [InClass(P, Paths()), InSet(v, SetOfAll(v, v, conditions = [LessEq(Degree(v, P), one)], domain = Vertices(P)))])"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "#### Testing Nonmembership methods"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`EndpointsNonmembership.definition()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "NotInSet(v, Endpoints(P)).definition(assumptions = [InClass(P, Paths())])"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "NotInSet(v, Endpoints(Path(V, E))).definition(assumptions = [InClass(Path(V, E), Paths())])"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`EndpointsNonmembership.as_defined()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "NotInSet(v, Endpoints(P)).as_defined()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "NotInSet(v, Endpoints(Path(V, E))).as_defined()"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`EndpointsNonmembership.unfold()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "NotInSet(v, Endpoints(P)).unfold(assumptions = [InClass(P, Paths()), NotInSet(v, Endpoints(P))])"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "NotInSet(v, Endpoints(Path(V, E))).unfold(assumptions = [InClass(Path(V, E), Paths()), NotInSet(v, Endpoints(Path(V, E)))])"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "`EndpointsNonmembership.conclude()`"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "NotInSet(v, Endpoints(P)).conclude(\n",
-    "    assumptions = [InClass(P, Paths()),\n",
-    "                   NotInSet(v, SetOfAll(v, v, conditions = [LessEq(Degree(v, P), one)], domain = Vertices(P)))])"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "NotInSet(v, Endpoints(Path(V, E))).conclude(\n",
-    "    assumptions = [InClass(Path(V, E), Paths()),\n",
-    "                   NotInSet(v, SetOfAll(v, v, conditions = [LessEq(Degree(v, Path(V, E)), one)], domain = Vertices(Path(V, E))))])"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%end demonstrations"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/allowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/allowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/disallowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/disallowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/thm_proof.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/thm_proof.ipynb
deleted file mode 100644
index 126f258f8def..000000000000
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_def/thm_proof.ipynb
+++ /dev/null
@@ -1,105 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">endpoints</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_def\">membership_def</a> theorem\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "theory = proveit.Theory() # the theorem's theory\n",
-    "\n",
-    "from proveit import v, X, defaults, Lambda\n",
-    "from proveit.logic.sets import InSet\n",
-    "from proveit.graphs.endpoints import endpoints_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%proving membership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "defaults.assumptions = membership_def.all_conditions()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "endpoints_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "endpoints_def_inst = endpoints_def.instantiate()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "temp_lambda = Lambda(X, InSet(v, X))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "endpoints_def_inst.substitution(temp_lambda)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%qed"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
deleted file mode 100644
index df2d242c76be..000000000000
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/allowed_presumptions.txt
+++ /dev/null
@@ -1 +0,0 @@
-proveit.logic.equality.lhs_via_equality
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/disallowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/disallowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
deleted file mode 100644
index c866ec2997ec..000000000000
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_folding/thm_proof.ipynb
+++ /dev/null
@@ -1,114 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">endpoints</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_folding\">membership_folding</a> theorem\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "theory = proveit.Theory() # the theorem's theory\n",
-    "\n",
-    "from proveit import v, X, defaults, Lambda\n",
-    "from proveit.logic.sets import InSet\n",
-    "from proveit.graphs.endpoints import endpoints_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%proving membership_folding"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "defaults.assumptions = membership_folding.all_conditions()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "endpoints_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "endpoints_def_inst = endpoints_def.instantiate()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "temp_lambda = Lambda(X, InSet(v, X))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "endpoints_def_membership = endpoints_def_inst.substitution(temp_lambda)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "endpoints_def_membership.derive_left_via_equality()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%qed"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
deleted file mode 100644
index 6aa517e4925f..000000000000
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/allowed_presumptions.txt
+++ /dev/null
@@ -1 +0,0 @@
-proveit.logic.equality.sub_right_side_into
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/disallowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/disallowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
deleted file mode 100644
index c183136ca760..000000000000
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/membership_unfolding/thm_proof.ipynb
+++ /dev/null
@@ -1,51 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">endpoints</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#membership_unfolding\">membership_unfolding</a> theorem\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "theory = proveit.Theory() # the theorem's theory\n",
-    "\n",
-    "from proveit.graphs.endpoints import endpoints_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%proving membership_unfolding"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%qed"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/allowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/allowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/disallowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/disallowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb
deleted file mode 100644
index 9d0ce535a316..000000000000
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_def/thm_proof.ipynb
+++ /dev/null
@@ -1,105 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">endpoints</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_def\">nonmembership_def</a> theorem\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "theory = proveit.Theory() # the theorem's theory\n",
-    "\n",
-    "from proveit import v, X, defaults, Lambda\n",
-    "from proveit.logic.sets import NotInSet\n",
-    "from proveit.graphs.endpoints import endpoints_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%proving nonmembership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "defaults.assumptions = nonmembership_def.all_conditions()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "endpoints_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "endpoints_def_inst = endpoints_def.instantiate()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "temp_lambda = Lambda(X, NotInSet(v, X))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "endpoints_def_inst.substitution(temp_lambda)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%qed"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt
deleted file mode 100644
index 21885e9bdad8..000000000000
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/allowed_presumptions.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-proveit.graphs.endpoints.nonmembership_def
-proveit.logic.equality.lhs_via_equality
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/disallowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/disallowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
deleted file mode 100644
index 4b17614dc223..000000000000
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_folding/thm_proof.ipynb
+++ /dev/null
@@ -1,95 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">endpoints</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_folding\">nonmembership_folding</a> theorem\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "theory = proveit.Theory() # the theorem's theory\n",
-    "\n",
-    "from proveit import defaults\n",
-    "from proveit.graphs.endpoints import nonmembership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%proving nonmembership_folding"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "defaults.assumptions = nonmembership_folding.all_conditions()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def_inst = nonmembership_def.instantiate().instantiate()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def_inst.derive_left_via_equality()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%qed"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt
deleted file mode 100644
index 9f467aab5ac2..000000000000
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/allowed_presumptions.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-proveit.graphs.endpoints.nonmembership_def
-proveit.logic.equality.rhs_via_equality
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/disallowed_presumptions.txt b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/disallowed_presumptions.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb
deleted file mode 100644
index 33a5fb32a73d..000000000000
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/proofs/nonmembership_unfolding/thm_proof.ipynb
+++ /dev/null
@@ -1,95 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">endpoints</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#nonmembership_unfolding\">nonmembership_unfolding</a> theorem\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "theory = proveit.Theory() # the theorem's theory\n",
-    "\n",
-    "from proveit import defaults\n",
-    "from proveit.graphs.endpoints import nonmembership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%proving nonmembership_unfolding"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "defaults.assumptions = nonmembership_unfolding.all_conditions()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def_inst = nonmembership_def.instantiate().instantiate()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def_inst.derive_right_via_equality()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%qed"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
deleted file mode 100644
index 79818e842e7d..000000000000
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/theorems.ipynb
+++ /dev/null
@@ -1,158 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Theorems (or conjectures) for the theory of <a class=\"ProveItLink\" href=\"theory.ipynb\">proveit.graphs.endpoints</a>\n",
-    "========"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "# Prepare this notebook for defining the theorems of a theory:\n",
-    "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
-    "\n",
-    "from proveit import v, E, P, V\n",
-    "from proveit.logic import And, Equals, Forall, InClass, NotEquals\n",
-    "from proveit.logic.sets import EmptySet, InSet, KPowerSet, NotInSet, SubsetEq\n",
-    "from proveit.numbers import one, two, LessEq\n",
-    "from proveit.graphs import Degree, Endpoints, Path, Vertices\n",
-    "\n",
-    "from proveit.logic.sets import SetOfAll\n",
-    "from proveit.graphs import Paths"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%begin theorems"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_def = (\n",
-    "    Forall(P,\n",
-    "       Forall(v,\n",
-    "       Equals(InSet(v, Endpoints(P)),\n",
-    "              InSet(v, SetOfAll(v, v, conditions = [LessEq(Degree(v, P), one)], domain = Vertices(P))))\n",
-    "       ),\n",
-    "       domain = Paths()\n",
-    "    )\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_unfolding = (\n",
-    "    Forall(P,\n",
-    "    Forall(v,\n",
-    "           InSet(v, SetOfAll(v, v, conditions = [LessEq(Degree(v, P), one)], domain = Vertices(P))),\n",
-    "           domain = Endpoints(P)),\n",
-    "    domain = Paths())\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "membership_folding = (\n",
-    "    Forall(P,\n",
-    "    Forall(v,\n",
-    "           InSet(v, Endpoints(P)),\n",
-    "           conditions = [InSet(v, SetOfAll(v, v, conditions = [LessEq(Degree(v, P), one)], domain = Vertices(P)))]\n",
-    "          ),\n",
-    "    domain = Paths())\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_def = (\n",
-    "    Forall(P,\n",
-    "       Forall(v,\n",
-    "       Equals(NotInSet(v, Endpoints(P)),\n",
-    "              NotInSet(v, SetOfAll(v, v, conditions = [LessEq(Degree(v, P), one)], domain = Vertices(P))))\n",
-    "       ),\n",
-    "       domain = Paths()\n",
-    "    )\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_unfolding = (\n",
-    "    Forall(P,\n",
-    "       Forall(v,\n",
-    "              NotInSet(v, SetOfAll(v, v, conditions = [LessEq(Degree(v, P), one)], domain = Vertices(P))),\n",
-    "              conditions = [NotInSet(v, Endpoints(P))]\n",
-    "       ),\n",
-    "       domain = Paths()\n",
-    "    )\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "nonmembership_folding = (\n",
-    "    Forall(P,\n",
-    "       Forall(v,\n",
-    "              NotInSet(v, Endpoints(P)),\n",
-    "              conditions = [NotInSet(v, SetOfAll(v, v, conditions = [LessEq(Degree(v, P), one)], domain = Vertices(P)))]\n",
-    "       ),\n",
-    "       domain = Paths()\n",
-    "    )\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%end theorems"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/endpoints/_theory_nbs_/theory.ipynb b/packages/proveit/graphs/endpoints/_theory_nbs_/theory.ipynb
deleted file mode 100644
index df59d50d32a9..000000000000
--- a/packages/proveit/graphs/endpoints/_theory_nbs_/theory.ipynb
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Theory of <a class=\"ProveItLink\" href=\"../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../_theory_nbs_/theory.ipynb\">graphs</a>.endpoints\n",
-    "========\n",
-    "\n",
-    "Provide description here."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import proveit\n",
-    "%theory # toggles between interactive and static modes"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/packages/proveit/graphs/endpoints/endpoints.py b/packages/proveit/graphs/endpoints/endpoints.py
deleted file mode 100644
index b37d933ca0e8..000000000000
--- a/packages/proveit/graphs/endpoints/endpoints.py
+++ /dev/null
@@ -1,31 +0,0 @@
-from proveit import Function, Literal
-
-class Endpoints(Function):
-    '''
-    Endpoints(P) denotes the set of two endpoints of a Path P = (V, E),
-    where Path P has vertex set V and edge set E. Endpoints(P) will be
-    a subset of the Path P's vertex set V, and for a non-trivial path
-    consisting of more than one vertex will consist of the 1-degree
-    vertices.
-    '''
-
-    # the literal operator of the Endpoints operator
-    _operator_ = Literal(
-            string_format='Endpts', latex_format=r'\mathrm{Endpts}',
-            theory=__file__)
-
-    def __init__(self, P, *, styles=None):
-        '''
-        Create the endpoints set EndPts(P) for Path P.
-        '''
-        self.path = P
-        Function.__init__(
-                self, Endpoints._operator_, P, styles=styles)
-
-    def membership_object(self, element):
-        from .endpoints_membership import EndpointsMembership
-        return EndpointsMembership(element, self)
-
-    def nonmembership_object(self, element):
-        from .endpoints_membership import EndpointsNonmembership
-        return EndpointsNonmembership(element, self)
\ No newline at end of file
diff --git a/packages/proveit/graphs/endpoints/endpoints_membership.py b/packages/proveit/graphs/endpoints/endpoints_membership.py
deleted file mode 100644
index 85d5c877b018..000000000000
--- a/packages/proveit/graphs/endpoints/endpoints_membership.py
+++ /dev/null
@@ -1,163 +0,0 @@
-from proveit import v, P, equality_prover, prover
-from proveit.logic import SetMembership, SetNonmembership
-
-
-class EndpointsMembership(SetMembership):
-    '''
-    Defines methods that apply to membership in the set Endpoints(P)
-    of the endpoints of path P.
-    '''
-
-    def __init__(self, element, domain):
-        SetMembership.__init__(self, element, domain)
-
-    @equality_prover('defined', 'define')
-    def definition(self, **defaults_config):
-        '''
-        From self = [elem in Endpoints(P)], where P is a path (i.e. P
-        is an element of the Paths class, or P has been explicitly
-        constructed as a Path(V,E) with vertex set V and edge set E),
-        deduce and return:
-            [elem in Endpoints(P)]
-            = [elem in {v | deg(v) <= 1}_{Vertices(P)}],
-        where the rhs of that equality is a SetOfAll construction.
-        '''
-
-        from . import membership_def
-        element = self.element
-        _P_sub  = self.domain.path  # or self.domain.operand
-        return membership_def.instantiate(
-                {v:element, P:_P_sub },auto_simplify=False)
-
-    def as_defined(self):
-        '''
-        From self = [elem in Endpoints(P)], return:
-        [elem in {v | deg(v) <= 1}_{Vertices(P)}],
-        i.e. the elem is in the SetOfAll v from Vertices(P) such
-        that deg(v) <= 1. 
-        The method returns an expression, not a Judgment, and does
-        not check that P is actually in the class of Paths.
-        '''
-        from proveit.logic import InSet, SetOfAll
-        from proveit.numbers import one, LessEq
-        from proveit.graphs import Degree, Vertices
-        element   = self.element
-        _domain   = self.domain
-        _path     = self.domain.path
-        _setofall = SetOfAll(
-                v, v, conditions = [LessEq(Degree(v, _path),one)],
-                domain = Vertices(_path))
-        return InSet(element, _setofall)
-
-    @prover
-    def unfold(self, **defaults_config):
-        '''
-        From self = [elem in Endpoints(P)],
-        derive and return [elem in {v | deg(v) <= 1}_{Vertices(P)}],
-        knowing or assuming self (and that P is a member of the
-        class of all Paths).
-        '''
-        from . import membership_unfolding
-        element = self.element
-        _P_sub  = self.domain.path  # or self.domain.operand
-        return membership_unfolding.instantiate(
-                {v:element, P:_P_sub },auto_simplify=False)
-
-    @prover
-    def conclude(self, **defaults_config):
-        '''
-        Called on self = [elem in Endpoints(P)], and
-        knowing or assuming [elem in {v | deg(v) <= 1}_{Vertices(P)}]
-        (and that P is a member of the class of Paths)
-        derive and return self.
-        '''
-        from . import membership_folding
-        element = self.element
-        _P_sub  = self.domain.path
-        return membership_folding.instantiate(
-            {v:element, P:_P_sub}, auto_simplify=False)
-
-
-class EndpointsNonmembership(SetNonmembership):
-    '''
-    Defines methods that apply to non-membership in the set 
-    Endpoints(P) of the endpoints of path P.
-    '''
-
-    def __init__(self, element, domain):
-        SetNonmembership.__init__(self, element, domain)
-
-    def side_effects(self, judgment):
-        '''
-        Currently no side-effects for EndpointsNonmembership.
-        '''
-        return
-        yield
-
-    @equality_prover('defined', 'define')
-    def definition(self, **defaults_config):
-        '''
-        From self = [elem not in Endpoints(P)], where P is a path
-        (i.e. P is an element of the Paths class, or P has been
-        explicitly constructed as a Path(V,E) with vertex set V and
-        edge set E), deduce and return:
-            [elem not in Endpoints(P)]
-            = [elem not in {v | deg(v) <= 1}_{Vertices(P)}],
-        where the rhs of that equality is a SetOfAll construction.
-        '''
-
-        from . import nonmembership_def
-        element = self.element
-        _P_sub  = self.domain.path  # or self.domain.operand
-        return nonmembership_def.instantiate(
-                {v:element, P:_P_sub },auto_simplify=False)
-
-    def as_defined(self):
-        '''
-        From self = [elem not in Endpoints(P)], return:
-        [elem not in {v | deg(v) <= 1}_{Vertices(P)}],
-        i.e. the elem is not in the SetOfAll v from Vertices(P) such
-        that deg(v) <= 1. 
-        The method returns an expression, not a Judgment, and does
-        not check that P is actually in the class of Paths.
-        '''
-        from proveit.logic import NotInSet, SetOfAll
-        from proveit.numbers import one, LessEq
-        from proveit.graphs import Degree, Vertices
-        element   = self.element
-        _domain   = self.domain
-        _path     = self.domain.path
-        _setofall = SetOfAll(
-                v, v, conditions = [LessEq(Degree(v, _path),one)],
-                domain = Vertices(_path))
-        return NotInSet(element, _setofall)
-
-    @prover
-    def unfold(self, **defaults_config):
-        '''
-        From self = [elem not in Endpoints(P)],
-        derive and return [elem not in {v | deg(v) <= 1}_{Vertices(P)}],
-        knowing or assuming self (and that P is a member of the
-        class of all Paths).
-        '''
-        from . import nonmembership_unfolding
-        element = self.element
-        _P_sub  = self.domain.path  # or self.domain.operand
-        return nonmembership_unfolding.instantiate(
-                {v:element, P:_P_sub },auto_simplify=False)
-
-    @prover
-    def conclude(self, **defaults_config):
-        '''
-        Called on self = [elem not in Endpoints(P)], and
-        knowing or assuming:
-                [elem not in {v | deg(v) <= 1}_{Vertices(P)}]
-        (and that P is a member of the class of Paths),
-        derive and return self.
-        '''
-        from . import nonmembership_folding
-        element = self.element
-        _P_sub  = self.domain.path
-        return nonmembership_folding.instantiate(
-            {v:element, P:_P_sub}, auto_simplify=False)
-

From 1a9aab3152c24379bf4de243e3b4798a50873a94 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 14 Jul 2025 11:51:45 -0600
Subject: [PATCH 147/159] Establish edges_def_by_vertices axiom in graphs

Establish the edges_def_by_vertices axiom in graphs, defining an edge in graph G as a two-element subset of the vertices of G. This was already contained in the axioms but hadn't been formalized with a name yet.
---
 packages/proveit/graphs/_theory_nbs_/axioms.ipynb | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
index 474591e55ff0..d82690b178e9 100644
--- a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
@@ -130,8 +130,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "# needs a name!\n",
-    "Forall(G, SubsetEq(Edges(G), KPowerSet(Vertices(G), two)), domain = Graphs())"
+    "edges_def_by_vertices = Forall(G, SubsetEq(Edges(G), KPowerSet(Vertices(G), two)), domain = Graphs())"
    ]
   },
   {

From 7dcfbe5db758562799d7076f9c9346c35cbe1cd5 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 14 Jul 2025 14:53:02 -0600
Subject: [PATCH 148/159] Establish Cycles(k,G) axiomatic def in walks pkg

Establish the axiomatic definition for Cycles(k,G) in the graphs/walks sub-theory package, utilizing the Restriction(f, S) class from the (now merged) 341-functions_def_and_function_restriction branch.
---
 .../graphs/walks/_theory_nbs_/axioms.ipynb    | 30 +++++++------------
 1 file changed, 11 insertions(+), 19 deletions(-)

diff --git a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
index ffb1b3b0fd5a..a186ca3d7960 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
@@ -18,9 +18,9 @@
     "# Prepare this notebook for defining the axioms of a theory:\n",
     "%axioms_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "# from ... import ...\n",
-    "from proveit import i, k, G, S, T, W, X, Function\n",
+    "from proveit import i, k, C, G, S, T, W, X, Function\n",
     "from proveit.logic import Card, Equals, Forall, Functions, Injections, InSet, Set, SetOfAll\n",
+    "from proveit.logic.sets import Restriction\n",
     "from proveit.numbers import zero, one, three, Add, greater_eq, Interval, Natural, subtract\n",
     "from proveit.graphs import (\n",
     "        AdjacentVertices, BeginningVertex, Circuits, ClosedTrails,\n",
@@ -262,7 +262,7 @@
    "source": [
     "### Cycles\n",
     "\n",
-    "A cycle $C$ of length $k$ in a simple graph $G$, denoted using $C \\in \\texttt{Cycles}(k, G)$, is a circuit in which no vertex is repeated (except the beginning and ending vertices). Another way of saying this is to realize that a cycle is a closed circuit $C \\in \\texttt{Circuits}(k, G)$ such that the restriction $C\\vert_{[0, 1, \\ldots, k-1]}$ is a length-($k$-$1$) path in $G$."
+    "A cycle $C$ of length $k$ in a simple graph $G$, denoted using $C \\in \\texttt{Cycles}(k, G)$, is a circuit in which no vertex is repeated (except the beginning and ending vertices). Another way of saying this is to realize that a cycle is a circuit (_i.e._, a closed trail) $C \\in \\texttt{Circuits}(k, G)$ such that the restriction $C\\vert_{[0, 1, \\ldots, k-1]}$ is a length-($k$-$1$) path in $G$."
    ]
   },
   {
@@ -271,26 +271,18 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "# this doesn't work -- the intersection would be empty\n",
-    "# what we really need is some \"restriction\" on the Circuit, making it a path\n",
-    "from proveit.logic.sets import Intersect\n",
-    "(\n",
+    "cycles_k_G_def = (\n",
     "    Forall(G, Forall(k,\n",
-    "        Equals(\n",
-    "            Cycles(k, G),\n",
-    "            Intersect(Circuits(k, G), Paths(subtract(k, one), G))\n",
-    "        ),\n",
-    "    domain = Natural), domain = Graphs())\n",
+    "        Equals(Cycles(k, G),\n",
+    "               SetOfAll(C, C,\n",
+    "               conditions = [InSet(Restriction(C, Interval(zero, subtract(k, one))),\n",
+    "                                   Paths(subtract(k, one), G))],\n",
+    "               domain = Circuits(k, G))),\n",
+    "    domain = Natural),\n",
+    "    domain = Graphs())\n",
     ")"
    ]
   },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "A __closed__ walk $W$ is a walk whose beginning and ending vertices are the same. We could define such closure using the observation that $|\\texttt{EndVertices}(W)| = 1$ or we can use some classes for beginning and ending vertices, producing $\\texttt{BeginningVertex}(W) = \\texttt{EndingVertex}(W)$."
-   ]
-  },
   {
    "cell_type": "code",
    "execution_count": null,

From 6a513856003425ce6d9b1c3e14e44d6fa668ba2f Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Tue, 15 Jul 2025 10:57:11 -0600
Subject: [PATCH 149/159] Update Circuits(k,G) & Cycles(k,G) defs to use k >= 3

Update the Circuits(k,G) & Cycles(k,G) axiomatic definitions in graphs/walks sub-theory package to use k >= 3 constraint. This leaves Circuits(k, G) (and thus Cycles, as well) undefined for natural k < 3 instead of proactively claiming the null set for such circuits and cycles. See related emails w/WW on 20250714. Also clean up the walks sub-theory package demonstrations notebook.
---
 .../graphs/walks/_theory_nbs_/axioms.ipynb    | 12 ++----
 .../walks/_theory_nbs_/demonstrations.ipynb   | 42 -------------------
 2 files changed, 4 insertions(+), 50 deletions(-)

diff --git a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
index a186ca3d7960..9f79fb3d145f 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
@@ -234,7 +234,7 @@
    "source": [
     "### Circuits\n",
     "\n",
-    "A circuit $C$ of length $k$ in a simple graph $G$, denoted using $C \\in \\texttt{Circuits}(k, G)$, is a closed trail of length $3$ or more. Instead of defining an intermediate “closed trail” class, we return to the trail definition as a walk with no repeated edges and add the closure constraint to the walk itself. Recall that the requirement that we have no repeated edges means that the edge sequence associated with circuit $C$ is a one-to-one (injective) function $S: [0, 1, \\ldots, k] \\xrightarrow[]{1:1} \\texttt{Edges}(G)$."
+    "A circuit $C$ of length $k$ in a simple graph $G$, denoted using $C \\in \\texttt{Circuits}(k, G)$, is a closed trail of length $3$ or more. This means that for $k \\in {3, 4, 5, \\ldots}$, a closed trail _is_ a circuit."
    ]
   },
   {
@@ -247,12 +247,8 @@
     "    Forall(G, Forall(k,\n",
     "        Equals(\n",
     "            Circuits(k, G),\n",
-    "            SetOfAll(W,\n",
-    "                 W,\n",
-    "                 conditions = [greater_eq(k, three)],\n",
-    "                 domain = ClosedTrails(k, G) )\n",
-    "        ),\n",
-    "    domain = Natural), domain = Graphs())\n",
+    "            ClosedTrails(k, G) ),\n",
+    "    conditions = [greater_eq(k, three)], domain = Natural), domain = Graphs())\n",
     ")"
    ]
   },
@@ -278,7 +274,7 @@
     "               conditions = [InSet(Restriction(C, Interval(zero, subtract(k, one))),\n",
     "                                   Paths(subtract(k, one), G))],\n",
     "               domain = Circuits(k, G))),\n",
-    "    domain = Natural),\n",
+    "    conditions = [greater_eq(k, three)], domain = Natural),\n",
     "    domain = Graphs())\n",
     ")"
    ]
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
index cfd4a3f95b28..25f331f205f0 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
@@ -899,48 +899,6 @@
     "                       greater_eq(k, three), InSet(C, Circuits(k, G))])"
    ]
   },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "A __walk__ $W$ in a simple graph $G$ is a sequence $ S = (v_{0}, v_{1}, \\ldots, v_{k})$ of vertices of $G$ such that two vertices are consecutive in sequence $S$ only if they are adjacent in $G$. We might formulate the constraint like this:\n",
-    "\n",
-    "$$\\texttt{Consecutive}(u, v, S) \\Rightarrow \\texttt{Adjacent}(u, v, G).$$"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "A sequence $S$ can be conceptualized as a function $S: \\mathbb{N} \\rightarrow X$, from the natural numbers to some set $X$, where $S(0)$ is the first element of the sequence, $S(1)$ the second, and so on."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    " A $(k+1)$-vertex walk $W \\in \\texttt{Walks}(G)$ would then be a sequence $S: \\{0, 1, \\ldots, k\\} \\rightarrow \\texttt{Vertices}(G)$ such that $\\texttt{Adjacent}(S(i), S(i+1), G)$ for $i \\in \\{0, 1, \\ldots, k-1\\}$. In this approach, $S(0) = s_{0}$ and $S(k) = s_{k}$ are the two endvertices of the walk $W$."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "A __path__ $P$ in a simple graph $G$ is a walk in $G$ such that no vertices (and thus no edges) are repeated. If we think of the path/walk as a literal sequence $S = (v_0, v_1, \\ldots, v_k)$, then the non-repetition of vertices might be formulated using a predicate such as $\\texttt{Unique}(S)$ or $\\texttt{NonRepeating}(S)$, or, if we can index the elements of the sequence $S$, we might claim that $\\forall_{v_{i}, v_{j} \\in S} \\big(v_{i} = v_{j} \\Leftrightarrow i = j\\big)$.\n",
-    "\n",
-    "If we think of the path/walk sequence as a function $S: \\{0, 1, \\ldots, k\\} \\rightarrow \\texttt{Vertices}(G)$, a path would be a walk where the sequence (function) $S$ is one-to-one (_i.e._, $S(i) = S(j) \\Rightarrow i = j$).\n",
-    "\n",
-    "domain?\n",
-    "\n",
-    "$W \\in \\texttt{Functions}(\\{0, 1, \\ldots, k\\}, \\texttt{Vertices}(G))$\n",
-    "\n",
-    "$W \\in \\texttt{Walks}(G) := W \\in \\texttt{Functions}(\\{0, 1, \\ldots, k\\}, \\texttt{Vertices}(G))$\n",
-    "\n",
-    "$\\forall_{G \\in \\texttt{Graphs}}\\forall_{k \\in \\mathbb{N}}\\big[\\texttt{Walks}(G, k) := \\texttt{Functions}(\\{0, 1, \\ldots, k\\}, \\texttt{Vertices}(G))\\big]$\n",
-    "\n",
-    "By the end of our discussion on Fri 6/27, generally thinking that we'd represent walks in $G$ as $\\texttt{Walks}(G, k)$ or walks of a specific length $k$ in graph $G$, and those can be represented as special functions (equivalent to a sequence), as written above. And despite the annoyance of using $0$-based indexing, such indexing can be useful since we then talk about lengths of walks as the number of edges, which will be one less than the number of vertices in the sequence. Paths of length $k$ can then be defined in terms of injective walks. And Trails can be defined in terms of injective functions into the edges — to be more clear, WW suggested we might have something like a claim that the EdgeSequence(Trail) is an injective function."
-   ]
-  },
   {
    "cell_type": "code",
    "execution_count": null,

From 85e84ad858397f2df6a9344fcbe0f814a3dab0ad Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 17 Jul 2025 15:11:01 -0600
Subject: [PATCH 150/159] Add EulerianCircuits class and related materials

Add the EulerianCircuits(G) class and related materials to the graphs/walks sub-theory package, including EulerianCircuitsMembership() class, and related axioms, theorems, and some testing and demonstrations in the graphs/walks/demonstrations.ipynb notebook.
---
 packages/proveit/graphs/__init__.py           |   3 +-
 packages/proveit/graphs/walks/__init__.py     |   3 +-
 .../graphs/walks/_theory_nbs_/axioms.ipynb    |  31 +++-
 .../walks/_theory_nbs_/demonstrations.ipynb   | 160 +++++++++++++++++-
 .../thm_proof.ipynb                           |  47 +++++
 .../thm_proof.ipynb                           |  47 +++++
 .../thm_proof.ipynb                           |  47 +++++
 .../thm_proof.ipynb                           |  47 +++++
 .../thm_proof.ipynb                           |  47 +++++
 .../graphs/walks/_theory_nbs_/theorems.ipynb  |  82 +++++++++
 packages/proveit/graphs/walks/walks.py        |  37 +++-
 .../proveit/graphs/walks/walks_membership.py  |  85 +++++++++-
 12 files changed, 627 insertions(+), 9 deletions(-)
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_membership_def/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_membership_folding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_membership_is_bool/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_membership_unfolding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_within_closed_walks/thm_proof.ipynb

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index 555a153c7aca..0b8112ad0de2 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -11,7 +11,8 @@
 from .walks import (BeginningVertex, Circuits, ClosedTrails,
           ClosedWalk, ClosedWalks, Cycles,
           EdgeSequence, EdgeSet, EndingVertex, EndVertices,
-          EulerianTrails, Paths, Trails, WalkLength, Walks)
+          EulerianCircuits, EulerianTrails, Paths, Trails,
+          WalkLength, Walks)
 
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
diff --git a/packages/proveit/graphs/walks/__init__.py b/packages/proveit/graphs/walks/__init__.py
index e606ccdaaab1..08045500d479 100644
--- a/packages/proveit/graphs/walks/__init__.py
+++ b/packages/proveit/graphs/walks/__init__.py
@@ -1,7 +1,8 @@
 from .walks import (BeginningVertex, Circuits, ClosedTrails,
         ClosedWalk, ClosedWalks, Cycles,
         EdgeSequence, EdgeSet, EndingVertex, EndVertices,
-        EulerianTrails, Paths, Trails, WalkLength, Walks)
+        EulerianCircuits, EulerianTrails, Paths, Trails,
+        WalkLength, Walks)
 
 # KEEP THE FOLLOWING IN __init__.py FOR THEORY PACKAGES.
 #  Make additions above, or add to sys.modules[__name__].__dict__ below.
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
index 9f79fb3d145f..cedf12073650 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
@@ -25,7 +25,7 @@
     "from proveit.graphs import (\n",
     "        AdjacentVertices, BeginningVertex, Circuits, ClosedTrails,\n",
     "        ClosedWalk, ClosedWalks, Cycles, Edges, EdgeSequence, EndingVertex,\n",
-    "        EndVertices, Graphs, Paths, Trails, Vertices, Walks)"
+    "        EndVertices, EulerianCircuits, Graphs, Paths, Size, Trails, Vertices, Walks)\n"
    ]
   },
   {
@@ -252,6 +252,35 @@
     ")"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Eulerian Circuits"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "An Eulerian circuit in graph $G$, denoted using $C \\in \\texttt{EulerianCircuits}(G)$, is a circuit in $G$ that uses every edge in $G$."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "eulerian_circuits_G_def = (\n",
+    "    Forall(G,\n",
+    "        Equals(\n",
+    "            EulerianCircuits(G),\n",
+    "            Circuits(Size(G), G) ),\n",
+    "    domain = Graphs())\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
index 25f331f205f0..9266d380e2e9 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
@@ -22,8 +22,8 @@
     "from proveit.graphs import (\n",
     "        AdjacentVertices, BeginningVertex, Circuits, ClosedTrails,\n",
     "        ClosedWalks, Cycles, Edges, EdgeSequence, EdgeSet, EndingVertex,\n",
-    "        EndVertices, EulerianTrails, Graph, Graphs, Paths, Trails, Vertices,\n",
-    "        WalkLength, Walks)\n",
+    "        EndVertices, EulerianCircuits, EulerianTrails, Graph, Graphs, Paths,\n",
+    "        Size, Trails, Vertices, WalkLength, Walks)\n",
     "%begin demonstrations\n"
    ]
   },
@@ -255,7 +255,32 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "# circuit membership under construction"
+    "InSet(C, Circuits(k, G))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "An __Eulerian circuit__ in graph $G$ is a circuit in $G$ that uses every edge of $G$. An Eulerian circuit in graph $G$ then always has length equal to the number of edges in $G$ (or the size of $G$), denoted by $||G||$."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "EulerianCircuits(G)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, EulerianCircuits(G))"
    ]
   },
   {
@@ -899,6 +924,135 @@
     "                       greater_eq(k, three), InSet(C, Circuits(k, G))])"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Eulerian Circuits Membership and Related Methods"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, EulerianCircuits(G))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, EulerianCircuits(G)).deduce_in_bool(assumptions = [InClass(G, Graphs())])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, EulerianCircuits(G)).definition(assumptions = [InClass(G, Graphs())])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, EulerianCircuits(G)).as_defined()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, EulerianCircuits(G)).unfold(assumptions = [InClass(G, Graphs()), InSet(C, EulerianCircuits(G))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, EulerianCircuits(G)).conclude(assumptions = [InClass(G, Graphs()), InSet(C, Circuits(Size(G), G))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, EulerianCircuits(G)).derive_element_in_closed_walks(\n",
+    "        assumptions = [InClass(G, Graphs()), InSet(C, EulerianCircuits(G))]\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from proveit.graphs import graph_size_in_natural\n",
+    "graph_size_in_natural"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "type(graph_size_in_natural.domain)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "type(Graphs())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Graphs"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Size(G).derive_size_in_natural(assumptions = [InClass(G, Graphs())])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, Walks(Size(G), G)).prove(\n",
+    "        assumptions = [InClass(G, Graphs()), InSet(Size(G), Natural), InSet(C, EulerianCircuits(G))]\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_membership_def/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_membership_def/thm_proof.ipynb
new file mode 100644
index 000000000000..435ae089897c
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_membership_def/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#eulerian_circuits_membership_def\">eulerian_circuits_membership_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving eulerian_circuits_membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_membership_folding/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_membership_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..e86518110458
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_membership_folding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#eulerian_circuits_membership_folding\">eulerian_circuits_membership_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving eulerian_circuits_membership_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_membership_is_bool/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_membership_is_bool/thm_proof.ipynb
new file mode 100644
index 000000000000..80213492a031
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_membership_is_bool/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#eulerian_circuits_membership_is_bool\">eulerian_circuits_membership_is_bool</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving eulerian_circuits_membership_is_bool"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_membership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_membership_unfolding/thm_proof.ipynb
new file mode 100644
index 000000000000..43c14cf544c1
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_membership_unfolding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#eulerian_circuits_membership_unfolding\">eulerian_circuits_membership_unfolding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving eulerian_circuits_membership_unfolding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_within_closed_walks/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_within_closed_walks/thm_proof.ipynb
new file mode 100644
index 000000000000..4f268fbb603d
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/eulerian_circuits_within_closed_walks/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#eulerian_circuits_within_closed_walks\">eulerian_circuits_within_closed_walks</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving eulerian_circuits_within_closed_walks"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
index 9ebe09fe908e..a8cd85a333fd 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
@@ -519,6 +519,63 @@
     ")"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### EulerianCircuitsMembership($G$)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from proveit.graphs import EulerianCircuits, Size"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "eulerian_circuits_membership_def = (\n",
+    "    Forall(G, Forall(C,\n",
+    "    Equals(\n",
+    "        InSet(C, EulerianCircuits(G)),\n",
+    "        InSet(C, Circuits(Size(G), G))\n",
+    "    )), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "eulerian_circuits_membership_unfolding = (\n",
+    "    Forall(G, Forall(C,\n",
+    "    InSet(C, Circuits(Size(G), G)\n",
+    "    ), domain = EulerianCircuits(G)), domain = Graphs())\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "eulerian_circuits_membership_folding = (\n",
+    "    Forall(G, Forall(C,\n",
+    "    InSet(C, EulerianCircuits(G)\n",
+    "    ), domain = Circuits(Size(G), G)), domain = Graphs())\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -626,6 +683,19 @@
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "eulerian_circuits_within_closed_walks = (\n",
+    "Forall(G,\n",
+    "    SubsetEq(EulerianCircuits(G), ClosedWalks(Size(G), G)),\n",
+    "domain = Graphs())\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -717,6 +787,18 @@
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "eulerian_circuits_membership_is_bool = Forall(G,\n",
+    "Forall(C, in_bool(InSet(C, EulerianCircuits(G)))),\n",
+    "domain = Graphs()\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/walks/walks.py b/packages/proveit/graphs/walks/walks.py
index ac361c0928b9..6bebc495faae 100644
--- a/packages/proveit/graphs/walks/walks.py
+++ b/packages/proveit/graphs/walks/walks.py
@@ -1,6 +1,6 @@
 from proveit import equality_prover, Function, Literal
 from proveit.logic import ClassMembership
-from proveit.graphs import Graph
+from proveit.graphs import Graph,  Size
 
 class Walks(Function):
     '''
@@ -215,6 +215,41 @@ def membership_object(self, element):
 #         return CircuitsNonmembership(element, self)
 
 
+class EulerianCircuits(Function):
+    '''
+    EulerianCircuits(G) represents the set of Eulerian circuits
+    of the simple undirected graph G. An Eulerian circuit in G is
+    a circuit in G that uses every edge of G. Since it uses every
+    edge, there is no length parameter k that appears in other
+    types of walks. Because it is a circuit, we expect an Eulerian
+    circuit to be non-trivial: it should consist of at least 3 edges.
+    The set of EulerianCircuits(G) could be an empty set.
+    '''
+
+    # the literal operator of the EulerianCircuits operation
+    _operator_ = Literal(string_format='EulerianCircuits',
+                         latex_format=r'\textrm{EulerianCircuits}',
+                         theory=__file__)
+
+    def __init__(self, G, *, styles=None):
+        '''
+        Represent EulerianCircuits(G), the set of all Eulerian
+        circuits in graph G.
+        '''
+        self.graph = G
+        self.length = Size(G)
+        Function.__init__(
+                self, EulerianCircuits._operator_, G, styles=styles)
+
+    def membership_object(self, element):
+        from .walks_membership import EulerianCircuitsMembership
+        return EulerianCircuitsMembership(element, self)
+
+#     def nonmembership_object(self, element):
+#         from .walks_membership import CircuitsNonmembership
+#         return CircuitsNonmembership(element, self)
+
+
 class Cycles(Function):
     '''
     Cycles(k, G) represents the set of cycles of length k in
diff --git a/packages/proveit/graphs/walks/walks_membership.py b/packages/proveit/graphs/walks/walks_membership.py
index bef9efc7a137..16289d5c43cf 100644
--- a/packages/proveit/graphs/walks/walks_membership.py
+++ b/packages/proveit/graphs/walks/walks_membership.py
@@ -5,8 +5,8 @@
 from proveit.logic.sets import Functions, Injections, SetOfAll
 from proveit.numbers import zero, one, Add, Interval, subtract
 from proveit.graphs import (AdjacentVertices, BeginningVertex,
-            ClosedWalks, Edges,
-            EdgeSequence, EndingVertex, Graph, Vertices, Walks)
+            Circuits, ClosedWalks, Edges, EdgeSequence, EndingVertex,
+            Graph, Size, Vertices, Walks)
 
 
 class WalksMembership(SetMembership):
@@ -658,3 +658,84 @@ def derive_element_in_closed_trails(self, **defaults_config):
             {G:_G, k:_k}, auto_simplify=False)
             .derive_superset_membership(self.element, auto_simplify=False))
 
+
+class EulerianCircuitsMembership(SetMembership):
+    '''
+    Defines methods that apply to membership in the set of Eulerian
+    circuits in the simple graph G, denoted EulerianCircuits(G). An
+    Eulieran circuit in G is a circuit that uses every edge (and thus
+    the length of an Eulerian circuit in G is always ||G||, i.e., the
+    number of edges in G (also called the size of G).
+    '''
+
+    def __init__(self, element, domain):
+        SetMembership.__init__(self, element, domain)
+
+    def side_effects(self, judgment):
+        '''
+        Yield side-effects when proving 'C in Circuits(k, G)' for
+        Natural k >= 3 and G in Graphs.
+        '''
+        yield self.derive_element_in_closed_walks
+
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self = [elem in EulerianCircuits(G)], deduce and return:
+        [elem in EulerianCircuits(G)] = [elem in Circuits(||G||, G)].
+        '''
+        from . import eulerian_circuits_membership_def
+        element = self.element
+        _G_sub  = self.domain.graph
+        return eulerian_circuits_membership_def.instantiate(
+                {G: _G_sub, C: element },auto_simplify=False)
+
+    def as_defined(self):
+        '''
+        From self = [elem in EulerianCircuits(G)], return the
+        expression (NOT a judgment): elem in Circuits(||G||, G).
+        '''
+        element = self.element
+        _G      = self.domain.graph
+        return InSet(element, Circuits(Size(_G), _G))
+
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        From self = [elem in EulerianCircuits(G)], and knowing or
+        assuming self, derive and return: elem Circuits(||G||, G).
+        '''
+        from . import eulerian_circuits_membership_unfolding
+        element = self.element
+        _G_sub  = self.domain.graph
+        return eulerian_circuits_membership_unfolding.instantiate(
+            {G: _G_sub, C: element}, auto_simplify=False)
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        From self = [C in EulerianCircuits(G)], derive and return
+        self, knowing or assuming that: C in Circuits(||G||, G).
+        '''
+        _C = self.element
+        _G  = self.domain.graph
+        from . import eulerian_circuits_membership_folding
+        return eulerian_circuits_membership_folding.instantiate(
+            {G: _G, C: _C}, auto_simplify=False)
+
+    @relation_prover
+    def deduce_in_bool(self, **defaults_config):
+        from . import eulerian_circuits_membership_is_bool
+        _G_sub = self.domain.graph
+        _C_sub = self.element
+        return eulerian_circuits_membership_is_bool.instantiate(
+            {G:_G_sub, C:_C_sub}, auto_simplify=False)
+
+    @prover
+    def derive_element_in_closed_walks(self, **defaults_config):
+        from . import eulerian_circuits_within_closed_walks
+        _G      = self.domain.graph
+        return (eulerian_circuits_within_closed_walks.instantiate(
+            {G:_G}, auto_simplify=False)
+            .derive_superset_membership(self.element, auto_simplify=False))
+

From 0981d5dcf416089dc774c53b1da716e08c522e1b Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 17 Jul 2025 15:13:45 -0600
Subject: [PATCH 151/159] Add graph_size_in_natural theorem to graphs theory
 package

Add graph_size_in_natural theorem to graphs theory package, along with related side_effects() and derive_size_in_natural() methods for the Size(G) class.
---
 .../graphs/_theory_nbs_/demonstrations.ipynb  | 11 ++++-
 .../graph_size_in_natural/thm_proof.ipynb     | 47 +++++++++++++++++++
 .../graphs/_theory_nbs_/theorems.ipynb        | 14 +++++-
 packages/proveit/graphs/graph.py              | 16 ++++++-
 4 files changed, 84 insertions(+), 4 deletions(-)
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/graph_size_in_natural/thm_proof.ipynb

diff --git a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
index 1d3516bdec3a..66940cbf11ee 100644
--- a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
@@ -19,7 +19,7 @@
     "from proveit.logic import InClass, InSet, KPowerSet, NotInSet, SubsetEq\n",
     "from proveit.numbers import two\n",
     "from proveit.graphs import (\n",
-    "        AdjacentVertices, Connected, Degree, Edges, Endpoints, Graph, Graphs,\n",
+    "        AdjacentVertices, Connected, Degree, Edges, Graph, Graphs,\n",
     "        HasEulerianCircuit, HasEulerianTrail, Order, Size, Vertices)\n",
     "%begin demonstrations"
    ]
@@ -95,6 +95,15 @@
     "Size(G).definition(assumptions = [InClass(G, Graphs())])"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Size(G).derive_size_in_natural(assumptions = [InClass(G, Graphs())])"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/graph_size_in_natural/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/graph_size_in_natural/thm_proof.ipynb
new file mode 100644
index 000000000000..cf568b63eec0
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/graph_size_in_natural/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#graph_size_in_natural\">graph_size_in_natural</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving graph_size_in_natural"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
index 069f9ce0003f..a4cdd7828eab 100644
--- a/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
@@ -21,10 +21,11 @@
     "from proveit import e, v, E, G, V, W\n",
     "from proveit.logic import Equals, Forall, Iff, Implies, InSet, InClass, NotInSet\n",
     "from proveit.logic.sets import Card, KPowerSet, SetOfAll, SubsetEq\n",
-    "from proveit.numbers import two, IntegerEven, IntegerOdd, Mult, Sum\n",
+    "from proveit.numbers import (zero, two, greater_eq, IntegerEven, IntegerOdd,\n",
+    "        Mult, Natural, Sum)\n",
     "from proveit.graphs import (\n",
     "        Connected, Degree, Edges, EndVertices, EulerianTrails, Graph, Graphs,\n",
-    "        HasEulerianCircuit, HasEulerianTrail, Vertices)"
+    "        HasEulerianCircuit, HasEulerianTrail, Size, Vertices)"
    ]
   },
   {
@@ -99,6 +100,15 @@
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "graph_size_in_natural = Forall(G, InSet(Size(G), Natural), domain = Graphs())"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
diff --git a/packages/proveit/graphs/graph.py b/packages/proveit/graphs/graph.py
index a4532036be37..482334b995e1 100644
--- a/packages/proveit/graphs/graph.py
+++ b/packages/proveit/graphs/graph.py
@@ -1,4 +1,4 @@
-from proveit import equality_prover, Function, Literal
+from proveit import equality_prover, Function, Literal, prover
 from proveit import E, G, V
 from proveit.logic import ClassMembership
 
@@ -119,6 +119,12 @@ def __init__(self, G, *, styles=None):
         Function.__init__(
                 self, Size._operator_, G, styles=styles)
 
+    def side_effects(self, judgment):
+        '''
+        Yield side-effects when representing 'Size(G)'.
+        '''
+        yield self.derive_size_in_natural
+
     def string(self, **kwargs):
         return '||' + self.operand.string() + '||'
 
@@ -135,6 +141,14 @@ def definition(self, **defaults_config):
         _G_sub = self.operand
         return graph_size_def.instantiate({G:_G_sub}, auto_simplify=False)
 
+    @prover
+    def derive_size_in_natural(self, **defaults_config):
+        from . import graph_size_in_natural
+        _G      = self.operand
+        return (graph_size_in_natural.instantiate(
+            {G:_G}, auto_simplify=False))
+
+
 
 class Connected(Function):
     '''

From e625955de26bcc7db0d1e057f98828f9bf16fc9e Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Thu, 17 Jul 2025 15:54:22 -0600
Subject: [PATCH 152/159] Changed Graphs(Literal) class to
 GraphsLiteral(Literal) class

Changed Graphs(Literal) class to GraphsLiteral(Literal) class and added the Graphs = GraphsLiteral() definition to graphs/common.ipynb, and updated all the graphs and walks axioms, theorems, and demonstrations notebooks.
---
 packages/proveit/graphs/__init__.py           |  2 +-
 .../proveit/graphs/_theory_nbs_/axioms.ipynb  | 18 ++--
 .../proveit/graphs/_theory_nbs_/common.ipynb  | 11 ++-
 .../graphs/_theory_nbs_/demonstrations.ipynb  | 12 +--
 .../graphs/_theory_nbs_/theorems.ipynb        | 22 ++---
 packages/proveit/graphs/graph.py              | 37 +++++++-
 .../graphs/walks/_theory_nbs_/axioms.ipynb    | 22 ++---
 .../walks/_theory_nbs_/demonstrations.ipynb   | 92 +++++++++----------
 .../graphs/walks/_theory_nbs_/theorems.ipynb  | 88 +++++++++---------
 9 files changed, 172 insertions(+), 132 deletions(-)

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index 0b8112ad0de2..84809d36ba4d 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -1,4 +1,4 @@
-from .graph import (Connected, Graph, Graphs, HasEulerianCircuit,
+from .graph import (Connected, Graph, GraphsLiteral, HasEulerianCircuit,
           HasEulerianTrail, Order, Size)
 from .edges import Edges
 from .inclusion import NotSubgraph, Subgraph
diff --git a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
index d82690b178e9..e1fba9d73111 100644
--- a/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/axioms.ipynb
@@ -45,7 +45,7 @@
    "source": [
     "graph_v_e_in_graphs = (\n",
     "    Forall(V,\n",
-    "    Forall(E, InClass(Graph(V, E), Graphs()), conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
+    "    Forall(E, InClass(Graph(V, E), Graphs), conditions = [SubsetEq(E, KPowerSet(V, two))])\n",
     "    )\n",
     ")"
    ]
@@ -58,7 +58,7 @@
    "source": [
     "graph_order_def = Forall(G, \n",
     "       Equals(Order(G), Card(Vertices(G))),\n",
-    "       domain = Graphs()\n",
+    "       domain = Graphs\n",
     "      )"
    ]
   },
@@ -70,7 +70,7 @@
    "source": [
     "graph_size_def = Forall(G, \n",
     "       Equals(Size(G), Card(Edges(G))),\n",
-    "       domain = Graphs()\n",
+    "       domain = Graphs\n",
     "      )"
    ]
   },
@@ -86,7 +86,7 @@
     "                 Forall((u, v),\n",
     "                         Exists((P, k), Equals(EndVertices(P), Set(u, v)), domains = [Paths(k, G), Natural]),\n",
     "                         domain = Vertices(G))),\n",
-    "          domain = Graphs()\n",
+    "          domain = Graphs\n",
     "    )\n",
     ")"
    ]
@@ -130,7 +130,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "edges_def_by_vertices = Forall(G, SubsetEq(Edges(G), KPowerSet(Vertices(G), two)), domain = Graphs())"
+    "edges_def_by_vertices = Forall(G, SubsetEq(Edges(G), KPowerSet(Vertices(G), two)), domain = Graphs)"
    ]
   },
   {
@@ -151,7 +151,7 @@
     "                    Equals(\n",
     "                        Degree(v, G),\n",
     "                        Card(SetOfAll(E, E, condition = InSet(v, E), domain = Edges(G)))),\n",
-    "        domain = Vertices(G)), domain = Graphs())\n",
+    "        domain = Vertices(G)), domain = Graphs)\n",
     ")"
    ]
   },
@@ -173,7 +173,7 @@
     "           Forall((u, v),\n",
     "                  Equals(AdjacentVertices(u, v, G), InSet(Set(u, v), Edges(G))),\n",
     "                  domain = Vertices(G)),\n",
-    "           domain = Graphs()\n",
+    "           domain = Graphs\n",
     "    )\n",
     ")"
    ]
@@ -247,7 +247,7 @@
     "       domain = ClosedWalks(Size(G), G))\n",
     "    ),\n",
     "conditions = [Connected(G)],\n",
-    "domain = Graphs()\n",
+    "domain = Graphs\n",
     ")"
    ]
   },
@@ -271,7 +271,7 @@
     "       domain = Walks(Size(G), G))\n",
     "    ),\n",
     "conditions = [Connected(G)],\n",
-    "domain = Graphs()\n",
+    "domain = Graphs\n",
     ")"
    ]
   },
diff --git a/packages/proveit/graphs/_theory_nbs_/common.ipynb b/packages/proveit/graphs/_theory_nbs_/common.ipynb
index 573d26d45828..7259187b2e2a 100644
--- a/packages/proveit/graphs/_theory_nbs_/common.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/common.ipynb
@@ -22,7 +22,7 @@
     "from proveit.logic import And, Or\n",
     "from proveit.logic.sets import InSet\n",
     "from proveit.numbers import one\n",
-    "from proveit.graphs import InGraph, NotInGraph"
+    "from proveit.graphs import GraphsLiteral, InGraph, NotInGraph"
    ]
   },
   {
@@ -34,6 +34,15 @@
     "%begin common"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Graphs = GraphsLiteral()"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
index 66940cbf11ee..9bc1685b4420 100644
--- a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
@@ -54,7 +54,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InClass(example_graph, Graphs())"
+    "InClass(example_graph, Graphs)"
    ]
   },
   {
@@ -73,7 +73,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Order(G).definition(assumptions = [InClass(G, Graphs())])"
+    "Order(G).definition(assumptions = [InClass(G, Graphs)])"
    ]
   },
   {
@@ -92,7 +92,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Size(G).definition(assumptions = [InClass(G, Graphs())])"
+    "Size(G).definition(assumptions = [InClass(G, Graphs)])"
    ]
   },
   {
@@ -101,7 +101,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Size(G).derive_size_in_natural(assumptions = [InClass(G, Graphs())])"
+    "Size(G).derive_size_in_natural(assumptions = [InClass(G, Graphs)])"
    ]
   },
   {
@@ -120,7 +120,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Connected(G).definition(assumptions = [InClass(G, Graphs())])"
+    "Connected(G).definition(assumptions = [InClass(G, Graphs)])"
    ]
   },
   {
@@ -235,7 +235,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "AdjacentVertices(u, v, G).definition(assumptions = [InClass(G, Graphs()), InSet(u, Vertices(G)), InSet(v, Vertices(G))])"
+    "AdjacentVertices(u, v, G).definition(assumptions = [InClass(G, Graphs), InSet(u, Vertices(G)), InSet(v, Vertices(G))])"
    ]
   },
   {
diff --git a/packages/proveit/graphs/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
index a4cdd7828eab..dd279cb52e5a 100644
--- a/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
@@ -54,7 +54,7 @@
     "total_deg_is_twice_num_of_edges = (\n",
     "        Forall(G, Equals(Sum(v, Degree(v, G), domain = Vertices(G)),\n",
     "                         Mult(two, Card(Edges(G)))),\n",
-    "        domain = Graphs())\n",
+    "        domain = Graphs)\n",
     ")"
    ]
   },
@@ -74,7 +74,7 @@
     "total_deg_is_even = (\n",
     "        Forall(G, InSet(Sum(v, Degree(v, G), domain = Vertices(G)),\n",
     "                         IntegerEven),\n",
-    "        domain = Graphs())\n",
+    "        domain = Graphs)\n",
     ")"
    ]
   },
@@ -95,7 +95,7 @@
     "        Forall(G,\n",
     "        InSet(Card(SetOfAll(v, v, condition = InSet(Degree(v, G), IntegerOdd), domain = Vertices(G))),\n",
     "              IntegerEven),\n",
-    "        domain = Graphs()\n",
+    "        domain = Graphs\n",
     "        )\n",
     ")"
    ]
@@ -106,7 +106,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "graph_size_in_natural = Forall(G, InSet(Size(G), Natural), domain = Graphs())"
+    "graph_size_in_natural = Forall(G, InSet(Size(G), Natural), domain = Graphs)"
    ]
   },
   {
@@ -304,7 +304,7 @@
     "           Iff(HasEulerianCircuit(G),\n",
     "               Forall(v, InSet(Degree(v, G), IntegerEven), domain = Vertices(G))),\n",
     "    conditions = [Connected(G)],\n",
-    "    domain = Graphs()\n",
+    "    domain = Graphs\n",
     "    )\n",
     ")"
    ]
@@ -319,7 +319,7 @@
     "    Forall(G,\n",
     "           Forall(v, InSet(Degree(v, G), IntegerEven), domain = Vertices(G)),\n",
     "    conditions = [HasEulerianCircuit(G)],\n",
-    "    domain = Graphs()\n",
+    "    domain = Graphs\n",
     "    )\n",
     ")"
    ]
@@ -334,7 +334,7 @@
     "    Forall(G,\n",
     "           HasEulerianCircuit(G),\n",
     "    conditions = [Connected(G), Forall(v, InSet(Degree(v, G), IntegerEven), domain = Vertices(G))],\n",
-    "    domain = Graphs()\n",
+    "    domain = Graphs\n",
     "    )\n",
     ")"
    ]
@@ -352,7 +352,7 @@
     "    Equals(Card(SetOfAll(v, v, condition = InSet(Degree(v, G), IntegerOdd), domain = Vertices(G))), two)\n",
     "    ),\n",
     "conditions = [Connected(G)],\n",
-    "domain = Graphs()\n",
+    "domain = Graphs\n",
     ")\n",
     ")"
    ]
@@ -367,7 +367,7 @@
     "Forall(G,\n",
     "    Equals(Card(SetOfAll(v, v, condition = InSet(Degree(v, G), IntegerOdd), domain = Vertices(G))), two),\n",
     "conditions = [HasEulerianTrail(G)],\n",
-    "domain = Graphs()\n",
+    "domain = Graphs\n",
     ")\n",
     ")"
    ]
@@ -382,7 +382,7 @@
     "Forall(G,\n",
     "    HasEulerianTrail(G),\n",
     "conditions = [Connected(G), Equals(Card(SetOfAll(v, v, condition = InSet(Degree(v, G), IntegerOdd), domain = Vertices(G))), two)],\n",
-    "domain = Graphs()\n",
+    "domain = Graphs\n",
     ")\n",
     ")"
    ]
@@ -401,7 +401,7 @@
     "                           domain = Vertices(G))),\n",
     "           domain = EulerianTrails(G)),\n",
     "conditions = [Connected(G), HasEulerianTrail(G)],\n",
-    "domain = Graphs()\n",
+    "domain = Graphs\n",
     ")\n",
     ")"
    ]
diff --git a/packages/proveit/graphs/graph.py b/packages/proveit/graphs/graph.py
index 482334b995e1..7abf95bad91a 100644
--- a/packages/proveit/graphs/graph.py
+++ b/packages/proveit/graphs/graph.py
@@ -2,13 +2,43 @@
 from proveit import E, G, V
 from proveit.logic import ClassMembership
 
-class Graphs(Literal):
+# class Graphs(Literal):
+#     '''
+#     Graphs represents the (mathematical) class of graphs, to which
+#     any specific graph G = (V, E) of vertices and edges belongs.
+#     This class might not be necessary, but is modeled on the
+#     HilbertSpacesLiteral class in the linear_algebra/inner_products
+#     theory package.
+#     '''
+
+#     # the literal string for representing the class of Graphs
+#     def __init__(self, *, styles=None):
+#         Literal.__init__(self, string_format='Graphs', 
+#                          latex_format=r'\textrm{Graphs}',
+#                          styles=styles)
+
+#     def membership_object(self, element):
+#         return GraphsMembership(element, self)
+
+#     @property
+#     def is_proper_class(self):
+#         '''
+#         Graphs consitute a proper class (i.e. instead of a set).
+#         This indicates that InClass() should be used instead of
+#         InSet() when this is a domain.
+#         '''
+#         return True
+
+
+class GraphsLiteral(Literal):
     '''
     Graphs represents the (mathematical) class of graphs, to which
     any specific graph G = (V, E) of vertices and edges belongs.
     This class might not be necessary, but is modeled on the
     HilbertSpacesLiteral class in the linear_algebra/inner_products
-    theory package.
+    theory package, and something similar involving the EmptySet in
+    logic/sets. 'Graphs' is then defined in the graphs/common nb
+    as Graphs = GraphsLiteral.
     '''
 
     # the literal string for representing the class of Graphs
@@ -33,8 +63,9 @@ def is_proper_class(self):
 class GraphsMembership(ClassMembership):
 
     def __init__(self, element, domain):
+        from . import Graphs
         ClassMembership.__init__(self, element, domain)
-        if domain != Graphs():
+        if domain != Graphs:
             raise TypeError("domain expected to be Graphs, not %s"
                             %domain.__class__)
 
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
index cedf12073650..4c87cf4cb082 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/axioms.ipynb
@@ -64,7 +64,7 @@
     "             domain = Functions(Interval(zero, k), Vertices(G)))\n",
     "    ),\n",
     "    domain = Natural),\n",
-    "    domain = Graphs()\n",
+    "    domain = Graphs\n",
     "    )\n",
     ")"
    ]
@@ -89,7 +89,7 @@
     "        Equals(BeginningVertex(W), Function(W, zero)),\n",
     "    domain =Walks(k, G)),\n",
     "    domain = Natural),\n",
-    "    domain = Graphs())\n",
+    "    domain = Graphs)\n",
     ")"
    ]
   },
@@ -106,7 +106,7 @@
     "        Equals(EndingVertex(W), Function(W, k)),\n",
     "    domain=Walks(k, G)),\n",
     "    domain = Natural),\n",
-    "    domain = Graphs())\n",
+    "    domain = Graphs)\n",
     ")"
    ]
   },
@@ -123,7 +123,7 @@
     "        Equals(EndVertices(W), Set(Function(W, zero), Function(W, k))),\n",
     "    domain=Walks(k, G)),\n",
     "    domain = Natural),\n",
-    "    domain = Graphs())\n",
+    "    domain = Graphs)\n",
     ")"
    ]
   },
@@ -149,7 +149,7 @@
     "                 conditions = [Equals(BeginningVertex(W), EndingVertex(W))],\n",
     "                 domain = Walks(k, G) )\n",
     "        ),\n",
-    "    domain = Natural), domain = Graphs())\n",
+    "    domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -177,7 +177,7 @@
     "                 conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
     "                 domain = Walks(k, G) )\n",
     "        ),\n",
-    "    domain = Natural), domain = Graphs())\n",
+    "    domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -196,7 +196,7 @@
     "                 conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
     "                 domain = ClosedWalks(k, G) )\n",
     "        ),\n",
-    "    domain = Natural), domain = Graphs())\n",
+    "    domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -224,7 +224,7 @@
     "                 conditions = [InSet(W, Injections(Interval(zero, subtract(k, one)), Vertices(G)))],\n",
     "                 domain = Walks(k, G), )\n",
     "        ),\n",
-    "    domain = Natural), domain = Graphs())\n",
+    "    domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -248,7 +248,7 @@
     "        Equals(\n",
     "            Circuits(k, G),\n",
     "            ClosedTrails(k, G) ),\n",
-    "    conditions = [greater_eq(k, three)], domain = Natural), domain = Graphs())\n",
+    "    conditions = [greater_eq(k, three)], domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -277,7 +277,7 @@
     "        Equals(\n",
     "            EulerianCircuits(G),\n",
     "            Circuits(Size(G), G) ),\n",
-    "    domain = Graphs())\n",
+    "    domain = Graphs)\n",
     ")"
    ]
   },
@@ -304,7 +304,7 @@
     "                                   Paths(subtract(k, one), G))],\n",
     "               domain = Circuits(k, G))),\n",
     "    conditions = [greater_eq(k, three)], domain = Natural),\n",
-    "    domain = Graphs())\n",
+    "    domain = Graphs)\n",
     ")"
    ]
   },
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
index 9266d380e2e9..c73b5b6a4bfc 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
@@ -330,7 +330,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "EndVertices(W).definition(assumptions = [InClass(G, Graphs()), InSet(WalkLength(W), Natural), InSet(W, Walks(WalkLength(W), G))])"
+    "EndVertices(W).definition(assumptions = [InClass(G, Graphs), InSet(WalkLength(W), Natural), InSet(W, Walks(WalkLength(W), G))])"
    ]
   },
   {
@@ -396,7 +396,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(W, Walks(k, G)).deduce_in_bool(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+    "InSet(W, Walks(k, G)).deduce_in_bool(assumptions = [InClass(G, Graphs), InSet(k, Natural)])"
    ]
   },
   {
@@ -405,7 +405,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(W, Walks(k, G)).definition(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+    "InSet(W, Walks(k, G)).definition(assumptions = [InClass(G, Graphs), InSet(k, Natural)])"
    ]
   },
   {
@@ -423,7 +423,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(W, Walks(k, G)).element_length_derivation(assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(W, Walks(k, G))])"
+    "InSet(W, Walks(k, G)).element_length_derivation(assumptions = [InClass(G, Graphs), InSet(k, Natural), InSet(W, Walks(k, G))])"
    ]
   },
   {
@@ -432,7 +432,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(W, Walks(k, G)).unfold(assumptions = [InSet(W, Walks(k, G)), InClass(G, Graphs()), InSet(k, Natural)])"
+    "InSet(W, Walks(k, G)).unfold(assumptions = [InSet(W, Walks(k, G)), InClass(G, Graphs), InSet(k, Natural)])"
    ]
   },
   {
@@ -442,7 +442,7 @@
    "outputs": [],
    "source": [
     "InSet(W, Walks(k, G)).conclude(\n",
-    "    assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "    assumptions = [InClass(G, Graphs), InSet(k, Natural),\n",
     "                   InSet(W, SetOfAll(S, S,\n",
     "                            conditions = [\n",
     "                                Forall(i, AdjacentVertices(Function(S, i), Function(S, Add(i, one)), G),\n",
@@ -457,7 +457,7 @@
    "outputs": [],
    "source": [
     "InSet(W, Walks(k, G)).conclude(\n",
-    "    assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "    assumptions = [InClass(G, Graphs), InSet(k, Natural),\n",
     "                   InSet(W, Functions(Interval(zero, k), Vertices(G))),\n",
     "                   Forall(i, AdjacentVertices(Function(W, i), Function(W, Add(i, one)), G),\n",
     "                                       domain = Interval(zero, subtract(k, one)))])"
@@ -485,7 +485,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(W, ClosedWalks(k, G)).deduce_in_bool(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+    "InSet(W, ClosedWalks(k, G)).deduce_in_bool(assumptions = [InClass(G, Graphs), InSet(k, Natural)])"
    ]
   },
   {
@@ -494,7 +494,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(W, ClosedWalks(k, G)).definition(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+    "InSet(W, ClosedWalks(k, G)).definition(assumptions = [InClass(G, Graphs), InSet(k, Natural)])"
    ]
   },
   {
@@ -513,7 +513,7 @@
    "outputs": [],
    "source": [
     "InSet(W, ClosedWalks(k, G)).unfold(\n",
-    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(W, ClosedWalks(k, G))])"
+    "        assumptions = [InClass(G, Graphs), InSet(k, Natural), InSet(W, ClosedWalks(k, G))])"
    ]
   },
   {
@@ -523,7 +523,7 @@
    "outputs": [],
    "source": [
     "InSet(W, ClosedWalks(k, G)).conclude(\n",
-    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "        assumptions = [InClass(G, Graphs), InSet(k, Natural),\n",
     "                       InSet(W, SetOfAll(S, S, conditions = [Equals(BeginningVertex(S), EndingVertex(S))],\n",
     "                                domain = Walks(k, G)))])"
    ]
@@ -535,7 +535,7 @@
    "outputs": [],
    "source": [
     "InSet(W, ClosedWalks(k, G)).derive_element_in_walks(\n",
-    "    assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(W, ClosedWalks(k, G))])"
+    "    assumptions = [InClass(G, Graphs), InSet(k, Natural), InSet(W, ClosedWalks(k, G))])"
    ]
   },
   {
@@ -560,7 +560,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(T, Trails(k, G)).deduce_in_bool(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+    "InSet(T, Trails(k, G)).deduce_in_bool(assumptions = [InClass(G, Graphs), InSet(k, Natural)])"
    ]
   },
   {
@@ -569,7 +569,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(T, Trails(k, G)).definition(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+    "InSet(T, Trails(k, G)).definition(assumptions = [InClass(G, Graphs), InSet(k, Natural)])"
    ]
   },
   {
@@ -587,7 +587,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(T, Trails(k, G)).unfold(assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(T, Trails(k, G))])"
+    "InSet(T, Trails(k, G)).unfold(assumptions = [InClass(G, Graphs), InSet(k, Natural), InSet(T, Trails(k, G))])"
    ]
   },
   {
@@ -597,7 +597,7 @@
    "outputs": [],
    "source": [
     "InSet(T, Trails(k, G)).conclude(\n",
-    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "        assumptions = [InClass(G, Graphs), InSet(k, Natural),\n",
     "                       InSet(T, SetOfAll(W, W, conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
     "                                        domain = Walks(k, G)))])"
    ]
@@ -610,7 +610,7 @@
    "source": [
     "InSet(T, Trails(k, G)).conclude(\n",
     "        assumptions = [\n",
-    "            InClass(G, Graphs()), InSet(k, Natural),\n",
+    "            InClass(G, Graphs), InSet(k, Natural),\n",
     "            And(InSet(T, Walks(k, G)),\n",
     "            InSet(EdgeSequence(T), Injections(Interval(zero, subtract(k, one)), Edges(G))))])"
    ]
@@ -622,7 +622,7 @@
    "outputs": [],
    "source": [
     "InSet(T, Trails(k, G)).derive_element_in_walks(\n",
-    "    assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(T, Trails(k, G))])"
+    "    assumptions = [InClass(G, Graphs), InSet(k, Natural), InSet(T, Trails(k, G))])"
    ]
   },
   {
@@ -647,7 +647,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(T, ClosedTrails(k, G)).deduce_in_bool(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+    "InSet(T, ClosedTrails(k, G)).deduce_in_bool(assumptions = [InClass(G, Graphs), InSet(k, Natural)])"
    ]
   },
   {
@@ -656,7 +656,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(T, ClosedTrails(k, G)).definition(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+    "InSet(T, ClosedTrails(k, G)).definition(assumptions = [InClass(G, Graphs), InSet(k, Natural)])"
    ]
   },
   {
@@ -674,7 +674,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(T, ClosedTrails(k, G)).unfold(assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(T, ClosedTrails(k, G))])"
+    "InSet(T, ClosedTrails(k, G)).unfold(assumptions = [InClass(G, Graphs), InSet(k, Natural), InSet(T, ClosedTrails(k, G))])"
    ]
   },
   {
@@ -684,7 +684,7 @@
    "outputs": [],
    "source": [
     "InSet(T, ClosedTrails(k, G)).conclude(\n",
-    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "        assumptions = [InClass(G, Graphs), InSet(k, Natural),\n",
     "                       InSet(T, SetOfAll(W, W, conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
     "                                        domain = ClosedWalks(k, G)))])"
    ]
@@ -697,7 +697,7 @@
    "source": [
     "InSet(T, ClosedTrails(k, G)).conclude(\n",
     "        assumptions = [\n",
-    "            InClass(G, Graphs()), InSet(k, Natural),\n",
+    "            InClass(G, Graphs), InSet(k, Natural),\n",
     "            And(InSet(T, ClosedWalks(k, G)),\n",
     "            InSet(EdgeSequence(T), Injections(Interval(zero, subtract(k, one)), Edges(G))))])"
    ]
@@ -709,7 +709,7 @@
    "outputs": [],
    "source": [
     "InSet(T, ClosedTrails(k, G)).derive_element_in_closed_walks(\n",
-    "    assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(T, ClosedTrails(k, G))])"
+    "    assumptions = [InClass(G, Graphs), InSet(k, Natural), InSet(T, ClosedTrails(k, G))])"
    ]
   },
   {
@@ -719,7 +719,7 @@
    "outputs": [],
    "source": [
     "InSet(T, Walks(k, G)).prove(\n",
-    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(T, ClosedTrails(k, G))]\n",
+    "        assumptions = [InClass(G, Graphs), InSet(k, Natural), InSet(T, ClosedTrails(k, G))]\n",
     ")"
    ]
   },
@@ -745,7 +745,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(P, Paths(k, G)).deduce_in_bool(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+    "InSet(P, Paths(k, G)).deduce_in_bool(assumptions = [InClass(G, Graphs), InSet(k, Natural)])"
    ]
   },
   {
@@ -754,7 +754,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(P, Paths(k, G)).definition(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+    "InSet(P, Paths(k, G)).definition(assumptions = [InClass(G, Graphs), InSet(k, Natural)])"
    ]
   },
   {
@@ -772,7 +772,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(P, Paths(k, G)).unfold(assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(P, Paths(k, G))])"
+    "InSet(P, Paths(k, G)).unfold(assumptions = [InClass(G, Graphs), InSet(k, Natural), InSet(P, Paths(k, G))])"
    ]
   },
   {
@@ -791,7 +791,7 @@
    "outputs": [],
    "source": [
     "InSet(P, Paths(k, G)).conclude(\n",
-    "    assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "    assumptions = [InClass(G, Graphs), InSet(k, Natural),\n",
     "                   InSet(P, Walks(k, G)), InSet(P, Injections(Interval(zero, k), Vertices(G)))])"
    ]
   },
@@ -802,7 +802,7 @@
    "outputs": [],
    "source": [
     "InSet(P, Paths(k, G)).conclude(\n",
-    "    assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "    assumptions = [InClass(G, Graphs), InSet(k, Natural),\n",
     "                   InSet(P, SetOfAll(W, W, conditions =[InSet(W, Injections(Interval(zero, k), Vertices(G)))],\n",
     "                                     domain = Walks(k, G)))])"
    ]
@@ -814,7 +814,7 @@
    "outputs": [],
    "source": [
     "InSet(P, Paths(k, G)).derive_element_in_trails(\n",
-    "    assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(P, Paths(k, G))])"
+    "    assumptions = [InClass(G, Graphs), InSet(k, Natural), InSet(P, Paths(k, G))])"
    ]
   },
   {
@@ -831,7 +831,7 @@
    "outputs": [],
    "source": [
     "InSet(P, Walks(k, G)).prove(\n",
-    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural), InSet(P, Paths(k, G))]\n",
+    "        assumptions = [InClass(G, Graphs), InSet(k, Natural), InSet(P, Paths(k, G))]\n",
     ")"
    ]
   },
@@ -857,7 +857,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(C, Circuits(k, G)).deduce_in_bool(assumptions = [InClass(G, Graphs()), InSet(k, Natural)])"
+    "InSet(C, Circuits(k, G)).deduce_in_bool(assumptions = [InClass(G, Graphs), InSet(k, Natural)])"
    ]
   },
   {
@@ -867,7 +867,7 @@
    "outputs": [],
    "source": [
     "InSet(C, Circuits(k, G)).definition(\n",
-    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural), greater_eq(k, three)])"
+    "        assumptions = [InClass(G, Graphs), InSet(k, Natural), greater_eq(k, three)])"
    ]
   },
   {
@@ -886,7 +886,7 @@
    "outputs": [],
    "source": [
     "InSet(C, Circuits(k, G)).unfold(\n",
-    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "        assumptions = [InClass(G, Graphs), InSet(k, Natural),\n",
     "                       greater_eq(k, three), InSet(C, Circuits(k, G))])"
    ]
   },
@@ -897,7 +897,7 @@
    "outputs": [],
    "source": [
     "InSet(C, Circuits(k, G)).conclude(\n",
-    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "        assumptions = [InClass(G, Graphs), InSet(k, Natural),\n",
     "                       greater_eq(k, three), InSet(C, ClosedTrails(k, G))])"
    ]
   },
@@ -908,7 +908,7 @@
    "outputs": [],
    "source": [
     "InSet(C, Circuits(k, G)).derive_element_in_closed_trails(\n",
-    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "        assumptions = [InClass(G, Graphs), InSet(k, Natural),\n",
     "                       greater_eq(k, three), InSet(C, Circuits(k, G))]\n",
     ")"
    ]
@@ -920,7 +920,7 @@
    "outputs": [],
    "source": [
     "InSet(C, Walks(k, G)).prove(\n",
-    "        assumptions = [InClass(G, Graphs()), InSet(k, Natural),\n",
+    "        assumptions = [InClass(G, Graphs), InSet(k, Natural),\n",
     "                       greater_eq(k, three), InSet(C, Circuits(k, G))])"
    ]
   },
@@ -946,7 +946,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(C, EulerianCircuits(G)).deduce_in_bool(assumptions = [InClass(G, Graphs())])"
+    "InSet(C, EulerianCircuits(G)).deduce_in_bool(assumptions = [InClass(G, Graphs)])"
    ]
   },
   {
@@ -955,7 +955,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(C, EulerianCircuits(G)).definition(assumptions = [InClass(G, Graphs())])"
+    "InSet(C, EulerianCircuits(G)).definition(assumptions = [InClass(G, Graphs)])"
    ]
   },
   {
@@ -973,7 +973,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(C, EulerianCircuits(G)).unfold(assumptions = [InClass(G, Graphs()), InSet(C, EulerianCircuits(G))])"
+    "InSet(C, EulerianCircuits(G)).unfold(assumptions = [InClass(G, Graphs), InSet(C, EulerianCircuits(G))])"
    ]
   },
   {
@@ -982,7 +982,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "InSet(C, EulerianCircuits(G)).conclude(assumptions = [InClass(G, Graphs()), InSet(C, Circuits(Size(G), G))])"
+    "InSet(C, EulerianCircuits(G)).conclude(assumptions = [InClass(G, Graphs), InSet(C, Circuits(Size(G), G))])"
    ]
   },
   {
@@ -992,7 +992,7 @@
    "outputs": [],
    "source": [
     "InSet(C, EulerianCircuits(G)).derive_element_in_closed_walks(\n",
-    "        assumptions = [InClass(G, Graphs()), InSet(C, EulerianCircuits(G))]\n",
+    "        assumptions = [InClass(G, Graphs), InSet(C, EulerianCircuits(G))]\n",
     ")"
    ]
   },
@@ -1021,7 +1021,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "type(Graphs())"
+    "type(Graphs)"
    ]
   },
   {
@@ -1039,7 +1039,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "# Size(G).derive_size_in_natural(assumptions = [InClass(G, Graphs())])"
+    "# Size(G).derive_size_in_natural(assumptions = [InClass(G, Graphs)])"
    ]
   },
   {
@@ -1049,7 +1049,7 @@
    "outputs": [],
    "source": [
     "InSet(C, Walks(Size(G), G)).prove(\n",
-    "        assumptions = [InClass(G, Graphs()), InSet(Size(G), Natural), InSet(C, EulerianCircuits(G))]\n",
+    "        assumptions = [InClass(G, Graphs), InSet(Size(G), Natural), InSet(C, EulerianCircuits(G))]\n",
     ")"
    ]
   },
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
index a8cd85a333fd..6af8b9c88110 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
@@ -60,7 +60,7 @@
     "             conditions = [Forall(i, AdjacentVertices(Function(S, i), Function(S, Add(i, one)), G),\n",
     "                                  domain = Interval(zero, subtract(k, one)))],\n",
     "             domain = Functions(Interval(zero, k), Vertices(G))))\n",
-    "    )), domain = Natural), domain = Graphs())\n",
+    "    )), domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -77,7 +77,7 @@
     "              conditions = [Forall(i, AdjacentVertices(Function(S, i), Function(S, Add(i, one)), G),\n",
     "                                  domain = Interval(zero, subtract(k, one)))],\n",
     "          domain = Functions(Interval(zero, k), Vertices(G)))),\n",
-    "    conditions = [InSet(W, Walks(k, G))]), domain = Natural), domain = Graphs())\n",
+    "    conditions = [InSet(W, Walks(k, G))]), domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -94,7 +94,7 @@
     "          SetOfAll(S, S,\n",
     "              conditions = [Forall(i, AdjacentVertices(Function(S, i), Function(S, Add(i, one)), G),\n",
     "                                  domain = Interval(zero, subtract(k, one)))],\n",
-    "          domain = Functions(Interval(zero, k), Vertices(G))))]), domain = Natural), domain = Graphs())\n",
+    "          domain = Functions(Interval(zero, k), Vertices(G))))]), domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -108,7 +108,7 @@
     "    Forall(G, Forall(k, Forall(W,\n",
     "    And(InSet(W, Functions(Interval(zero, k), Vertices(G))),\n",
     "        Forall(i, AdjacentVertices(Function(W, i), Function(W, Add(i, one)), G), domain = Interval(zero, subtract(k, one)))),\n",
-    "    conditions = [InSet(W, Walks(k, G))]), domain = Natural), domain = Graphs())\n",
+    "    conditions = [InSet(W, Walks(k, G))]), domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -124,7 +124,7 @@
     "    conditions = [Forall(i, AdjacentVertices(Function(W, i), Function(W, Add(i, one)), G),\n",
     "        domain = Interval(zero, subtract(k, one)))],\n",
     "    domain = Functions(Interval(zero, k), Vertices(G))),\n",
-    "    domain = Natural), domain = Graphs())\n",
+    "    domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -141,7 +141,7 @@
     "        Equals(WalkLength(W), k),\n",
     "    domain = Walks(k, G)),\n",
     "    domain = Natural),\n",
-    "    domain = Graphs())\n",
+    "    domain = Graphs)\n",
     ")"
    ]
   },
@@ -167,7 +167,7 @@
     "         S,\n",
     "         conditions = [Equals(BeginningVertex(S), EndingVertex(S))],\n",
     "         domain = Walks(k, G)))\n",
-    ")), domain = Natural), domain = Graphs())\n",
+    ")), domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -184,7 +184,7 @@
     "               S,\n",
     "               conditions = [Equals(BeginningVertex(S), EndingVertex(S))],\n",
     "               domain = Walks(k, G))),\n",
-    "domain = ClosedWalks(k, G)), domain = Natural), domain = Graphs())\n",
+    "domain = ClosedWalks(k, G)), domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -200,7 +200,7 @@
     "    domain = SetOfAll(S, S,\n",
     "                  conditions = [Equals(BeginningVertex(S), EndingVertex(S))],\n",
     "                  domain = Walks(k, G))),\n",
-    "domain = Natural), domain = Graphs())\n",
+    "domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -226,7 +226,7 @@
     "                 W,\n",
     "                 conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
     "                 domain = Walks(k, G) ))\n",
-    "    )), domain = Natural), domain = Graphs())\n",
+    "    )), domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -243,7 +243,7 @@
     "        W,\n",
     "        conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
     "        domain = Walks(k, G) )),\n",
-    "    domain = Trails(k, G)), domain = Natural), domain = Graphs())\n",
+    "    domain = Trails(k, G)), domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -260,7 +260,7 @@
     "    domain = SetOfAll(W,\n",
     "        W,\n",
     "        conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
-    "        domain = Walks(k, G) )), domain = Natural), domain = Graphs())\n",
+    "        domain = Walks(k, G) )), domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -274,7 +274,7 @@
     "    Forall(G, Forall(k, Forall(T,\n",
     "    And(InSet(T, Walks(k, G)),\n",
     "        InSet(EdgeSequence(T), Injections(Interval(zero, subtract(k, one)), Edges(G)))),\n",
-    "    domain = Trails(k, G)), domain = Natural), domain = Graphs())\n",
+    "    domain = Trails(k, G)), domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -288,7 +288,7 @@
     "    Forall(G, Forall(k, Forall(W,\n",
     "    InSet(W, Trails(k, G)),\n",
     "    conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
-    "    domain = Walks(k, G)), domain = Natural), domain = Graphs())\n",
+    "    domain = Walks(k, G)), domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -314,7 +314,7 @@
     "                 W,\n",
     "                 conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
     "                 domain = ClosedWalks(k, G) ))\n",
-    "    )), domain = Natural), domain = Graphs())\n",
+    "    )), domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -331,7 +331,7 @@
     "        W,\n",
     "        conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
     "        domain = ClosedWalks(k, G) )),\n",
-    "    domain = ClosedTrails(k, G)), domain = Natural), domain = Graphs())\n",
+    "    domain = ClosedTrails(k, G)), domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -348,7 +348,7 @@
     "    domain = SetOfAll(W,\n",
     "        W,\n",
     "        conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
-    "        domain = ClosedWalks(k, G) )), domain = Natural), domain = Graphs())\n",
+    "        domain = ClosedWalks(k, G) )), domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -362,7 +362,7 @@
     "    Forall(G, Forall(k, Forall(T,\n",
     "    And(InSet(T, ClosedWalks(k, G)),\n",
     "        InSet(EdgeSequence(T), Injections(Interval(zero, subtract(k, one)), Edges(G)))),\n",
-    "    domain = ClosedTrails(k, G)), domain = Natural), domain = Graphs())\n",
+    "    domain = ClosedTrails(k, G)), domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -376,7 +376,7 @@
     "    Forall(G, Forall(k, Forall(W,\n",
     "    InSet(W, ClosedTrails(k, G)),\n",
     "    conditions = [InSet(EdgeSequence(W), Injections(Interval(zero, subtract(k, one)), Edges(G)))],\n",
-    "    domain = ClosedWalks(k, G)), domain = Natural), domain = Graphs())\n",
+    "    domain = ClosedWalks(k, G)), domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -402,7 +402,7 @@
     "             W,\n",
     "             conditions = [InSet(W, Injections(Interval(zero, k), Vertices(G)))],\n",
     "             domain = Walks(k, G)))\n",
-    "    )), domain = Natural), domain = Graphs())\n",
+    "    )), domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -420,7 +420,7 @@
     "             conditions = [InSet(W, Injections(Interval(zero, k), Vertices(G)))],\n",
     "             domain = Walks(k, G))),\n",
     "    conditions = [InSet(P, Paths(k, G))]),\n",
-    "    domain = Natural), domain = Graphs())\n",
+    "    domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -436,7 +436,7 @@
     "        domain = SetOfAll(W, W,\n",
     "             conditions = [InSet(W, Injections(Interval(zero, k), Vertices(G)))],\n",
     "             domain = Walks(k, G))),\n",
-    "    domain = Natural), domain = Graphs())\n",
+    "    domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -451,7 +451,7 @@
     "        And(InSet(P, Walks(k, G)),\n",
     "        InSet(P, Injections(Interval(zero, k), Vertices(G)))),\n",
     "    conditions = [InSet(P, Paths(k, G))]),\n",
-    "    domain = Natural), domain = Graphs())\n",
+    "    domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -465,7 +465,7 @@
     "    Forall(G, Forall(k, Forall(W,\n",
     "        InSet(W, Paths(k, G)),\n",
     "    conditions = [InSet(W, Injections(Interval(zero, k), Vertices(G)))], domain = Walks(k, G)),\n",
-    "    domain = Natural), domain = Graphs())\n",
+    "    domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -487,7 +487,7 @@
     "    Equals(\n",
     "        InSet(C, Circuits(k, G)),\n",
     "        InSet(C, ClosedTrails(k, G))\n",
-    "    )), conditions = [greater_eq(k, three)], domain = Natural), domain = Graphs())\n",
+    "    )), conditions = [greater_eq(k, three)], domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -500,7 +500,7 @@
     "circuits_membership_unfolding = (\n",
     "    Forall(G, Forall(k, Forall(C,\n",
     "        InSet(C, ClosedTrails(k, G)),\n",
-    "        domain = Circuits(k, G)), conditions = [greater_eq(k, three)], domain = Natural), domain = Graphs())\n",
+    "        domain = Circuits(k, G)), conditions = [greater_eq(k, three)], domain = Natural), domain = Graphs)\n",
     ")"
    ]
   },
@@ -515,7 +515,7 @@
     "        InSet(C, Circuits(k, G)),\n",
     "        domain = ClosedTrails(k, G)),\n",
     "    conditions = [greater_eq(k, three)], domain = Natural),\n",
-    "    domain = Graphs())\n",
+    "    domain = Graphs)\n",
     ")"
    ]
   },
@@ -546,7 +546,7 @@
     "    Equals(\n",
     "        InSet(C, EulerianCircuits(G)),\n",
     "        InSet(C, Circuits(Size(G), G))\n",
-    "    )), domain = Graphs())\n",
+    "    )), domain = Graphs)\n",
     ")"
    ]
   },
@@ -559,7 +559,7 @@
     "eulerian_circuits_membership_unfolding = (\n",
     "    Forall(G, Forall(C,\n",
     "    InSet(C, Circuits(Size(G), G)\n",
-    "    ), domain = EulerianCircuits(G)), domain = Graphs())\n",
+    "    ), domain = EulerianCircuits(G)), domain = Graphs)\n",
     ")"
    ]
   },
@@ -572,7 +572,7 @@
     "eulerian_circuits_membership_folding = (\n",
     "    Forall(G, Forall(C,\n",
     "    InSet(C, EulerianCircuits(G)\n",
-    "    ), domain = Circuits(Size(G), G)), domain = Graphs())\n",
+    "    ), domain = Circuits(Size(G), G)), domain = Graphs)\n",
     ")"
    ]
   },
@@ -597,7 +597,7 @@
     "conditions = [Equals(EndVertices(W), Set(u, v))],\n",
     "domains = [Natural, Walks(j, G)]),\n",
     "domain = Vertices(G)),\n",
-    "domain = Graphs())"
+    "domain = Graphs)"
    ]
   },
   {
@@ -618,7 +618,7 @@
     "    Forall(k,\n",
     "        SubsetEq(ClosedWalks(k, G), Walks(k, G)),\n",
     "    domain = Natural),\n",
-    "    domain = Graphs())\n",
+    "    domain = Graphs)\n",
     ")"
    ]
   },
@@ -633,7 +633,7 @@
     "    Forall(k,\n",
     "        SubsetEq(Trails(k, G), Walks(k, G)),\n",
     "    domain = Natural),\n",
-    "    domain = Graphs())\n",
+    "    domain = Graphs)\n",
     ")"
    ]
   },
@@ -648,7 +648,7 @@
     "    Forall(k,\n",
     "        SubsetEq(ClosedTrails(k, G), ClosedWalks(k, G)),\n",
     "    domain = Natural),\n",
-    "    domain = Graphs())\n",
+    "    domain = Graphs)\n",
     ")"
    ]
   },
@@ -663,7 +663,7 @@
     "    Forall(k,\n",
     "        SubsetEq(Paths(k, G), Trails(k, G)),\n",
     "    domain = Natural),\n",
-    "    domain = Graphs())\n",
+    "    domain = Graphs)\n",
     ")"
    ]
   },
@@ -679,7 +679,7 @@
     "    SubsetEq(Circuits(k, G), ClosedTrails(k, G)),\n",
     "    conditions = [greater_eq(k, three)],\n",
     "domain = Natural),\n",
-    "domain = Graphs())\n",
+    "domain = Graphs)\n",
     ")"
    ]
   },
@@ -692,7 +692,7 @@
     "eulerian_circuits_within_closed_walks = (\n",
     "Forall(G,\n",
     "    SubsetEq(EulerianCircuits(G), ClosedWalks(Size(G), G)),\n",
-    "domain = Graphs())\n",
+    "domain = Graphs)\n",
     ")"
    ]
   },
@@ -713,7 +713,7 @@
     "Forall(k,\n",
     "Forall(W, in_bool(InSet(W, Walks(k, G)))),\n",
     "domain = Natural),\n",
-    "domain = Graphs()\n",
+    "domain = Graphs\n",
     ")"
    ]
   },
@@ -727,7 +727,7 @@
     "Forall(k,\n",
     "Forall(W, in_bool(InSet(W, ClosedWalks(k, G)))),\n",
     "domain = Natural),\n",
-    "domain = Graphs()\n",
+    "domain = Graphs\n",
     ")"
    ]
   },
@@ -741,7 +741,7 @@
     "Forall(k,\n",
     "Forall(T, in_bool(InSet(T, Trails(k, G)))),\n",
     "domain = Natural),\n",
-    "domain = Graphs()\n",
+    "domain = Graphs\n",
     ")"
    ]
   },
@@ -755,7 +755,7 @@
     "Forall(k,\n",
     "Forall(T, in_bool(InSet(T, ClosedTrails(k, G)))),\n",
     "domain = Natural),\n",
-    "domain = Graphs()\n",
+    "domain = Graphs\n",
     ")"
    ]
   },
@@ -769,7 +769,7 @@
     "Forall(k,\n",
     "Forall(P, in_bool(InSet(P, Paths(k, G)))),\n",
     "domain = Natural),\n",
-    "domain = Graphs()\n",
+    "domain = Graphs\n",
     ")"
    ]
   },
@@ -783,7 +783,7 @@
     "Forall(k,\n",
     "Forall(C, in_bool(InSet(C, Circuits(k, G)))),\n",
     "domain = Natural),\n",
-    "domain = Graphs()\n",
+    "domain = Graphs\n",
     ")"
    ]
   },
@@ -795,7 +795,7 @@
    "source": [
     "eulerian_circuits_membership_is_bool = Forall(G,\n",
     "Forall(C, in_bool(InSet(C, EulerianCircuits(G)))),\n",
-    "domain = Graphs()\n",
+    "domain = Graphs\n",
     ")"
    ]
   },

From 7ab82f48a1fb57c2a9682ddba3eb41f5dd265182 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sat, 19 Jul 2025 14:48:58 -0600
Subject: [PATCH 153/159] Correct typo in CyclesMembership() call

Correct a typo in call of CyclesMembership().
---
 packages/proveit/graphs/walks/walks.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/proveit/graphs/walks/walks.py b/packages/proveit/graphs/walks/walks.py
index 6bebc495faae..848293b6c9d8 100644
--- a/packages/proveit/graphs/walks/walks.py
+++ b/packages/proveit/graphs/walks/walks.py
@@ -280,7 +280,7 @@ def __init__(self, k, G, *, styles=None):
 
     def membership_object(self, element):
         from .walks_membership import CyclesMembership
-        return CyclessMembership(element, self)
+        return CyclesMembership(element, self)
 
 #     def nonmembership_object(self, element):
 #         from .walks_membership import CyclesNonmembership

From 4c3912b89eea877de2c9212a5603621a8177c1a6 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sat, 19 Jul 2025 14:52:07 -0600
Subject: [PATCH 154/159] Establish CyclesMembership() class

Establish the CyclesMembership() class along with related theorems and methods, including theorems cycles_membership_def, cycles_membership_unfolding, etc.
---
 .../graphs/walks/_theory_nbs_/common.ipynb    |  44 ++++-
 .../thm_proof.ipynb                           |  47 ++++++
 .../cycles_membership_def/thm_proof.ipynb     |  47 ++++++
 .../cycles_membership_folding/thm_proof.ipynb |  47 ++++++
 .../cycles_membership_is_bool/thm_proof.ipynb |  47 ++++++
 .../thm_proof.ipynb                           |  47 ++++++
 .../cycles_within_circuits/thm_proof.ipynb    |  47 ++++++
 .../graphs/walks/_theory_nbs_/theorems.ipynb  | 159 +++++++++++++++++-
 .../proveit/graphs/walks/walks_membership.py  | 112 +++++++++++-
 9 files changed, 587 insertions(+), 10 deletions(-)
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/circuit_partitions_into_cycles/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_membership_def/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_membership_folding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_membership_is_bool/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_membership_unfolding/thm_proof.ipynb
 create mode 100644 packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_within_circuits/thm_proof.ipynb

diff --git a/packages/proveit/graphs/walks/_theory_nbs_/common.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/common.ipynb
index 22e8ac141800..3e822a6f5d42 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/common.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/common.ipynb
@@ -18,7 +18,9 @@
     "# Prepare this notebook for defining the common expressions of a theory:\n",
     "%common_expressions_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "# from ... import ..."
+    "from proveit import e, i, k, n, C, G, W, ExprTuple, ExprRange, IndexedVar\n",
+    "from proveit.numbers import one\n",
+    "from proveit.graphs import Cycles, EdgeSet"
    ]
   },
   {
@@ -35,7 +37,45 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "C_1_to_n = ExprTuple(ExprRange(i, IndexedVar(C, i), one, n))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "W_1_to_n = ExprTuple(ExprRange(i, IndexedVar(W, i), one, n))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "EdgeSet_W_1_to_n = ExprTuple(ExprRange(i, EdgeSet(IndexedVar(W, i)), one, n))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "e_1_to_n = ExprRange(i, IndexedVar(e, i), one, n)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Cycles_e_1_to_n = ExprTuple(ExprRange(i, Cycles(IndexedVar(e, i), G), one, n))"
+   ]
   },
   {
    "cell_type": "code",
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/circuit_partitions_into_cycles/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/circuit_partitions_into_cycles/thm_proof.ipynb
new file mode 100644
index 000000000000..60f184ce019c
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/circuit_partitions_into_cycles/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#circuit_partitions_into_cycles\">circuit_partitions_into_cycles</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving circuit_partitions_into_cycles"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_membership_def/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_membership_def/thm_proof.ipynb
new file mode 100644
index 000000000000..6e43be9a74f7
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_membership_def/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#cycles_membership_def\">cycles_membership_def</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving cycles_membership_def"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_membership_folding/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_membership_folding/thm_proof.ipynb
new file mode 100644
index 000000000000..483faf8c1a98
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_membership_folding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#cycles_membership_folding\">cycles_membership_folding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving cycles_membership_folding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_membership_is_bool/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_membership_is_bool/thm_proof.ipynb
new file mode 100644
index 000000000000..1456e0eb57d2
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_membership_is_bool/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#cycles_membership_is_bool\">cycles_membership_is_bool</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving cycles_membership_is_bool"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_membership_unfolding/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_membership_unfolding/thm_proof.ipynb
new file mode 100644
index 000000000000..6de35181d787
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_membership_unfolding/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#cycles_membership_unfolding\">cycles_membership_unfolding</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving cycles_membership_unfolding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_within_circuits/thm_proof.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_within_circuits/thm_proof.ipynb
new file mode 100644
index 000000000000..65f5da0e2b6b
--- /dev/null
+++ b/packages/proveit/graphs/walks/_theory_nbs_/proofs/cycles_within_circuits/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">walks</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#cycles_within_circuits\">cycles_within_circuits</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving cycles_within_circuits"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
index 6af8b9c88110..e49d5ea2c5cc 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/theorems.ipynb
@@ -18,14 +18,17 @@
     "# Prepare this notebook for defining the theorems of a theory:\n",
     "%theorems_notebook # Keep this at the top following 'import proveit'.\n",
     "\n",
-    "from proveit import i, j, k, u, v, C, G, P, S, T, W, Function\n",
+    "from proveit import i, j, k, n, u, v, C, G, P, S, T, W, Function\n",
     "from proveit.logic import And, Equals, Exists, Forall, in_bool\n",
-    "from proveit.logic.sets import Functions, Injections, InSet, Set, SetOfAll, SubsetEq\n",
+    "from proveit.logic.sets import (Disjoint, Functions, Injections, InSet,\n",
+    "        Set, SetOfAll, SubsetEq, Union)\n",
     "from proveit.numbers import (zero, one, three, Add, greater_eq,\n",
-    "        Interval, LessEq, Natural, subtract)\n",
+    "        Interval, LessEq, Natural, NaturalPos, subtract)\n",
     "from proveit.graphs import (AdjacentVertices, BeginningVertex, Circuits,\n",
-    "        ClosedTrails, ClosedWalks, Edges, EdgeSequence, EndingVertex,\n",
-    "        EndVertices, Graphs, Paths, Trails, Vertices, WalkLength, Walks) \n"
+    "        ClosedTrails, ClosedWalks, Edges, EdgeSet, EdgeSequence, EndingVertex,\n",
+    "        EndVertices, Graphs, Paths, Trails, Vertices, WalkLength, Walks)\n",
+    "# some convenient common expressions:\n",
+    "from proveit.graphs.walks import W_1_to_n, e_1_to_n, EdgeSet_W_1_to_n, Cycles_e_1_to_n"
    ]
   },
   {
@@ -580,7 +583,94 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "#### The existence of a $u$-$v$ walk implies the existence of a $u$-$v$ path:"
+    "#### CycesMembership($k$, $G$)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from proveit.logic.sets import Restriction\n",
+    "from proveit.graphs import Cycles"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "cycles_membership_def = (\n",
+    "    Forall(G, Forall(k, Forall(C,\n",
+    "    Equals(\n",
+    "        InSet(C, Cycles(k, G)),\n",
+    "        InSet(C, SetOfAll(W, W,\n",
+    "               conditions = [InSet(Restriction(W, Interval(zero, subtract(k, one))),\n",
+    "                                   Paths(subtract(k, one), G))],\n",
+    "               domain = Circuits(k, G)))\n",
+    "    )), conditions = [greater_eq(k, three)], domain = Natural), domain = Graphs)\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "cycles_membership_unfolding = (\n",
+    "    Forall(G, Forall(k, Forall(C,\n",
+    "    InSet(C, SetOfAll(W, W,\n",
+    "             conditions = [InSet(Restriction(W, Interval(zero, subtract(k, one))),\n",
+    "                                   Paths(subtract(k, one), G))],\n",
+    "             domain = Circuits(k, G))),\n",
+    "    domain = Cycles(k, G)),\n",
+    "    conditions = [greater_eq(k, three)],\n",
+    "    domain = Natural),\n",
+    "    domain = Graphs)\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "cycles_membership_folding = (\n",
+    "    Forall(G, Forall(k, Forall(C,\n",
+    "    InSet(C, Cycles(k, G)),\n",
+    "    domain = SetOfAll(W, W,\n",
+    "             conditions = [InSet(Restriction(W, Interval(zero, subtract(k, one))),\n",
+    "                                   Paths(subtract(k, one), G))],\n",
+    "             domain = Circuits(k, G))),\n",
+    "    conditions = [greater_eq(k, three)],\n",
+    "    domain = Natural),\n",
+    "    domain = Graphs)\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### General Theorems Involving Walks, Trails, Paths, Circuits, & Cycles"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "##### The existence of a $u$-$v$ walk implies the existence of a $u$-$v$ path:"
    ]
   },
   {
@@ -600,6 +690,36 @@
     "domain = Graphs)"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "##### Every circuit can be partitioned into a collection of edge-disjoint cycles:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "circuit_partitions_into_cycles = (\n",
+    "Forall(G,\n",
+    "Forall(k,\n",
+    "Forall(C,\n",
+    "    Exists(n,\n",
+    "    Exists(e_1_to_n,\n",
+    "    Exists(W_1_to_n,\n",
+    "    And(Equals(EdgeSet(C), Union(*EdgeSet_W_1_to_n)), Disjoint(*EdgeSet_W_1_to_n)).with_wrapping_at(1),\n",
+    "    domains = [*Cycles_e_1_to_n]),\n",
+    "    domain  = NaturalPos),\n",
+    "    domain = NaturalPos),\n",
+    "domain = Circuits(k, G)),\n",
+    "domain = Natural),\n",
+    "domain = Graphs)\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -696,6 +816,20 @@
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "cycles_within_circuits = (\n",
+    "    Forall(G, Forall(k,\n",
+    "    SubsetEq(Cycles(k, G), Circuits(k, G)),\n",
+    "    conditions = [greater_eq(k, three)], domain = Natural),\n",
+    "    domain = Graphs)\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -799,6 +933,19 @@
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "cycles_membership_is_bool = Forall(G, Forall(k, \n",
+    "Forall(C, in_bool(InSet(C, Cycles(k, G)))),\n",
+    "domain = Natural),\n",
+    "domain = Graphs\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/walks/walks_membership.py b/packages/proveit/graphs/walks/walks_membership.py
index 16289d5c43cf..af64412cd148 100644
--- a/packages/proveit/graphs/walks/walks_membership.py
+++ b/packages/proveit/graphs/walks/walks_membership.py
@@ -2,11 +2,11 @@
         prover, relation_prover)
 from proveit.logic import (Equals, Forall, InSet, SetMembership,
             SetNonmembership)
-from proveit.logic.sets import Functions, Injections, SetOfAll
+from proveit.logic.sets import Functions, Injections, Restriction, SetOfAll
 from proveit.numbers import zero, one, Add, Interval, subtract
 from proveit.graphs import (AdjacentVertices, BeginningVertex,
             Circuits, ClosedWalks, Edges, EdgeSequence, EndingVertex,
-            Graph, Size, Vertices, Walks)
+            Graph, Paths, Size, Vertices, Walks)
 
 
 class WalksMembership(SetMembership):
@@ -739,3 +739,111 @@ def derive_element_in_closed_walks(self, **defaults_config):
             {G:_G}, auto_simplify=False)
             .derive_superset_membership(self.element, auto_simplify=False))
 
+
+class CyclesMembership(SetMembership):
+    '''
+    Defines methods that apply to membership in the set of length-k
+    cycles in the simple graph G, denoted Cycles(k, G). A cycle in G
+    is circuit (i.e., a closed trail) in which no vertex is repeated.
+    '''
+
+    def __init__(self, element, domain):
+        SetMembership.__init__(self, element, domain)
+
+    def side_effects(self, judgment):
+        '''
+        Yield side-effects when proving 'C in Cycles(k, G)' for
+        Natural k >= 3 and G in Graphs.
+        '''
+        yield self.derive_element_in_circuits
+
+    @equality_prover('defined', 'define')
+    def definition(self, **defaults_config):
+        '''
+        From self = [elem in Cycles(k, G)], with k >= 3, deduce
+        and return:
+            [elem in Cycles(k, G)]
+                = elem in {W in Circuits(k, G) |
+                           W|_{0,1,...,k-1} in Paths(k-1, G)}.
+
+        That is, an elem in Cycles(k, G) is equal to an elem being in
+        the set of Circuits(k, G) whose restriction to domain
+        {0,1,...,k-1} gives a path of length (k-1) in G.
+        '''
+        from . import cycles_membership_def
+        element = self.element
+        _G_sub  = self.domain.graph
+        _k_sub  = self.domain.length
+        return cycles_membership_def.instantiate(
+                {G: _G_sub, k: _k_sub, C: element },auto_simplify=False)
+
+    def as_defined(self):
+        '''
+        From self = [elem in Cycles(k, G)], return the expression
+        (NOT a judgment):
+            elem in {W in Circuits(k, G) |
+                     W|_{0,1,...,k-1} in Paths(k-1, G)}.
+        '''
+        element = self.element
+        _G      = self.domain.graph
+        _k      = self.domain.length
+        return (InSet(element,
+                SetOfAll(W, W,
+                conditions = [
+                    InSet(Restriction(W, Interval(zero, subtract(_k, one))),
+                          Paths(subtract(_k, one), _G))],
+                domain = Circuits(_k, _G))))
+
+    @prover
+    def unfold(self, **defaults_config):
+        '''
+        From self = [elem in Cycles(k, G)], and knowing or assuming
+        self and k >= 3, derive and return:
+            elem in {W in Circuits(k, G) |
+                     W|_{0,1,...,k-1} in Paths(k-1, G)}.
+        '''
+        from . import cycles_membership_unfolding
+        element = self.element
+        _G_sub  = self.domain.graph
+        _k_sub  = self.domain.length
+        return cycles_membership_unfolding.instantiate(
+            {G: _G_sub, k: _k_sub, C: element}, auto_simplify=False)
+
+    @prover
+    def conclude(self, **defaults_config):
+        '''
+        Called on self = [C in Cycles(k, G)], derive and return
+        self, knowing or assuming BOTH of the following:
+        (1) k >= 3
+        (2) C in {W in Circuits(k, G) |
+                  W|_{0,1,...,k-1} in Paths(k-1, G)}
+        '''
+        _C = self.element
+        _G  = self.domain.graph
+        _k  = self.domain.length
+        from . import cycles_membership_folding
+        return cycles_membership_folding.instantiate(
+            {G: _G, k: _k, C: _C}, auto_simplify=False)
+
+    @relation_prover
+    def deduce_in_bool(self, **defaults_config):
+        from . import cycles_membership_is_bool
+        _G_sub = self.domain.graph
+        _k_sub = self.domain.length
+        _C_sub = self.element
+        return cycles_membership_is_bool.instantiate(
+            {G:_G_sub, k:_k_sub, C:_C_sub}, auto_simplify=False)
+
+    @prover
+    def derive_element_in_circuits(self, **defaults_config):
+        '''
+        Usually called as a side effect when proving C in Cycles(k, G):
+        derive C in Circuits(k, G).
+        '''
+        from . import cycles_within_circuits
+        _G      = self.domain.graph
+        _k      = self.domain.length
+        return (cycles_within_circuits.instantiate(
+            {G:_G, k:_k}, auto_simplify=False)
+            .derive_superset_membership(self.element, auto_simplify=False))
+

From be40b931d8cca2296d25e4794e8c94f05807b947 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sat, 19 Jul 2025 14:55:08 -0600
Subject: [PATCH 155/159] Establish side_effects() and derive_size_in_natural()
 methods in GraphMembership

Establish the side_effects() and derive_size_in_natural() methods in the GraphMembership() class, allowing the size of graph G (i.e. the number of edges in graph G) to be automatically understood to be a natural number whenever we have G in Graphs.
---
 packages/proveit/graphs/graph.py | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/packages/proveit/graphs/graph.py b/packages/proveit/graphs/graph.py
index 7abf95bad91a..7f7f7e09fc60 100644
--- a/packages/proveit/graphs/graph.py
+++ b/packages/proveit/graphs/graph.py
@@ -69,8 +69,28 @@ def __init__(self, element, domain):
             raise TypeError("domain expected to be Graphs, not %s"
                             %domain.__class__)
 
+    def side_effects(self, judgment):
+        '''
+        Yield side-effects when proving or asusming 'G in Graphs',
+        the main side-effect being that ||G|| in Natural.
+        '''
+        yield self.derive_size_in_natural
+
     # def conclude(): see if and when needed
 
+    @prover
+    def derive_size_in_natural(self, **defaults_config):
+        '''
+        From (G in Graphs), derive ||G|| in Natural, i.e. derive the
+        fact that the size of G (the number of edges in G) is a
+        Natural number. Called as a side-effect.
+        '''
+        from . import graph_size_in_natural
+        _G = self.element
+        return graph_size_in_natural.instantiate(
+                {G:_G}, auto_simplify=False)
+
+
 class Graph(Function):
     '''
     Graph(V, E) represents a graph with vertex set V and edge set E.

From bee9571a0ff295179df664c395c19384406cf717 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sat, 19 Jul 2025 14:56:05 -0600
Subject: [PATCH 156/159] Update demonstrations nbs for graphs and graphs/walks

Update demonstrations nbs for graphs and graphs/walks for recent updates to classes and methods.
---
 .../graphs/_theory_nbs_/demonstrations.ipynb  | 11 +++-
 .../walks/_theory_nbs_/demonstrations.ipynb   | 64 +++++++++++++++++--
 2 files changed, 67 insertions(+), 8 deletions(-)

diff --git a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
index 9bc1685b4420..e1a2e9396cb2 100644
--- a/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/demonstrations.ipynb
@@ -17,7 +17,7 @@
     "import proveit\n",
     "from proveit import e, u, v, x, E, G, P, V\n",
     "from proveit.logic import InClass, InSet, KPowerSet, NotInSet, SubsetEq\n",
-    "from proveit.numbers import two\n",
+    "from proveit.numbers import two, Natural\n",
     "from proveit.graphs import (\n",
     "        AdjacentVertices, Connected, Degree, Edges, Graph, Graphs,\n",
     "        HasEulerianCircuit, HasEulerianTrail, Order, Size, Vertices)\n",
@@ -95,13 +95,20 @@
     "Size(G).definition(assumptions = [InClass(G, Graphs)])"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "$\\texttt{Size}(G) \\in \\mathbb{N}$ is derived automatically as an incidental/side-effect:"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
    "source": [
-    "Size(G).derive_size_in_natural(assumptions = [InClass(G, Graphs)])"
+    "InSet(Size(G), Natural).prove(assumptions = [InClass(G, Graphs)])"
    ]
   },
   {
diff --git a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
index c73b5b6a4bfc..adff0f2a4ac7 100644
--- a/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
+++ b/packages/proveit/graphs/walks/_theory_nbs_/demonstrations.ipynb
@@ -996,14 +996,47 @@
     ")"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Cycles Membership and Related Methods"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, Cycles(k, G))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, Cycles(k, G)).deduce_in_bool(assumptions = [InClass(G, Graphs), InSet(k, Natural)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, Cycles(k, G)).definition(assumptions = [InClass(G, Graphs), InSet(k, Natural), greater_eq(k, three)])"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
    "source": [
-    "from proveit.graphs import graph_size_in_natural\n",
-    "graph_size_in_natural"
+    "InSet(C, Cycles(k, G)).as_defined()"
    ]
   },
   {
@@ -1012,7 +1045,8 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "type(graph_size_in_natural.domain)"
+    "InSet(C, Cycles(k, G)).unfold(\n",
+    "        assumptions = [InClass(G, Graphs), InSet(k, Natural), greater_eq(k, three), InSet(C, Cycles(k, G))])"
    ]
   },
   {
@@ -1021,7 +1055,24 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "type(Graphs)"
+    "from proveit.logic.sets import Restriction\n",
+    "InSet(C, Cycles(k, G)).conclude(\n",
+    "        assumptions = [InClass(G, Graphs), InSet(k, Natural), greater_eq(k, three),\n",
+    "                       InSet(C, SetOfAll(W, W,\n",
+    "                       conditions=[InSet(Restriction(W, Interval(zero, subtract(k, one))), Paths(subtract(k, one), G))],\n",
+    "                       domain=Circuits(k, G)))])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "InSet(C, Cycles(k, G)).derive_element_in_circuits(\n",
+    "        assumptions = [InClass(G, Graphs), InSet(k, Natural),\n",
+    "                       greater_eq(k, three), InSet(C, Cycles(k, G))]\n",
+    ")"
    ]
   },
   {
@@ -1030,7 +1081,8 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Graphs"
+    "InSet(C, Walks(k, G)).prove(assumptions = [InClass(G, Graphs), InSet(k, Natural),\n",
+    "                       greater_eq(k, three), InSet(C, Cycles(k, G))])"
    ]
   },
   {
@@ -1039,7 +1091,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "# Size(G).derive_size_in_natural(assumptions = [InClass(G, Graphs)])"
+    "Size(G).derive_size_in_natural(assumptions = [InClass(G, Graphs)])"
    ]
   },
   {

From 1f2deccfa8f4510197b4580071e7dfcf8f529547 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Sat, 19 Jul 2025 17:42:31 -0600
Subject: [PATCH 157/159] Add dev comments to graphs/union/axioms

Add development comments to the graphs/union/axioms nb, for use in future development (graphs/union axioms do not yet capture the main idea that the union of graphs is itself a graph).
---
 .../graphs/union/_theory_nbs_/axioms.ipynb    | 20 +++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/packages/proveit/graphs/union/_theory_nbs_/axioms.ipynb b/packages/proveit/graphs/union/_theory_nbs_/axioms.ipynb
index f14d75785541..6cfe753efda8 100644
--- a/packages/proveit/graphs/union/_theory_nbs_/axioms.ipynb
+++ b/packages/proveit/graphs/union/_theory_nbs_/axioms.ipynb
@@ -57,6 +57,26 @@
     ")"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "But that membership axiom doesn't really get at the heart of the desired idea that the union of a set of graphs is itself a graph. To better achieve that and to avoid the idiosyncratic construct $x \\in G$ (meaning $x \\in \\texttt{Vertices}(G) \\lor x \\in \\texttt{Edges}(G)$), we could instead try:\n",
+    "\n",
+    "$\\forall_{G_{1}, G_{2}, \\ldots, G_{n} \\in \\texttt{Graphs}}\n",
+    " \\big[ G_{1} \\cup G_{2} \\cup \\ldots \\cup G_{n} \\in \\texttt{Graphs} \\big]$\n",
+    "\n",
+    "$\\forall_{G_{1}, G_{2}, \\ldots, G_{n} \\in \\texttt{Graphs}}\n",
+    " \\big[\\texttt{Vertices}(G_{1} \\cup G_{2} \\cup \\ldots \\cup G_{n})\n",
+    " = \\texttt{Vertices}(G_{1}) \\cup \\texttt{Vertices}(G_{2}) \\cup \\ldots \\texttt{Vertices}(G_{n})\\big]$\n",
+    "\n",
+    " $\\forall_{G_{1}, G_{2}, \\ldots, G_{n} \\in \\texttt{Graphs}}\n",
+    " \\big[\\texttt{Edges}(G_{1} \\cup G_{2} \\cup \\ldots \\cup G_{n})\n",
+    " = \\texttt{Edges}(G_{1}) \\cup \\texttt{Edges}(G_{2}) \\cup \\ldots \\texttt{Edges}(G_{n})\\big]$\n",
+    "\n",
+    "where we us all three as axiomatic. Alternatively, we could possibly use the Vertices() and Edges() statements as axioms, then prove the more general union statement as a theorem. The proof might be accomplished by showing that the new Edges() set is a subset of the set of 2-element subsets of the new Vertices() set, and then we have the axiom that $\\forall_{V}\\forall_{E \\subseteq [V]^{2}}(\\texttt{Graph}(V, E) \\in \\texttt{Graphs})$."
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From 47e8a4c1e86adb7df3b1f545b423e8c09f77a3a7 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Mon, 28 Jul 2025 17:24:41 -0600
Subject: [PATCH 158/159] Add FiniteGraphsLiteral() & FiniteGraphsMembership()
 classes

Add FiniteGraphsLiteral() & FiniteGraphsMembership() classes to the graphs theory package in graphs.py. This is in anticipation of some possible problems involving cardinalities of vertex and edge sets if we're not careful to distinguish finite and infinite graphs. Future commit(s) will actually rectify some errors where we've assumed that the size of a graph was finite (for example, assuming the size of a graph G, or the number of edges in G, was a Natural number). This also establishes the FiniteGraphs label or string in the graphs/common notebook for use in imports.
---
 packages/proveit/graphs/__init__.py           |   5 +-
 .../proveit/graphs/_theory_nbs_/common.ipynb  |  11 +-
 packages/proveit/graphs/graph.py              | 102 ++++++++++++------
 3 files changed, 85 insertions(+), 33 deletions(-)

diff --git a/packages/proveit/graphs/__init__.py b/packages/proveit/graphs/__init__.py
index 84809d36ba4d..8beff63a88b5 100644
--- a/packages/proveit/graphs/__init__.py
+++ b/packages/proveit/graphs/__init__.py
@@ -1,5 +1,6 @@
-from .graph import (Connected, Graph, GraphsLiteral, HasEulerianCircuit,
-          HasEulerianTrail, Order, Size)
+from .graph import (Connected, FiniteGraphsLiteral, Graph,
+          GraphsLiteral, HasEulerianCircuit, HasEulerianTrail,
+          Order, Size)
 from .edges import Edges
 from .inclusion import NotSubgraph, Subgraph
 from .membership import (
diff --git a/packages/proveit/graphs/_theory_nbs_/common.ipynb b/packages/proveit/graphs/_theory_nbs_/common.ipynb
index 7259187b2e2a..d846ba23e451 100644
--- a/packages/proveit/graphs/_theory_nbs_/common.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/common.ipynb
@@ -22,7 +22,7 @@
     "from proveit.logic import And, Or\n",
     "from proveit.logic.sets import InSet\n",
     "from proveit.numbers import one\n",
-    "from proveit.graphs import GraphsLiteral, InGraph, NotInGraph"
+    "from proveit.graphs import FiniteGraphsLiteral, GraphsLiteral, InGraph, NotInGraph"
    ]
   },
   {
@@ -43,6 +43,15 @@
     "Graphs = GraphsLiteral()"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "FiniteGraphs = FiniteGraphsLiteral()"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/packages/proveit/graphs/graph.py b/packages/proveit/graphs/graph.py
index 7f7f7e09fc60..b6d0f791c14f 100644
--- a/packages/proveit/graphs/graph.py
+++ b/packages/proveit/graphs/graph.py
@@ -2,33 +2,6 @@
 from proveit import E, G, V
 from proveit.logic import ClassMembership
 
-# class Graphs(Literal):
-#     '''
-#     Graphs represents the (mathematical) class of graphs, to which
-#     any specific graph G = (V, E) of vertices and edges belongs.
-#     This class might not be necessary, but is modeled on the
-#     HilbertSpacesLiteral class in the linear_algebra/inner_products
-#     theory package.
-#     '''
-
-#     # the literal string for representing the class of Graphs
-#     def __init__(self, *, styles=None):
-#         Literal.__init__(self, string_format='Graphs', 
-#                          latex_format=r'\textrm{Graphs}',
-#                          styles=styles)
-
-#     def membership_object(self, element):
-#         return GraphsMembership(element, self)
-
-#     @property
-#     def is_proper_class(self):
-#         '''
-#         Graphs consitute a proper class (i.e. instead of a set).
-#         This indicates that InClass() should be used instead of
-#         InSet() when this is a domain.
-#         '''
-#         return True
-
 
 class GraphsLiteral(Literal):
     '''
@@ -38,7 +11,10 @@ class GraphsLiteral(Literal):
     HilbertSpacesLiteral class in the linear_algebra/inner_products
     theory package, and something similar involving the EmptySet in
     logic/sets. 'Graphs' is then defined in the graphs/common nb
-    as Graphs = GraphsLiteral.
+    as Graphs = GraphsLiteral(). This class of graphs includes both
+    finite and infinite graphs, but is initially conceptualized as
+    the class of simple graphs (i.e. no loops and no parallel edges).
+    See FiniteGraphsLiteral() for the class of finite graphs.
     '''
 
     # the literal string for representing the class of Graphs
@@ -53,13 +29,46 @@ def membership_object(self, element):
     @property
     def is_proper_class(self):
         '''
-        Graphs consitute a proper class (i.e. instead of a set).
+        The class of Graphs is a proper class (i.e., instead of a set).
         This indicates that InClass() should be used instead of
         InSet() when this is a domain.
         '''
         return True
 
 
+class FiniteGraphsLiteral(Literal):
+    '''
+    FiniteGraphsLiteral() represents the (mathematical) class of
+    finite graphs (i.e., graphs with a finite set of vertices and
+    a finite set of edges), to which any specific finite graph
+    G = (V, E) of vertices and edges belongs. This class of graphs
+    is initially conceptualized as the class of simple finite graphs
+    (i.e. no loops and no parallel edges).
+    The string 'FiniteGraphs' is then defined in the graphs/common nb
+    as FiniteGraphs = FiniteGraphsLiteral(), and should be imported
+    from there.
+    '''
+
+    # the literal string for representing the class FiniteGraphs
+    def __init__(self, *, styles=None):
+        Literal.__init__(self, string_format='FiniteGraphs', 
+                         latex_format=r'\textrm{FiniteGraphs}',
+                         styles=styles)
+
+    def membership_object(self, element):
+        return FiniteGraphsMembership(element, self)
+
+    @property
+    def is_proper_class(self):
+        '''
+        The class of finite graphs is a proper class (i.e. instead
+        of a set). This method is used to indicates that InClass()
+        should be used instead of InSet() when FiniteGraphs is being
+        used as a domain.
+        '''
+        return True
+
+
 class GraphsMembership(ClassMembership):
 
     def __init__(self, element, domain):
@@ -71,8 +80,9 @@ def __init__(self, element, domain):
 
     def side_effects(self, judgment):
         '''
-        Yield side-effects when proving or asusming 'G in Graphs',
+        Yield side-effects when proving or assuming 'G in Graphs',
         the main side-effect being that ||G|| in Natural.
+        This needs updated, since Graphs includes infinite graphs.
         '''
         yield self.derive_size_in_natural
 
@@ -90,6 +100,38 @@ def derive_size_in_natural(self, **defaults_config):
         return graph_size_in_natural.instantiate(
                 {G:_G}, auto_simplify=False)
 
+class FiniteGraphsMembership(ClassMembership):
+
+    def __init__(self, element, domain):
+        from . import FiniteGraphs
+        ClassMembership.__init__(self, element, domain)
+        if domain != FiniteGraphs:
+            raise TypeError(
+                f"Domain expected to be FiniteGraphs, not {domain.__class__}")
+
+    def side_effects(self, judgment):
+        '''
+        Yield side-effects when proving or assuming 'G in FiniteGraphs',
+        the main side-effect being that ||G|| in Natural.
+        Should extend this to also have |G| in Natural.
+        Should extend this to also have G in Graphs.
+        '''
+        yield self.derive_size_in_natural
+
+    # def conclude(): see if and when needed
+
+    @prover
+    def derive_size_in_natural(self, **defaults_config):
+        '''
+        From (G in FiniteGraphs), derive ||G|| in Natural, i.e.
+        derive the fact that the size of G (the number of edges in G)
+        is a Natural number. Called as a side-effect.
+        '''
+        from . import graph_size_in_natural
+        _G = self.element
+        return graph_size_in_natural.instantiate(
+                {G:_G}, auto_simplify=False)
+
 
 class Graph(Function):
     '''

From 4b630c037cf8117539f72280b129f06cbf004e75 Mon Sep 17 00:00:00 2001
From: Warren Craft <wdcraft@unm.edu>
Date: Fri, 8 Aug 2025 14:27:31 -0600
Subject: [PATCH 159/159] Add deg_is_natural theorem to graphs sub-theory pkg

Add to the graphs sub-theory package the deg_is_natural theorem stating that the degree of any vertex is a natural number. Would also LIKE to have that the degree is ODD XOR EVEN, but the evens and odds are currently developed in a separate branch, and the XOR is developed in its own branch as well.
---
 .../proofs/deg_is_natural/thm_proof.ipynb     | 47 +++++++++++++++++++
 .../graphs/_theory_nbs_/theorems.ipynb        | 24 ++++++++++
 2 files changed, 71 insertions(+)
 create mode 100644 packages/proveit/graphs/_theory_nbs_/proofs/deg_is_natural/thm_proof.ipynb

diff --git a/packages/proveit/graphs/_theory_nbs_/proofs/deg_is_natural/thm_proof.ipynb b/packages/proveit/graphs/_theory_nbs_/proofs/deg_is_natural/thm_proof.ipynb
new file mode 100644
index 000000000000..4b11317ab94f
--- /dev/null
+++ b/packages/proveit/graphs/_theory_nbs_/proofs/deg_is_natural/thm_proof.ipynb
@@ -0,0 +1,47 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Proof of <a class=\"ProveItLink\" href=\"../../../../_theory_nbs_/theory.ipynb\">proveit</a>.<a class=\"ProveItLink\" href=\"../../theory.ipynb\">graphs</a>.<a class=\"ProveItLink\" href=\"../../theorems.ipynb#deg_is_natural\">deg_is_natural</a> theorem\n",
+    "========"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import proveit\n",
+    "theory = proveit.Theory() # the theorem's theory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%proving deg_is_natural"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/packages/proveit/graphs/_theory_nbs_/theorems.ipynb b/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
index dd279cb52e5a..b59c4465fef9 100644
--- a/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
+++ b/packages/proveit/graphs/_theory_nbs_/theorems.ipynb
@@ -37,6 +37,30 @@
     "%begin theorems"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Some Basic Facts About Vertices and Degree\n",
+    "\n",
+    "Later, when XOr, IntegerEven, and IntegerOdd classes are available, update theorems with the fact that $\\texttt{deg}(v)$ is either even or odd (but not both). Currently XOr class is in a separate branch, and the even and odd classes are their own separate branch."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "deg_is_natural = (\n",
+    "Forall(G,\n",
+    "Forall(v,\n",
+    "       InSet(Degree(v, G), Natural),\n",
+    "domain = Vertices(G)),\n",
+    "domain = Graphs)\n",
+    ")"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
