├── .github └── workflows │ └── main.yml ├── .gitignore ├── LICENSE ├── README.rst ├── docs ├── Makefile ├── _build │ ├── .buildinfo │ ├── .doctrees │ │ ├── cellcomplexes.doctree │ │ ├── environment.pickle │ │ ├── index.doctree │ │ ├── intro.doctree │ │ ├── sections.doctree │ │ └── sheaves.doctree │ ├── .nojekyll │ ├── _sources │ │ ├── cellcomplexes.rst.txt │ │ ├── index.rst.txt │ │ ├── intro.rst.txt │ │ ├── sections.rst.txt │ │ └── sheaves.rst.txt │ ├── _static │ │ ├── ajax-loader.gif │ │ ├── alabaster.css │ │ ├── basic.css │ │ ├── comment-bright.png │ │ ├── comment-close.png │ │ ├── comment.png │ │ ├── custom.css │ │ ├── doctools.js │ │ ├── down-pressed.png │ │ ├── down.png │ │ ├── file.png │ │ ├── jquery-3.1.0.js │ │ ├── jquery.js │ │ ├── minus.png │ │ ├── plus.png │ │ ├── pygments.css │ │ ├── searchtools.js │ │ ├── underscore-1.3.1.js │ │ ├── underscore.js │ │ ├── up-pressed.png │ │ ├── up.png │ │ └── websupport.js │ ├── cellcomplexes.html │ ├── doctrees │ │ ├── cellcomplexes.doctree │ │ ├── environment.pickle │ │ ├── index.doctree │ │ ├── intro.doctree │ │ ├── sections.doctree │ │ └── sheaves.doctree │ ├── genindex.html │ ├── html │ │ ├── .buildinfo │ │ ├── .nojekyll │ │ ├── _sources │ │ │ ├── cellcomplexes.rst.txt │ │ │ ├── index.rst.txt │ │ │ ├── intro.rst.txt │ │ │ ├── sections.rst.txt │ │ │ └── sheaves.rst.txt │ │ ├── _static │ │ │ ├── ajax-loader.gif │ │ │ ├── alabaster.css │ │ │ ├── basic.css │ │ │ ├── comment-bright.png │ │ │ ├── comment-close.png │ │ │ ├── comment.png │ │ │ ├── custom.css │ │ │ ├── doctools.js │ │ │ ├── down-pressed.png │ │ │ ├── down.png │ │ │ ├── file.png │ │ │ ├── jquery-3.1.0.js │ │ │ ├── jquery.js │ │ │ ├── minus.png │ │ │ ├── plus.png │ │ │ ├── pygments.css │ │ │ ├── searchtools.js │ │ │ ├── underscore-1.3.1.js │ │ │ ├── underscore.js │ │ │ ├── up-pressed.png │ │ │ ├── up.png │ │ │ └── websupport.js │ │ ├── cellcomplexes.html │ │ ├── genindex.html │ │ ├── index.html │ │ ├── intro.html │ │ ├── objects.inv │ │ ├── search.html │ │ ├── searchindex.js │ │ ├── sections.html │ │ └── sheaves.html │ ├── index.html │ ├── intro.html │ ├── objects.inv │ ├── search.html │ ├── searchindex.js │ ├── sections.html │ └── sheaves.html ├── cellcomplexes.rst ├── conf.py ├── index.rst ├── install.rst ├── intro.rst ├── sections.rst └── sheaves.rst ├── pysheaf.png ├── pysheaf.svg ├── pysheaf ├── .ipynb_checkpoints │ ├── ACEKComplx Example-checkpoint.ipynb │ ├── SheafCohomologyExample4-9-checkpoint.ipynb │ └── SheafExample4-10-checkpoint.ipynb ├── ACEKComplx Example.ipynb ├── DeapGeneticAlgorithmExample.py ├── Pipfile ├── SearchAndRescue.py ├── SheafBuildingExample.ipynb ├── SheafCohomologyExample4-9.ipynb ├── SheafExample4-10.ipynb ├── __init__.py ├── analysisTools.py ├── consistencyFiltrationExample.py ├── dataTools.py ├── linearSheafExample.py ├── logic_example.py ├── logic_netlist.json ├── pysheaf.py ├── requirements.txt └── unitTestPysheaf.py └── setup.py /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: website 2 | 3 | # build the documentation whenever there are new commits on master 4 | on: 5 | push: 6 | branches: 7 | - master 8 | # Alternative: only build for tags. 9 | # tags: 10 | # - '*' 11 | 12 | # security: restrict permissions for CI jobs. 13 | permissions: 14 | contents: read 15 | 16 | jobs: 17 | # Build the documentation and upload the static HTML files as an artifact. 18 | build: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v4 22 | - uses: actions/setup-python@v5 23 | with: 24 | python-version: '3.12' 25 | 26 | - run: pip install -e . 27 | # ADJUST THIS: build your documentation into docs/. 28 | # We use a custom build script for pdoc itself, ideally you just run `pdoc -o docs/ ...` here. 29 | - run: pdoc --logo https://github.com/kb1dds/pysheaf/blob/master/pysheaf.png?raw=true pysheaf/ -o docs/ 30 | 31 | - uses: actions/upload-pages-artifact@v3 32 | with: 33 | path: docs/ 34 | 35 | # Deploy the artifact to GitHub pages. 36 | # This is a separate job so that only actions/deploy-pages has the necessary permissions. 37 | deploy: 38 | needs: build 39 | runs-on: ubuntu-latest 40 | permissions: 41 | pages: write 42 | id-token: write 43 | environment: 44 | name: github-pages 45 | url: ${{ steps.deployment.outputs.page_url }} 46 | steps: 47 | - id: deployment 48 | uses: actions/deploy-pages@v4 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled python modules. 2 | *.pyc 3 | *.ipynb_check* 4 | 5 | # Setuptools distribution folder. 6 | /dist/ 7 | 8 | # Python egg metadata, regenerated from source files by setuptools. 9 | /*.egg-info 10 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | PySheaf: Sheaf-theoretic toolbox 2 | ================================ 3 | 4 | This repository consists of Python 3.6 libraries for manipulating cell complexes and sheaves of sets or vector spaces on cell complexes [1]_, [2]_, [3]_, [4]_, [5]_, [6]_ 5 | 6 | Documentation: 7 | -------------- 8 | 9 | Full documentation for PySheaf is at ``_ 10 | 11 | You might also think the best strategy is to look at some example code! 12 | There are several examples in Jupyter notebooks here: ``_ 13 | 14 | Download: 15 | --------- 16 | 17 | You can install by cloning this repo (there is no PyPI package). For Linux, you can do:: 18 | 19 | $ git clone https://github.com/kb1dds/pysheaf.git 20 | $ pip install pysheaf 21 | 22 | Usage: 23 | ------ 24 | 25 | The general plan of usage is 26 | 27 | 1. First (usually on paper!) lay out the cell complex that will serve as the base for your sheaf. *Give each cell a unique label.* 28 | 29 | 2. Determine all of the stalks over each cell, and the restriction maps. Restriction maps can be a mixture of `numpy` matrices or arbitrary single-input Python function objects. 30 | 31 | 3. Construct a `Sheaf` instance and add each of your cells as `Cell` instances with the `Sheaf.AddCell` method. Make sure to use your unique label for each `Cell`, because that is how PySheaf identifies them! Once you've done that, create each restriction as a `Coface` instance and add it to the sheaf using the `Sheaf.AddCoface` method. The `Sheaf.AddCoface` method will connect the listed `Cell`s based on their labels. `Cell`s and `Coface`s can be added later if you want, and they can be added in any order provided any `Coface` refers to `Cell`s that already exist. 32 | 33 | 4. Install some data into the sheaf by way of an `Assignment` to some of the `Cell`s. 34 | 35 | 5. Analyze the sheaf and its data: 36 | a. You can compute consistency radius with `Sheaf.ComputeConsistencyRadius()` 37 | b. You can improve the consistency radius by extending or altering the values of the assignment with `Sheaf.FuseAssignment()`. This will only alter Cells whose `Cell.mOptimizationCell` attribute is `True`. You can also change the optimization algorithm if you want. 38 | c. You can find all star open sets whose local consistency is less than a desired bound using `Sheaf.CellIndexesLessThanConsistencyThreshold()`. 39 | 40 | Have a look at the example code for some ideas! 41 | 42 | This code is under active development, so not everything works as it should. If you find anything that you can correct, feel free to send me suggestions! 43 | 44 | | Thanks! 45 | | Michael Robinson 46 | | American University 47 | | kb1dds@gmail.com 48 | | michaelr@american.edu 49 | 50 | .. [1] http://www.drmichaelrobinson.net/sheaftutorial/index.html 51 | 52 | .. [2] https://www.youtube.com/user/drmichaelrobinson 53 | 54 | .. [3] Cliff Joslyn, Emilie Hogan, Michael Robinson, "Towards a topological framework for integrating semantic information sources," Semantic Technologies for Intelligence, Defense, and Security (STIDS), 2014. http://ceur-ws.org/Vol-1304/STIDS2014_P2_JoslynEtAl.pdf 55 | 56 | .. [4] Michael Robinson, "Sheaves are the canonical datastructure for information integration," Information Fusion, 36 (2017), pp. 208-224. (preprint version is http://arxiv.org/abs/1603.01446) 57 | 58 | .. [5] Michael Robinson, "Sheaf and cosheaf methods for analyzing multi-model systems," http://arXiv.org/abs/1604.04647 59 | 60 | .. [6] Michael Robinson, *Topological Signal Processing*, Springer, 2014. 61 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = PySheaf 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | github: 18 | @$(SPHINXBUILD) -b html "$(SOURCEDIR)" $(BUILDDIR) 19 | touch $(BUILDDIR)/html/.nojekyll 20 | ghp-import $(BUILDDIR)/html/ 21 | git push -u origin gh-pages 22 | @echo 23 | @echo "Published to Github" 24 | 25 | # Catch-all target: route all unknown targets to Sphinx using the new 26 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 27 | %: Makefile 28 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 29 | -------------------------------------------------------------------------------- /docs/_build/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: c923a31e154911d189bbfea2fc3a3d87 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /docs/_build/.doctrees/cellcomplexes.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/.doctrees/cellcomplexes.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/.doctrees/environment.pickle -------------------------------------------------------------------------------- /docs/_build/.doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/.doctrees/index.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/intro.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/.doctrees/intro.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/sections.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/.doctrees/sections.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/sheaves.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/.doctrees/sheaves.doctree -------------------------------------------------------------------------------- /docs/_build/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/.nojekyll -------------------------------------------------------------------------------- /docs/_build/_sources/cellcomplexes.rst.txt: -------------------------------------------------------------------------------- 1 | The CellComplex type 2 | ==================== 3 | 4 | The :py:class:`CellComplex` class consists of a list of :py:class:`Cell` instances and methods that manipulate the complex as a whole. It is also the base class for the :py:class:`Sheaf` class. The indices into the list of :py:class:`Cell` instances are used throughout PySheaf, and are the usual way to refer to individual :py:class:`Cell` instances when they are in context in a :py:class:`CellComplex`. Because the indices are necessary to construct the :py:class:`Cofaces` as well, it is usually necessary to determine the necessary cells ahead of time, and then build the :py:class:`CellComplex` instance all at once. 5 | 6 | .. py:class:: CellComplex 7 | 8 | .. py:attribute:: cells 9 | 10 | List of :py:class:`Cell` instances that form this cell. Indices into this list are used throughout PySheaf, and they are generally expected to be static once created. 11 | 12 | .. py:method:: homology(k,subcomplex=None,compactSupport=False,tol=1e-5) 13 | 14 | Compute the degree `k` homology of the :py:class:`CellComplex`. If you want relative homology, the `subcomplex` field specifies a list of indices into :py:class:`CellComplex.cells` for the relative subcomplex. If you want compactly supported homology (if you don't know what that means, you don't) then set `compactSupport=True`. The `tol` argument sets the tolerance below which a singular value is said to be zero, and thus is to be considered part of the kernel. This returns a :py:class:`numpy.ndarray` whose columns are the generators for homology. 15 | 16 | .. py:method:: boundary(k,subcomplex=None,compactSupport=False) 17 | 18 | Compute the degree `k` boundary map of the :py:class:`CellComplex`, returning it as a :py:class:`numpy.ndarray`. If you want relative homology, the `subcomplex` field specifies a list of indices into :py:class:`CellComplex.cells` for the relative subcomplex. If you want compactly supported homology (if you don't know what that means, you don't) then set `compactSupport=True`. 19 | 20 | .. py:method:: components(cells=[]) 21 | 22 | Compute connected components of the :py:class:`CellComplex`. The optional argument `cells` specifies list of permissible indices into :py:attr:`CellComplex.cells`. Returns a list of lists of indices into :py:attr:`CellComplex.cells`. 23 | 24 | .. py:method:: star(cells) 25 | 26 | Compute the star of a list of `cells` (specified as a list of indices into :py:attr:`CellComplex.cells`) in the topology of the :py:class:`CellComplex`. Returns a list of indices into :py:attr:`CellComplex.cells`. 27 | 28 | .. py:method:: closure(cells) 29 | 30 | Compute the closure of a list of `cells` (specified as a list of indices into :py:attr:`CellComplex.cells`) in the topology of the :py:class:`CellComplex`. Returns a list of indices into :py:attr:`CellComplex.cells`. 31 | 32 | .. py:method:: skeleton(k) 33 | 34 | Compute the dimension `k` skeleton of the :py:class:`CellComplex`. Returns a list of indices into :py:attr:`CellComplex.cells`. 35 | 36 | .. py:method:: cofaces(c,cells=[]) 37 | 38 | Return a generator that iterates over over :py:class:`Coface` instances (of *all* dimensions) for a cell whose index in :py:attr:`CellComplex.cells` is `c`. The optional argument specifies a list of indices into :py:attr:`CellComplex.cells` that are permitted to be traversed. 39 | 40 | .. warning :: duplicate :py:class:`Coface` instances are possible! 41 | 42 | Constructing :py:class:`CellComplex` instances 43 | ---------------------------------------------- 44 | 45 | A :py:class:`Cell` represents a single topological disk that is present in a given :py:class:`CellComplex`. Mostly, it contains references to other cells by their respective indices into :py:attr:`CellComplex.cells`. 46 | 47 | .. py:class:: Cell 48 | 49 | Base class representing a topological disk of a definite dimension. 50 | 51 | .. py:attribute:: dimension 52 | 53 | The dimension of the disk that this :py:class:`Cell` represents. The actual points of the disk are *not* represented, merely its dimension. (Note: this is *not* the dimension of the stalk over the cell in a :py:class:`SheafCell`) 54 | 55 | .. py:attribute:: compactClosure 56 | 57 | Flag that specifies if the topological closure of the :py:class:`Cell` in the :py:class:`CellComplex` is compact. Usually this should be `True`, as only those cells with compact closure are included in a homology calculation. Roughly speaking, those cells that have "missing" boundaries do not have compact closure. 58 | 59 | .. py:attribute:: name 60 | 61 | An optional name for the :py:class:`Cell`, which is generally not used by PySheaf. 62 | 63 | .. py:attribute:: cofaces 64 | 65 | A list of :py:class:`Coface` instances, specifying each coface of this cell. It is assumed that this coface points to a strictly higher-dimensional cell, and you will encounter endless loops if this assumption is violated. It is *not* assumed that the cofaces are all *one* dimension higher, though. It is not necessary to specify a transitive closure -- all cofaces -- as this can be determined by the containing :py:class:`CellComplex` as needed using :py:meth:`CellComplex.cofaces()`. 66 | 67 | The :py:class:`Coface` class specifies a single coface relation, in the context of a :py:class:`CellComplex`. 68 | 69 | .. py:class:: Coface 70 | 71 | Class representing a coface relation between two :py:class:`Cell` instances. The lower-dimension cell is implied to be the one holding this instance as its :py:attr:`Cell.cofaces` attribute, so this class *only* refers to the higher-dimension cell. 72 | 73 | .. py:attribute:: index 74 | 75 | The index of the higher-dimension cell in the containing :py:class:`CellComplex`. 76 | 77 | .. py:attribute:: orientation 78 | 79 | The orientation of this coface relation, usually either +1 or -1. 80 | 81 | :py:class:`CellComplex` instances are best built all at once. So for instance, a cell complex consisting of four vertices, named `A`, `B`, `C`, `D`, five edges `AB`, `AC`, `BC`, `BD`, `CD`, and one triangle `ABC` is constructed thusly:: 82 | 83 | pysheaf.CellComplex([pysheaf.Cell(dimension=0, 84 | compactClosure=True, 85 | name='A', 86 | cofaces=[pysheaf.Coface(index=4,orientation=1), # Index 4 = 'AB' 87 | pysheaf.Coface(index=5,orientation=1)]), # Index 5 = 'AC' 88 | pysheaf.Cell(dimension=0, 89 | compactClosure=True, 90 | name='B', 91 | cofaces=[pysheaf.Coface(index=4,orientation=-1), # Index 4 = 'AB' 92 | pysheaf.Coface(index=6,orientation=1), # Index 6 = 'BC' 93 | pysheaf.Coface(index=7,orientation=1)]), # Index 7 = 'BD' 94 | pysheaf.Cell(dimension=0, 95 | compactClosure=True, 96 | name='C', 97 | cofaces=[pysheaf.Coface(index=5,orientation=-1), # Index 5 = 'AC' 98 | pysheaf.Coface(index=6,orientation=-1), # Index 6 = 'BC' 99 | pysheaf.Coface(index=8,orientation=1)]), # Index 8 = 'CD' 100 | pysheaf.Cell(dimension=0, 101 | compactClosure=True, 102 | name='D', 103 | cofaces=[pysheaf.Coface(index=7,orientation=-1), # Index 7 = 'BD' 104 | pysheaf.Coface(index=8,orientation=-1)]),# Index 4 = 'CD' 105 | pysheaf.Cell(dimension=1, 106 | compactClosure=True, 107 | name='AB', 108 | cofaces=[pysheaf.Coface(index=9,orientation=1)]), # Index 9 = 'ABC' 109 | pysheaf.Cell(dimension=1, 110 | compactClosure=True, 111 | name='AC', 112 | cofaces=[pysheaf.Coface(index=9,orientation=-1)]),# Index 9 = 'ABC' 113 | pysheaf.Cell(dimension=1, 114 | compactClosure=True, 115 | name='BC', 116 | cofaces=[pysheaf.Coface(index=9,orientation=1)]), # Index 9 = 'ABC' 117 | pysheaf.Cell(dimension=1, 118 | compactClosure=True, 119 | name='BD', 120 | cofaces=[]), 121 | pysheaf.Cell(dimension=1, 122 | compactClosure=True, 123 | name='CD', 124 | cofaces=[]), 125 | pysheaf.Cell(dimension=2, 126 | compactClosure=True, 127 | name='ABC', 128 | cofaces=[])]) 129 | 130 | Subclasses of :py:class:`CellComplex` 131 | ------------------------------------- 132 | 133 | Since certain kinds of cell complex are specified combinatorially, PySheaf provides subclasses of :py:class:`CellComplex` whose constructors are a bit less verbose. 134 | 135 | .. py:class:: AbstractSimplicialComplex(CellComplex) 136 | 137 | An abstract simplicial complex is defined as a list of lists. Each list specifies a top dimensional simplex (a *toplex*). 138 | 139 | .. py:method:: __init__(toplexes,maxdim=None) 140 | 141 | It is only necessary to pass the constructor a generating set of `toplexes`, as all other simplices will be generated as :py:class:`Cell` instances as appropriate. Because of this, an :py:class:`AbstractSimplicialComplex` should not be constructed with high-dimensional simplices! To avoid problems, you may need to set the `maxdim` to be the largest dimension you want to have constructed. Simplices are sorted from greatest dimension to least in the resulting :py:attr:`AbstractSimplicialComplex.cells` list. 142 | 143 | .. py:class:: DirectedGraph(CellComplex) 144 | 145 | A directed graph consists of a list of ordered pairs of vertices. Strictly speaking, this is a directed, weighted *multi* graph, since duplicate edges are allowed. 146 | 147 | .. py:method:: __init__(graph,vertex_capacity=-1) 148 | 149 | Create a cell complex from a directed graph, where `graph` is a list of pairs (src,dest) or triples (src,dest,capacity) of numbers representing vertices. The optional `vertex_capacity` sets all the weights to the same value. Orientations of the resulting :py:class:`Coface` instances are taken from the ordering of the vertices in the tuples in `graph`. 150 | 151 | The vertex labeled `None` in any of these tuples is an external connection. In the resulting :py:class:`DirectedGraph.cells`, the cells are indexed as follows: 152 | 1. First all of the edges (in the order given), 153 | 2. then all vertices (in the order they are given; not by their numerical values) 154 | -------------------------------------------------------------------------------- /docs/_build/_sources/index.rst.txt: -------------------------------------------------------------------------------- 1 | .. PySheaf documentation master file, created by 2 | sphinx-quickstart on Tue Apr 11 15:52:28 2017. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to PySheaf's documentation! 7 | =================================== 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents: 12 | 13 | intro 14 | cellcomplexes 15 | sheaves 16 | sections 17 | 18 | 19 | Indices and tables 20 | ================== 21 | 22 | * :ref:`genindex` 23 | * :ref:`modindex` 24 | * :ref:`search` 25 | -------------------------------------------------------------------------------- /docs/_build/_sources/intro.rst.txt: -------------------------------------------------------------------------------- 1 | Introduction 2 | ============ 3 | 4 | PySheaf is a Python module that implements cellular sheaves with a view towards computing useful invariants such as cohomology, consistency radius, and induced maps. It is based on the idea that cell complexes are topological spaces, and that sheaves on cell complexes have at least that structure with some additional information as well. The design follows the principles set out in the following book, which might be helpful to consult: 5 | 6 | Michael Robinson, *Topological Signal Processing*, Springer, 2014. 7 | 8 | Although PySheaf can compute (co)homology of sheaves and cell complexes, the primary workflow for sheaves is 9 | 10 | 1. Construct the :py:class:`Sheaf` instance, which involves defining lists of :py:class:`SheafCell` and :py:class:`SheafCoface` instances. Presently, the :py:class:`Sheaf` instance will remain fixed once constructed. Therefore, make sure to have all stalks and restrictions defined at this point! 11 | 2. If you want to compute cohomology of the :py:class:`Sheaf`, you can do so using the :py:meth:`Sheaf.cohomology()` or :py:meth:`Sheaf.betti()` 12 | 3. Construct various :py:class:`Section` instances for the data you have. Key point: a :py:class:`Section` refers to a *local* section. Its :py:class:`SectionCell` members refer to the :py:class:`Sheaf` you've just finished building, so you must built the :py:class:`Sheaf` first! 13 | 4. Process the data using the :py:class:`Sheaf` and :py:class:`Section` instances: 14 | 15 | a. You can measure the consistency using :py:meth:`Sheaf.consistencyRadius()` 16 | b. You can fit a nearest global section using :py:meth:`Sheaf.fuseAssignment()` 17 | c. You may also use :py:meth:`Section.extend()` 18 | 19 | 5. If you want to relate your :py:class:`Sheaf` to others, you may construct a :py:class:`SheafMorphism` instance, which incidentally may *also* be used as a restriction morphism if you want to build a :py:class:`Sheaf` *of* sheaves! 20 | 21 | For cell complexes, you can do steps (1) and (2). Instead of a :py:class:`Sheaf`, you define a :py:class:`CellComplex` built from lists of :py:class:`Cell` and :py:class:`Coface` instances. 22 | 23 | PySheaf is very much under active development and exploration, since there aren't well-established ways of computing using sheaves to process data. Expect some rough edges, but feel free to suggest improvements! 24 | -------------------------------------------------------------------------------- /docs/_build/_sources/sections.rst.txt: -------------------------------------------------------------------------------- 1 | The :py:class:`Section` class 2 | ============================= 3 | 4 | A :py:class:`Section` represents a local section, which is an instance of data stored in a sheaf. A :py:class:`Section` is constructed with a :py:class:`Sheaf` instance in mind, and therefore contains indices that refer into the :py:attr:`Sheaf.cells` list. A given :py:class:`Sheaf` might have several :py:class:`Section` instances. 5 | 6 | .. py:class:: Section 7 | 8 | .. py:attribute:: sectionCells 9 | 10 | The list of :py:class:`SectionCell` instances corresponding to this local section. Although mathematically local sections are not multi-valued, it is possible that duplicates are present as there are no checks for this. 11 | 12 | .. py:method:: support() 13 | 14 | List the :py:attr:`Sheaf.cells` indices in the support of this :py:class:`Section` 15 | 16 | .. py:method:: extend(sheaf,cell,value=None,tol=1e-5) 17 | 18 | Extend this :py:class:`Section` to another cell whose index is `cell` in the :py:attr:`Sheaf.cells` list of the `sheaf` and returns `True` if this can be done consistently according to the tolerance `tol`. You can optionally specify a `value` from the stalk over that cell; in this case the method can be used to test if this is a consistent choice or not. 19 | 20 | .. py:class:: SectionCell 21 | 22 | A single value from the stalk over a given cell, consisting of the 23 | 24 | .. py:attribute:: value 25 | 26 | itself, which ought to be of the appropriate type (can be passed to the functions :py:attr:`SheafCell.metric` and/or :py:attr:`SheafCoface.restriction`). One also needs to specify 27 | 28 | .. py:attribute:: support 29 | 30 | which records the :py:attr:`Sheaf.cells` index of the cell whose stalk from which this value was taken. 31 | 32 | 33 | Data fusion with :py:class:`Section` and :py:class:`Sheaf` instances 34 | -------------------------------------------------------------------- 35 | 36 | Given some data in a :py:class:`Section` for a :py:class:`Sheaf` you can measure the overall consistency radius with 37 | 38 | .. py:method:: Sheaf.consistencyRadius(assignment, tol=1e-5) 39 | 40 | where `assignment` is the :py:class:`Section` to be tested. The optional `tol` specifies the tolerance for consistency, to be used in conjunction with each :py:attr:`SheafCell.metric` in the :py:class:`Sheaf`. 41 | 42 | Similarly, if you want the nearest global section to your data, you can call 43 | 44 | .. py:method:: Sheaf.fuseAssignment(assignment, tol=1e-5) 45 | 46 | which returns a new :py:class:`Section` instance that is the global section nearest to your `assignment`. In this case, the tolerance `tol` is passed to :py:func:`scipy.optimize.minimize`. 47 | -------------------------------------------------------------------------------- /docs/_build/_sources/sheaves.rst.txt: -------------------------------------------------------------------------------- 1 | The :py:class:`Sheaf` type 2 | ========================== 3 | 4 | The :py:class:`Sheaf` class derives from :py:class:`CellComplex` to describe its base space. The additional attributes and methods of :py:class:`Sheaf` describe the "vertical fiber" structure of the sheaf. 5 | 6 | .. py:class:: Sheaf(CellComplex) 7 | 8 | The base sheaf class in PySheaf consists of a list :py:attr:`cell` of :py:class:`SheafCell` instances, describing the cells and the stalks over them. Restriction maps are built into :py:class:`SheafCoface` instances that are stored with each :py:class:`SheafCell`. 9 | 10 | .. py:method:: coboundary(k,compactSupport=False) 11 | 12 | Compute the degree `k` coboundary map of the :py:class:`Sheaf`, returning it as a :py:class:`numpy.ndarray`. If you want compactly supported cohomology (if you don't know what that means, you don't) then set `compactSupport=True`. 13 | 14 | .. py:method:: cohomology(k,compactSupport=False) 15 | 16 | Compute the degree `k` sheaf cohomology for the :py:class:`Sheaf`. If you want compactly supported cohomology (if you don't know what that means, you don't) then set `compactSupport=True`. This returns a :py:class:`numpy.ndarray` whose columns are the generators for cohomology. 17 | 18 | .. py:method:: betti(k) 19 | 20 | The dimension of the degree `k` sheaf cohomology space. 21 | 22 | .. warning :: This is not the dimension of the :py:meth:`CellComplex.homology()`, which is inherited into :py:class:`Sheaf`! 23 | 24 | .. py:class:: SheafCell(Cell) 25 | 26 | .. py:attribute:: stalkDim 27 | 28 | The dimension of the stalk over this cell. 29 | 30 | .. warning :: This has nothing to do with :py:attr:`SheafCell.dimension` inherited from :py:attr:`Cell`. 31 | 32 | .. py:attribute:: metric 33 | 34 | The metric on the stalk, used to measure distances between values in that stalk. This must by a function object that takes two arguments, each of which is a :py:class:`numpy.ndarray` and produces a numerical value. By default, it is the Euclidean distance given by :py:func:`numpy.linalg.norm()`. 35 | 36 | .. py:attribute:: cofaces 37 | 38 | Like :py:class:`Cell`, this should be a list of coface relations, but unlike :py:class:`Cell`, they must be :py:class:`SheafCoface` instances! 39 | 40 | .. py:class:: SheafCoface(Coface) 41 | 42 | A coface relation in a sheaf on a cell complex is built just like a :py:class:`Coface` in a :py:class:`CellComplex`, but with the addition of a :py:attr:`restriction`. 43 | 44 | .. py:attribute:: restriction 45 | 46 | A restriction in a sheaf generally needs to be a morphism in some category. It must be an object that supports *composition*, namely a class that implements a multiplication operator. In most examples, this is one of :py:class:`SetMorphism` (for functions between sets), :py:class:`LinearMorphism` (for linear maps), or a :py:class:`SheafMorphism` (for a :py:class:`Sheaf` of sheaves). Note that if you construct a :py:class:`SheafCoface` by passing a :py:class:`numpy.ndarray`, PySheaf will construct a :py:class:`LinearMorphism` restriction automatically. 47 | 48 | Morphisms: :py:class:`SetMorphism`, :py:class:`LinearMorphism`, and :py:class:`SheafMorphism` 49 | --------------------------------------------------------------------------------------------- 50 | 51 | Since cellular sheaves are special functors from the face category of a cell complex to some other *data category*, PySheaf supports three kinds of *data categories*: 52 | 53 | 1. Sets, 54 | 2. Finite dimensional vector spaces (via :py:mod:`numpy`), and 55 | 3. Sheaves (of some of other type). 56 | 57 | The restrictions in a given :py:class:`SheafCoface` instance are therefore of a corresponding morphism class: 58 | 59 | 1. :py:class:`SetMorphism`, 60 | 2. :py:class:`LinearMorphism`, and 61 | 3. :py:class:`SheafMorphism`. 62 | 63 | The simplest of these is :py:class:`SetMorphism`. 64 | 65 | .. py:class:: SetMorphism 66 | 67 | This represents a *set* morphism, otherwise known as a *function* between sets. This is implemented by a single attribute 68 | 69 | .. py:attribute:: fcn 70 | 71 | which is a function object taking one argument. 72 | 73 | :py:class:`SetMorphism` objects support a multiplication operator, which composes their respective :py:attr:`fcn` attributes to form a new function object. They also support call semantics, so you can simply call a :py:class:`SetMorphism` object as a function to access its :py:attr:`fcn` attribute. 74 | 75 | Namely, if you say:: 76 | 77 | foo = pysheaf.SetMorphism( lambda x : x**2 ) 78 | bar = pysheaf.SetMorphism( lambda y : 3*y ) 79 | 80 | then:: 81 | 82 | foo(3) 83 | 84 | returns 9 and:: 85 | 86 | baaz = foo * bar 87 | baaz(1) 88 | 89 | is also 9. 90 | 91 | A :py:class:`Sheaf` with only :py:class:`SetMorphism` restrictions does not allow you to compute :py:meth:`Sheaf.cohomology()`. For that, you need linearity, which is implemented by the following subclass of :py:class:`SetMorphism`. 92 | 93 | .. py:class:: LinearMorphism(SetMorphism) 94 | 95 | This implements a linear map, encoded as a :py:class:`numpy.ndarray`. Since it subclasses :py:class:`SetMorphism`, it inherits composition (as multiplication, which is of course *also* matrix multiplication) and call semantics. It also stores the matrix as a new attribute 96 | 97 | .. py:attribute:: matrix 98 | 99 | as you might expect. 100 | 101 | When constructing a :py:class:`SheafCoface`, if you pass an :py:class:`numpy.ndarray` as the `restriction` argument, PySheaf will automatically create :py:class:`LinearMorphism` objects as the restriction. 102 | 103 | The final kind of morphism that is supported is :py:class:`SheafMorphism`, which supports composition by implementing a multiplication operator, but *not* call semantics since sheaf morphisms are *not* functions. (It is true that they induce functions of various kinds, but PySheaf refrains from demanding that any particular kind of induced maps be computed by default.) 104 | 105 | .. py:class:: SheafMorphism 106 | 107 | A sheaf morphism from one sheaf to another consists of lists :py:attr:`destinations` and :py:attr:`maps` which correspond to the :py:attr:`Sheaf.cells` list in the domain sheaf. 108 | 109 | .. py:attribute:: destinations 110 | 111 | List of indices into the codomain sheaf's :py:attr:`Sheaf.cells` list for each component map of the sheaf morphism. Entries correspond to the :py:attr:`Sheaf.cells` list in the domain sheaf. 112 | 113 | .. py:attribute:: maps 114 | 115 | List of component maps (each of which may be any morphism class, like :py:class:`SetMorphism`, :py:class:`LinearMorphism`, or even :py:class:`SetMorphism`) corresponding to the :py:attr:`Sheaf.cells` list in the domain sheaf. 116 | 117 | Constructing :py:class:`Sheaf` instances 118 | ---------------------------------------- 119 | 120 | :py:class:`Sheaf` objects are constructed in essentially the same way as :py:class:`CellComplex` objects. Determining the indices for the :py:attr:`Sheaf.cells` list is crucial, as each :py:attr:`SheafCoface.index` will refer into it. Changes to the base space -- the inherited structure from :py:class:`CellComplex` -- are not easy and will generally involve many updates. Additionally, each :py:attr:`SheafCoface.restriction` ought to be known beforehand, though these can be changed at run time if needed. 121 | -------------------------------------------------------------------------------- /docs/_build/_static/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/_static/ajax-loader.gif -------------------------------------------------------------------------------- /docs/_build/_static/comment-bright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/_static/comment-bright.png -------------------------------------------------------------------------------- /docs/_build/_static/comment-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/_static/comment-close.png -------------------------------------------------------------------------------- /docs/_build/_static/comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/_static/comment.png -------------------------------------------------------------------------------- /docs/_build/_static/custom.css: -------------------------------------------------------------------------------- 1 | /* This file intentionally left blank. */ 2 | -------------------------------------------------------------------------------- /docs/_build/_static/doctools.js: -------------------------------------------------------------------------------- 1 | /* 2 | * doctools.js 3 | * ~~~~~~~~~~~ 4 | * 5 | * Sphinx JavaScript utilities for all documentation. 6 | * 7 | * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | 12 | /** 13 | * select a different prefix for underscore 14 | */ 15 | $u = _.noConflict(); 16 | 17 | /** 18 | * make the code below compatible with browsers without 19 | * an installed firebug like debugger 20 | if (!window.console || !console.firebug) { 21 | var names = ["log", "debug", "info", "warn", "error", "assert", "dir", 22 | "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", 23 | "profile", "profileEnd"]; 24 | window.console = {}; 25 | for (var i = 0; i < names.length; ++i) 26 | window.console[names[i]] = function() {}; 27 | } 28 | */ 29 | 30 | /** 31 | * small helper function to urldecode strings 32 | */ 33 | jQuery.urldecode = function(x) { 34 | return decodeURIComponent(x).replace(/\+/g, ' '); 35 | }; 36 | 37 | /** 38 | * small helper function to urlencode strings 39 | */ 40 | jQuery.urlencode = encodeURIComponent; 41 | 42 | /** 43 | * This function returns the parsed url parameters of the 44 | * current request. Multiple values per key are supported, 45 | * it will always return arrays of strings for the value parts. 46 | */ 47 | jQuery.getQueryParameters = function(s) { 48 | if (typeof s == 'undefined') 49 | s = document.location.search; 50 | var parts = s.substr(s.indexOf('?') + 1).split('&'); 51 | var result = {}; 52 | for (var i = 0; i < parts.length; i++) { 53 | var tmp = parts[i].split('=', 2); 54 | var key = jQuery.urldecode(tmp[0]); 55 | var value = jQuery.urldecode(tmp[1]); 56 | if (key in result) 57 | result[key].push(value); 58 | else 59 | result[key] = [value]; 60 | } 61 | return result; 62 | }; 63 | 64 | /** 65 | * highlight a given string on a jquery object by wrapping it in 66 | * span elements with the given class name. 67 | */ 68 | jQuery.fn.highlightText = function(text, className) { 69 | function highlight(node) { 70 | if (node.nodeType == 3) { 71 | var val = node.nodeValue; 72 | var pos = val.toLowerCase().indexOf(text); 73 | if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { 74 | var span = document.createElement("span"); 75 | span.className = className; 76 | span.appendChild(document.createTextNode(val.substr(pos, text.length))); 77 | node.parentNode.insertBefore(span, node.parentNode.insertBefore( 78 | document.createTextNode(val.substr(pos + text.length)), 79 | node.nextSibling)); 80 | node.nodeValue = val.substr(0, pos); 81 | } 82 | } 83 | else if (!jQuery(node).is("button, select, textarea")) { 84 | jQuery.each(node.childNodes, function() { 85 | highlight(this); 86 | }); 87 | } 88 | } 89 | return this.each(function() { 90 | highlight(this); 91 | }); 92 | }; 93 | 94 | /* 95 | * backward compatibility for jQuery.browser 96 | * This will be supported until firefox bug is fixed. 97 | */ 98 | if (!jQuery.browser) { 99 | jQuery.uaMatch = function(ua) { 100 | ua = ua.toLowerCase(); 101 | 102 | var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || 103 | /(webkit)[ \/]([\w.]+)/.exec(ua) || 104 | /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || 105 | /(msie) ([\w.]+)/.exec(ua) || 106 | ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || 107 | []; 108 | 109 | return { 110 | browser: match[ 1 ] || "", 111 | version: match[ 2 ] || "0" 112 | }; 113 | }; 114 | jQuery.browser = {}; 115 | jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; 116 | } 117 | 118 | /** 119 | * Small JavaScript module for the documentation. 120 | */ 121 | var Documentation = { 122 | 123 | init : function() { 124 | this.fixFirefoxAnchorBug(); 125 | this.highlightSearchWords(); 126 | this.initIndexTable(); 127 | 128 | }, 129 | 130 | /** 131 | * i18n support 132 | */ 133 | TRANSLATIONS : {}, 134 | PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, 135 | LOCALE : 'unknown', 136 | 137 | // gettext and ngettext don't access this so that the functions 138 | // can safely bound to a different name (_ = Documentation.gettext) 139 | gettext : function(string) { 140 | var translated = Documentation.TRANSLATIONS[string]; 141 | if (typeof translated == 'undefined') 142 | return string; 143 | return (typeof translated == 'string') ? translated : translated[0]; 144 | }, 145 | 146 | ngettext : function(singular, plural, n) { 147 | var translated = Documentation.TRANSLATIONS[singular]; 148 | if (typeof translated == 'undefined') 149 | return (n == 1) ? singular : plural; 150 | return translated[Documentation.PLURALEXPR(n)]; 151 | }, 152 | 153 | addTranslations : function(catalog) { 154 | for (var key in catalog.messages) 155 | this.TRANSLATIONS[key] = catalog.messages[key]; 156 | this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); 157 | this.LOCALE = catalog.locale; 158 | }, 159 | 160 | /** 161 | * add context elements like header anchor links 162 | */ 163 | addContextElements : function() { 164 | $('div[id] > :header:first').each(function() { 165 | $('\u00B6'). 166 | attr('href', '#' + this.id). 167 | attr('title', _('Permalink to this headline')). 168 | appendTo(this); 169 | }); 170 | $('dt[id]').each(function() { 171 | $('\u00B6'). 172 | attr('href', '#' + this.id). 173 | attr('title', _('Permalink to this definition')). 174 | appendTo(this); 175 | }); 176 | }, 177 | 178 | /** 179 | * workaround a firefox stupidity 180 | * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 181 | */ 182 | fixFirefoxAnchorBug : function() { 183 | if (document.location.hash) 184 | window.setTimeout(function() { 185 | document.location.href += ''; 186 | }, 10); 187 | }, 188 | 189 | /** 190 | * highlight the search words provided in the url in the text 191 | */ 192 | highlightSearchWords : function() { 193 | var params = $.getQueryParameters(); 194 | var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; 195 | if (terms.length) { 196 | var body = $('div.body'); 197 | if (!body.length) { 198 | body = $('body'); 199 | } 200 | window.setTimeout(function() { 201 | $.each(terms, function() { 202 | body.highlightText(this.toLowerCase(), 'highlighted'); 203 | }); 204 | }, 10); 205 | $('') 207 | .appendTo($('#searchbox')); 208 | } 209 | }, 210 | 211 | /** 212 | * init the domain index toggle buttons 213 | */ 214 | initIndexTable : function() { 215 | var togglers = $('img.toggler').click(function() { 216 | var src = $(this).attr('src'); 217 | var idnum = $(this).attr('id').substr(7); 218 | $('tr.cg-' + idnum).toggle(); 219 | if (src.substr(-9) == 'minus.png') 220 | $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); 221 | else 222 | $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); 223 | }).css('display', ''); 224 | if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { 225 | togglers.click(); 226 | } 227 | }, 228 | 229 | /** 230 | * helper function to hide the search marks again 231 | */ 232 | hideSearchWords : function() { 233 | $('#searchbox .highlight-link').fadeOut(300); 234 | $('span.highlighted').removeClass('highlighted'); 235 | }, 236 | 237 | /** 238 | * make the url absolute 239 | */ 240 | makeURL : function(relativeURL) { 241 | return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; 242 | }, 243 | 244 | /** 245 | * get the current relative url 246 | */ 247 | getCurrentURL : function() { 248 | var path = document.location.pathname; 249 | var parts = path.split(/\//); 250 | $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { 251 | if (this == '..') 252 | parts.pop(); 253 | }); 254 | var url = parts.join('/'); 255 | return path.substring(url.lastIndexOf('/') + 1, path.length - 1); 256 | }, 257 | 258 | initOnKeyListeners: function() { 259 | $(document).keyup(function(event) { 260 | var activeElementType = document.activeElement.tagName; 261 | // don't navigate when in search box or textarea 262 | if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { 263 | switch (event.keyCode) { 264 | case 37: // left 265 | var prevHref = $('link[rel="prev"]').prop('href'); 266 | if (prevHref) { 267 | window.location.href = prevHref; 268 | return false; 269 | } 270 | case 39: // right 271 | var nextHref = $('link[rel="next"]').prop('href'); 272 | if (nextHref) { 273 | window.location.href = nextHref; 274 | return false; 275 | } 276 | } 277 | } 278 | }); 279 | } 280 | }; 281 | 282 | // quick alias for translations 283 | _ = Documentation.gettext; 284 | 285 | $(document).ready(function() { 286 | Documentation.init(); 287 | }); -------------------------------------------------------------------------------- /docs/_build/_static/down-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/_static/down-pressed.png -------------------------------------------------------------------------------- /docs/_build/_static/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/_static/down.png -------------------------------------------------------------------------------- /docs/_build/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/_static/file.png -------------------------------------------------------------------------------- /docs/_build/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/_static/minus.png -------------------------------------------------------------------------------- /docs/_build/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/_static/plus.png -------------------------------------------------------------------------------- /docs/_build/_static/pygments.css: -------------------------------------------------------------------------------- 1 | .highlight .hll { background-color: #ffffcc } 2 | .highlight { background: #eeffcc; } 3 | .highlight .c { color: #408090; font-style: italic } /* Comment */ 4 | .highlight .err { border: 1px solid #FF0000 } /* Error */ 5 | .highlight .k { color: #007020; font-weight: bold } /* Keyword */ 6 | .highlight .o { color: #666666 } /* Operator */ 7 | .highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ 8 | .highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ 9 | .highlight .cp { color: #007020 } /* Comment.Preproc */ 10 | .highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ 11 | .highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ 12 | .highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ 13 | .highlight .gd { color: #A00000 } /* Generic.Deleted */ 14 | .highlight .ge { font-style: italic } /* Generic.Emph */ 15 | .highlight .gr { color: #FF0000 } /* Generic.Error */ 16 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 17 | .highlight .gi { color: #00A000 } /* Generic.Inserted */ 18 | .highlight .go { color: #333333 } /* Generic.Output */ 19 | .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ 20 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 21 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 22 | .highlight .gt { color: #0044DD } /* Generic.Traceback */ 23 | .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ 24 | .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ 25 | .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ 26 | .highlight .kp { color: #007020 } /* Keyword.Pseudo */ 27 | .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ 28 | .highlight .kt { color: #902000 } /* Keyword.Type */ 29 | .highlight .m { color: #208050 } /* Literal.Number */ 30 | .highlight .s { color: #4070a0 } /* Literal.String */ 31 | .highlight .na { color: #4070a0 } /* Name.Attribute */ 32 | .highlight .nb { color: #007020 } /* Name.Builtin */ 33 | .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ 34 | .highlight .no { color: #60add5 } /* Name.Constant */ 35 | .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ 36 | .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ 37 | .highlight .ne { color: #007020 } /* Name.Exception */ 38 | .highlight .nf { color: #06287e } /* Name.Function */ 39 | .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ 40 | .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ 41 | .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ 42 | .highlight .nv { color: #bb60d5 } /* Name.Variable */ 43 | .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ 44 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 45 | .highlight .mb { color: #208050 } /* Literal.Number.Bin */ 46 | .highlight .mf { color: #208050 } /* Literal.Number.Float */ 47 | .highlight .mh { color: #208050 } /* Literal.Number.Hex */ 48 | .highlight .mi { color: #208050 } /* Literal.Number.Integer */ 49 | .highlight .mo { color: #208050 } /* Literal.Number.Oct */ 50 | .highlight .sa { color: #4070a0 } /* Literal.String.Affix */ 51 | .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ 52 | .highlight .sc { color: #4070a0 } /* Literal.String.Char */ 53 | .highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ 54 | .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ 55 | .highlight .s2 { color: #4070a0 } /* Literal.String.Double */ 56 | .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ 57 | .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ 58 | .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ 59 | .highlight .sx { color: #c65d09 } /* Literal.String.Other */ 60 | .highlight .sr { color: #235388 } /* Literal.String.Regex */ 61 | .highlight .s1 { color: #4070a0 } /* Literal.String.Single */ 62 | .highlight .ss { color: #517918 } /* Literal.String.Symbol */ 63 | .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ 64 | .highlight .fm { color: #06287e } /* Name.Function.Magic */ 65 | .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ 66 | .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ 67 | .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ 68 | .highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ 69 | .highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /docs/_build/_static/up-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/_static/up-pressed.png -------------------------------------------------------------------------------- /docs/_build/_static/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/_static/up.png -------------------------------------------------------------------------------- /docs/_build/doctrees/cellcomplexes.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/doctrees/cellcomplexes.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/doctrees/environment.pickle -------------------------------------------------------------------------------- /docs/_build/doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/doctrees/index.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/intro.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/doctrees/intro.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/sections.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/doctrees/sections.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/sheaves.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/doctrees/sheaves.doctree -------------------------------------------------------------------------------- /docs/_build/html/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: c923a31e154911d189bbfea2fc3a3d87 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /docs/_build/html/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/html/.nojekyll -------------------------------------------------------------------------------- /docs/_build/html/_sources/cellcomplexes.rst.txt: -------------------------------------------------------------------------------- 1 | The CellComplex type 2 | ==================== 3 | 4 | The :py:class:`CellComplex` class consists of a list of :py:class:`Cell` instances and methods that manipulate the complex as a whole. It is also the base class for the :py:class:`Sheaf` class. The indices into the list of :py:class:`Cell` instances are used throughout PySheaf, and are the usual way to refer to individual :py:class:`Cell` instances when they are in context in a :py:class:`CellComplex`. Because the indices are necessary to construct the :py:class:`Cofaces` as well, it is usually necessary to determine the necessary cells ahead of time, and then build the :py:class:`CellComplex` instance all at once. 5 | 6 | .. py:class:: CellComplex 7 | 8 | .. py:attribute:: cells 9 | 10 | List of :py:class:`Cell` instances that form this cell. Indices into this list are used throughout PySheaf, and they are generally expected to be static once created. 11 | 12 | .. py:method:: homology(k,subcomplex=None,compactSupport=False,tol=1e-5) 13 | 14 | Compute the degree `k` homology of the :py:class:`CellComplex`. If you want relative homology, the `subcomplex` field specifies a list of indices into :py:class:`CellComplex.cells` for the relative subcomplex. If you want compactly supported homology (if you don't know what that means, you don't) then set `compactSupport=True`. The `tol` argument sets the tolerance below which a singular value is said to be zero, and thus is to be considered part of the kernel. This returns a :py:class:`numpy.ndarray` whose columns are the generators for homology. 15 | 16 | .. py:method:: boundary(k,subcomplex=None,compactSupport=False) 17 | 18 | Compute the degree `k` boundary map of the :py:class:`CellComplex`, returning it as a :py:class:`numpy.ndarray`. If you want relative homology, the `subcomplex` field specifies a list of indices into :py:class:`CellComplex.cells` for the relative subcomplex. If you want compactly supported homology (if you don't know what that means, you don't) then set `compactSupport=True`. 19 | 20 | .. py:method:: components(cells=[]) 21 | 22 | Compute connected components of the :py:class:`CellComplex`. The optional argument `cells` specifies list of permissible indices into :py:attr:`CellComplex.cells`. Returns a list of lists of indices into :py:attr:`CellComplex.cells`. 23 | 24 | .. py:method:: star(cells) 25 | 26 | Compute the star of a list of `cells` (specified as a list of indices into :py:attr:`CellComplex.cells`) in the topology of the :py:class:`CellComplex`. Returns a list of indices into :py:attr:`CellComplex.cells`. 27 | 28 | .. py:method:: closure(cells) 29 | 30 | Compute the closure of a list of `cells` (specified as a list of indices into :py:attr:`CellComplex.cells`) in the topology of the :py:class:`CellComplex`. Returns a list of indices into :py:attr:`CellComplex.cells`. 31 | 32 | .. py:method:: skeleton(k) 33 | 34 | Compute the dimension `k` skeleton of the :py:class:`CellComplex`. Returns a list of indices into :py:attr:`CellComplex.cells`. 35 | 36 | .. py:method:: cofaces(c,cells=[]) 37 | 38 | Return a generator that iterates over over :py:class:`Coface` instances (of *all* dimensions) for a cell whose index in :py:attr:`CellComplex.cells` is `c`. The optional argument specifies a list of indices into :py:attr:`CellComplex.cells` that are permitted to be traversed. 39 | 40 | .. warning :: duplicate :py:class:`Coface` instances are possible! 41 | 42 | Constructing :py:class:`CellComplex` instances 43 | ---------------------------------------------- 44 | 45 | A :py:class:`Cell` represents a single topological disk that is present in a given :py:class:`CellComplex`. Mostly, it contains references to other cells by their respective indices into :py:attr:`CellComplex.cells`. 46 | 47 | .. py:class:: Cell 48 | 49 | Base class representing a topological disk of a definite dimension. 50 | 51 | .. py:attribute:: dimension 52 | 53 | The dimension of the disk that this :py:class:`Cell` represents. The actual points of the disk are *not* represented, merely its dimension. (Note: this is *not* the dimension of the stalk over the cell in a :py:class:`SheafCell`) 54 | 55 | .. py:attribute:: compactClosure 56 | 57 | Flag that specifies if the topological closure of the :py:class:`Cell` in the :py:class:`CellComplex` is compact. Usually this should be `True`, as only those cells with compact closure are included in a homology calculation. Roughly speaking, those cells that have "missing" boundaries do not have compact closure. 58 | 59 | .. py:attribute:: name 60 | 61 | An optional name for the :py:class:`Cell`, which is generally not used by PySheaf. 62 | 63 | .. py:attribute:: cofaces 64 | 65 | A list of :py:class:`Coface` instances, specifying each coface of this cell. It is assumed that this coface points to a strictly higher-dimensional cell, and you will encounter endless loops if this assumption is violated. It is *not* assumed that the cofaces are all *one* dimension higher, though. It is not necessary to specify a transitive closure -- all cofaces -- as this can be determined by the containing :py:class:`CellComplex` as needed using :py:meth:`CellComplex.cofaces()`. 66 | 67 | The :py:class:`Coface` class specifies a single coface relation, in the context of a :py:class:`CellComplex`. 68 | 69 | .. py:class:: Coface 70 | 71 | Class representing a coface relation between two :py:class:`Cell` instances. The lower-dimension cell is implied to be the one holding this instance as its :py:attr:`Cell.cofaces` attribute, so this class *only* refers to the higher-dimension cell. 72 | 73 | .. py:attribute:: index 74 | 75 | The index of the higher-dimension cell in the containing :py:class:`CellComplex`. 76 | 77 | .. py:attribute:: orientation 78 | 79 | The orientation of this coface relation, usually either +1 or -1. 80 | 81 | :py:class:`CellComplex` instances are best built all at once. So for instance, a cell complex consisting of four vertices, named `A`, `B`, `C`, `D`, five edges `AB`, `AC`, `BC`, `BD`, `CD`, and one triangle `ABC` is constructed thusly:: 82 | 83 | pysheaf.CellComplex([pysheaf.Cell(dimension=0, 84 | compactClosure=True, 85 | name='A', 86 | cofaces=[pysheaf.Coface(index=4,orientation=1), # Index 4 = 'AB' 87 | pysheaf.Coface(index=5,orientation=1)]), # Index 5 = 'AC' 88 | pysheaf.Cell(dimension=0, 89 | compactClosure=True, 90 | name='B', 91 | cofaces=[pysheaf.Coface(index=4,orientation=-1), # Index 4 = 'AB' 92 | pysheaf.Coface(index=6,orientation=1), # Index 6 = 'BC' 93 | pysheaf.Coface(index=7,orientation=1)]), # Index 7 = 'BD' 94 | pysheaf.Cell(dimension=0, 95 | compactClosure=True, 96 | name='C', 97 | cofaces=[pysheaf.Coface(index=5,orientation=-1), # Index 5 = 'AC' 98 | pysheaf.Coface(index=6,orientation=-1), # Index 6 = 'BC' 99 | pysheaf.Coface(index=8,orientation=1)]), # Index 8 = 'CD' 100 | pysheaf.Cell(dimension=0, 101 | compactClosure=True, 102 | name='D', 103 | cofaces=[pysheaf.Coface(index=7,orientation=-1), # Index 7 = 'BD' 104 | pysheaf.Coface(index=8,orientation=-1)]),# Index 4 = 'CD' 105 | pysheaf.Cell(dimension=1, 106 | compactClosure=True, 107 | name='AB', 108 | cofaces=[pysheaf.Coface(index=9,orientation=1)]), # Index 9 = 'ABC' 109 | pysheaf.Cell(dimension=1, 110 | compactClosure=True, 111 | name='AC', 112 | cofaces=[pysheaf.Coface(index=9,orientation=-1)]),# Index 9 = 'ABC' 113 | pysheaf.Cell(dimension=1, 114 | compactClosure=True, 115 | name='BC', 116 | cofaces=[pysheaf.Coface(index=9,orientation=1)]), # Index 9 = 'ABC' 117 | pysheaf.Cell(dimension=1, 118 | compactClosure=True, 119 | name='BD', 120 | cofaces=[]), 121 | pysheaf.Cell(dimension=1, 122 | compactClosure=True, 123 | name='CD', 124 | cofaces=[]), 125 | pysheaf.Cell(dimension=2, 126 | compactClosure=True, 127 | name='ABC', 128 | cofaces=[])]) 129 | 130 | Subclasses of :py:class:`CellComplex` 131 | ------------------------------------- 132 | 133 | Since certain kinds of cell complex are specified combinatorially, PySheaf provides subclasses of :py:class:`CellComplex` whose constructors are a bit less verbose. 134 | 135 | .. py:class:: AbstractSimplicialComplex(CellComplex) 136 | 137 | An abstract simplicial complex is defined as a list of lists. Each list specifies a top dimensional simplex (a *toplex*). 138 | 139 | .. py:method:: __init__(toplexes,maxdim=None) 140 | 141 | It is only necessary to pass the constructor a generating set of `toplexes`, as all other simplices will be generated as :py:class:`Cell` instances as appropriate. Because of this, an :py:class:`AbstractSimplicialComplex` should not be constructed with high-dimensional simplices! To avoid problems, you may need to set the `maxdim` to be the largest dimension you want to have constructed. Simplices are sorted from greatest dimension to least in the resulting :py:attr:`AbstractSimplicialComplex.cells` list. 142 | 143 | .. py:class:: DirectedGraph(CellComplex) 144 | 145 | A directed graph consists of a list of ordered pairs of vertices. Strictly speaking, this is a directed, weighted *multi* graph, since duplicate edges are allowed. 146 | 147 | .. py:method:: __init__(graph,vertex_capacity=-1) 148 | 149 | Create a cell complex from a directed graph, where `graph` is a list of pairs (src,dest) or triples (src,dest,capacity) of numbers representing vertices. The optional `vertex_capacity` sets all the weights to the same value. Orientations of the resulting :py:class:`Coface` instances are taken from the ordering of the vertices in the tuples in `graph`. 150 | 151 | The vertex labeled `None` in any of these tuples is an external connection. In the resulting :py:class:`DirectedGraph.cells`, the cells are indexed as follows: 152 | 1. First all of the edges (in the order given), 153 | 2. then all vertices (in the order they are given; not by their numerical values) 154 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/index.rst.txt: -------------------------------------------------------------------------------- 1 | .. PySheaf documentation master file, created by 2 | sphinx-quickstart on Tue Apr 11 15:52:28 2017. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to PySheaf's documentation! 7 | =================================== 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents: 12 | 13 | intro 14 | cellcomplexes 15 | sheaves 16 | sections 17 | 18 | 19 | Indices and tables 20 | ================== 21 | 22 | * :ref:`genindex` 23 | * :ref:`modindex` 24 | * :ref:`search` 25 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/intro.rst.txt: -------------------------------------------------------------------------------- 1 | Introduction 2 | ============ 3 | 4 | PySheaf is a Python module that implements cellular sheaves with a view towards computing useful invariants such as cohomology, consistency radius, and induced maps. It is based on the idea that cell complexes are topological spaces, and that sheaves on cell complexes have at least that structure with some additional information as well. The design follows the principles set out in the following book, which might be helpful to consult: 5 | 6 | Michael Robinson, *Topological Signal Processing*, Springer, 2014. 7 | 8 | Although PySheaf can compute (co)homology of sheaves and cell complexes, the primary workflow for sheaves is 9 | 10 | 1. Construct the :py:class:`Sheaf` instance, which involves defining lists of :py:class:`SheafCell` and :py:class:`SheafCoface` instances. Presently, the :py:class:`Sheaf` instance will remain fixed once constructed. Therefore, make sure to have all stalks and restrictions defined at this point! 11 | 2. If you want to compute cohomology of the :py:class:`Sheaf`, you can do so using the :py:meth:`Sheaf.cohomology()` or :py:meth:`Sheaf.betti()` 12 | 3. Construct various :py:class:`Section` instances for the data you have. Key point: a :py:class:`Section` refers to a *local* section. Its :py:class:`SectionCell` members refer to the :py:class:`Sheaf` you've just finished building, so you must built the :py:class:`Sheaf` first! 13 | 4. Process the data using the :py:class:`Sheaf` and :py:class:`Section` instances: 14 | 15 | a. You can measure the consistency using :py:meth:`Sheaf.consistencyRadius()` 16 | b. You can fit a nearest global section using :py:meth:`Sheaf.fuseAssignment()` 17 | c. You may also use :py:meth:`Section.extend()` 18 | 19 | 5. If you want to relate your :py:class:`Sheaf` to others, you may construct a :py:class:`SheafMorphism` instance, which incidentally may *also* be used as a restriction morphism if you want to build a :py:class:`Sheaf` *of* sheaves! 20 | 21 | For cell complexes, you can do steps (1) and (2). Instead of a :py:class:`Sheaf`, you define a :py:class:`CellComplex` built from lists of :py:class:`Cell` and :py:class:`Coface` instances. 22 | 23 | PySheaf is very much under active development and exploration, since there aren't well-established ways of computing using sheaves to process data. Expect some rough edges, but feel free to suggest improvements! 24 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/sections.rst.txt: -------------------------------------------------------------------------------- 1 | The :py:class:`Section` class 2 | ============================= 3 | 4 | A :py:class:`Section` represents a local section, which is an instance of data stored in a sheaf. A :py:class:`Section` is constructed with a :py:class:`Sheaf` instance in mind, and therefore contains indices that refer into the :py:attr:`Sheaf.cells` list. A given :py:class:`Sheaf` might have several :py:class:`Section` instances. 5 | 6 | .. py:class:: Section 7 | 8 | .. py:attribute:: sectionCells 9 | 10 | The list of :py:class:`SectionCell` instances corresponding to this local section. Although mathematically local sections are not multi-valued, it is possible that duplicates are present as there are no checks for this. 11 | 12 | .. py:method:: support() 13 | 14 | List the :py:attr:`Sheaf.cells` indices in the support of this :py:class:`Section` 15 | 16 | .. py:method:: extend(sheaf,cell,value=None,tol=1e-5) 17 | 18 | Extend this :py:class:`Section` to another cell whose index is `cell` in the :py:attr:`Sheaf.cells` list of the `sheaf` and returns `True` if this can be done consistently according to the tolerance `tol`. You can optionally specify a `value` from the stalk over that cell; in this case the method can be used to test if this is a consistent choice or not. 19 | 20 | .. py:class:: SectionCell 21 | 22 | A single value from the stalk over a given cell, consisting of the 23 | 24 | .. py:attribute:: value 25 | 26 | itself, which ought to be of the appropriate type (can be passed to the functions :py:attr:`SheafCell.metric` and/or :py:attr:`SheafCoface.restriction`). One also needs to specify 27 | 28 | .. py:attribute:: support 29 | 30 | which records the :py:attr:`Sheaf.cells` index of the cell whose stalk from which this value was taken. 31 | 32 | 33 | Data fusion with :py:class:`Section` and :py:class:`Sheaf` instances 34 | -------------------------------------------------------------------- 35 | 36 | Given some data in a :py:class:`Section` for a :py:class:`Sheaf` you can measure the overall consistency radius with 37 | 38 | .. py:method:: Sheaf.consistencyRadius(assignment, tol=1e-5) 39 | 40 | where `assignment` is the :py:class:`Section` to be tested. The optional `tol` specifies the tolerance for consistency, to be used in conjunction with each :py:attr:`SheafCell.metric` in the :py:class:`Sheaf`. 41 | 42 | Similarly, if you want the nearest global section to your data, you can call 43 | 44 | .. py:method:: Sheaf.fuseAssignment(assignment, tol=1e-5) 45 | 46 | which returns a new :py:class:`Section` instance that is the global section nearest to your `assignment`. In this case, the tolerance `tol` is passed to :py:func:`scipy.optimize.minimize`. 47 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/sheaves.rst.txt: -------------------------------------------------------------------------------- 1 | The :py:class:`Sheaf` type 2 | ========================== 3 | 4 | The :py:class:`Sheaf` class derives from :py:class:`CellComplex` to describe its base space. The additional attributes and methods of :py:class:`Sheaf` describe the "vertical fiber" structure of the sheaf. 5 | 6 | .. py:class:: Sheaf(CellComplex) 7 | 8 | The base sheaf class in PySheaf consists of a list :py:attr:`cell` of :py:class:`SheafCell` instances, describing the cells and the stalks over them. Restriction maps are built into :py:class:`SheafCoface` instances that are stored with each :py:class:`SheafCell`. 9 | 10 | .. py:method:: coboundary(k,compactSupport=False) 11 | 12 | Compute the degree `k` coboundary map of the :py:class:`Sheaf`, returning it as a :py:class:`numpy.ndarray`. If you want compactly supported cohomology (if you don't know what that means, you don't) then set `compactSupport=True`. 13 | 14 | .. py:method:: cohomology(k,compactSupport=False) 15 | 16 | Compute the degree `k` sheaf cohomology for the :py:class:`Sheaf`. If you want compactly supported cohomology (if you don't know what that means, you don't) then set `compactSupport=True`. This returns a :py:class:`numpy.ndarray` whose columns are the generators for cohomology. 17 | 18 | .. py:method:: betti(k) 19 | 20 | The dimension of the degree `k` sheaf cohomology space. 21 | 22 | .. warning :: This is not the dimension of the :py:meth:`CellComplex.homology()`, which is inherited into :py:class:`Sheaf`! 23 | 24 | .. py:class:: SheafCell(Cell) 25 | 26 | .. py:attribute:: stalkDim 27 | 28 | The dimension of the stalk over this cell. 29 | 30 | .. warning :: This has nothing to do with :py:attr:`SheafCell.dimension` inherited from :py:attr:`Cell`. 31 | 32 | .. py:attribute:: metric 33 | 34 | The metric on the stalk, used to measure distances between values in that stalk. This must by a function object that takes two arguments, each of which is a :py:class:`numpy.ndarray` and produces a numerical value. By default, it is the Euclidean distance given by :py:func:`numpy.linalg.norm()`. 35 | 36 | .. py:attribute:: cofaces 37 | 38 | Like :py:class:`Cell`, this should be a list of coface relations, but unlike :py:class:`Cell`, they must be :py:class:`SheafCoface` instances! 39 | 40 | .. py:class:: SheafCoface(Coface) 41 | 42 | A coface relation in a sheaf on a cell complex is built just like a :py:class:`Coface` in a :py:class:`CellComplex`, but with the addition of a :py:attr:`restriction`. 43 | 44 | .. py:attribute:: restriction 45 | 46 | A restriction in a sheaf generally needs to be a morphism in some category. It must be an object that supports *composition*, namely a class that implements a multiplication operator. In most examples, this is one of :py:class:`SetMorphism` (for functions between sets), :py:class:`LinearMorphism` (for linear maps), or a :py:class:`SheafMorphism` (for a :py:class:`Sheaf` of sheaves). Note that if you construct a :py:class:`SheafCoface` by passing a :py:class:`numpy.ndarray`, PySheaf will construct a :py:class:`LinearMorphism` restriction automatically. 47 | 48 | Morphisms: :py:class:`SetMorphism`, :py:class:`LinearMorphism`, and :py:class:`SheafMorphism` 49 | --------------------------------------------------------------------------------------------- 50 | 51 | Since cellular sheaves are special functors from the face category of a cell complex to some other *data category*, PySheaf supports three kinds of *data categories*: 52 | 53 | 1. Sets, 54 | 2. Finite dimensional vector spaces (via :py:mod:`numpy`), and 55 | 3. Sheaves (of some of other type). 56 | 57 | The restrictions in a given :py:class:`SheafCoface` instance are therefore of a corresponding morphism class: 58 | 59 | 1. :py:class:`SetMorphism`, 60 | 2. :py:class:`LinearMorphism`, and 61 | 3. :py:class:`SheafMorphism`. 62 | 63 | The simplest of these is :py:class:`SetMorphism`. 64 | 65 | .. py:class:: SetMorphism 66 | 67 | This represents a *set* morphism, otherwise known as a *function* between sets. This is implemented by a single attribute 68 | 69 | .. py:attribute:: fcn 70 | 71 | which is a function object taking one argument. 72 | 73 | :py:class:`SetMorphism` objects support a multiplication operator, which composes their respective :py:attr:`fcn` attributes to form a new function object. They also support call semantics, so you can simply call a :py:class:`SetMorphism` object as a function to access its :py:attr:`fcn` attribute. 74 | 75 | Namely, if you say:: 76 | 77 | foo = pysheaf.SetMorphism( lambda x : x**2 ) 78 | bar = pysheaf.SetMorphism( lambda y : 3*y ) 79 | 80 | then:: 81 | 82 | foo(3) 83 | 84 | returns 9 and:: 85 | 86 | baaz = foo * bar 87 | baaz(1) 88 | 89 | is also 9. 90 | 91 | A :py:class:`Sheaf` with only :py:class:`SetMorphism` restrictions does not allow you to compute :py:meth:`Sheaf.cohomology()`. For that, you need linearity, which is implemented by the following subclass of :py:class:`SetMorphism`. 92 | 93 | .. py:class:: LinearMorphism(SetMorphism) 94 | 95 | This implements a linear map, encoded as a :py:class:`numpy.ndarray`. Since it subclasses :py:class:`SetMorphism`, it inherits composition (as multiplication, which is of course *also* matrix multiplication) and call semantics. It also stores the matrix as a new attribute 96 | 97 | .. py:attribute:: matrix 98 | 99 | as you might expect. 100 | 101 | When constructing a :py:class:`SheafCoface`, if you pass an :py:class:`numpy.ndarray` as the `restriction` argument, PySheaf will automatically create :py:class:`LinearMorphism` objects as the restriction. 102 | 103 | The final kind of morphism that is supported is :py:class:`SheafMorphism`, which supports composition by implementing a multiplication operator, but *not* call semantics since sheaf morphisms are *not* functions. (It is true that they induce functions of various kinds, but PySheaf refrains from demanding that any particular kind of induced maps be computed by default.) 104 | 105 | .. py:class:: SheafMorphism 106 | 107 | A sheaf morphism from one sheaf to another consists of lists :py:attr:`destinations` and :py:attr:`maps` which correspond to the :py:attr:`Sheaf.cells` list in the domain sheaf. 108 | 109 | .. py:attribute:: destinations 110 | 111 | List of indices into the codomain sheaf's :py:attr:`Sheaf.cells` list for each component map of the sheaf morphism. Entries correspond to the :py:attr:`Sheaf.cells` list in the domain sheaf. 112 | 113 | .. py:attribute:: maps 114 | 115 | List of component maps (each of which may be any morphism class, like :py:class:`SetMorphism`, :py:class:`LinearMorphism`, or even :py:class:`SetMorphism`) corresponding to the :py:attr:`Sheaf.cells` list in the domain sheaf. 116 | 117 | Constructing :py:class:`Sheaf` instances 118 | ---------------------------------------- 119 | 120 | :py:class:`Sheaf` objects are constructed in essentially the same way as :py:class:`CellComplex` objects. Determining the indices for the :py:attr:`Sheaf.cells` list is crucial, as each :py:attr:`SheafCoface.index` will refer into it. Changes to the base space -- the inherited structure from :py:class:`CellComplex` -- are not easy and will generally involve many updates. Additionally, each :py:attr:`SheafCoface.restriction` ought to be known beforehand, though these can be changed at run time if needed. 121 | -------------------------------------------------------------------------------- /docs/_build/html/_static/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/html/_static/ajax-loader.gif -------------------------------------------------------------------------------- /docs/_build/html/_static/comment-bright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/html/_static/comment-bright.png -------------------------------------------------------------------------------- /docs/_build/html/_static/comment-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/html/_static/comment-close.png -------------------------------------------------------------------------------- /docs/_build/html/_static/comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/html/_static/comment.png -------------------------------------------------------------------------------- /docs/_build/html/_static/custom.css: -------------------------------------------------------------------------------- 1 | /* This file intentionally left blank. */ 2 | -------------------------------------------------------------------------------- /docs/_build/html/_static/doctools.js: -------------------------------------------------------------------------------- 1 | /* 2 | * doctools.js 3 | * ~~~~~~~~~~~ 4 | * 5 | * Sphinx JavaScript utilities for all documentation. 6 | * 7 | * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | 12 | /** 13 | * select a different prefix for underscore 14 | */ 15 | $u = _.noConflict(); 16 | 17 | /** 18 | * make the code below compatible with browsers without 19 | * an installed firebug like debugger 20 | if (!window.console || !console.firebug) { 21 | var names = ["log", "debug", "info", "warn", "error", "assert", "dir", 22 | "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", 23 | "profile", "profileEnd"]; 24 | window.console = {}; 25 | for (var i = 0; i < names.length; ++i) 26 | window.console[names[i]] = function() {}; 27 | } 28 | */ 29 | 30 | /** 31 | * small helper function to urldecode strings 32 | */ 33 | jQuery.urldecode = function(x) { 34 | return decodeURIComponent(x).replace(/\+/g, ' '); 35 | }; 36 | 37 | /** 38 | * small helper function to urlencode strings 39 | */ 40 | jQuery.urlencode = encodeURIComponent; 41 | 42 | /** 43 | * This function returns the parsed url parameters of the 44 | * current request. Multiple values per key are supported, 45 | * it will always return arrays of strings for the value parts. 46 | */ 47 | jQuery.getQueryParameters = function(s) { 48 | if (typeof s == 'undefined') 49 | s = document.location.search; 50 | var parts = s.substr(s.indexOf('?') + 1).split('&'); 51 | var result = {}; 52 | for (var i = 0; i < parts.length; i++) { 53 | var tmp = parts[i].split('=', 2); 54 | var key = jQuery.urldecode(tmp[0]); 55 | var value = jQuery.urldecode(tmp[1]); 56 | if (key in result) 57 | result[key].push(value); 58 | else 59 | result[key] = [value]; 60 | } 61 | return result; 62 | }; 63 | 64 | /** 65 | * highlight a given string on a jquery object by wrapping it in 66 | * span elements with the given class name. 67 | */ 68 | jQuery.fn.highlightText = function(text, className) { 69 | function highlight(node) { 70 | if (node.nodeType == 3) { 71 | var val = node.nodeValue; 72 | var pos = val.toLowerCase().indexOf(text); 73 | if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { 74 | var span = document.createElement("span"); 75 | span.className = className; 76 | span.appendChild(document.createTextNode(val.substr(pos, text.length))); 77 | node.parentNode.insertBefore(span, node.parentNode.insertBefore( 78 | document.createTextNode(val.substr(pos + text.length)), 79 | node.nextSibling)); 80 | node.nodeValue = val.substr(0, pos); 81 | } 82 | } 83 | else if (!jQuery(node).is("button, select, textarea")) { 84 | jQuery.each(node.childNodes, function() { 85 | highlight(this); 86 | }); 87 | } 88 | } 89 | return this.each(function() { 90 | highlight(this); 91 | }); 92 | }; 93 | 94 | /* 95 | * backward compatibility for jQuery.browser 96 | * This will be supported until firefox bug is fixed. 97 | */ 98 | if (!jQuery.browser) { 99 | jQuery.uaMatch = function(ua) { 100 | ua = ua.toLowerCase(); 101 | 102 | var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || 103 | /(webkit)[ \/]([\w.]+)/.exec(ua) || 104 | /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || 105 | /(msie) ([\w.]+)/.exec(ua) || 106 | ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || 107 | []; 108 | 109 | return { 110 | browser: match[ 1 ] || "", 111 | version: match[ 2 ] || "0" 112 | }; 113 | }; 114 | jQuery.browser = {}; 115 | jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; 116 | } 117 | 118 | /** 119 | * Small JavaScript module for the documentation. 120 | */ 121 | var Documentation = { 122 | 123 | init : function() { 124 | this.fixFirefoxAnchorBug(); 125 | this.highlightSearchWords(); 126 | this.initIndexTable(); 127 | 128 | }, 129 | 130 | /** 131 | * i18n support 132 | */ 133 | TRANSLATIONS : {}, 134 | PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, 135 | LOCALE : 'unknown', 136 | 137 | // gettext and ngettext don't access this so that the functions 138 | // can safely bound to a different name (_ = Documentation.gettext) 139 | gettext : function(string) { 140 | var translated = Documentation.TRANSLATIONS[string]; 141 | if (typeof translated == 'undefined') 142 | return string; 143 | return (typeof translated == 'string') ? translated : translated[0]; 144 | }, 145 | 146 | ngettext : function(singular, plural, n) { 147 | var translated = Documentation.TRANSLATIONS[singular]; 148 | if (typeof translated == 'undefined') 149 | return (n == 1) ? singular : plural; 150 | return translated[Documentation.PLURALEXPR(n)]; 151 | }, 152 | 153 | addTranslations : function(catalog) { 154 | for (var key in catalog.messages) 155 | this.TRANSLATIONS[key] = catalog.messages[key]; 156 | this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); 157 | this.LOCALE = catalog.locale; 158 | }, 159 | 160 | /** 161 | * add context elements like header anchor links 162 | */ 163 | addContextElements : function() { 164 | $('div[id] > :header:first').each(function() { 165 | $('\u00B6'). 166 | attr('href', '#' + this.id). 167 | attr('title', _('Permalink to this headline')). 168 | appendTo(this); 169 | }); 170 | $('dt[id]').each(function() { 171 | $('\u00B6'). 172 | attr('href', '#' + this.id). 173 | attr('title', _('Permalink to this definition')). 174 | appendTo(this); 175 | }); 176 | }, 177 | 178 | /** 179 | * workaround a firefox stupidity 180 | * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 181 | */ 182 | fixFirefoxAnchorBug : function() { 183 | if (document.location.hash) 184 | window.setTimeout(function() { 185 | document.location.href += ''; 186 | }, 10); 187 | }, 188 | 189 | /** 190 | * highlight the search words provided in the url in the text 191 | */ 192 | highlightSearchWords : function() { 193 | var params = $.getQueryParameters(); 194 | var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; 195 | if (terms.length) { 196 | var body = $('div.body'); 197 | if (!body.length) { 198 | body = $('body'); 199 | } 200 | window.setTimeout(function() { 201 | $.each(terms, function() { 202 | body.highlightText(this.toLowerCase(), 'highlighted'); 203 | }); 204 | }, 10); 205 | $('') 207 | .appendTo($('#searchbox')); 208 | } 209 | }, 210 | 211 | /** 212 | * init the domain index toggle buttons 213 | */ 214 | initIndexTable : function() { 215 | var togglers = $('img.toggler').click(function() { 216 | var src = $(this).attr('src'); 217 | var idnum = $(this).attr('id').substr(7); 218 | $('tr.cg-' + idnum).toggle(); 219 | if (src.substr(-9) == 'minus.png') 220 | $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); 221 | else 222 | $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); 223 | }).css('display', ''); 224 | if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { 225 | togglers.click(); 226 | } 227 | }, 228 | 229 | /** 230 | * helper function to hide the search marks again 231 | */ 232 | hideSearchWords : function() { 233 | $('#searchbox .highlight-link').fadeOut(300); 234 | $('span.highlighted').removeClass('highlighted'); 235 | }, 236 | 237 | /** 238 | * make the url absolute 239 | */ 240 | makeURL : function(relativeURL) { 241 | return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; 242 | }, 243 | 244 | /** 245 | * get the current relative url 246 | */ 247 | getCurrentURL : function() { 248 | var path = document.location.pathname; 249 | var parts = path.split(/\//); 250 | $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { 251 | if (this == '..') 252 | parts.pop(); 253 | }); 254 | var url = parts.join('/'); 255 | return path.substring(url.lastIndexOf('/') + 1, path.length - 1); 256 | }, 257 | 258 | initOnKeyListeners: function() { 259 | $(document).keyup(function(event) { 260 | var activeElementType = document.activeElement.tagName; 261 | // don't navigate when in search box or textarea 262 | if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { 263 | switch (event.keyCode) { 264 | case 37: // left 265 | var prevHref = $('link[rel="prev"]').prop('href'); 266 | if (prevHref) { 267 | window.location.href = prevHref; 268 | return false; 269 | } 270 | case 39: // right 271 | var nextHref = $('link[rel="next"]').prop('href'); 272 | if (nextHref) { 273 | window.location.href = nextHref; 274 | return false; 275 | } 276 | } 277 | } 278 | }); 279 | } 280 | }; 281 | 282 | // quick alias for translations 283 | _ = Documentation.gettext; 284 | 285 | $(document).ready(function() { 286 | Documentation.init(); 287 | }); -------------------------------------------------------------------------------- /docs/_build/html/_static/down-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/html/_static/down-pressed.png -------------------------------------------------------------------------------- /docs/_build/html/_static/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/html/_static/down.png -------------------------------------------------------------------------------- /docs/_build/html/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/html/_static/file.png -------------------------------------------------------------------------------- /docs/_build/html/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/html/_static/minus.png -------------------------------------------------------------------------------- /docs/_build/html/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/html/_static/plus.png -------------------------------------------------------------------------------- /docs/_build/html/_static/pygments.css: -------------------------------------------------------------------------------- 1 | .highlight .hll { background-color: #ffffcc } 2 | .highlight { background: #eeffcc; } 3 | .highlight .c { color: #408090; font-style: italic } /* Comment */ 4 | .highlight .err { border: 1px solid #FF0000 } /* Error */ 5 | .highlight .k { color: #007020; font-weight: bold } /* Keyword */ 6 | .highlight .o { color: #666666 } /* Operator */ 7 | .highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ 8 | .highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ 9 | .highlight .cp { color: #007020 } /* Comment.Preproc */ 10 | .highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ 11 | .highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ 12 | .highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ 13 | .highlight .gd { color: #A00000 } /* Generic.Deleted */ 14 | .highlight .ge { font-style: italic } /* Generic.Emph */ 15 | .highlight .gr { color: #FF0000 } /* Generic.Error */ 16 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 17 | .highlight .gi { color: #00A000 } /* Generic.Inserted */ 18 | .highlight .go { color: #333333 } /* Generic.Output */ 19 | .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ 20 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 21 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 22 | .highlight .gt { color: #0044DD } /* Generic.Traceback */ 23 | .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ 24 | .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ 25 | .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ 26 | .highlight .kp { color: #007020 } /* Keyword.Pseudo */ 27 | .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ 28 | .highlight .kt { color: #902000 } /* Keyword.Type */ 29 | .highlight .m { color: #208050 } /* Literal.Number */ 30 | .highlight .s { color: #4070a0 } /* Literal.String */ 31 | .highlight .na { color: #4070a0 } /* Name.Attribute */ 32 | .highlight .nb { color: #007020 } /* Name.Builtin */ 33 | .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ 34 | .highlight .no { color: #60add5 } /* Name.Constant */ 35 | .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ 36 | .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ 37 | .highlight .ne { color: #007020 } /* Name.Exception */ 38 | .highlight .nf { color: #06287e } /* Name.Function */ 39 | .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ 40 | .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ 41 | .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ 42 | .highlight .nv { color: #bb60d5 } /* Name.Variable */ 43 | .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ 44 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 45 | .highlight .mb { color: #208050 } /* Literal.Number.Bin */ 46 | .highlight .mf { color: #208050 } /* Literal.Number.Float */ 47 | .highlight .mh { color: #208050 } /* Literal.Number.Hex */ 48 | .highlight .mi { color: #208050 } /* Literal.Number.Integer */ 49 | .highlight .mo { color: #208050 } /* Literal.Number.Oct */ 50 | .highlight .sa { color: #4070a0 } /* Literal.String.Affix */ 51 | .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ 52 | .highlight .sc { color: #4070a0 } /* Literal.String.Char */ 53 | .highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ 54 | .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ 55 | .highlight .s2 { color: #4070a0 } /* Literal.String.Double */ 56 | .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ 57 | .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ 58 | .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ 59 | .highlight .sx { color: #c65d09 } /* Literal.String.Other */ 60 | .highlight .sr { color: #235388 } /* Literal.String.Regex */ 61 | .highlight .s1 { color: #4070a0 } /* Literal.String.Single */ 62 | .highlight .ss { color: #517918 } /* Literal.String.Symbol */ 63 | .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ 64 | .highlight .fm { color: #06287e } /* Name.Function.Magic */ 65 | .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ 66 | .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ 67 | .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ 68 | .highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ 69 | .highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /docs/_build/html/_static/up-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/html/_static/up-pressed.png -------------------------------------------------------------------------------- /docs/_build/html/_static/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/html/_static/up.png -------------------------------------------------------------------------------- /docs/_build/html/index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Welcome to PySheaf’s documentation! — PySheaf 0.1 documentation 10 | 11 | 12 | 13 | 14 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 |
43 |
44 | 45 | 68 |
69 |

Indices and tables

70 | 75 |
76 | 77 | 78 |
79 |
80 |
81 | 115 |
116 |
117 | 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /docs/_build/html/intro.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Introduction — PySheaf 0.1 documentation 10 | 11 | 12 | 13 | 14 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
42 |
43 |
44 |
45 | 46 |
47 |

Introduction

48 |

PySheaf is a Python module that implements cellular sheaves with a view towards computing useful invariants such as cohomology, consistency radius, and induced maps. It is based on the idea that cell complexes are topological spaces, and that sheaves on cell complexes have at least that structure with some additional information as well. The design follows the principles set out in the following book, which might be helpful to consult:

49 |

Michael Robinson, Topological Signal Processing, Springer, 2014.

50 |

Although PySheaf can compute (co)homology of sheaves and cell complexes, the primary workflow for sheaves is

51 |
    52 |
  1. Construct the Sheaf instance, which involves defining lists of SheafCell and SheafCoface instances. Presently, the Sheaf instance will remain fixed once constructed. Therefore, make sure to have all stalks and restrictions defined at this point!
  2. 53 |
  3. If you want to compute cohomology of the Sheaf, you can do so using the Sheaf.cohomology() or Sheaf.betti()
  4. 54 |
  5. Construct various Section instances for the data you have. Key point: a Section refers to a local section. Its SectionCell members refer to the Sheaf you’ve just finished building, so you must built the Sheaf first!
  6. 55 |
  7. Process the data using the Sheaf and Section instances:
      56 |
    1. You can measure the consistency using Sheaf.consistencyRadius()
    2. 57 |
    3. You can fit a nearest global section using Sheaf.fuseAssignment()
    4. 58 |
    5. You may also use Section.extend()
    6. 59 |
    60 |
  8. 61 |
  9. If you want to relate your Sheaf to others, you may construct a SheafMorphism instance, which incidentally may also be used as a restriction morphism if you want to build a Sheaf of sheaves!
  10. 62 |
63 |

For cell complexes, you can do steps (1) and (2). Instead of a Sheaf, you define a CellComplex built from lists of Cell and Coface instances.

64 |

PySheaf is very much under active development and exploration, since there aren’t well-established ways of computing using sheaves to process data. Expect some rough edges, but feel free to suggest improvements!

65 |
66 | 67 | 68 |
69 |
70 |
71 | 100 |
101 |
102 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /docs/_build/html/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/html/objects.inv -------------------------------------------------------------------------------- /docs/_build/html/search.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Search — PySheaf 0.1 documentation 10 | 11 | 12 | 13 | 14 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 |
48 |
49 |
50 |
51 | 52 |

Search

53 |
54 | 55 |

56 | Please activate JavaScript to enable the search 57 | functionality. 58 |

59 |
60 |

61 | From here you can search these documents. Enter your search 62 | words into the box below and click "search". Note that the search 63 | function will automatically search for all of the words. Pages 64 | containing fewer words won't appear in the result list. 65 |

66 |
67 | 68 | 69 | 70 |
71 | 72 |
73 | 74 |
75 | 76 |
77 |
78 |
79 | 89 |
90 |
91 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /docs/_build/html/searchindex.js: -------------------------------------------------------------------------------- 1 | Search.setIndex({docnames:["cellcomplexes","index","intro","sections","sheaves"],envversion:50,filenames:["cellcomplexes.rst","index.rst","intro.rst","sections.rst","sheaves.rst"],objects:{"":{AbstractSimplicialComplex:[0,0,1,""],Cell:[0,0,1,""],CellComplex:[0,0,1,""],Coface:[0,0,1,""],DirectedGraph:[0,0,1,""],LinearMorphism:[4,0,1,""],Section:[3,0,1,""],SectionCell:[3,0,1,""],SetMorphism:[4,0,1,""],Sheaf:[4,0,1,""],SheafCell:[4,0,1,""],SheafCoface:[4,0,1,""],SheafMorphism:[4,0,1,""]},AbstractSimplicialComplex:{__init__:[0,1,1,""]},Cell:{cofaces:[0,2,1,""],compactClosure:[0,2,1,""],dimension:[0,2,1,""],name:[0,2,1,""]},CellComplex:{boundary:[0,1,1,""],cells:[0,2,1,""],closure:[0,1,1,""],cofaces:[0,1,1,""],components:[0,1,1,""],homology:[0,1,1,""],skeleton:[0,1,1,""],star:[0,1,1,""]},Coface:{index:[0,2,1,""],orientation:[0,2,1,""]},DirectedGraph:{__init__:[0,1,1,""]},LinearMorphism:{matrix:[4,2,1,""]},Section:{extend:[3,1,1,""],sectionCells:[3,2,1,""],support:[3,1,1,""]},SectionCell:{support:[3,2,1,""],value:[3,2,1,""]},SetMorphism:{fcn:[4,2,1,""]},Sheaf:{betti:[4,1,1,""],coboundary:[4,1,1,""],cohomology:[4,1,1,""],consistencyRadius:[3,1,1,""],fuseAssignment:[3,1,1,""]},SheafCell:{cofaces:[4,2,1,""],metric:[4,2,1,""],stalkDim:[4,2,1,""]},SheafCoface:{restriction:[4,2,1,""]},SheafMorphism:{destinations:[4,2,1,""],maps:[4,2,1,""]}},objnames:{"0":["py","class","Python class"],"1":["py","method","Python method"],"2":["py","attribute","Python attribute"]},objtypes:{"0":"py:class","1":"py:method","2":"py:attribute"},terms:{"abstract":0,"case":3,"class":[0,1,4],"default":4,"final":4,"function":[3,4],"new":[3,4],"return":[0,3,4],"static":0,"true":[0,3,4],For:[2,4],Its:2,One:3,The:[1,2],__init__:0,abc:0,abstractsimplicialcomplex:0,access:4,accord:3,activ:2,actual:0,addit:[2,4],addition:4,ahead:0,all:[0,2],allow:[0,4],also:[0,2,3,4],although:[2,3],ani:[0,4],anoth:[3,4],appropri:[0,3],aren:2,argument:[0,4],assign:3,assum:0,assumpt:0,attribut:[0,4],automat:4,avoid:0,baaz:4,bar:4,base:[0,2,4],becaus:0,beforehand:4,below:0,best:0,betti:[2,4],between:[0,4],bit:0,book:2,boundari:0,build:[0,2],built:[0,2,4],calcul:0,call:[3,4],can:[0,2,3,4],capac:0,categori:4,cell:[0,2,3,4],cellcomplex:[1,2,4],cellular:[2,4],certain:0,chang:4,check:3,choic:3,closur:0,coboundari:4,codomain:4,cofac:[0,2,4],cohomolog:[2,4],column:[0,4],combinatori:0,compact:0,compactclosur:0,compactli:[0,4],compactsupport:[0,4],complex:[0,2,4],compon:[0,4],compos:4,composit:4,comput:[0,2,4],conjunct:3,connect:0,consid:0,consist:[0,2,3,4],consistencyradiu:[2,3],construct:[1,2,3],constructor:0,consult:2,contain:[0,3],content:1,context:0,correspond:[3,4],cours:4,creat:[0,4],crucial:4,data:[1,2,4],defin:[0,2],definit:0,degre:[0,4],demand:4,deriv:4,describ:4,design:2,dest:0,destin:4,determin:[0,4],develop:2,dimens:[0,4],dimension:[0,4],direct:0,directedgraph:0,disk:0,distanc:4,doe:4,domain:4,don:[0,4],done:3,duplic:[0,3],each:[0,3,4],easi:4,edg:[0,2],either:0,encod:4,encount:0,endless:0,entri:4,essenti:4,establish:2,euclidean:4,even:4,exampl:4,expect:[0,2,4],explor:2,extend:[2,3],extern:0,face:4,fals:[0,4],fcn:4,feel:2,fiber:4,field:0,finish:2,finit:4,first:[0,2],fit:2,five:0,fix:2,flag:0,follow:[0,2,4],foo:4,form:[0,4],four:0,free:2,from:[0,2,3,4],functor:4,fuseassign:[2,3],fusion:1,gener:[0,4],given:[0,3,4],global:[2,3],graph:0,greatest:0,has:4,have:[0,2,3],help:2,high:0,higher:0,hold:0,homolog:[0,2,4],idea:2,implement:[2,4],impli:0,improv:2,incident:2,includ:0,index:[0,1,3,4],indic:[0,3,4],individu:0,induc:[2,4],inform:2,inherit:4,instanc:[1,2],instead:2,introduct:1,invari:2,involv:[2,4],iter:0,its:[0,4],itself:3,just:[2,4],kei:2,kernel:0,kind:[0,4],know:[0,4],known:4,label:0,lambda:4,largest:0,least:[0,2],less:0,like:4,linalg:4,linear:4,linearmorph:1,list:[0,2,3,4],local:[2,3],loop:0,lower:0,mai:[0,2,4],make:2,mani:4,manipul:0,map:[0,2,4],mathemat:3,matrix:4,maxdim:0,mean:[0,4],measur:[2,3,4],member:2,mere:0,method:[0,3,4],metric:[3,4],michael:2,might:[2,3,4],mind:3,minim:3,miss:0,modul:[1,2],morphism:[1,2],most:4,mostli:0,much:2,multi:[0,3],multipl:4,must:[2,4],name:[0,4],ndarrai:[0,4],nearest:[2,3],necessari:0,need:[0,3,4],none:[0,3],norm:4,note:[0,4],noth:4,number:0,numer:[0,4],numpi:[0,4],object:4,onc:[0,2],one:[0,4],onli:[0,4],oper:4,optim:3,option:[0,3],order:0,orient:0,other:[0,2,4],otherwis:4,ought:[3,4],out:2,over:[0,3,4],overal:3,page:1,pair:0,part:0,particular:4,pass:[0,3,4],permiss:0,permit:0,point:[0,2],possibl:[0,3],present:[0,2,3],primari:2,principl:2,problem:0,process:2,produc:4,provid:0,pysheaf:[0,2,4],python:2,radiu:[2,3],record:3,refer:[0,2,3,4],refrain:4,rel:0,relat:[0,2,4],remain:2,repres:[0,3,4],respect:[0,4],restrict:[2,3,4],result:0,robinson:2,rough:2,roughli:0,run:4,sai:4,said:0,same:[0,4],scipi:3,search:1,section:[1,2],sectioncel:[2,3],semant:4,set:[0,2,4],setmorph:1,sever:3,sheaf:[0,1,2],sheafcel:[0,2,3,4],sheafcofac:[2,3,4],sheafmorph:[1,2],sheav:[2,4],should:[0,4],signal:2,similarli:3,simplest:4,simplex:0,simpli:4,simplic:0,simplici:0,sinc:[0,2,4],singl:[0,3,4],singular:0,skeleton:0,some:[2,3,4],sort:0,space:[2,4],speak:0,special:4,specifi:[0,3],springer:2,src:0,stalk:[0,2,3,4],stalkdim:4,star:0,step:2,store:[3,4],strictli:0,structur:[2,4],subclass:[1,4],subcomplex:0,suggest:2,support:[0,3,4],sure:2,take:4,taken:[0,3],test:3,thei:[0,4],them:4,therefor:[2,3,4],thi:[0,2,3,4],those:0,though:[0,4],three:4,throughout:0,thu:0,thusli:0,time:[0,4],tol:[0,3],toler:[0,3],top:0,toplex:0,topolog:[0,2],toward:2,transit:0,travers:0,triangl:0,tripl:0,tupl:0,two:[0,4],type:[1,3],under:2,unlik:4,updat:4,use:2,used:[0,2,3,4],useful:2,using:[0,2],usual:0,valu:[0,3,4],variou:[2,4],vector:4,verbos:0,veri:2,vertex:0,vertex_capac:0,vertic:[0,4],via:4,view:2,violat:0,wai:[0,2,4],want:[0,2,3,4],weight:0,well:[0,2],what:[0,4],when:[0,4],where:[0,3],which:[0,2,3,4],whole:0,whose:[0,3,4],workflow:2,you:[0,2,3,4],your:[2,3],zero:0},titles:["The CellComplex type","Welcome to PySheaf’s documentation!","Introduction","The Section class","The Sheaf type"],titleterms:{"class":3,The:[0,3,4],cellcomplex:0,construct:[0,4],data:3,document:1,fusion:3,indic:1,instanc:[0,3,4],introduct:2,linearmorph:4,morphism:4,pysheaf:1,section:3,setmorph:4,sheaf:[3,4],sheafmorph:4,subclass:0,tabl:1,type:[0,4],welcom:1}}) -------------------------------------------------------------------------------- /docs/_build/index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Welcome to PySheaf’s documentation! — PySheaf 0.1 documentation 10 | 11 | 12 | 13 | 14 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 |
43 |
44 | 45 | 68 |
69 |

Indices and tables

70 | 75 |
76 | 77 | 78 |
79 |
80 |
81 | 115 |
116 |
117 | 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /docs/_build/intro.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Introduction — PySheaf 0.1 documentation 10 | 11 | 12 | 13 | 14 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
42 |
43 |
44 |
45 | 46 |
47 |

Introduction

48 |

PySheaf is a Python module that implements cellular sheaves with a view towards computing useful invariants such as cohomology, consistency radius, and induced maps. It is based on the idea that cell complexes are topological spaces, and that sheaves on cell complexes have at least that structure with some additional information as well. The design follows the principles set out in the following book, which might be helpful to consult:

49 |

Michael Robinson, Topological Signal Processing, Springer, 2014.

50 |

Although PySheaf can compute (co)homology of sheaves and cell complexes, the primary workflow for sheaves is

51 |
    52 |
  1. Construct the Sheaf instance, which involves defining lists of SheafCell and SheafCoface instances. Presently, the Sheaf instance will remain fixed once constructed. Therefore, make sure to have all stalks and restrictions defined at this point!
  2. 53 |
  3. If you want to compute cohomology of the Sheaf, you can do so using the Sheaf.cohomology() or Sheaf.betti()
  4. 54 |
  5. Construct various Section instances for the data you have. Key point: a Section refers to a local section. Its SectionCell members refer to the Sheaf you’ve just finished building, so you must built the Sheaf first!
  6. 55 |
  7. Process the data using the Sheaf and Section instances:
      56 |
    1. You can measure the consistency using Sheaf.consistencyRadius()
    2. 57 |
    3. You can fit a nearest global section using Sheaf.fuseAssignment()
    4. 58 |
    5. You may also use Section.extend()
    6. 59 |
    60 |
  8. 61 |
  9. If you want to relate your Sheaf to others, you may construct a SheafMorphism instance, which incidentally may also be used as a restriction morphism if you want to build a Sheaf of sheaves!
  10. 62 |
63 |

For cell complexes, you can do steps (1) and (2). Instead of a Sheaf, you define a CellComplex built from lists of Cell and Coface instances.

64 |

PySheaf is very much under active development and exploration, since there aren’t well-established ways of computing using sheaves to process data. Expect some rough edges, but feel free to suggest improvements!

65 |
66 | 67 | 68 |
69 |
70 |
71 | 100 |
101 |
102 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /docs/_build/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/docs/_build/objects.inv -------------------------------------------------------------------------------- /docs/_build/search.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Search — PySheaf 0.1 documentation 10 | 11 | 12 | 13 | 14 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 |
48 |
49 |
50 |
51 | 52 |

Search

53 |
54 | 55 |

56 | Please activate JavaScript to enable the search 57 | functionality. 58 |

59 |
60 |

61 | From here you can search these documents. Enter your search 62 | words into the box below and click "search". Note that the search 63 | function will automatically search for all of the words. Pages 64 | containing fewer words won't appear in the result list. 65 |

66 |
67 | 68 | 69 | 70 |
71 | 72 |
73 | 74 |
75 | 76 |
77 |
78 |
79 | 89 |
90 |
91 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /docs/_build/searchindex.js: -------------------------------------------------------------------------------- 1 | Search.setIndex({docnames:["cellcomplexes","index","intro","sections","sheaves"],envversion:50,filenames:["cellcomplexes.rst","index.rst","intro.rst","sections.rst","sheaves.rst"],objects:{"":{AbstractSimplicialComplex:[0,0,1,""],Cell:[0,0,1,""],CellComplex:[0,0,1,""],Coface:[0,0,1,""],DirectedGraph:[0,0,1,""],LinearMorphism:[4,0,1,""],Section:[3,0,1,""],SectionCell:[3,0,1,""],SetMorphism:[4,0,1,""],Sheaf:[4,0,1,""],SheafCell:[4,0,1,""],SheafCoface:[4,0,1,""],SheafMorphism:[4,0,1,""]},AbstractSimplicialComplex:{__init__:[0,1,1,""]},Cell:{cofaces:[0,2,1,""],compactClosure:[0,2,1,""],dimension:[0,2,1,""],name:[0,2,1,""]},CellComplex:{boundary:[0,1,1,""],cells:[0,2,1,""],closure:[0,1,1,""],cofaces:[0,1,1,""],components:[0,1,1,""],homology:[0,1,1,""],skeleton:[0,1,1,""],star:[0,1,1,""]},Coface:{index:[0,2,1,""],orientation:[0,2,1,""]},DirectedGraph:{__init__:[0,1,1,""]},LinearMorphism:{matrix:[4,2,1,""]},Section:{extend:[3,1,1,""],sectionCells:[3,2,1,""],support:[3,1,1,""]},SectionCell:{support:[3,2,1,""],value:[3,2,1,""]},SetMorphism:{fcn:[4,2,1,""]},Sheaf:{betti:[4,1,1,""],coboundary:[4,1,1,""],cohomology:[4,1,1,""],consistencyRadius:[3,1,1,""],fuseAssignment:[3,1,1,""]},SheafCell:{cofaces:[4,2,1,""],metric:[4,2,1,""],stalkDim:[4,2,1,""]},SheafCoface:{restriction:[4,2,1,""]},SheafMorphism:{destinations:[4,2,1,""],maps:[4,2,1,""]}},objnames:{"0":["py","class","Python class"],"1":["py","method","Python method"],"2":["py","attribute","Python attribute"]},objtypes:{"0":"py:class","1":"py:method","2":"py:attribute"},terms:{"abstract":0,"case":3,"class":[0,1,4],"default":4,"final":4,"function":[3,4],"new":[3,4],"return":[0,3,4],"static":0,"true":[0,3,4],For:[2,4],Its:2,One:3,The:[1,2],__init__:0,abc:0,abstractsimplicialcomplex:0,access:4,accord:3,activ:2,actual:0,addit:[2,4],addition:4,ahead:0,all:[0,2],allow:[0,4],also:[0,2,3,4],although:[2,3],ani:[0,4],anoth:[3,4],appropri:[0,3],aren:2,argument:[0,4],assign:3,assum:0,assumpt:0,attribut:[0,4],automat:4,avoid:0,baaz:4,bar:4,base:[0,2,4],becaus:0,beforehand:4,below:0,best:0,betti:[2,4],between:[0,4],bit:0,book:2,boundari:0,build:[0,2],built:[0,2,4],calcul:0,call:[3,4],can:[0,2,3,4],capac:0,categori:4,cell:[0,2,3,4],cellcomplex:[1,2,4],cellular:[2,4],certain:0,chang:4,check:3,choic:3,closur:0,coboundari:4,codomain:4,cofac:[0,2,4],cohomolog:[2,4],column:[0,4],combinatori:0,compact:0,compactclosur:0,compactli:[0,4],compactsupport:[0,4],complex:[0,2,4],compon:[0,4],compos:4,composit:4,comput:[0,2,4],conjunct:3,connect:0,consid:0,consist:[0,2,3,4],consistencyradiu:[2,3],construct:[1,2,3],constructor:0,consult:2,contain:[0,3],content:1,context:0,correspond:[3,4],cours:4,creat:[0,4],crucial:4,data:[1,2,4],defin:[0,2],definit:0,degre:[0,4],demand:4,deriv:4,describ:4,design:2,dest:0,destin:4,determin:[0,4],develop:2,dimens:[0,4],dimension:[0,4],direct:0,directedgraph:0,disk:0,distanc:4,doe:4,domain:4,don:[0,4],done:3,duplic:[0,3],each:[0,3,4],easi:4,edg:[0,2],either:0,encod:4,encount:0,endless:0,entri:4,essenti:4,establish:2,euclidean:4,even:4,exampl:4,expect:[0,2,4],explor:2,extend:[2,3],extern:0,face:4,fals:[0,4],fcn:4,feel:2,fiber:4,field:0,finish:2,finit:4,first:[0,2],fit:2,five:0,fix:2,flag:0,follow:[0,2,4],foo:4,form:[0,4],four:0,free:2,from:[0,2,3,4],functor:4,fuseassign:[2,3],fusion:1,gener:[0,4],given:[0,3,4],global:[2,3],graph:0,greatest:0,has:4,have:[0,2,3],help:2,high:0,higher:0,hold:0,homolog:[0,2,4],idea:2,implement:[2,4],impli:0,improv:2,incident:2,includ:0,index:[0,1,3,4],indic:[0,3,4],individu:0,induc:[2,4],inform:2,inherit:4,instanc:[1,2],instead:2,introduct:1,invari:2,involv:[2,4],iter:0,its:[0,4],itself:3,just:[2,4],kei:2,kernel:0,kind:[0,4],know:[0,4],known:4,label:0,lambda:4,largest:0,least:[0,2],less:0,like:4,linalg:4,linear:4,linearmorph:1,list:[0,2,3,4],local:[2,3],loop:0,lower:0,mai:[0,2,4],make:2,mani:4,manipul:0,map:[0,2,4],mathemat:3,matrix:4,maxdim:0,mean:[0,4],measur:[2,3,4],member:2,mere:0,method:[0,3,4],metric:[3,4],michael:2,might:[2,3,4],mind:3,minim:3,miss:0,modul:[1,2],morphism:[1,2],most:4,mostli:0,much:2,multi:[0,3],multipl:4,must:[2,4],name:[0,4],ndarrai:[0,4],nearest:[2,3],necessari:0,need:[0,3,4],none:[0,3],norm:4,note:[0,4],noth:4,number:0,numer:[0,4],numpi:[0,4],object:4,onc:[0,2],one:[0,4],onli:[0,4],oper:4,optim:3,option:[0,3],order:0,orient:0,other:[0,2,4],otherwis:4,ought:[3,4],out:2,over:[0,3,4],overal:3,page:1,pair:0,part:0,particular:4,pass:[0,3,4],permiss:0,permit:0,point:[0,2],possibl:[0,3],present:[0,2,3],primari:2,principl:2,problem:0,process:2,produc:4,provid:0,pysheaf:[0,2,4],python:2,radiu:[2,3],record:3,refer:[0,2,3,4],refrain:4,rel:0,relat:[0,2,4],remain:2,repres:[0,3,4],respect:[0,4],restrict:[2,3,4],result:0,robinson:2,rough:2,roughli:0,run:4,sai:4,said:0,same:[0,4],scipi:3,search:1,section:[1,2],sectioncel:[2,3],semant:4,set:[0,2,4],setmorph:1,sever:3,sheaf:[0,1,2],sheafcel:[0,2,3,4],sheafcofac:[2,3,4],sheafmorph:[1,2],sheav:[2,4],should:[0,4],signal:2,similarli:3,simplest:4,simplex:0,simpli:4,simplic:0,simplici:0,sinc:[0,2,4],singl:[0,3,4],singular:0,skeleton:0,some:[2,3,4],sort:0,space:[2,4],speak:0,special:4,specifi:[0,3],springer:2,src:0,stalk:[0,2,3,4],stalkdim:4,star:0,step:2,store:[3,4],strictli:0,structur:[2,4],subclass:[1,4],subcomplex:0,suggest:2,support:[0,3,4],sure:2,take:4,taken:[0,3],test:3,thei:[0,4],them:4,therefor:[2,3,4],thi:[0,2,3,4],those:0,though:[0,4],three:4,throughout:0,thu:0,thusli:0,time:[0,4],tol:[0,3],toler:[0,3],top:0,toplex:0,topolog:[0,2],toward:2,transit:0,travers:0,triangl:0,tripl:0,tupl:0,two:[0,4],type:[1,3],under:2,unlik:4,updat:4,use:2,used:[0,2,3,4],useful:2,using:[0,2],usual:0,valu:[0,3,4],variou:[2,4],vector:4,verbos:0,veri:2,vertex:0,vertex_capac:0,vertic:[0,4],via:4,view:2,violat:0,wai:[0,2,4],want:[0,2,3,4],weight:0,well:[0,2],what:[0,4],when:[0,4],where:[0,3],which:[0,2,3,4],whole:0,whose:[0,3,4],workflow:2,you:[0,2,3,4],your:[2,3],zero:0},titles:["The CellComplex type","Welcome to PySheaf’s documentation!","Introduction","The Section class","The Sheaf type"],titleterms:{"class":3,The:[0,3,4],cellcomplex:0,construct:[0,4],data:3,document:1,fusion:3,indic:1,instanc:[0,3,4],introduct:2,linearmorph:4,morphism:4,pysheaf:1,section:3,setmorph:4,sheaf:[3,4],sheafmorph:4,subclass:0,tabl:1,type:[0,4],welcom:1}}) -------------------------------------------------------------------------------- /docs/cellcomplexes.rst: -------------------------------------------------------------------------------- 1 | The CellComplex type 2 | ==================== 3 | 4 | The :py:class:`CellComplex` class consists of a list of :py:class:`Cell` instances and methods that manipulate the complex as a whole. It is also the base class for the :py:class:`Sheaf` class. The indices into the list of :py:class:`Cell` instances are used throughout PySheaf, and are the usual way to refer to individual :py:class:`Cell` instances when they are in context in a :py:class:`CellComplex`. Because the indices are necessary to construct the :py:class:`Cofaces` as well, it is usually necessary to determine the necessary cells ahead of time, and then build the :py:class:`CellComplex` instance all at once. 5 | 6 | .. py:class:: CellComplex 7 | 8 | .. py:attribute:: cells 9 | 10 | List of :py:class:`Cell` instances that form this cell. Indices into this list are used throughout PySheaf, and they are generally expected to be static once created. 11 | 12 | .. py:method:: homology(k,subcomplex=None,compactSupport=False,tol=1e-5) 13 | 14 | Compute the degree `k` homology of the :py:class:`CellComplex`. If you want relative homology, the `subcomplex` field specifies a list of indices into :py:class:`CellComplex.cells` for the relative subcomplex. If you want compactly supported homology (if you don't know what that means, you don't) then set `compactSupport=True`. The `tol` argument sets the tolerance below which a singular value is said to be zero, and thus is to be considered part of the kernel. This returns a :py:class:`numpy.ndarray` whose columns are the generators for homology. 15 | 16 | .. py:method:: betti(k, compactSupport=False,tol=1e-5) 17 | 18 | Compute the degree `k` Betti number of the :py:class:`CellComplex`. This is the dimension of the degree `k` homology space computed using :py:meth:`CellComplex.homology()`. 19 | 20 | .. warning :: This differs from the Betti number associated to the *cohomology* of any :py:class:`Sheaf`. To access that, use :py:meth:`Sheaf.cobetti()` instead! 21 | 22 | .. py:method:: boundary(k,subcomplex=None,compactSupport=False) 23 | 24 | Compute the degree `k` boundary map of the :py:class:`CellComplex`, returning it as a :py:class:`numpy.ndarray`. If you want relative homology, the `subcomplex` field specifies a list of indices into :py:class:`CellComplex.cells` for the relative subcomplex. If you want compactly supported homology (if you don't know what that means, you don't) then set `compactSupport=True`. 25 | 26 | .. py:method:: components(cells=[]) 27 | 28 | Compute connected components of the :py:class:`CellComplex`. The optional argument `cells` specifies list of permissible indices into :py:attr:`CellComplex.cells`. Returns a list of lists of indices into :py:attr:`CellComplex.cells`. 29 | 30 | .. py:method:: star(cells) 31 | 32 | Compute the star of a list of `cells` (specified as a list of indices into :py:attr:`CellComplex.cells`) in the topology of the :py:class:`CellComplex`. Returns a list of indices into :py:attr:`CellComplex.cells`. 33 | 34 | .. py:method:: closure(cells) 35 | 36 | Compute the closure of a list of `cells` (specified as a list of indices into :py:attr:`CellComplex.cells`) in the topology of the :py:class:`CellComplex`. Returns a list of indices into :py:attr:`CellComplex.cells`. 37 | 38 | .. py:method:: skeleton(k) 39 | 40 | Compute the dimension `k` skeleton of the :py:class:`CellComplex`. Returns a list of indices into :py:attr:`CellComplex.cells`. 41 | 42 | .. py:method:: cofaces(c,cells=[]) 43 | 44 | Return a generator that iterates over over :py:class:`Coface` instances (of *all* dimensions) for a cell whose index in :py:attr:`CellComplex.cells` is `c`. The optional argument specifies a list of indices into :py:attr:`CellComplex.cells` that are permitted to be traversed. 45 | 46 | .. warning :: duplicate :py:class:`Coface` instances are possible! 47 | 48 | Constructing :py:class:`CellComplex` instances 49 | ---------------------------------------------- 50 | 51 | A :py:class:`Cell` represents a single topological disk that is present in a given :py:class:`CellComplex`. Mostly, it contains references to other cells by their respective indices into :py:attr:`CellComplex.cells`. 52 | 53 | .. py:class:: Cell 54 | 55 | Base class representing a topological disk of a definite dimension. 56 | 57 | .. py:attribute:: dimension 58 | 59 | The dimension of the disk that this :py:class:`Cell` represents. The actual points of the disk are *not* represented, merely its dimension. (Note: this is *not* the dimension of the stalk over the cell in a :py:class:`SheafCell`) 60 | 61 | .. py:attribute:: compactClosure 62 | 63 | Flag that specifies if the topological closure of the :py:class:`Cell` in the :py:class:`CellComplex` is compact. Usually this should be `True`, as only those cells with compact closure are included in a homology calculation. Roughly speaking, those cells that have "missing" boundaries do not have compact closure. 64 | 65 | .. py:attribute:: name 66 | 67 | An optional name for the :py:class:`Cell`, which is generally not used by PySheaf. 68 | 69 | .. py:attribute:: cofaces 70 | 71 | A list of :py:class:`Coface` instances, specifying each coface of this cell. It is assumed that this coface points to a strictly higher-dimensional cell, and you will encounter endless loops if this assumption is violated. It is *not* assumed that the cofaces are all *one* dimension higher, though. It is not necessary to specify a transitive closure -- all cofaces -- as this can be determined by the containing :py:class:`CellComplex` as needed using :py:meth:`CellComplex.cofaces()`. 72 | 73 | The :py:class:`Coface` class specifies a single coface relation, in the context of a :py:class:`CellComplex`. 74 | 75 | .. py:class:: Coface 76 | 77 | Class representing a coface relation between two :py:class:`Cell` instances. The lower-dimension cell is implied to be the one holding this instance as its :py:attr:`Cell.cofaces` attribute, so this class *only* refers to the higher-dimension cell. 78 | 79 | .. py:attribute:: index 80 | 81 | The index of the higher-dimension cell in the containing :py:class:`CellComplex`. 82 | 83 | .. py:attribute:: orientation 84 | 85 | The orientation of this coface relation, usually either +1 or -1. 86 | 87 | :py:class:`CellComplex` instances are best built all at once. So for instance, a cell complex consisting of four vertices, named `A`, `B`, `C`, `D`, five edges `AB`, `AC`, `BC`, `BD`, `CD`, and one triangle `ABC` is constructed thusly:: 88 | 89 | pysheaf.CellComplex([pysheaf.Cell(dimension=0, 90 | compactClosure=True, 91 | name='A', 92 | cofaces=[pysheaf.Coface(index=4,orientation=1), # Index 4 = 'AB' 93 | pysheaf.Coface(index=5,orientation=1)]), # Index 5 = 'AC' 94 | pysheaf.Cell(dimension=0, 95 | compactClosure=True, 96 | name='B', 97 | cofaces=[pysheaf.Coface(index=4,orientation=-1), # Index 4 = 'AB' 98 | pysheaf.Coface(index=6,orientation=1), # Index 6 = 'BC' 99 | pysheaf.Coface(index=7,orientation=1)]), # Index 7 = 'BD' 100 | pysheaf.Cell(dimension=0, 101 | compactClosure=True, 102 | name='C', 103 | cofaces=[pysheaf.Coface(index=5,orientation=-1), # Index 5 = 'AC' 104 | pysheaf.Coface(index=6,orientation=-1), # Index 6 = 'BC' 105 | pysheaf.Coface(index=8,orientation=1)]), # Index 8 = 'CD' 106 | pysheaf.Cell(dimension=0, 107 | compactClosure=True, 108 | name='D', 109 | cofaces=[pysheaf.Coface(index=7,orientation=-1), # Index 7 = 'BD' 110 | pysheaf.Coface(index=8,orientation=-1)]),# Index 4 = 'CD' 111 | pysheaf.Cell(dimension=1, 112 | compactClosure=True, 113 | name='AB', 114 | cofaces=[pysheaf.Coface(index=9,orientation=1)]), # Index 9 = 'ABC' 115 | pysheaf.Cell(dimension=1, 116 | compactClosure=True, 117 | name='AC', 118 | cofaces=[pysheaf.Coface(index=9,orientation=-1)]),# Index 9 = 'ABC' 119 | pysheaf.Cell(dimension=1, 120 | compactClosure=True, 121 | name='BC', 122 | cofaces=[pysheaf.Coface(index=9,orientation=1)]), # Index 9 = 'ABC' 123 | pysheaf.Cell(dimension=1, 124 | compactClosure=True, 125 | name='BD', 126 | cofaces=[]), 127 | pysheaf.Cell(dimension=1, 128 | compactClosure=True, 129 | name='CD', 130 | cofaces=[]), 131 | pysheaf.Cell(dimension=2, 132 | compactClosure=True, 133 | name='ABC', 134 | cofaces=[])]) 135 | 136 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # PySheaf documentation build configuration file, created by 4 | # sphinx-quickstart on Thu Apr 20 18:12:14 2017. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | # If extensions (or modules to document with autodoc) are in another directory, 16 | # add these directories to sys.path here. If the directory is relative to the 17 | # documentation root, use os.path.abspath to make it absolute, like shown here. 18 | # 19 | # import os 20 | # import sys 21 | # sys.path.insert(0, os.path.abspath('.')) 22 | 23 | 24 | # -- General configuration ------------------------------------------------ 25 | 26 | # If your documentation needs a minimal Sphinx version, state it here. 27 | # 28 | # needs_sphinx = '1.0' 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = ['sphinx.ext.autodoc', 34 | 'sphinx.ext.imgmath', 35 | 'sphinx.ext.githubpages'] 36 | 37 | # Add any paths that contain templates here, relative to this directory. 38 | templates_path = ['_templates'] 39 | 40 | # The suffix(es) of source filenames. 41 | # You can specify multiple suffix as a list of string: 42 | # 43 | # source_suffix = ['.rst', '.md'] 44 | source_suffix = '.rst' 45 | 46 | # The master toctree document. 47 | master_doc = 'index' 48 | 49 | # General information about the project. 50 | project = u'PySheaf' 51 | copyright = u'2017, Michael Robinson' 52 | author = u'Michael Robinson' 53 | 54 | # The version info for the project you're documenting, acts as replacement for 55 | # |version| and |release|, also used in various other places throughout the 56 | # built documents. 57 | # 58 | # The short X.Y version. 59 | version = u'0.3' 60 | # The full version, including alpha/beta/rc tags. 61 | release = u'0.3' 62 | 63 | # The language for content autogenerated by Sphinx. Refer to documentation 64 | # for a list of supported languages. 65 | # 66 | # This is also used if you do content translation via gettext catalogs. 67 | # Usually you set "language" from the command line for these cases. 68 | language = None 69 | 70 | # List of patterns, relative to source directory, that match files and 71 | # directories to ignore when looking for source files. 72 | # This patterns also effect to html_static_path and html_extra_path 73 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 74 | 75 | # The name of the Pygments (syntax highlighting) style to use. 76 | pygments_style = 'sphinx' 77 | 78 | # If true, `todo` and `todoList` produce output, else they produce nothing. 79 | todo_include_todos = False 80 | 81 | 82 | # -- Options for HTML output ---------------------------------------------- 83 | 84 | # The theme to use for HTML and HTML Help pages. See the documentation for 85 | # a list of builtin themes. 86 | # 87 | html_theme = 'alabaster' 88 | 89 | # Theme options are theme-specific and customize the look and feel of a theme 90 | # further. For a list of options available for each theme, see the 91 | # documentation. 92 | # 93 | # html_theme_options = {} 94 | 95 | # Add any paths that contain custom static files (such as style sheets) here, 96 | # relative to this directory. They are copied after the builtin static files, 97 | # so a file named "default.css" will overwrite the builtin "default.css". 98 | html_static_path = ['_static'] 99 | 100 | 101 | # -- Options for HTMLHelp output ------------------------------------------ 102 | 103 | # Output file base name for HTML help builder. 104 | htmlhelp_basename = 'PySheafdoc' 105 | 106 | 107 | # -- Options for LaTeX output --------------------------------------------- 108 | 109 | latex_elements = { 110 | # The paper size ('letterpaper' or 'a4paper'). 111 | # 112 | # 'papersize': 'letterpaper', 113 | 114 | # The font size ('10pt', '11pt' or '12pt'). 115 | # 116 | # 'pointsize': '10pt', 117 | 118 | # Additional stuff for the LaTeX preamble. 119 | # 120 | # 'preamble': '', 121 | 122 | # Latex figure (float) alignment 123 | # 124 | # 'figure_align': 'htbp', 125 | } 126 | 127 | # Grouping the document tree into LaTeX files. List of tuples 128 | # (source start file, target name, title, 129 | # author, documentclass [howto, manual, or own class]). 130 | latex_documents = [ 131 | (master_doc, 'PySheaf.tex', u'PySheaf Documentation', 132 | u'Michael Robinson', 'manual'), 133 | ] 134 | 135 | 136 | # -- Options for manual page output --------------------------------------- 137 | 138 | # One entry per manual page. List of tuples 139 | # (source start file, name, description, authors, manual section). 140 | man_pages = [ 141 | (master_doc, 'pysheaf', u'PySheaf Documentation', 142 | [author], 1) 143 | ] 144 | 145 | 146 | # -- Options for Texinfo output ------------------------------------------- 147 | 148 | # Grouping the document tree into Texinfo files. List of tuples 149 | # (source start file, target name, title, author, 150 | # dir menu entry, description, category) 151 | texinfo_documents = [ 152 | (master_doc, 'PySheaf', u'PySheaf Documentation', 153 | author, 'PySheaf', 'One line description of project.', 154 | 'Miscellaneous'), 155 | ] 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. PySheaf documentation master file, created by 2 | sphinx-quickstart on Tue Apr 11 15:52:28 2017. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to PySheaf's documentation! 7 | =================================== 8 | 9 | The PySheaf library is an experimental platform for computational and applied sheaf theory. Have a look at the latest version at the PySheaf GitHub repository: ``_ 10 | 11 | Sheaves are managed by subclassing from :py:class:`CellComplex`, which is a little awkward as :py:class:`SheafCell` is subclassed from :py:class:`Cell`, etc. However, the idea is that everything that can be done to the base space of a sheaf is inherited from its underlying :py:class:`CellComplex` structure. 12 | 13 | Assignments of sheaves have their own :py:class:`Assignment` class. This data structure does not self-check for consistency, so it is properly an "assignment" or "serration". :py:class:`Assignment` instances know how to extend themselves consistent with a :py:class:`Sheaf`. 14 | 15 | .. toctree:: 16 | :maxdepth: 2 17 | :caption: Contents: 18 | 19 | intro 20 | install 21 | cellcomplexes 22 | sheaves 23 | sections 24 | 25 | 26 | Indices and tables 27 | ================== 28 | 29 | * :ref:`genindex` 30 | * :ref:`modindex` 31 | * :ref:`search` 32 | -------------------------------------------------------------------------------- /docs/install.rst: -------------------------------------------------------------------------------- 1 | Installation instructions for PySheaf using a conda environment 2 | =============================================================== 3 | 4 | PySheaf is written for python 2.7. To install and test PySheaf we recommend using a virtual environment. The instructions below will walk you through the following steps: 5 | 6 | 1. Download and install miniconda (or anaconda if you prefer) 7 | 2. Create a :py:mod:`conda` environment 8 | 3. Download and install the PySheaf repository 9 | 4. Run unit tests 10 | 11 | Download and install miniconda: 12 | ------------------------------- 13 | 14 | *If you already have an anaconda or miniconda distribution you may skip this part.* 15 | 16 | Anaconda and Miniconda are source distributions of Python used by the mathematics and scientific communities that simplify package management and version control. Both use the :py:mod:`conda` package management system and both provide environments to isolate python packages and their dependencies. Anaconda includes :py:mod:`conda`, :py:mod:`conda-build`, :py:mod:`python` and over 150 python packages. Miniconda is a smaller version that only includes :py:mod:`conda`, :py:mod:`python`, and the packages they depend on. For our purposes we will install miniconda to create a minimal environment adequate for testing and using pysheaf. 17 | 18 | To download miniconda go to ``_ and chose your operating system. Both Anaconda and Miniconda install multiple Python versions. The python version you choose will be used by default but in a virtual environment we will specify the version. Installation instructions are described on the site. 19 | 20 | You can test that your installation was successful by entering:: 21 | 22 | conda list 23 | 24 | on the command line. To view the python versions available enter:: 25 | 26 | conda search python 27 | 28 | Create a :py:mod:`conda` environment 29 | ------------------------------------ 30 | 31 | The :py:mod:`conda` environment will expose only the version of python and the python packages that you choose. On the command line enter:: 32 | 33 | conda create --name pysheafenv python=2.7 34 | 35 | Conda environments are stored within your miniconda (anaconda) directory in the envs folder. To see a list of your environments enter:: 36 | 37 | conda info -e 38 | 39 | To remove the pysheafenv environment enter:: 40 | 41 | conda remove --name pysheafenv --all 42 | 43 | To use the environment you must activate it. On Windows:: 44 | 45 | activate pysheafenv 46 | 47 | On OS X or Linux:: 48 | 49 | source activate pysheafenv 50 | 51 | This will add (pysheafenv) to your command prompt. 52 | 53 | To deactivate the environment on Windows:: 54 | 55 | deactivate 56 | 57 | On OS X or Linux:: 58 | 59 | source deactivate 60 | 61 | Download and install the PySheaf repository 62 | ------------------------------------------- 63 | 64 | Activate pysheafenv as described above. To see what packages were installed enter:: 65 | 66 | conda list 67 | 68 | Change to the directory where you wish PySheaf to be installed. 69 | 70 | The :py:mod:`pip` package was installed automatically with python 2.7. We will need the :py:mod:`pip` package manager to install PySheaf directly from github. 71 | 72 | Because we wish to test the installation using the :py:mod:`unittest` module we will use the -e for editable option. This will also permit us to review the code from the current directory:: 73 | 74 | pip install -e git+https://github.com/kb1dds/pysheaf.git#egg=pysheaf 75 | 76 | Depending on your system (Windows in particular) this may or may not install all of the dependencies. If you get an error message that something is missing you can install the missing dependencies using :py:mod:`conda`. PySheaf requires :py:mod:`numpy`, :py:mod:`networkx`, :py:mod:`scipy`, and :py:mod:`deap`. 77 | To install these using :py:mod:`conda`:: 78 | 79 | conda install numpy networkx scipy 80 | conda install -c conda-forge deap 81 | 82 | **Note:** If you only wish to install the PySheaf package for purposes of imports and do not wish to run the tests or review the source code then use the following for pip install:: 83 | 84 | pip install git+https://github.com/kb1dds/pysheaf.git 85 | 86 | If you look at the installed packages for this environment:: 87 | 88 | conda list 89 | 90 | you will see PySheaf has been added to the packages. (If your default python installation is python 2.7 and you do not wish to use a virtual environment you may try this pip command directly without the use of :py:mod:`conda`. Success will depend on your system's installed packages and configuration.) 91 | 92 | Run unit tests 93 | -------------- 94 | 95 | Assuming you have installed the package into PySheaf you will now change to that directory and run the tests:: 96 | 97 | cd src/pysheaf 98 | python -m unittest discover 99 | 100 | If everything is working you will get a bunch of warnings and a line that looks something like:: 101 | 102 | Ran 57 tests in 0.070s 103 | OK 104 | -------------------------------------------------------------------------------- /docs/intro.rst: -------------------------------------------------------------------------------- 1 | Introduction 2 | ============ 3 | 4 | PySheaf is a Python module that implements cellular sheaves with a view towards computing useful invariants such as cohomology, consistency radius, and induced maps. It is based on the idea that cell complexes are topological spaces, and that sheaves on cell complexes have at least that structure with some additional information as well. The design follows the principles set out in the following book, which might be helpful to consult: 5 | 6 | Michael Robinson, *Topological Signal Processing*, Springer, 2014. 7 | 8 | Although PySheaf can compute (co)homology of sheaves and cell complexes, the primary workflow for sheaves is 9 | 10 | 1. Construct the :py:class:`Sheaf` instance, which involves defining lists of :py:class:`SheafCell` and :py:class:`SheafCoface` instances. Presently, the :py:class:`Sheaf` instance will remain fixed once constructed. Therefore, make sure to have all stalks and restrictions defined at this point! 11 | 2. If you want to compute cohomology of the :py:class:`Sheaf`, you can do so using the :py:meth:`Sheaf.cohomology()` or :py:meth:`Sheaf.cobetti()` 12 | 3. Construct various :py:class:`Assignment` instances for the data you have. Key point: a :py:class:`Assignment` refers to a *local* section. Its :py:class:`AssignmentCell` members refer to the :py:class:`Sheaf` you've just finished building, so you must built the :py:class:`Sheaf` first! 13 | 4. Process the data using the :py:class:`Sheaf` and :py:class:`Assignment` instances: 14 | 15 | a. You can measure the consistency using :py:meth:`Sheaf.consistencyRadius()` 16 | b. You can extend the assignment using :py:meth:`Sheaf.minimizeConsistencyRadius()` or fit a nearest global section using :py:meth:`Sheaf.fuseAssignment()` 17 | c. You may also use :py:meth:`Assignment.extend()` or :py:meth:`Assignment.maximalExtend()` 18 | 19 | 5. If you want to relate your :py:class:`Sheaf` to others, you may construct a :py:class:`SheafMorphism` instance, which incidentally may *also* be used as a restriction morphism if you want to build a :py:class:`Sheaf` *of* sheaves! 20 | 21 | For cell complexes, you can do steps (1) and (2). Instead of a :py:class:`Sheaf`, you define a :py:class:`CellComplex` built from lists of :py:class:`Cell` and :py:class:`Coface` instances. 22 | 23 | PySheaf is very much under active development and exploration, since there aren't well-established ways of computing using sheaves to process data. Expect some rough edges, but feel free to suggest improvements! 24 | -------------------------------------------------------------------------------- /docs/sections.rst: -------------------------------------------------------------------------------- 1 | The :py:class:`Assignment` class 2 | ================================ 3 | 4 | A :py:class:`Assignment` represents a local section, which is an instance of data stored in a sheaf. A :py:class:`Assignment` is constructed with a :py:class:`Sheaf` instance in mind, and therefore contains indices that refer into the :py:attr:`Sheaf.cells` list. A given :py:class:`Sheaf` might have several :py:class:`Assignment` instances. 5 | 6 | .. py:class:: Assignment 7 | 8 | .. py:attribute:: assignmentCells 9 | 10 | The list of :py:class:`AssignmentCell` instances corresponding to this assignment. Although mathematically assignments and/or sections are not multi-valued, it is possible that duplicates are present as there are no checks for this. 11 | 12 | .. py:method:: support() 13 | 14 | List the :py:attr:`Sheaf.cells` indices in the support of this :py:class:`Assignment` 15 | 16 | .. py:method:: extend(sheaf,cell,value=None,tol=1e-5) 17 | 18 | Extend this :py:class:`Assignment` to another cell whose index is `cell` in the :py:attr:`Sheaf.cells` list of the `sheaf` and returns `True` if this can be done consistently according to the tolerance `tol`. You can optionally specify a `value` from the stalk over that cell; in this case the method can be used to test if this is a consistent choice or not. 19 | 20 | .. py:method:: maximalExtend(sheaf,multiassign=False,tol=1e-5) 21 | 22 | Extend this :py:class:`Assignment` to a maximal assignment that's non-conflicting (if `multiassign=False`) or one in which multiple values can be given to a given cell (if `multiassign=True`). 23 | 24 | .. py:class:: AssignmentCell 25 | 26 | A single value from the stalk over a given cell, consisting of the 27 | 28 | .. py:attribute:: value 29 | 30 | itself, which ought to be of the appropriate type (can be passed to the functions :py:attr:`SheafCell.metric` and/or :py:attr:`SheafCoface.restriction`). One also needs to specify 31 | 32 | .. py:attribute:: support 33 | 34 | which records the :py:attr:`Sheaf.cells` index of the cell whose stalk from which this value was taken. 35 | 36 | 37 | Data fusion with :py:class:`Assignment` and :py:class:`Sheaf` instances 38 | ----------------------------------------------------------------------- 39 | 40 | Given some data in a :py:class:`Assignment` for a :py:class:`Sheaf` you can measure the overall consistency radius with 41 | 42 | .. py:method:: Sheaf.consistencyRadius(assignment, testSupport=None, tol=1e-5) 43 | 44 | where `assignment` is the :py:class:`Assignment` to be tested. The optional `tol` specifies the tolerance for consistency, to be used in conjunction with each :py:attr:`SheafCell.metric` in the :py:class:`Sheaf`. 45 | 46 | The optional `testSupport` parameter is a list of cell indices on which consistency is to be assessed. If it is listed as `None`, then the entire base space is to be tested. 47 | 48 | .. warning :: It is not assumed that `testSupport` is an open set in the topology of the underlying base space. :py:meth:`Sheaf.consistencyRadius` automatically extends the `assignment` to be supported on the star over `testSupport`. 49 | 50 | .. warning :: Consistency radius is measured using the cells specified in the :py:class:`Assignment` and all cells that are specified as :py:attr:`Sheaf.Cofaces`. Preimages through :py:attr:`Sheaf.restriction` maps are not computed, so values on faces are not tested. 51 | 52 | If you want to extend your :py:class:`Assignment` to be supported on all cells of its :py:class:`Sheaf`, leaving the existing :py:class:`Assignment` unchanged, while extending it as much as possible. This is done either via :py:meth:`Assignment.maximalExtend` or the following: 53 | 54 | .. py:method:: Sheaf.minimizeConsistencyRadius(assignment, activeCells=None, testSupport=None, method='nelder-mead', ord = np.inf, options={}, tol=1e-5) 55 | 56 | This constructs a new :py:class:`Assignment` instance based on an existing `assignment`. The `activeCells` is the set of cells whose values are to be changed. If `activeCells` is `None`, all cells outside the support of the assignment will be changed, but nothing in the support of the assignment will be changed. 57 | 58 | As in other methods, `testSupport` is the set of cells over which consistency radius is measured. 59 | 60 | Currently, any optimization supported by `scipy.optimize.minimize` is supported as a `method` oprtion, and `tol` is the passed to :py:func:`scipy.optimize.minimize`. 61 | 62 | On the other hand, if you want the nearest global section to your data, you can call 63 | 64 | .. py:method:: Sheaf.fuseAssignment(assignment, activeCells=None, testSupport=None, method='SLSQP', options={}, tol=1e-5) 65 | 66 | which returns a new :py:class:`Assignment` instance that is the global section nearest to your `assignment`. In this case, the tolerance `tol` is passed to :py:func:`scipy.optimize.minimize`. 67 | 68 | As in :py:meth:`Sheaf.consistencyRadius`, the `testSupport` specifies a list of cells under which consistency is measured. 69 | 70 | The `activeCells` argument is a list of cells whose stalks are allowed to be changed by the fusion process. If passed as `None`, all values in the stalks over all cells may be changed. 71 | 72 | The method is a string, specifying the optimizer method to be used. There are currently three optimizers implemented, 'KernelProj', 'SLSQP', and 'GA': 73 | 74 | 'KernelProj': Uses kernel projection for sheaves of vector spaces. In this case, every restriction map must be given as a :py:class:`LinearMorphism`, and :py:meth:`Sheaf.isLinear` must return `True`. Kernel projection is usually the fastest and most accurate method if it is available. 75 | 'SLSQP': This algorithm is :py:meth:`scipy.optimize.minimize` default for bounded optimization 76 | 'GA': This genetic algorithm was implemented using DEAP for optimizations over nondifferentiable functions. For this algorithm, it takes `options`: a dictionary to store changes to parameters, the keys must be identical to the current parameters. 77 | 78 | 1. `initial_pop_size` - the number of individuals in the starting population 79 | 2. `mutation_rate` - the proportion of the offspring (newly created individuals each round) that are from mutations rather than mating 80 | 3. `num_generations` - the number of iterations that the genetic algorithm runs 81 | 4. `num_ele_Hallfame` - the number of top individuals that should be reported in the hall of fame (hof) 82 | 83 | Covers of :py:class:`CellComplex` instances based on a :py:class:`Assignment` of a :py:class:`Sheaf` 84 | ---------------------------------------------------------------------------------------------------- 85 | 86 | One can restrict attention to portions of a :py:class:`Assignment` instance. This allows its consistency with its :py:class:`Sheaf` to be assessed locally. By restricting the consistency testing to a list `testSupport` of cells in :py:meth:`Sheaf.consistencyRadius`, callers can examine consistency on a part of the base space of the :py:class:`Sheaf`. 87 | 88 | Given a `threshold` for consistency, one can compute cover in which each list consists of cells that are consistent to that `threshold`. This is computed by 89 | 90 | .. py:method:: Sheaf.consistentCollection(self,assignment,threshold,testSupport=None,tol=1e-5) 91 | 92 | which relies on the aforementioned `threshold` and a :py:class:`Assignment` instance `assignment`. 93 | 94 | As in :py:meth:`Sheaf.consistencyRadius`, `testSupport` specifies what portion of the base :py:class:`CellComplex` is being analyzed. 95 | -------------------------------------------------------------------------------- /docs/sheaves.rst: -------------------------------------------------------------------------------- 1 | The :py:class:`Sheaf` type 2 | ========================== 3 | 4 | The :py:class:`Sheaf` class derives from :py:class:`CellComplex` to describe its base space. The additional attributes and methods of :py:class:`Sheaf` describe the "vertical fiber" structure of the sheaf. 5 | 6 | .. py:class:: Sheaf(CellComplex) 7 | 8 | The base sheaf class in PySheaf consists of a list :py:attr:`cell` of :py:class:`SheafCell` instances, describing the cells and the stalks over them. Restriction maps are built into :py:class:`SheafCoface` instances that are stored with each :py:class:`SheafCell`. 9 | 10 | .. py:method:: coboundary(k,compactSupport=False) 11 | 12 | Compute the degree `k` coboundary map of the :py:class:`Sheaf`, returning it as a :py:class:`numpy.ndarray`. If you want compactly supported cohomology (if you don't know what that means, you don't) then set `compactSupport=True`. 13 | 14 | .. py:method:: cohomology(k,compactSupport=False) 15 | 16 | Compute the degree `k` sheaf cohomology for the :py:class:`Sheaf`. If you want compactly supported cohomology (if you don't know what that means, you don't) then set `compactSupport=True`. This returns a :py:class:`numpy.ndarray` whose columns are the generators for cohomology. 17 | 18 | .. py:method:: cobetti(k) 19 | 20 | The dimension of the degree `k` sheaf cohomology space. 21 | 22 | .. warning :: This is not the dimension of the :py:meth:`CellComplex.homology()`, which is inherited into :py:class:`Sheaf`! 23 | 24 | .. py:class:: SheafCell(Cell) 25 | 26 | .. py:attribute:: stalkDim 27 | 28 | The dimension of the stalk over this cell. 29 | 30 | .. warning :: This has nothing to do with :py:attr:`SheafCell.dimension` inherited from :py:attr:`Cell`. 31 | 32 | .. py:attribute:: metric 33 | 34 | The metric on the stalk, used to measure distances between values in that stalk. This must by a function object that takes two arguments, each of which is a :py:class:`numpy.ndarray` and produces a numerical value. By default, it is the Euclidean distance given by :py:func:`numpy.linalg.norm()`. 35 | 36 | .. py:attribute:: cofaces 37 | 38 | Like :py:class:`Cell`, this should be a list of coface relations, but unlike :py:class:`Cell`, they must be :py:class:`SheafCoface` instances! 39 | 40 | .. py:attribute:: bounds 41 | 42 | The portion of the stalk in which legal values live. This is used by the optimizer in :py:meth:`Sheaf.fuseAssignment` to set bounds on which values are used. This should either be `None` (in which the stalk represents the entire vector space) or a list of `(min,max)` pairs of length :py:attr:`SheafCell.stalkDim`. Use `None` for any bound you wish to ignore. 43 | 44 | .. py:class:: SheafCoface(Coface) 45 | 46 | A coface relation in a sheaf on a cell complex is built just like a :py:class:`Coface` in a :py:class:`CellComplex`, but with the addition of a :py:attr:`restriction`. 47 | 48 | .. py:attribute:: restriction 49 | 50 | A restriction in a sheaf generally needs to be a morphism in some category. It must be an object that supports *composition*, namely a class that implements a multiplication operator. In most examples, this is one of :py:class:`SetMorphism` (for functions between sets), :py:class:`LinearMorphism` (for linear maps), or a :py:class:`SheafMorphism` (for a :py:class:`Sheaf` of sheaves). Note that if you construct a :py:class:`SheafCoface` by passing a :py:class:`numpy.ndarray`, PySheaf will construct a :py:class:`LinearMorphism` restriction automatically. 51 | 52 | Morphisms: :py:class:`SetMorphism`, :py:class:`LinearMorphism`, and :py:class:`SheafMorphism` 53 | --------------------------------------------------------------------------------------------- 54 | 55 | Since cellular sheaves are special functors from the face category of a cell complex to some other *data category*, PySheaf supports three kinds of *data categories*: 56 | 57 | 1. Sets, 58 | 2. Finite dimensional vector spaces (via :py:mod:`numpy`), and 59 | 3. Sheaves (of some of other type). 60 | 61 | The restrictions in a given :py:class:`SheafCoface` instance are therefore of a corresponding morphism class: 62 | 63 | 1. :py:class:`SetMorphism`, 64 | 2. :py:class:`LinearMorphism`, and 65 | 3. :py:class:`SheafMorphism`. 66 | 67 | The simplest of these is :py:class:`SetMorphism`. 68 | 69 | .. py:class:: SetMorphism 70 | 71 | This represents a *set* morphism, otherwise known as a *function* between sets. This is implemented by a single attribute 72 | 73 | .. py:attribute:: fcn 74 | 75 | which is a function object taking one argument. 76 | 77 | :py:class:`SetMorphism` objects support a multiplication operator, which composes their respective :py:attr:`fcn` attributes to form a new function object. They also support call semantics, so you can simply call a :py:class:`SetMorphism` object as a function to access its :py:attr:`fcn` attribute. 78 | 79 | Namely, if you say:: 80 | 81 | foo = pysheaf.SetMorphism( lambda x : x**2 ) 82 | bar = pysheaf.SetMorphism( lambda y : 3*y ) 83 | 84 | then:: 85 | 86 | foo(3) 87 | 88 | returns 9 and:: 89 | 90 | baaz = foo * bar 91 | baaz(1) 92 | 93 | is also 9. 94 | 95 | A :py:class:`Sheaf` with only :py:class:`SetMorphism` restrictions does not allow you to compute :py:meth:`Sheaf.cohomology()`. For that, you need linearity, which is implemented by the following subclass of :py:class:`SetMorphism`. 96 | 97 | .. py:class:: LinearMorphism(SetMorphism) 98 | 99 | This implements a linear map, encoded as a :py:class:`numpy.ndarray`. Since it subclasses :py:class:`SetMorphism`, it inherits composition (as multiplication, which is of course *also* matrix multiplication) and call semantics. It also stores the matrix as a new attribute 100 | 101 | .. py:attribute:: matrix 102 | 103 | as you might expect. 104 | 105 | When constructing a :py:class:`SheafCoface`, if you pass an :py:class:`numpy.ndarray` as the `restriction` argument, PySheaf will automatically create :py:class:`LinearMorphism` objects as the restriction. 106 | 107 | The final kind of morphism that is supported is :py:class:`SheafMorphism`, which supports composition by implementing a multiplication operator, but *not* call semantics since sheaf morphisms are *not* functions. (It is true that they induce functions of various kinds, but PySheaf refrains from demanding that any particular kind of induced maps be computed by default.) 108 | 109 | .. py:class:: SheafMorphism 110 | 111 | A sheaf morphism from one sheaf to another consists of lists :py:attr:`destinations` and :py:attr:`maps` which correspond to the :py:attr:`Sheaf.cells` list in the domain sheaf. 112 | 113 | .. py:attribute:: destinations 114 | 115 | List of indices into the codomain sheaf's :py:attr:`Sheaf.cells` list for each component map of the sheaf morphism. Entries correspond to the :py:attr:`Sheaf.cells` list in the domain sheaf. 116 | 117 | .. py:attribute:: maps 118 | 119 | List of component maps (each of which may be any morphism class, like :py:class:`SetMorphism`, :py:class:`LinearMorphism`, or even :py:class:`SetMorphism`) corresponding to the :py:attr:`Sheaf.cells` list in the domain sheaf. 120 | 121 | Constructing :py:class:`Sheaf` instances 122 | ---------------------------------------- 123 | 124 | :py:class:`Sheaf` objects are constructed in essentially the same way as :py:class:`CellComplex` objects. Determining the indices for the :py:attr:`Sheaf.cells` list is crucial, as each :py:attr:`SheafCoface.index` will refer into it. Changes to the base space -- the inherited structure from :py:class:`CellComplex` -- are not easy and will generally involve many updates. Additionally, each :py:attr:`SheafCoface.restriction` ought to be known beforehand, though these can be changed at run time if needed. 125 | -------------------------------------------------------------------------------- /pysheaf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kb1dds/pysheaf/abe0d072367396bea3344d5cd56d1d6da3270aed/pysheaf.png -------------------------------------------------------------------------------- /pysheaf/.ipynb_checkpoints/ACEKComplx Example-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [], 3 | "metadata": {}, 4 | "nbformat": 4, 5 | "nbformat_minor": 0 6 | } 7 | -------------------------------------------------------------------------------- /pysheaf/.ipynb_checkpoints/SheafExample4-10-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 6, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import pysheaf as ps\n", 12 | "import matplotlib.pyplot as plt\n", 13 | "import numpy as np\n", 14 | "from numpy.linalg import matrix_rank" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 9, 20 | "metadata": { 21 | "collapsed": false 22 | }, 23 | "outputs": [], 24 | "source": [ 25 | "### Example from p.100 of textbook\n", 26 | "### Cells are [v0,v1,e1,e2,e3,e4] indexed by position in list\n", 27 | "\n", 28 | "pr1 = np.matrix([1,0])\n", 29 | "pr2 = np.matrix([0,1])\n", 30 | "restsum = np.matrix([1,1])\n", 31 | " \n", 32 | "cfv0e1 = ps.SheafCoface(2,1,pr1)\n", 33 | "cfv0e2 = ps.SheafCoface(3,1,pr2)\n", 34 | "cfv1e1 = ps.SheafCoface(2,-1,pr1)\n", 35 | "cfv1e2 = ps.SheafCoface(3,-1,pr2)\n", 36 | "cfv0e3 = ps.SheafCoface(4,1,restsum)\n", 37 | "cfv1e4 = ps.SheafCoface(5,1,restsum)\n", 38 | "\n", 39 | "v0 = ps.SheafCell(dimension=0,id=0,stalkDim=2,name='v0',\n", 40 | " cofaces=[cfv0e1,cfv0e2])\n", 41 | "v1 = ps.SheafCell(dimension=0,id=1,stalkDim=2,name='v1',\n", 42 | " cofaces=[cfv1e1,cfv1e2])\n", 43 | "e1 = ps.SheafCell(dimension=1,id=2,stalkDim=1,name='e1')\n", 44 | "e2 = ps.SheafCell(dimension=1,id=3,stalkDim=1,name='e2')\n", 45 | "e3 = ps.SheafCell(dimension=1,id=4,stalkDim=1,name='e3')\n", 46 | "e4 = ps.SheafCell(dimension=1,id=5,stalkDim=1,name='e4')\n", 47 | "\n", 48 | "sheaf = ps.Sheaf([v0,v1,e1,e2,e3,e4])" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 54, 54 | "metadata": { 55 | "collapsed": false 56 | }, 57 | "outputs": [ 58 | { 59 | "name": "stdout", 60 | "output_type": "stream", 61 | "text": [ 62 | "[[ 1.+0.j 0.+0.j -1.+0.j 0.+0.j]\n", 63 | " [ 0.+0.j 1.+0.j 0.+0.j -1.+0.j]\n", 64 | " [ 0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", 65 | " [ 0.+0.j 0.+0.j 0.+0.j 0.+0.j]]\n" 66 | ] 67 | } 68 | ], 69 | "source": [ 70 | "d=sheaf.coboundary(0)\n", 71 | "print d\n" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 55, 77 | "metadata": { 78 | "collapsed": false 79 | }, 80 | "outputs": [ 81 | { 82 | "name": "stdout", 83 | "output_type": "stream", 84 | "text": [ 85 | "2\n" 86 | ] 87 | } 88 | ], 89 | "source": [ 90 | "ker = d.shape[1] - matrix_rank(d)\n", 91 | "print ker" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": 56, 97 | "metadata": { 98 | "collapsed": false 99 | }, 100 | "outputs": [ 101 | { 102 | "data": { 103 | "text/plain": [ 104 | "array([[-0.70710678-0.j, 0.00000000-0.j],\n", 105 | " [ 0.00000000-0.j, 0.70710678-0.j],\n", 106 | " [-0.70710678-0.j, 0.00000000-0.j],\n", 107 | " [ 0.00000000-0.j, 0.70710678-0.j]])" 108 | ] 109 | }, 110 | "execution_count": 56, 111 | "metadata": {}, 112 | "output_type": "execute_result" 113 | } 114 | ], 115 | "source": [ 116 | "sheaf.cohomology(0)" 117 | ] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "execution_count": 53, 122 | "metadata": { 123 | "collapsed": false 124 | }, 125 | "outputs": [ 126 | { 127 | "data": { 128 | "text/plain": [ 129 | "2" 130 | ] 131 | }, 132 | "execution_count": 53, 133 | "metadata": {}, 134 | "output_type": "execute_result" 135 | } 136 | ], 137 | "source": [ 138 | "sheaf.betti(0)" 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": null, 144 | "metadata": { 145 | "collapsed": true 146 | }, 147 | "outputs": [], 148 | "source": [] 149 | } 150 | ], 151 | "metadata": { 152 | "kernelspec": { 153 | "display_name": "Python 2", 154 | "language": "python", 155 | "name": "python2" 156 | }, 157 | "language_info": { 158 | "codemirror_mode": { 159 | "name": "ipython", 160 | "version": 2 161 | }, 162 | "file_extension": ".py", 163 | "mimetype": "text/x-python", 164 | "name": "python", 165 | "nbconvert_exporter": "python", 166 | "pygments_lexer": "ipython2", 167 | "version": "2.7.10" 168 | } 169 | }, 170 | "nbformat": 4, 171 | "nbformat_minor": 0 172 | } 173 | -------------------------------------------------------------------------------- /pysheaf/ACEKComplx Example.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 4, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import pysheaf as ps" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 5, 17 | "metadata": { 18 | "collapsed": true 19 | }, 20 | "outputs": [], 21 | "source": [ 22 | "cellA = ps.Cell(0,name='A',id=0,cofaces=[ps.Coface(4,-1),ps.Coface(5, -1),ps.Coface(6, -1)])\n", 23 | "cellC = ps.Cell(0,name='C',id=1,cofaces=[ps.Coface(4, 1),ps.Coface(8, -1),ps.Coface(9, -1)])\n", 24 | "cellE = ps.Cell(0,name='E',id=2,cofaces=[ps.Coface(5, 1),ps.Coface(8, 1)])\n", 25 | "cellK = ps.Cell(0,name='K',id=3,cofaces=[ps.Coface(6, 1),ps.Coface(9, 1)])\n", 26 | "cellAC = ps.Cell(1,name='AC',id=4,cofaces=[ps.Coface(7, 1)])\n", 27 | "cellAE = ps.Cell(1,name='AE',id=5)\n", 28 | "cellAK = ps.Cell(1,name='AK',id=6,cofaces=[ps.Coface(7, -1)])\n", 29 | "cellACK = ps.Cell(2,name='ACK',id=7)\n", 30 | "cellCE = ps.Cell(1,name='CE',id=8)\n", 31 | "cellCK = ps.Cell(1,name='CK',id=9,cofaces=[ps.Coface(7, 1)])\n", 32 | "cmplx = ps.CellComplex([cellA,cellC,cellE,cellK,cellAC,cellAE,cellAK,cellACK,cellCE, cellCK])" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": 7, 38 | "metadata": { 39 | "collapsed": false 40 | }, 41 | "outputs": [ 42 | { 43 | "data": { 44 | "text/plain": [ 45 | "array([], shape=(0, 4), dtype=float64)" 46 | ] 47 | }, 48 | "execution_count": 7, 49 | "metadata": {}, 50 | "output_type": "execute_result" 51 | } 52 | ], 53 | "source": [ 54 | "cmplx.boundary(0)" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": 8, 60 | "metadata": { 61 | "collapsed": false 62 | }, 63 | "outputs": [ 64 | { 65 | "data": { 66 | "text/plain": [ 67 | "array([[-1., -1., -1., 0., 0.],\n", 68 | " [ 1., 0., 0., -1., -1.],\n", 69 | " [ 0., 1., 0., 1., 0.],\n", 70 | " [ 0., 0., 1., 0., 1.]])" 71 | ] 72 | }, 73 | "execution_count": 8, 74 | "metadata": {}, 75 | "output_type": "execute_result" 76 | } 77 | ], 78 | "source": [ 79 | "cmplx.boundary(1)" 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": null, 85 | "metadata": { 86 | "collapsed": true 87 | }, 88 | "outputs": [], 89 | "source": [ 90 | "cmplx.homology" 91 | ] 92 | } 93 | ], 94 | "metadata": { 95 | "kernelspec": { 96 | "display_name": "Python 2", 97 | "language": "python", 98 | "name": "python2" 99 | }, 100 | "language_info": { 101 | "codemirror_mode": { 102 | "name": "ipython", 103 | "version": 2 104 | }, 105 | "file_extension": ".py", 106 | "mimetype": "text/x-python", 107 | "name": "python", 108 | "nbconvert_exporter": "python", 109 | "pygments_lexer": "ipython2", 110 | "version": "2.7.10" 111 | } 112 | }, 113 | "nbformat": 4, 114 | "nbformat_minor": 0 115 | } 116 | -------------------------------------------------------------------------------- /pysheaf/Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [dev-packages] 7 | 8 | [packages] 9 | networkx = "==2.1" 10 | scipy = "==1.0.0" 11 | matplotlib = "==2.2.0" 12 | numpy = "==1.14.2" 13 | deap = "==1.2.2" 14 | 15 | [requires] 16 | python_version = "3.6" 17 | -------------------------------------------------------------------------------- /pysheaf/SheafExample4-10.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 6, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import pysheaf as ps\n", 12 | "import matplotlib.pyplot as plt\n", 13 | "import numpy as np\n", 14 | "from numpy.linalg import matrix_rank" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 9, 20 | "metadata": { 21 | "collapsed": false 22 | }, 23 | "outputs": [], 24 | "source": [ 25 | "### Example from p.100 of textbook\n", 26 | "### Cells are [v0,v1,e1,e2,e3,e4] indexed by position in list\n", 27 | "\n", 28 | "pr1 = np.matrix([1,0])\n", 29 | "pr2 = np.matrix([0,1])\n", 30 | "restsum = np.matrix([1,1])\n", 31 | " \n", 32 | "cfv0e1 = ps.SheafCoface(2,1,pr1)\n", 33 | "cfv0e2 = ps.SheafCoface(3,1,pr2)\n", 34 | "cfv1e1 = ps.SheafCoface(2,-1,pr1)\n", 35 | "cfv1e2 = ps.SheafCoface(3,-1,pr2)\n", 36 | "cfv0e3 = ps.SheafCoface(4,1,restsum)\n", 37 | "cfv1e4 = ps.SheafCoface(5,1,restsum)\n", 38 | "\n", 39 | "v0 = ps.SheafCell(dimension=0,id=0,stalkDim=2,name='v0',\n", 40 | " cofaces=[cfv0e1,cfv0e2])\n", 41 | "v1 = ps.SheafCell(dimension=0,id=1,stalkDim=2,name='v1',\n", 42 | " cofaces=[cfv1e1,cfv1e2])\n", 43 | "e1 = ps.SheafCell(dimension=1,id=2,stalkDim=1,name='e1')\n", 44 | "e2 = ps.SheafCell(dimension=1,id=3,stalkDim=1,name='e2')\n", 45 | "e3 = ps.SheafCell(dimension=1,id=4,stalkDim=1,name='e3')\n", 46 | "e4 = ps.SheafCell(dimension=1,id=5,stalkDim=1,name='e4')\n", 47 | "\n", 48 | "sheaf = ps.Sheaf([v0,v1,e1,e2,e3,e4])" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 54, 54 | "metadata": { 55 | "collapsed": false 56 | }, 57 | "outputs": [ 58 | { 59 | "name": "stdout", 60 | "output_type": "stream", 61 | "text": [ 62 | "[[ 1.+0.j 0.+0.j -1.+0.j 0.+0.j]\n", 63 | " [ 0.+0.j 1.+0.j 0.+0.j -1.+0.j]\n", 64 | " [ 0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", 65 | " [ 0.+0.j 0.+0.j 0.+0.j 0.+0.j]]\n" 66 | ] 67 | } 68 | ], 69 | "source": [ 70 | "d=sheaf.coboundary(0)\n", 71 | "print d\n" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 55, 77 | "metadata": { 78 | "collapsed": false 79 | }, 80 | "outputs": [ 81 | { 82 | "name": "stdout", 83 | "output_type": "stream", 84 | "text": [ 85 | "2\n" 86 | ] 87 | } 88 | ], 89 | "source": [ 90 | "ker = d.shape[1] - matrix_rank(d)\n", 91 | "print ker" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": 56, 97 | "metadata": { 98 | "collapsed": false 99 | }, 100 | "outputs": [ 101 | { 102 | "data": { 103 | "text/plain": [ 104 | "array([[-0.70710678-0.j, 0.00000000-0.j],\n", 105 | " [ 0.00000000-0.j, 0.70710678-0.j],\n", 106 | " [-0.70710678-0.j, 0.00000000-0.j],\n", 107 | " [ 0.00000000-0.j, 0.70710678-0.j]])" 108 | ] 109 | }, 110 | "execution_count": 56, 111 | "metadata": {}, 112 | "output_type": "execute_result" 113 | } 114 | ], 115 | "source": [ 116 | "sheaf.cohomology(0)" 117 | ] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "execution_count": 53, 122 | "metadata": { 123 | "collapsed": false 124 | }, 125 | "outputs": [ 126 | { 127 | "data": { 128 | "text/plain": [ 129 | "2" 130 | ] 131 | }, 132 | "execution_count": 53, 133 | "metadata": {}, 134 | "output_type": "execute_result" 135 | } 136 | ], 137 | "source": [ 138 | "sheaf.betti(0)" 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": null, 144 | "metadata": { 145 | "collapsed": true 146 | }, 147 | "outputs": [], 148 | "source": [] 149 | } 150 | ], 151 | "metadata": { 152 | "kernelspec": { 153 | "display_name": "Python 2", 154 | "language": "python", 155 | "name": "python2" 156 | }, 157 | "language_info": { 158 | "codemirror_mode": { 159 | "name": "ipython", 160 | "version": 2 161 | }, 162 | "file_extension": ".py", 163 | "mimetype": "text/x-python", 164 | "name": "python", 165 | "nbconvert_exporter": "python", 166 | "pygments_lexer": "ipython2", 167 | "version": "2.7.10" 168 | } 169 | }, 170 | "nbformat": 4, 171 | "nbformat_minor": 0 172 | } 173 | -------------------------------------------------------------------------------- /pysheaf/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | # Python 3.6 Sheaf theoretic toolbox 3 | 4 | This library provides tools for manipulating sheaves of pseudometric spaces on partially ordered sets. The primarly class is a `Sheaf`, which subclasses `NetworkX.DiGraph`; the idea is that the `DiGraph` specifies the Hasse diagram for the partially ordered set. 5 | 6 | Most of the details you need to get started are in the `pysheaf` module. Start there first. For specific sheaves that havew linear maps as restrictions, you might consider looking at `dataTools`. Finally, there are several detailed examples to explore. 7 | 8 | ## General usage instructions 9 | 10 | 1. First (usually on paper!) lay out the cell complex that will serve as the base for your sheaf. *Give each cell a unique label.* 11 | 12 | 2. Determine all of the stalks over each cell, and the restriction maps. Restriction maps can be a mixture of `numpy` matrices or arbitrary single-input Python function objects. 13 | 14 | 3. Construct a `Sheaf` instance and add each of your cells as `Cell` instances with the `Sheaf.AddCell` method. Make sure to use your unique label for each `Cell`, because that is how PySheaf identifies them! Once you've done that, create each restriction as a `Coface` instance and add it to the sheaf using the `Sheaf.AddCoface` method. The `Sheaf.AddCoface` method will connect the listed `Cell`s based on their labels. `Cell`s and `Coface`s can be added later if you want, and they can be added in any order provided any `Coface` refers to `Cell`s that already exist. 15 | 16 | 4. Install some data into the sheaf by way of an `Assignment` to some of the `Cell`s. 17 | 18 | 5. Analyze the sheaf and its data: 19 | a. You can compute consistency radius with `Sheaf.ComputeConsistencyRadius()` 20 | b. You can improve the consistency radius by extending or altering the values of the assignment with `Sheaf.FuseAssignment()`. This will only alter Cells whose `Cell.mOptimizationCell` attribute is `True`. You can also change the optimization algorithm if you want. 21 | c. You can find all star open sets whose local consistency is less than a desired bound using `Sheaf.CellIndexesLessThanConsistencyThreshold()`. 22 | 23 | """ 24 | 25 | from .pysheaf import * 26 | -------------------------------------------------------------------------------- /pysheaf/analysisTools.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | # Copyright (c) 2018 Michael Robinson & Steven Fiacco 4 | 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | import numpy as np 24 | import pysheaf as ps 25 | import pysheaf.dataTools 26 | import networkx as nx 27 | 28 | def LocallyFuseAssignment( sheaf ): 29 | ''' 30 | Perform Sheaf.FuseAssignment() locally, which should use less memory (but is probably slower) 31 | ''' 32 | 33 | # Any cell marked as not being solved for doesn't get extended assignments 34 | sheaf.ClearExtendedAssignments() 35 | 36 | # Locality for this is based on connected sets of optimization cells. 37 | optimization_cell_indices=sheaf.GetOptimizationCellIndexList() 38 | 39 | # To find connected components of optimization cells, build an undirected graph whose vertices are optimization cells 40 | # and edges are induced by the sheaf's graph 41 | G=sheaf.to_undirected().subgraph(optimization_cell_indices) 42 | 43 | # For each component, 44 | # 1. Turn on each component as optimization cells, 45 | # 2. turn off the rest, and 46 | # 3. run FuseAssignment. 47 | for component in nx.connected_components(G): 48 | # TODO TBD: The views thing is not working correctly. I think I need to copy! 49 | for node in sheaf.nodes(): 50 | if node in component: 51 | sheaf.GetCell(node).mOptimizationCell=True 52 | else: 53 | sheaf.GetCell(node).mOptimizationCell=False 54 | sheaf.GetCell(node).ClearExtendedAssignment() 55 | 56 | # Focus our attention on this component, only. (This avoids flowdown dependencies from other cells) 57 | subsheaf=nx.classes.graphviews.subgraph_view(sheaf,filter_node=lambda x: (x in component) or [nd2 for nd2 in component if x in sheaf.successors(nd2)]) 58 | 59 | # Perform the optimization 60 | subsheaf.FuseAssignment() 61 | 62 | # Put the optimization cells back to the way they were 63 | for node in sheaf.nodes(): 64 | if node in optimization_cell_indices: 65 | sheaf.GetCell(node).mOptimizationCell=True 66 | else: 67 | sheaf.GetCell(node).mOptimizationCell=False 68 | 69 | # Propagate all extended assignments, since that's what Sheaf.FuseAssignment() does at this point 70 | for c in sheaf.GetCellIndexList(): 71 | sheaf.MaximallyExtendCell(c) 72 | 73 | return 74 | 75 | def BuildConstantSheaf(G, dataDimension=1): 76 | """Construct a constant sheaf on a graph G with a given dataDimension""" 77 | shf=ps.Sheaf() 78 | 79 | # Add cells for each node in the graph 80 | for node in G.nodes(): 81 | shf.AddCell(node, ps.Cell('vector',dataDimension=dataDimension)) 82 | 83 | # Add cofaces for each edge in the graph 84 | for edge in G.edges(): 85 | shf.AddCoface(edge[0],edge[1],ps.Coface('vector','vector',dataTools.LinearMorphism(np.eye(dataDimension)))) 86 | 87 | return shf # BuildConstantSheaf 88 | 89 | class LinearAlgebraSheafAnalysisTool: 90 | def __init__(self, inputSheaf): 91 | self.mSheaf = inputSheaf 92 | return # __init__ 93 | def GetEdgeMorphism(self,cellIndexStart, cellIndexTo): 94 | return self.mSheaf.GetCoface(cellIndexStart,cellIndexTo).mEdgeMethod # GetEdgeMorphism 95 | 96 | def GetAllEdgeMorphisms(self): 97 | all_edges_on_sheaf = self.mSheaf.edges() 98 | all_morphisms_list = [] 99 | for edge in all_edges_on_sheaf: 100 | all_morphisms_list.append(self.GetEdgeMorphism(edge[0],edge[1])) 101 | return all_morphisms_list 102 | -------------------------------------------------------------------------------- /pysheaf/consistencyFiltrationExample.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Wed Oct 31 16:16:22 2018 4 | 5 | @author: mrobinson 6 | """ 7 | 8 | import pysheaf as ps 9 | 10 | shf=ps.Sheaf() 11 | 12 | shf.AddCell('A',ps.Cell('Scalar')) 13 | shf.AddCell('B',ps.Cell('Scalar')) 14 | shf.AddCell('C',ps.Cell('Scalar')) 15 | 16 | shf.AddCoface('A','C',ps.Coface('Scalar','Scalar',lambda x: x)) 17 | shf.AddCoface('B','C',ps.Coface('Scalar','Scalar',lambda x: x)) 18 | shf.GetCell('A').SetDataAssignment(ps.Assignment('Scalar',0)) 19 | shf.GetCell('B').SetDataAssignment(ps.Assignment('Scalar',1)) 20 | shf.GetCell('C').SetDataAssignment(ps.Assignment('Scalar',0.25)) 21 | 22 | shf.mPreventRedundantExtendedAssignments=False 23 | 24 | shf.MaximallyExtendCell('A') 25 | shf.MaximallyExtendCell('B') 26 | shf.MaximallyExtendCell('C') 27 | 28 | print('Consistency radius : {}'.format(shf.ComputeConsistencyRadius())) 29 | 30 | for thres in [0., 0.2, 0.3, 0.8]: 31 | print('Consistent stars at {} : {}'.format(thres,shf.ConsistentStarCollection(thres))) 32 | -------------------------------------------------------------------------------- /pysheaf/dataTools.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | # dataTools is meant to serve as a place to put general serialize/deserialize/compare/edgeMethods that may be 5 | # useful for other users. 6 | 7 | 8 | class SetMorphism(): 9 | """A morphism in a subcategory of Set, described by a function object""" 10 | def __init__(self,fcn): 11 | self.fcn=fcn 12 | 13 | def __mul__(self,other): # Composition of morphisms 14 | return SetMorphism(lambda x : self.fcn(other.fcn(x))) 15 | 16 | def __call__(self,arg): # Calling the morphism on an element of the set 17 | return self.fcn(arg) 18 | 19 | class LinearMorphism(SetMorphism): 20 | """A morphism in a category that has a matrix representation""" 21 | def __init__(self,matrix): 22 | self.matrix=matrix 23 | SetMorphism.__init__(self,lambda x: np.dot(matrix,x)) 24 | 25 | def __mul__(self,other): # Composition of morphisms 26 | try: # Try to multiply matrices. This might fail if the other morphism isn't a LinearMorphism 27 | return LinearMorphism(np.dot(self.matrix, other.matrix)) 28 | except AttributeError: 29 | return SetMorphism.__mul__(self,other) -------------------------------------------------------------------------------- /pysheaf/linearSheafExample.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | # Copyright (c) 2018 Michael Robinson & Steven Fiacco 4 | 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | import numpy as np 24 | import pysheaf as ps 25 | import pysheaf.dataTools 26 | import pysheaf.analysisTools 27 | 28 | 29 | def CompareArrays(array1,array2): 30 | return np.average(array1-array2) #CompareArrays 31 | 32 | if __name__ == '__main__': 33 | print("+-+-+-+-+-+-+-+-+-+-+-+-+") 34 | print("+-Linear Sheaf Example!-+") 35 | print("+-+-+-+-+-+-+-+-+-+-+-+-+") 36 | 37 | graph = ps.Sheaf() 38 | 39 | LINEAR_TYPE = "linear_morphism_type" 40 | graph.AddCell(0,ps.Cell(LINEAR_TYPE,CompareArrays,dataDimension=4)) 41 | graph.AddCell(1,ps.Cell(LINEAR_TYPE,CompareArrays,dataDimension=4)) 42 | graph.AddCell(2,ps.Cell(LINEAR_TYPE,CompareArrays,dataDimension=2)) 43 | 44 | 45 | graph.GetCell(0).SetDataAssignment(ps.Assignment(LINEAR_TYPE,np.array([5,6,7,8]))) 46 | graph.GetCell(0).SetBounds([(0,None),(0,None),(0,None),(0,None)]) 47 | graph.GetCell(0).mOptimizationCell = True 48 | 49 | graph.GetCell(1).SetDataAssignment(ps.Assignment(LINEAR_TYPE,np.array([15,16,17,18]))) 50 | graph.GetCell(2).SetDataAssignment(ps.Assignment(LINEAR_TYPE,np.array([30,32]))) 51 | 52 | graph.AddCoface(0,1,ps.Coface(LINEAR_TYPE,LINEAR_TYPE,dataTools.LinearMorphism(np.array([[1,0,0,0], 53 | [0,1,0,0], 54 | [0,0,1,0], 55 | [0,0,0,1]])))) 56 | graph.AddCoface(1,2,ps.Coface(LINEAR_TYPE,LINEAR_TYPE,dataTools.LinearMorphism(np.array([[2,0,0,0], 57 | [0,2,0,0]])))) 58 | graph.MaximallyExtendCell(0) 59 | print("consistency radius before gobal fuse assignment:",graph.ComputeConsistencyRadius()) 60 | graph.ClearExtendedAssignments() 61 | 62 | print(graph.FuseAssignment()) 63 | print("consistency radius after global fuse assignment:",graph.ComputeConsistencyRadius()) 64 | 65 | 66 | 67 | analysisDemo= analysisTools.LinearAlgebraSheafAnalysisTool(graph); 68 | 69 | all_morphisms = analysisDemo.GetAllEdgeMorphisms() 70 | -------------------------------------------------------------------------------- /pysheaf/logic_example.py: -------------------------------------------------------------------------------- 1 | """ 2 | # Example to demonstrate the use of `Sheaf.fromNetlist()` to build a sheaf specified by a JSON file. 3 | 4 | """ 5 | 6 | # MIT License 7 | 8 | # Copyright (c) 2024 Michael Robinson 9 | 10 | # Permission is hereby granted, free of charge, to any person obtaining a copy 11 | # of this software and associated documentation files (the "Software"), to deal 12 | # in the Software without restriction, including without limitation the rights 13 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | # copies of the Software, and to permit persons to whom the Software is 15 | # furnished to do so, subject to the following conditions: 16 | 17 | # The above copyright notice and this permission notice shall be included in all 18 | # copies or substantial portions of the Software. 19 | 20 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | # SOFTWARE. 27 | 28 | import json 29 | import numpy as np 30 | import networkx as nx 31 | import pysheaf as ps 32 | #import matplotlib.pyplot as plt 33 | 34 | netlist=json.load(open('pysheaf/logic_netlist.json')) 35 | 36 | shf = ps.Sheaf() 37 | shf.fromNetlist(netlist) 38 | shf.mNumpyNormType = 2 39 | 40 | #pos=nx.layout.spring_layout(shf) 41 | #nx.draw_networkx_labels(shf,pos) 42 | #nx.draw_networkx_edges(shf,pos) 43 | #plt.show() 44 | 45 | for a in [0,1]: 46 | for b in [0,1]: 47 | for c in [0,1]: 48 | q = min((1-a*b)+c,1) 49 | 50 | shf.GetCell('A').SetDataAssignment(ps.Assignment('cell',np.array((a,)))) 51 | shf.GetCell('B').SetDataAssignment(ps.Assignment('cell',np.array((b,)))) 52 | shf.GetCell('C').SetDataAssignment(ps.Assignment('cell',np.array((c,)))) 53 | 54 | shf.FuseAssignment() 55 | 56 | qp = shf.GetCell('Q').mDataAssignment 57 | 58 | print('A={}, B={}, C={}, Q={} =?= {} '.format(a,b,c,q,qp)) 59 | 60 | -------------------------------------------------------------------------------- /pysheaf/logic_netlist.json: -------------------------------------------------------------------------------- 1 | { "AND2" : { "data_dimension" : 2, 2 | "bounds" : "[(0,1)]*2", 3 | "ports" : { "IN1" : "lambda x: x[0]", 4 | "IN2" : "lambda x: x[1]", 5 | "OUT" : "lambda x: x[0]*x[1]" } 6 | }, 7 | "OR2" : { "data_dimension" : 2, 8 | "bounds" : "[(0,1)]*2", 9 | "ports" : { "IN1" : "lambda x: x[0]", 10 | "IN2" : "lambda x: x[1]", 11 | "OUT" : "lambda x: min(x[0]+x[1],1)" } 12 | }, 13 | "NOT" : { "data_dimension" : 1, 14 | "bounds" : "[(0,1)]", 15 | "ports" : { "IN" : "lambda x: x[0]", 16 | "OUT" : "lambda x: 1-x[0]" } 17 | }, 18 | "A": { "data_dimension" : 1, 19 | "bounds" : "[(0,1)]", 20 | "optimize" : 0, 21 | "connections" : [ 22 | { "part" : "AND2", 23 | "port" : "IN1"} 24 | ] 25 | }, 26 | "B": { "data_dimension" : 1, 27 | "bounds" : "[(0,1)]", 28 | "optimize" : 0, 29 | "connections" : [ 30 | { "part" : "AND2", 31 | "port" : "IN2"} 32 | ] 33 | }, 34 | "C" : { "data_dimension" : 1, 35 | "bounds" : "[(0,1)]", 36 | "optimize" : 0, 37 | "connections" : [ 38 | { "part" : "OR2", 39 | "port" : "IN1"} 40 | ] 41 | }, 42 | "E" : { "data_dimension" : 1, 43 | "bounds" : "[(0,1)]", 44 | "connections" : [ 45 | { "part" : "AND2", 46 | "port" : "OUT"}, 47 | { "part" : "NOT", 48 | "port" : "IN"} 49 | ] 50 | }, 51 | "F" : { "data_dimension" : 1, 52 | "bounds" : "[(0,1)]", 53 | "connections" : [ 54 | { "part" : "NOT", 55 | "port" : "OUT"}, 56 | { "part" : "OR2", 57 | "port" : "IN2"} 58 | ] 59 | }, 60 | "Q" : { "data_dimension" : 1, 61 | "bounds" : "[(0,1)]", 62 | "connections" : [ 63 | { "part" : "OR2", 64 | "port" : "OUT"} 65 | ] 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /pysheaf/requirements.txt: -------------------------------------------------------------------------------- 1 | networkx==2.1 2 | scipy==1.0.0 3 | matplotlib==2.2.0 4 | numpy==1.14.2 5 | deap==1.2.2 6 | -------------------------------------------------------------------------------- /pysheaf/unitTestPysheaf.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | # Copyright (c) 2018 Michael Robinson & Steven Fiacco 4 | 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | import numpy as np 24 | import pysheaf as ps 25 | 26 | def Pow2(inputNumber): 27 | return inputNumber**2 # Pow2 28 | def Pow3(inputNumber): 29 | return inputNumber**3 # Pow3 30 | def CompareScalars(leftValue,rightValue): 31 | return abs(leftValue - rightValue) # CompareScalars 32 | def SerializeScalars(assignmentValue): 33 | return np.array([assignmentValue]) # SerializeScalars 34 | 35 | 36 | 37 | if __name__ == '__main__': 38 | print("+-+-+-+-+-+-+-+-+-+-+") 39 | print("+-Unit Test Pysheaf-+") 40 | print("+-+-+-+-+-+-+-+-+-+-+") 41 | graph = ps.Sheaf() 42 | graph.mPreventRedundantExtendedAssignments = False 43 | 44 | TEST_TYPE = "test_type" 45 | graph.AddCell(0,ps.Cell(TEST_TYPE,CompareScalars,serializeAssignmentMethod= SerializeScalars)) 46 | graph.AddCell(1,ps.Cell(TEST_TYPE,CompareScalars,serializeAssignmentMethod= SerializeScalars)) 47 | graph.AddCell(2,ps.Cell(TEST_TYPE,CompareScalars,serializeAssignmentMethod= SerializeScalars)) 48 | graph.AddCell(3,ps.Cell(TEST_TYPE,CompareScalars,serializeAssignmentMethod= SerializeScalars)) 49 | graph.AddCell(4,ps.Cell(TEST_TYPE,CompareScalars,serializeAssignmentMethod= SerializeScalars)) 50 | graph.AddCell(5,ps.Cell(TEST_TYPE,CompareScalars,serializeAssignmentMethod= SerializeScalars)) 51 | 52 | assert(graph.number_of_nodes() == 6), "Incorrect number of cells" 53 | 54 | """ 55 | Test Structure 56 | 57 | 0 58 | | 59 | 1 60 | | 61 | 2 62 | / \ 63 | 4 3 64 | \ / 65 | 5 66 | """ 67 | 68 | coface_square = ps.Coface(TEST_TYPE,TEST_TYPE,Pow2) 69 | graph.AddCoface(0,1,coface_square) 70 | coface_square = ps.Coface(TEST_TYPE,TEST_TYPE,Pow2) 71 | graph.AddCoface(1,2,coface_square) 72 | coface_square = ps.Coface(TEST_TYPE,TEST_TYPE,Pow2) 73 | graph.AddCoface(2,3,coface_square) 74 | coface_square = ps.Coface(TEST_TYPE,TEST_TYPE,Pow2) 75 | graph.AddCoface(2,4,coface_square) 76 | coface_square = ps.Coface(TEST_TYPE,TEST_TYPE,Pow2) 77 | graph.AddCoface(3,5,coface_square) 78 | coface_square = ps.Coface(TEST_TYPE,TEST_TYPE,Pow3) 79 | graph.AddCoface(4,5,coface_square) 80 | 81 | assert(graph.number_of_edges() == 6), "Incorrect number of cofaces" 82 | 83 | print("number of nodes in graph",graph.number_of_nodes()) 84 | print("number of edges in graph",graph.number_of_edges()) 85 | 86 | known_test_values = [2,4,16,256,65536,16777216] 87 | graph.GetCell(0).SetDataAssignment(ps.Assignment(TEST_TYPE,2)) 88 | 89 | print("dataAssignment: ",graph.GetCell(0).mDataAssignment) 90 | 91 | graph.MaximallyExtendCell(0) 92 | 93 | 94 | assert(graph.GetCell(0).GetDataAssignment().mValue == known_test_values[0]), "Incorrect dataAssignment" 95 | assert(graph.GetCell(1).GetExtendedAssignmentValueList() == [ps.Assignment(TEST_TYPE,known_test_values[1])]), "Incorrect ExtendedAssignment" 96 | assert(graph.GetCell(2).GetExtendedAssignmentValueList() == [ps.Assignment(TEST_TYPE,known_test_values[2])]), "Incorrect ExtendedAssignment" 97 | assert(graph.GetCell(3).GetExtendedAssignmentValueList() == [ps.Assignment(TEST_TYPE,known_test_values[3])]), "Incorrect ExtendedAssignment" 98 | assert(graph.GetCell(4).GetExtendedAssignmentValueList() == [ps.Assignment(TEST_TYPE,known_test_values[3])]), "Incorrect ExtendedAssignment" 99 | assert(graph.GetCell(5).GetExtendedAssignmentValueList() == [ps.Assignment(TEST_TYPE,known_test_values[4]),ps.Assignment(TEST_TYPE,known_test_values[5])]), "Incorrect ExtendedAssignment" 100 | 101 | 102 | cell2_test_value = 6 103 | cell2_test_answer = abs(known_test_values[2] - cell2_test_value) 104 | cell5_test_value = 12345 105 | cell5_test_answer = abs(known_test_values[5] - cell5_test_value) 106 | 107 | graph.GetCell(2).SetDataAssignment(ps.Assignment(TEST_TYPE,cell2_test_value)) 108 | graph.GetCell(5).SetDataAssignment(ps.Assignment(TEST_TYPE,cell5_test_value)) 109 | 110 | print("Single cell consistency:",graph.GetCell(2).ComputeConsistency(np.inf)) 111 | 112 | assert(graph.GetCell(2).ComputeConsistency(np.inf) == cell2_test_answer), "Incorrect consistency" 113 | assert(graph.GetCell(5).ComputeConsistency(np.inf) == cell5_test_answer), "Incorrect consistency" 114 | 115 | print("consistency radius:",graph.ComputeConsistencyRadius()) 116 | 117 | print("nodes in graph:",graph.nodes()) 118 | 119 | print("vales for 5: ",graph.GetCell(5).GetExtendedAssignmentValueList()) 120 | 121 | graph.GetCell(0).mOptimizationCell = True 122 | graph.mPreventRedundantExtendedAssignments = True 123 | 124 | cell2_test_value = 81 125 | cell5_test_value = 43046721 126 | result_answer = 3 127 | 128 | graph.GetCell(2).SetDataAssignment(ps.Assignment(TEST_TYPE,cell2_test_value)) 129 | graph.GetCell(5).SetDataAssignment(ps.Assignment(TEST_TYPE,cell5_test_value)) 130 | 131 | graph.ClearExtendedAssignments() 132 | graph.mNumpyNormType = None 133 | graph.MaximallyExtendCell(0) 134 | print("consistency radius before fuse assignment:",graph.ComputeConsistencyRadius()) 135 | 136 | 137 | 138 | fuse_results = graph.FuseAssignment() 139 | assert(abs(result_answer - fuse_results.x[0]) <.1), "Incorrect fuse assignment result" 140 | print("consistency radius after fuse assignment:",graph.ComputeConsistencyRadius()) 141 | 142 | 143 | print("+-+-+-+-+-+-+-+-+-+-+") 144 | print("+-All tests passed!-+") 145 | print("+-+-+-+-+-+-+-+-+-+-+") -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Persistence-capable sheaf manipulation library setup script 2 | # 3 | # Copyright (c) 2017, Michael Robinson 4 | # This software comes with no warrantees express or implied 5 | 6 | from setuptools import setup 7 | #from Cython.Build import cythonize 8 | 9 | def readme(): 10 | with open('README') as f: 11 | return f.read() 12 | 13 | setup(name='pysheaf', 14 | version='0.3.1', 15 | description='Python applied sheaf computation library', 16 | url='http://github.com/kb1dds/pysheaf', 17 | author='Michael Robinson and Brenda Praggastis and Janelle Henrich', 18 | author_email='michaelr@american.edu', 19 | license='MIT', 20 | packages=['pysheaf'], 21 | install_requires=['scipy >= 1.0','numpy','networkx','deap','pdoc'], 22 | classifiers=[ 23 | 'Development Status :: 3 - Alpha', 24 | 'License :: OSI Approved :: MIT License', 25 | 'Programming Language :: Python :: 3.6', 26 | 'Topic :: Scientific/Engineering :: Mathematics', 27 | ], 28 | # ext_modules=cythonize('pysheaf/pysheaf.py'), 29 | zip_safe=False) 30 | --------------------------------------------------------------------------------