├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── release.yml │ └── run-tests.yml ├── .gitignore ├── .readthedocs.yaml ├── Dependencies └── TenEig2 │ ├── KLtranspose.p │ ├── NwtnHomotopy.p │ ├── ParticalDerivative.p │ ├── PolynomialDecompose.p │ ├── biSolver.p │ ├── distinct.p │ ├── eeig.p │ ├── evalTensorEig.p │ ├── generateRandTensor.p │ ├── getSuppOfAxm.p │ ├── getVariablesInPolynomial.p │ ├── heig.p │ ├── monomial.p │ ├── polynomial.p │ ├── polynomialEval.p │ ├── polynomialSystem.p │ ├── realFilter.p │ ├── rteig.p │ ├── rteneig.p │ ├── solutionsInBinaryTree.p │ ├── teig.p │ ├── teneig.p │ ├── tensor2poly.p │ └── zeig.p ├── Distributions ├── Hypergraph Analysis Toolbox.mltbx ├── Hypergraph Analysis Toolbox.prj └── Old │ ├── Hypergraph Analysis Toolbox.mltbx │ └── Hypergraph Analysis Toolbox.prj ├── Matlab ├── +Data │ ├── aminer_cocitation.mat │ ├── aminer_coreference.mat │ ├── citeseer_cocitation.mat │ ├── citeseer_coreference.mat │ ├── cora_cocitation.mat │ ├── cora_coreference.mat │ ├── dblp.mat │ └── karate.mat ├── +HAT │ ├── +BarhIM │ │ └── barhIM.m │ ├── +GraphRepresentation │ │ ├── BollaLaplacian.m │ │ ├── RodriguezLaplacian.m │ │ ├── ZhouLaplacian.m │ │ ├── cliqueGraph.m │ │ ├── lineGraph.m │ │ └── starGraph.m │ ├── +LinePlotIM │ │ └── lineplotIM.m │ ├── +ScatterIM │ │ ├── applyColors.m │ │ ├── colorByCardinality.m │ │ ├── colorNodesByDegree.m │ │ ├── fitMarkersToAxes.m │ │ └── scatterIM.m │ ├── +SortIM │ │ ├── cardinalitySort.asv │ │ ├── cardinalitySort.m │ │ └── min_max_sort.m │ ├── +TensorRepresentation │ │ ├── adjacencyTensor.m │ │ └── degreeTensor.m │ ├── +TensorSimilarity │ │ ├── Hamming.m │ │ ├── SpectralH.m │ │ ├── SpectralS.m │ │ └── tmpTenEval.m │ ├── +simpleHypergraphs │ │ ├── hyperchain.m │ │ ├── hyperring.m │ │ └── hyperstar.m │ ├── A32IM.m │ ├── A42IM.m │ ├── averageDistance.m │ ├── centrality.m │ ├── clusteringCoefficient.m │ ├── ctrbk.m │ ├── directSimilarity.m │ ├── getBmatrix.m │ ├── hyperedges2IM.m │ ├── indirectSimilarity.m │ ├── load.asv │ ├── load.m │ ├── matrixEntropy.m │ ├── multicorrelations.asv │ ├── multicorrelations.m │ ├── plotIncidenceMatrix.m │ ├── tensorEntropy.m │ ├── tmpTenEval.m │ ├── toyHG.m │ ├── uniformEdgeSet.m │ └── uniformErdosRenyi.m ├── @Hypergraph │ ├── Hypergraph.m │ ├── sConnectedComponents.m │ └── sRadius.m └── README.md ├── Python ├── HAT │ ├── HAT.py │ ├── __init__.py │ ├── __pycache__ │ │ ├── GraphDecompositions.cpython-38.pyc │ │ ├── __init__.cpython-38.pyc │ │ └── graph.cpython-38.pyc │ ├── data │ │ ├── aminer_cocitation.mat │ │ ├── aminer_coreference.mat │ │ ├── citeseer_cocitation.mat │ │ ├── citeseer_coreference.mat │ │ ├── cora_cocitation.mat │ │ ├── cora_coreference.mat │ │ └── dblp.mat │ ├── draw.py │ ├── dynamics.py │ ├── export.py │ ├── graph.py │ ├── hypergraph.py │ ├── laplacian.py │ ├── metrics.py │ ├── multilinalg.py │ └── tensors.py ├── LICENSE ├── PYPIREADME.md ├── README.md └── pyproject.toml ├── README.md ├── Tests ├── README.md ├── control_can.py ├── hypergraph_constructors.py ├── laplacians.py ├── matlab_basic_tests.m ├── metrics.py └── run_tests.py ├── demos ├── MATLAB Documentation │ ├── IntroToHAT.asv │ ├── IntroToHAT.m │ ├── Introduction.mlx │ └── multicorrelation.mlx ├── Matlab Development Demos │ ├── Development Demo.m │ ├── PHAT_application_note.m │ └── sample_incidence_matrix.png ├── Matlab Documentation Examples │ ├── IntroToHAT.m │ ├── Introduction.mlx │ └── multicorrelation.mlx └── Python Documentation │ ├── HAT_Test.ipynb │ ├── Introduction.ipynb │ └── Multicorrelation.ipynb ├── docs ├── .readthedocs.yaml ├── HAT.rst ├── Makefile ├── _static │ ├── GC.png │ ├── GH.png │ ├── GL.png │ ├── GS.png │ ├── IncidenceMatrix.png │ ├── index_dyadic_decomp.png │ └── vis.png ├── conf.py ├── dev.rst ├── index.rst ├── install.rst ├── make.bat ├── ref.rst └── tutorials.rst └── increment_version.py /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. See error 18 | 19 | **Expected behavior** 20 | A clear and concise description of what you expected to happen. 21 | 22 | **Screenshots** 23 | If applicable, add screenshots to help explain your problem. 24 | 25 | **Additional context** 26 | Add any other context about the problem here. 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Publish to PyPI 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | pull_request: 8 | branches: 9 | - 'main' 10 | types: 11 | - closed 12 | 13 | 14 | jobs: 15 | build-n-publish: 16 | name: Build and publish to PyPI 17 | runs-on: ubuntu-latest 18 | environment: 19 | name: pypi 20 | url: https://pypi.org/p/HypergraphAnalysisToolbox/ 21 | permissions: 22 | id-token: write # this permission is mandatory for Trusted Publishing (pypi) 23 | contents: write # this permission is mandatory for editing the contents of the repository 24 | 25 | steps: 26 | - name: Checkout source 27 | uses: actions/checkout@v4 # Updated to latest version 28 | 29 | - name: Set up Python 30 | uses: actions/setup-python@v5 # Updated to latest version 31 | with: 32 | python-version: "3.10" # Specify a concrete version 33 | 34 | - name: Increment version 35 | env: 36 | GH_PAT: ${{ secrets.GH_PAT }} 37 | run: | 38 | python -m pip install --upgrade pip 39 | python -m pip install toml 40 | python increment_version.py 41 | git config --global user.name "github-actions[bot]" 42 | git config --global user.email "github-actions[bot]@users.noreply.github.com" 43 | git remote set-url origin https://github.com/${{ github.repository }} 44 | git add . 45 | git commit -m "🤖 AUTO: Incremented version automatically" 46 | git push https://${GH_PAT}@github.com/${{ github.repository }} HEAD:${{ github.ref_name }} 47 | continue-on-error: true # Avoid breaking the workflow if no changes are made 48 | 49 | 50 | - name: Install build dependencies 51 | run: | 52 | python -m pip install --upgrade pip 53 | python -m pip install -U build twine 54 | 55 | - name: Build package 56 | run: python -m build Python/ 57 | 58 | - name: Check distribution 59 | run: twine check --strict Python/dist/* 60 | 61 | - name: Publish to PyPI 62 | uses: pypa/gh-action-pypi-publish@v1.12.3 63 | with: 64 | password: ${{ secrets.PYPI_API_TOKEN }} 65 | packages-dir: Python/dist/ 66 | verbose: true 67 | -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: Run Tests on Merge 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - main 7 | 8 | jobs: 9 | run-tests: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | # Checkout the code 14 | - name: Checkout code 15 | uses: actions/checkout@v3 16 | 17 | # Set up Python environment 18 | - name: Set up Python 19 | uses: actions/setup-python@v4 20 | with: 21 | python-version: '3.x' 22 | 23 | # Install dependencies (update with your project-specific requirements) 24 | - name: Install dependencies 25 | run: | 26 | python -m pip install --upgrade pip 27 | 28 | # Install the package to be tested 29 | - name: Install HAT 30 | run: | 31 | cd Python 32 | pip install -e . 33 | cd .. 34 | 35 | # Run the test cases 36 | - name: Run test cases 37 | run: | 38 | python ./Tests/run_tests.py 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | docs/_build/ 2 | Python/HAT_Test.ipynb 3 | Python/HAT/__pycache__/ 4 | *.ipynb* 5 | *.png 6 | Python/HAT_IM.png 7 | Python/HAT_IM2.png 8 | Python/HAT_IM3.png 9 | Python/HAT/indirectSimilarity.py 10 | Python/del.py 11 | *.png 12 | *.asv 13 | Python/HAT/__pycache__/__init__.cpython-38.pyc 14 | .github/*/*.pdf 15 | .github/ISSUE_TEMPLATE/*.pdf 16 | .github/ISSUE_TEMPLATE/*.jpeg 17 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the version of Python and other tools you might need 9 | build: 10 | os: ubuntu-22.04 11 | tools: 12 | python: "3.11" 13 | 14 | # Build documentation in the docs/ directory with Sphinx 15 | sphinx: 16 | configuration: docs/conf.py 17 | 18 | # We recommend specifying your dependencies to enable reproducible builds: 19 | # https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 20 | # python: 21 | # install: 22 | # - requirements: docs/requirements.txt 23 | -------------------------------------------------------------------------------- /Dependencies/TenEig2/KLtranspose.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/KLtranspose.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/NwtnHomotopy.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/NwtnHomotopy.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/ParticalDerivative.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/ParticalDerivative.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/PolynomialDecompose.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/PolynomialDecompose.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/biSolver.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/biSolver.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/distinct.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/distinct.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/eeig.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/eeig.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/evalTensorEig.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/evalTensorEig.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/generateRandTensor.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/generateRandTensor.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/getSuppOfAxm.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/getSuppOfAxm.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/getVariablesInPolynomial.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/getVariablesInPolynomial.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/heig.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/heig.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/monomial.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/monomial.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/polynomial.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/polynomial.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/polynomialEval.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/polynomialEval.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/polynomialSystem.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/polynomialSystem.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/realFilter.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/realFilter.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/rteig.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/rteig.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/rteneig.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/rteneig.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/solutionsInBinaryTree.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/solutionsInBinaryTree.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/teig.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/teig.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/teneig.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/teneig.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/tensor2poly.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/tensor2poly.p -------------------------------------------------------------------------------- /Dependencies/TenEig2/zeig.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Dependencies/TenEig2/zeig.p -------------------------------------------------------------------------------- /Distributions/Hypergraph Analysis Toolbox.mltbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Distributions/Hypergraph Analysis Toolbox.mltbx -------------------------------------------------------------------------------- /Distributions/Hypergraph Analysis Toolbox.prj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hypergraph Analysis Toolbox 4 | Joshua Pickard 5 | jpic@umich.edu 6 | Rajapakse Lab & iReprogram 7 | Hypergraph Analysis Toolbox (HAT) is a software for the analysis and visualization of multi-way interactions in data as hypergraphs. 8 | Hypergraph Analysis Tolbox (HAT) is a software suite for the analysis and visualization of hypergraphs and higher order structures. Motivated to investigate Pore-C data, HAT is intended as a general prupose, versatile software for hypergraph construction, visualization, and analysis. HAT addresses the following hypergraph problems: 9 | 1. Construction 10 | 2. Visualization 11 | 3. Expansion and numeric representation 12 | 4. Structral Properties 13 | 5. Controllability 14 | 6. Similarity Measures 15 | Documentation of HAT, information on the Python distribution, and related work are available at: https://hypergraph-analysis-toolbox.readthedocs.io/ 16 | C:\Users\test\Desktop\HAT Cover.png 17 | 1.0.1 18 | ${PROJECT_ROOT}\Hypergraph Analysis Toolbox.mltbx 19 | 20 | 21 | 22 | 23 | 3a4bf4e2-8c4a-45f0-9f0a-01a88d403ed4 24 | 25 | true 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | false 35 | 36 | 37 | Hypergraph Analysis Toolbox 38 | 39 | 40 | 41 | 42 | 43 | 44 | false 45 | true 46 | true 47 | true 48 | true 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | C:\Joshua\Hypergraph-Analysis-Toolbox\Matlab 90 | 91 | 92 | C:\Joshua\Hypergraph-Analysis-Toolbox\Matlab\+Data 93 | C:\Joshua\Hypergraph-Analysis-Toolbox\Matlab\+HAT 94 | C:\Joshua\Hypergraph-Analysis-Toolbox\Matlab\@Hypergraph 95 | C:\Joshua\Hypergraph-Analysis-Toolbox\Matlab\README.md 96 | 97 | 98 | 99 | 100 | 101 | C:\Joshua\Hypergraph-Analysis-Toolbox\Distributions\Hypergraph Analysis Toolbox.mltbx 102 | 103 | 104 | 105 | C:\Program Files\MATLAB\R2021b 106 | 107 | 108 | 109 | 110 | 111 | true 112 | 113 | 114 | 115 | 116 | false 117 | false 118 | true 119 | false 120 | false 121 | false 122 | false 123 | false 124 | 10.0 125 | false 126 | true 127 | win64 128 | true 129 | 130 | 131 | -------------------------------------------------------------------------------- /Distributions/Old/Hypergraph Analysis Toolbox.mltbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Distributions/Old/Hypergraph Analysis Toolbox.mltbx -------------------------------------------------------------------------------- /Distributions/Old/Hypergraph Analysis Toolbox.prj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hypergraph Analysis Toolbox 4 | Joshua Pickard 5 | jpic@umich.edu 6 | Rajapakse Lab @ Michigan & iReprogram Inc. 7 | Hypergraph Analysis Toolbox (HAT) is a general purpose software for studying multi-way relationships through hypergraphs. 8 | Hypergraph Analysis Toolbox (HAT) is a general purpose software for studying multi-way relationships through hypergraphs. Methods for hypergraph constructions, visualization, and the analysis of structural and dynamical properties are provided. 9 | 10 | 1.0 11 | ${PROJECT_ROOT}\Hypergraph Analysis Toolbox.mltbx 12 | 13 | 14 | 15 | 16 | 3a560f8f-b0a2-4e14-b8b4-6512dcf93fec 17 | 18 | true 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | false 28 | 29 | 30 | 31 | 32 | 33 | R2022b 34 | R2022b 35 | true 36 | true 37 | true 38 | true 39 | true 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | ${PROJECT_ROOT}\Matlab 80 | 81 | 82 | 83 | 84 | 85 | 86 | C:\Users\picka\Documents\my_projects\DBTM\PoreC-Hypergraph-Analysis-Toolbox\Distributions\Hypergraph Analysis Toolbox.mltbx 87 | 88 | 89 | 90 | C:\Program Files\MATLAB\R2022b 91 | 92 | 93 | 94 | false 95 | false 96 | true 97 | false 98 | false 99 | false 100 | false 101 | false 102 | 10.0 103 | false 104 | true 105 | win64 106 | true 107 | 108 | 109 | -------------------------------------------------------------------------------- /Matlab/+Data/aminer_cocitation.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Matlab/+Data/aminer_cocitation.mat -------------------------------------------------------------------------------- /Matlab/+Data/aminer_coreference.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Matlab/+Data/aminer_coreference.mat -------------------------------------------------------------------------------- /Matlab/+Data/citeseer_cocitation.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Matlab/+Data/citeseer_cocitation.mat -------------------------------------------------------------------------------- /Matlab/+Data/citeseer_coreference.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Matlab/+Data/citeseer_coreference.mat -------------------------------------------------------------------------------- /Matlab/+Data/cora_cocitation.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Matlab/+Data/cora_cocitation.mat -------------------------------------------------------------------------------- /Matlab/+Data/cora_coreference.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Matlab/+Data/cora_coreference.mat -------------------------------------------------------------------------------- /Matlab/+Data/dblp.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Matlab/+Data/dblp.mat -------------------------------------------------------------------------------- /Matlab/+Data/karate.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Matlab/+Data/karate.mat -------------------------------------------------------------------------------- /Matlab/+HAT/+BarhIM/barhIM.m: -------------------------------------------------------------------------------- 1 | function b = barhIM(ax, A) 2 | %barhIM Plots horizontal stripes for aesthetic value. 3 | % 4 | 5 | [m, ~] = size(A); 6 | 7 | currXMethod = ax.XLimitMethod; 8 | currYMethod = ax.YLimitMethod; 9 | 10 | ax.XLimitMethod = 'tight'; 11 | ax.YLimitMethod = 'tight'; 12 | 13 | bars = 1:2:m; 14 | b = barh(ax, bars, (ax.XLim(2) + 1)*ones(size(bars))); 15 | b.FaceColor = [0.3 0.3 0.3]; 16 | b.FaceAlpha = 0.15; 17 | b.BarWidth = 0.5; 18 | b.EdgeAlpha = 0; 19 | b.BaseValue = ax.XLim(1); 20 | 21 | if mod(m, 2) == 0 22 | b2 = barh(ax, m, ax.XLim(2)); 23 | b2.BarWidth = 1; 24 | b2.FaceAlpha = 0; 25 | b2.EdgeAlpha = 0; 26 | b2.BaseValue = ax.XLim(1); 27 | end 28 | 29 | ax.XLimitMethod = currXMethod; 30 | ax.YLimitMethod = currYMethod; 31 | end 32 | 33 | -------------------------------------------------------------------------------- /Matlab/+HAT/+GraphRepresentation/BollaLaplacian.m: -------------------------------------------------------------------------------- 1 | %% Decompositions.GraphDecomp.BollaLaplacian 2 | % Returns the adjacency matrix and laplacian matrix of a graph 3 | % corresponding to the decomposition of the input hypergraph according to 4 | % Mariana Bolla. 5 | %% Syntax 6 | % [adjMat, lapMat] = BollaLaplacian(HG); 7 | %% Input 8 | % HG - hypergraph object with incidence matrix property obj.IM 9 | %% Output 10 | % * adjMat - adjacency matrix of the decomposed hypergraph 11 | % * lapMat - graph Laplacian matrix of the decomposed hypergraph 12 | %% Disclaimer 13 | % The definition of Bolla's Laplacian from a hypergraph was taken from the 14 | % second page of the paper: 15 | % * Bolla, M. (1993). Spectra, euclidean representations and clusterings of hypergraphs. Discrete Mathematics, 117. 16 | function [adjMat,lapMat] = BollaLaplacian(HG) 17 | %BOLALAPLACIAN Summary of this function goes here 18 | % Detailed explanation goes here 19 | 20 | H = HG.IM; 21 | de=sum(H,1)'; 22 | 23 | Deinv=sparse(1:length(de),1:length(de),1./de,length(de),length(de)); %diag(1./de) 24 | adjMat=H*Deinv*H'; 25 | dv=sum(H,2); 26 | Dv=sparse(1:length(dv),1:length(dv),dv,length(dv),length(dv)); 27 | lapMat=Dv-adjMat; 28 | 29 | end 30 | 31 | -------------------------------------------------------------------------------- /Matlab/+HAT/+GraphRepresentation/RodriguezLaplacian.m: -------------------------------------------------------------------------------- 1 | %% Decompositions.GraphDecomp.RodriguezLaplacian 2 | % Returns the adjacency matrix and laplacian matrix of a graph 3 | % corresponding to the decomposition of the input hypergraph according to 4 | % J.A. Rodriguez. 5 | %% Syntax 6 | % [adjMat, lapMat] = RodriguezLaplacian(HG); 7 | %% Input 8 | % HG - hypergraph object with incidence matrix property obj.IM 9 | %% Output 10 | % * adjMat - adjacency matrix of the decomposed hypergraph 11 | % * lapMat - graph Laplacian matrix of the decomposed hypergraph 12 | %% Disclaimer 13 | % The definition of Rodriguez's Laplacian from a hypergraph was taken from the 14 | % below papers 15 | % * Rodriguez, J. A. (2002). On the Laplacian eigenvalues and metric parameters of hypergraphs. Linear and Multilinear Algebra, 50(1), 1-14. 16 | % * Rodriguez, J. A. (2003). On the Laplacian spectrum and walk-regular hypergraphs. Linear and Multilinear Algebra, 51, 285–297. 17 | %% Code 18 | function [adjMat,lapMat] = RodriguezLaplacian(HG) 19 | %RODRIGUEZLAPLACIAN Summary of this function goes here 20 | % Detailed explanation goes here 21 | H = HG.IM; 22 | 23 | adjMat=H*1*H'; 24 | adjMat=adjMat-diag(diag(adjMat)); 25 | Dvr=diag(sum(adjMat,2)); 26 | lapMat=Dvr-adjMat; 27 | end 28 | 29 | -------------------------------------------------------------------------------- /Matlab/+HAT/+GraphRepresentation/ZhouLaplacian.m: -------------------------------------------------------------------------------- 1 | %% Decompositions.GraphDecomp.ZhouLaplacian 2 | % Returns the adjacency matrix and laplacian matrix of a graph 3 | % corresponding to the decomposition of the input hypergraph according to 4 | % Dengyong Zhou. 5 | %% Syntax 6 | % [adjMat, lapMat] = ZhouLaplacian(HG); 7 | %% Input 8 | % HG - hypergraph object with incidence matrix property obj.IM 9 | %% Output 10 | % * adjMat - adjacency matrix of the decomposed hypergraph 11 | % * lapMat - graph Laplacian matrix of the decomposed hypergraph 12 | %% Disclaimer 13 | % The definition of Bolla's Laplacian from a hypergraph was taken from 14 | % equation 3.3 of the below paper: 15 | % 16 | % Zhou, D., Huang, J., & Sch¨olkopf, B. (2005). Beyond pairwise classification and clustering using hypergraphs (Technical Report 143). Max Plank Institute for Biological Cybernetics, T¨ubingen, Germany. 17 | %% Code 18 | function [adjMat,lapMat] = ZhouLaplacian(HG) 19 | H = HG.IM; 20 | eW = HG.edgeWeights; 21 | de=sum(H,1)'; 22 | 23 | dv=H*eW; 24 | dv(dv==0)=Inf; % convention 25 | Dvinv=sparse(1:length(dv),1:length(dv),1./sqrt(dv),length(dv),length(dv));%diag(1./sqrt(dv)) 26 | Deinv=sparse(1:length(de),1:length(de),1./de,length(de),length(de));%diag(1./de); 27 | W=sparse(1:length(eW),1:length(eW),eW,length(eW),length(eW));%diag(eW); 28 | lapMat=eye(size(H,1))-Dvinv*H*W*Deinv*H'*Dvinv; 29 | adjMat=H*W*Deinv*W*H'; 30 | end 31 | 32 | -------------------------------------------------------------------------------- /Matlab/+HAT/+GraphRepresentation/cliqueGraph.m: -------------------------------------------------------------------------------- 1 | %% Decompositions.GraphDecomp.cliqueGraph 2 | % Returns the adjacency matrix and graph Laplacian of the clique-expansion 3 | % of the input hypergraph. 4 | %% Syntax 5 | % [adjMat, lapMat] = cliqueGraph(HG) 6 | %% Input 7 | % HG - hypergraph object with incidence matrix property obj.IM 8 | %% Output 9 | % * adjMat - adjacency matrix of the clique expansion 10 | % * lapMat - graph Laplacian matrix of the clique expansion 11 | %% Disclaimer 12 | % 13 | %% Code 14 | function [adjMat,lapMat] = cliqueGraph(HG) 15 | H = HG.IM; 16 | eW = HG.edgeWeights; 17 | de=sum(H,1)'; 18 | 19 | adjMat=H*sparse(1:length(eW),1:length(eW),eW,length(eW),length(eW))*H'; 20 | adjMat=adjMat-diag(diag(adjMat)); 21 | adjMat(adjMat>0) = 1; 22 | eW1=(de-1).*eW; 23 | dvc=H*eW1; %this should be same as sum(adjMat,2) 24 | dvc(dvc==0)=Inf; % convention 25 | Dvc=sparse(1:length(dvc),1:length(dvc),1./sqrt(dvc),length(dvc),length(dvc));%diag(1./sqrt(dvc))) 26 | lapMat=eye(size(Dvc))-Dvc*adjMat*Dvc; % normalized Laplacian 27 | end 28 | 29 | -------------------------------------------------------------------------------- /Matlab/+HAT/+GraphRepresentation/lineGraph.m: -------------------------------------------------------------------------------- 1 | %% Decompositions.GraphDecomp.lineGraph 2 | % Returns the adjacency matrix and graph Laplacian of the line-graph 3 | % of the input hypergraph. Note that the line graph is equivalent to the 4 | % clique-expansion of the dual hypergraph. 5 | %% Syntax 6 | % [adjMat, lapMat] = lineGraph(HG) 7 | %% Input 8 | % HG - hypergraph object with incidence matrix property obj.IM 9 | %% Output 10 | % * adjMat - adjacency matrix of the line graph 11 | % * lapMat - graph Laplacian matrix of the line graph 12 | %% Disclaimer 13 | % 14 | %% Code 15 | function [adjMat,lapMat] = lineGraph(HG) 16 | %LINEGRAPH the line graph is the clique expansion of the dual (and the dual 17 | % is the transpose of the original incidence matrix). 18 | 19 | H = Hypergraph('IM', HG.IM'); 20 | [adjMat, lapMat] = HAT.GraphRepresentation.cliqueGraph(H); 21 | 22 | end 23 | 24 | -------------------------------------------------------------------------------- /Matlab/+HAT/+GraphRepresentation/starGraph.m: -------------------------------------------------------------------------------- 1 | %% Decompositions.GraphDecomp.starGraph 2 | % Returns the adjacency matrix and graph Laplacian of the star-expansion 3 | % of the input hypergraph. 4 | %% Syntax 5 | % A = starGraph(HG) 6 | %% Input 7 | % * HG - hypergraph object with incidence matrix property obj.IM 8 | %% Output 9 | % * adjMat - adjacency matrix of the star expansion 10 | %% Disclaimer 11 | % 12 | %% Code 13 | function [adjMat] = starGraph(HG) 14 | 15 | H = HG.IM; 16 | [n, m] = size(H); 17 | 18 | adjMat = zeros(n + m); 19 | adjMat(n+1:n+m,1:n) = H'; 20 | adjMat(1:n,n+1:m+n) = H; 21 | 22 | end 23 | 24 | -------------------------------------------------------------------------------- /Matlab/+HAT/+LinePlotIM/lineplotIM.m: -------------------------------------------------------------------------------- 1 | function p = lineplotIM(ax, A, lineargs) 2 | %LINEPLOTIM Summary of this function goes here 3 | % Detailed explanation goes here 4 | [m, n] = size(A); 5 | Abin = ones(m, n); 6 | Abin(A == 0) = 0; 7 | 8 | % incidence matrix with nz entries scaled to node number. 9 | Y = (Abin' * sparse(1:m, 1:m, 1:m, m, m))'; 10 | 11 | % matrix holding x-values associated with each hyperedge plot 12 | X = ndgrid(1:n, 1:m)'; 13 | 14 | % some cell array manipulations! 15 | Ycell = mat2cell(Y', ones(size(Y,2),1)); 16 | Xcell = mat2cell(X', ones(size(X,2),1)); 17 | 18 | % remove zero entries from each cell 19 | for idx = 1:size(Ycell,1) 20 | logical_idx = Ycell{idx} == 0; 21 | Ycell{idx}(logical_idx) = []; 22 | Xcell{idx}(logical_idx) = []; 23 | end 24 | 25 | % a cell array with plotting triplets: 26 | % 1. XData 27 | % 2. YData 28 | % 3. lineargs 29 | plottingCell = cell(3*size(Y,2),1); 30 | plottingCell(1:3:end) = Xcell; 31 | plottingCell(2:3:end) = Ycell; 32 | plottingCell(3:3:end) = lineargs; 33 | 34 | p = plot(ax, plottingCell{:}); 35 | end 36 | 37 | -------------------------------------------------------------------------------- /Matlab/+HAT/+ScatterIM/applyColors.m: -------------------------------------------------------------------------------- 1 | function s = applyColors(s,colors, indices, sets) 2 | %APPLYCOLORS Applies colors to a scatter plot s. 3 | % colors can take four forms: 4 | % 1. (1,3) RGB triple. This applies one color to all markers of the scatter plot. 5 | % 2. (m,3) RGB matrix. This applies a unique color to all markers of the 6 | % scatter plot as specified by the matrix. 7 | % 3. (m,1) integer vector. This assigns a color to each marker by indexing 8 | % from this vector to the current colormap. 9 | arguments 10 | s 11 | colors 12 | indices = [] 13 | sets = [] 14 | end 15 | numMarkers = size(s.XData,2); 16 | if all(size(colors) == [numMarkers, 1]) || all(size(colors) == [1 3]) || all(size(colors) == [numMarkers 3]) 17 | s.CData = colors; 18 | else 19 | applyGroupedColors(s, indices, sets, colors); 20 | end 21 | 22 | end 23 | 24 | function s = applyGroupedColors(s, indices, node_sets, colors) 25 | %This function applies a row-wise color scheme to a 26 | %scatter plot on the assumption that that scatter plot comes from an 27 | %incidence matrix. 28 | % TODO: replace this with s.CData vector input and colormap setting 29 | % 30 | % This function gives user control over which color to assing to each node. 31 | % It is possible to color sets of nodes uniquely using CData's vector arg 32 | % form, but this restricts the possible colors to MATLAB's colormaps. 33 | % 34 | % s: scatter object. Each point is a nz entry in the incidence 35 | % matrix. 36 | % indices: (m,1) double. This is the object returned by running find() 37 | % on the incidence matrix that the scatter object represents. Passing in 38 | % the y-indices will color the scatter object by rows, and passing in the 39 | % x-indices will color the scatter object by columns. 40 | % node_sets: (k,1) cell array. Each cell is a 1D array of integers on 1 41 | % to m representing nodes. Nodes in a single cell are to be filled in the 42 | % same color. If y-indices are passed in for indices, then these cells 43 | % should have integers representing hyperedges. 44 | % colors:(k,3) RGB matrix. The ith row of this matrix is the color of the 45 | % ith cell of node_sets. 46 | 47 | 48 | ColorData = zeros(size(indices,1),3); 49 | for i = 1:size(node_sets,2) 50 | color = colors(i, :); 51 | markers_to_color = node_sets{i}; 52 | 53 | idx = ismember(indices, markers_to_color); 54 | idx = cast(repmat(idx, 1, 3), "double"); 55 | 56 | ColorData = ColorData + idx * diag(color); 57 | end 58 | s.CData = ColorData; 59 | end 60 | 61 | -------------------------------------------------------------------------------- /Matlab/+HAT/+ScatterIM/colorByCardinality.m: -------------------------------------------------------------------------------- 1 | function s = colorByCardinality(s, A) 2 | %COLORBYCARDINALITY Colors the edges of the incidence matrix by the number 3 | %of vertices within each edge. 4 | % s: scatter object representing the incidence matrix 5 | % A: incidence matrix 6 | 7 | [i, ~] = find(A); 8 | 9 | colors = zeros(size(i)); 10 | cards = sum(A,1); 11 | count = 1; 12 | for index = 1:length(cards) 13 | for k = 1:(cards(index)) 14 | colors(count) = cards(index); 15 | count = count + 1; 16 | end 17 | end 18 | 19 | % s.CData = colors(idx); 20 | s.CData = colors; 21 | end 22 | 23 | -------------------------------------------------------------------------------- /Matlab/+HAT/+ScatterIM/colorNodesByDegree.m: -------------------------------------------------------------------------------- 1 | function s = colorNodesByDegree(s, A) 2 | %COLORNODESBYDEGREE Colors each node of the incidence matrix by the number 3 | % edges it is present in. 4 | % s: scatter object representing the incidence matrix 5 | % A: incidence matrix 6 | 7 | [i, j] = find(A); 8 | [~, idx] = sort(i); 9 | j = j(idx); 10 | [~, idx] = sort(j); 11 | 12 | colors = zeros(size(j)); 13 | cards = sum(A,2); 14 | count = 1; 15 | for index = 1:length(cards) 16 | for k = 1:(cards(index)) 17 | colors(count) = cards(index); 18 | count = count + 1; 19 | end 20 | end 21 | 22 | s.CData = colors(idx); 23 | end 24 | 25 | -------------------------------------------------------------------------------- /Matlab/+HAT/+ScatterIM/fitMarkersToAxes.m: -------------------------------------------------------------------------------- 1 | function ax = fitMarkersToAxes(s, ax) 2 | %FITMARKERSTOAXES Adjusts the SizeData property of the scatter object s to 3 | %fit withing the axes ax. gca is passed in by default. 4 | arguments 5 | s 6 | ax = gca 7 | end 8 | 9 | marker = s.Marker; 10 | 11 | % these are all the MATLAB built-in markers for scatter. 12 | small = '.'; 13 | medium = ['p', 'h', 'x', '|']; 14 | large = ['s', 'd', '^', '<', '>', 'v', '_', '*', '+']; 15 | 16 | currentunits = get(ax,'Units'); 17 | set(ax, 'Units', 'Points'); 18 | axpos = get(ax,'Position'); % [left bottom width height] 19 | set(ax, 'Units', currentunits); 20 | 21 | space = min(axpos(3)/diff(ax.XLim), axpos(4)/diff(ax.YLim)); 22 | 23 | if ismember(marker, small) 24 | scale_marker = 2; 25 | elseif ismember(marker, medium) 26 | scale_marker = 0.8; 27 | else 28 | scale_marker = 0.72; 29 | end 30 | 31 | area = pi*(scale_marker*space/(2))^2; 32 | set(s, 'SizeData', area); 33 | end 34 | 35 | -------------------------------------------------------------------------------- /Matlab/+HAT/+ScatterIM/scatterIM.m: -------------------------------------------------------------------------------- 1 | function s = scatterIM(A, ax, color) 2 | %SCATTERIM Summary of this function goes here 3 | % Detailed explanation goes here 4 | arguments 5 | A (:,:) 6 | ax = gca 7 | color = 'k' 8 | end 9 | % grab indices of nonzero entries of the incidence matrix to be used in 10 | % the scatter plot 11 | [i, j] = find(A); 12 | s = scatter(ax, j, i, [], color); 13 | end 14 | 15 | -------------------------------------------------------------------------------- /Matlab/+HAT/+SortIM/cardinalitySort.asv: -------------------------------------------------------------------------------- 1 | function An = cardinalitySort(A, direction) 2 | %CARDINALITYSORT Returns a new incidence matrix whose edges are sorted by 3 | %cardinality. 4 | arguments 5 | A (:,:) 6 | direction = 'descend' 7 | end 8 | 9 | cardinality = sum(A,1); 10 | [~, idx] = sort(cardinality, direction); 11 | An = A(:, idx); 12 | 13 | end 14 | 15 | -------------------------------------------------------------------------------- /Matlab/+HAT/+SortIM/cardinalitySort.m: -------------------------------------------------------------------------------- 1 | function An = cardinalitySort(A, direction) 2 | %CARDINALITYSORT Returns a new incidence matrix whose edges are sorted by 3 | %cardinality. 4 | arguments 5 | A (:,:) 6 | direction = 'descend' 7 | end 8 | 9 | cardinality = sum(A,1); 10 | [~, idx] = sort(cardinality, direction); 11 | An = A(:, idx); 12 | 13 | end 14 | 15 | -------------------------------------------------------------------------------- /Matlab/+HAT/+SortIM/min_max_sort.m: -------------------------------------------------------------------------------- 1 | function An = min_max_sort(A) 2 | %MIN_MAX_SORT Returns a new incidence matrix whose edges are sorted first 3 | %on minimum node index, then on maximum node index. 4 | 5 | Bn = min_max(A); 6 | [~, idx] = sortrows(Bn, [1, 2]); 7 | An = A(:, idx); 8 | 9 | % TODO: learn how sortrows breaks ties! 10 | % As implemented, min_max_sort considers ONLY the minimum and maximum 11 | % node indices of a hyperedge. I suspect that the figures in Dotson's 12 | % PoreC paper break ties using intermediate node values. 13 | end 14 | 15 | function B = min_max(A) 16 | %MIN_MAX takes an (m,n) incidence matrix and returns an (m,2) array of the 17 | %minimum and maximum node indices of each hyperedge. 18 | % A: (n,m) double. 19 | [n, m] = size(A); 20 | indices = ((1:n) .* ones(m, 1))'; 21 | 22 | % "incidence matrix" with node index in place of ones 23 | Ai = A .* indices; 24 | 25 | % min and max should ignore zero values in the "incidence matrix" 26 | Ai(Ai == 0) = nan; 27 | 28 | [~, I_max] = max(Ai, [], 1, 'omitnan'); 29 | [~, I_min] = min(Ai, [], 1, 'omitnan'); 30 | B = [I_min; I_max]'; 31 | 32 | end -------------------------------------------------------------------------------- /Matlab/+HAT/+TensorRepresentation/adjacencyTensor.m: -------------------------------------------------------------------------------- 1 | %% Decompositions.TensorDecomp.adjacencyTensor 2 | % 3 | %% Syntax 4 | % 5 | %% Input 6 | % 7 | %% Output 8 | % 9 | %% Disclaimer 10 | % 11 | %% Code 12 | function adjTensor = adjacencyTensor(HG) 13 | % H is the incidence matrix of a hypergraph 14 | % Return the generalized adjacency tensor of the hypergraph 15 | H = HG.IM; 16 | eW = HG.edgeWeights; 17 | 18 | numNodes = size(H, 1); 19 | order = max(sum(H, 1)); 20 | adjTensor = zeros(numNodes^order, 1); 21 | 22 | for i = 1:size(H, 2) 23 | hyperEdge = find(H(:, i)>0); 24 | 25 | if length(hyperEdge) == 1 26 | dummyEdges = nmultichoosek(hyperEdge, order); 27 | coefficient = 1; 28 | elseif length(hyperEdge) == order 29 | dummyEdges = hyperEdge'; 30 | coefficient = 1/factorial(order-1); 31 | else 32 | dummyEdges = nmultichoosek(hyperEdge, order); 33 | dummyEdges = dummyEdges(arrayfun(@(x) all(ismember(hyperEdge', dummyEdges(x, :))), 1:size(dummyEdges, 1))', :); 34 | dummyEdgesCell = mat2cell(dummyEdges, ones(1, size(dummyEdges, 1)), size(dummyEdges, 2)); 35 | numCounts = cellfun(@(x) histcounts(x), dummyEdgesCell, 'Uni', 0); 36 | numCounts = cell2mat(numCounts); 37 | coefficient = length(hyperEdge)/sum(factorial(order)./prod(factorial(numCounts), 2)); 38 | end 39 | 40 | coefficient=coefficient*eW(i); 41 | 42 | for m = 1:size(dummyEdges, 1) 43 | p = unique(perms(dummyEdges(m, :)), 'rows'); 44 | for t = 1:size(p, 1) 45 | adjTensor(indexMapping(ones(1, order)*numNodes, p(t, :))) = coefficient; 46 | end 47 | end 48 | end 49 | adjTensor = reshape(adjTensor, ones(1, order)*numNodes); 50 | end 51 | 52 | 53 | function combs = nmultichoosek(values, k) 54 | n = numel(values); 55 | combs = bsxfun(@minus, nchoosek(1:n+k-1,k), 0:k-1); 56 | combs = reshape(values(combs),[],k); 57 | end 58 | 59 | function linearIdx = indexMapping(sz, subscript) 60 | fisrtSub = subscript(1); 61 | subscript = subscript(2:end)-1; 62 | szProd = zeros(1, length(sz)-1); 63 | for i = 1:length(sz)-1 64 | szProd(i) = prod(sz(1:i)); 65 | end 66 | linearIdx = fisrtSub+sum(subscript.*szProd); 67 | end -------------------------------------------------------------------------------- /Matlab/+HAT/+TensorRepresentation/degreeTensor.m: -------------------------------------------------------------------------------- 1 | function D = degreeTensor(HG) 2 | %DEGREETENSOR Generates degree tensor 3 | % 4 | % Auth: Joshua Pickard 5 | % jpic@umich.edu 6 | % Date: April 17, 2023 7 | H = HG.IM; 8 | eW = HG.edgeWeights; 9 | numNodes = size(H, 1); 10 | order = sum(H(:,1), 1); 11 | 12 | % Used to generate linear indices 13 | p = cumprod([1 (numNodes * ones(1, order-1))]); 14 | 15 | d = H * eW; 16 | % d = sum(H,2) .* eW; 17 | D = zeros(numNodes*ones(1,order)); 18 | for i=1:numNodes 19 | LINIDX = ((i*ones(1,order))-1)*p(:)+1; 20 | D(LINIDX) = d(i); 21 | end 22 | 23 | end 24 | 25 | -------------------------------------------------------------------------------- /Matlab/+HAT/+TensorSimilarity/Hamming.m: -------------------------------------------------------------------------------- 1 | function d = Hamming(A1, A2) 2 | % A1 and A2 are adjacency tensors of two hypergraphs 3 | % Returns the Hamming distance between two hypergraphs 4 | 5 | sz = size(A1); 6 | order = length(sz); 7 | d = sum(abs(A1-A2), 'all')/(sz(1)^order-sz(1)); 8 | 9 | end 10 | -------------------------------------------------------------------------------- /Matlab/+HAT/+TensorSimilarity/SpectralH.m: -------------------------------------------------------------------------------- 1 | function d = SpectralH(A1,A2) 2 | % A1 and A2 are adjacency tensors of two hypergraphs 3 | % Returns the spectral distance (based on generalized singular values) 4 | % between two hypergraphs 5 | 6 | sz = size(A1); 7 | numNodes = sz(1); 8 | order = length(sz); 9 | 10 | D1 = zeros(numNodes^order, 1); 11 | D2 = zeros(numNodes^order, 1); 12 | for i = 1:numNodes 13 | D1(indexMapping(sz, i*ones(1, order))) = sum(A1(i, :), 'all'); 14 | D2(indexMapping(sz, i*ones(1, order))) = sum(A2(i, :), 'all'); 15 | end 16 | 17 | D1 = reshape(D1, ones(1, order)*numNodes); 18 | D2 = reshape(D2, ones(1, order)*numNodes); 19 | 20 | Lm1 = reshape(D1-A1, sz(1), sz(1)^(order-1)); 21 | Lm2 = reshape(D2-A2, sz(1), sz(1)^(order-1)); 22 | 23 | s1 = svd(Lm1, 'econ'); 24 | s2 = svd(Lm2, 'econ'); 25 | 26 | s1 = s1./sum(s1); 27 | s2 = s2./sum(s2); 28 | 29 | d = sum(abs(s1-s2).^2)/length(s1); 30 | end 31 | 32 | 33 | 34 | function linearIdx = indexMapping(sz, subscript) 35 | fisrtSub = subscript(1); 36 | subscript = subscript(2:end)-1; 37 | szProd = zeros(1, length(sz)-1); 38 | for i = 1:length(sz)-1 39 | szProd(i) = prod(sz(1:i)); 40 | end 41 | linearIdx = fisrtSub+sum(subscript.*szProd); 42 | end 43 | -------------------------------------------------------------------------------- /Matlab/+HAT/+TensorSimilarity/SpectralS.m: -------------------------------------------------------------------------------- 1 | function d = SpectralS(A1,A2) 2 | % A1 and A2 are adjacency tensors of two hypergraphs 3 | % Returns the spectral distance (based on H-eigenvalue) 4 | % between two hypergraphs 5 | 6 | sz = size(A1); 7 | numNodes = sz(1); 8 | order = length(sz); 9 | 10 | D1 = zeros(numNodes^order, 1); 11 | D2 = zeros(numNodes^order, 1); 12 | for i = 1:numNodes 13 | D1(indexMapping(sz, i*ones(1, order))) = sum(A1(i, :), 'all'); 14 | D2(indexMapping(sz, i*ones(1, order))) = sum(A2(i, :), 'all'); 15 | end 16 | 17 | D1 = reshape(D1, ones(1, order)*numNodes); 18 | D2 = reshape(D2, ones(1, order)*numNodes); 19 | 20 | L1 = reshape(D1-A1, sz); 21 | L2 = reshape(D2-A2, sz); 22 | 23 | heig1 = uniquetol(heig(L1)', 1e-4); 24 | heig2 = uniquetol(heig(L2)', 1e-4); 25 | 26 | if length(heig1) <= length(heig2) 27 | heig1 = [zeros(length(heig2)-length(heig1), 1); heig1]; 28 | else 29 | heig2 = [zeros(length(heig1)-length(heig2), 1); heig2]; 30 | end 31 | 32 | heig1 = heig1./sum(heig1); 33 | heig2 = heig2./sum(heig2); 34 | 35 | d = sum(abs(heig1-heig2).^2); 36 | end 37 | 38 | function linearIdx = indexMapping(sz, subscript) 39 | fisrtSub = subscript(1); 40 | subscript = subscript(2:end)-1; 41 | szProd = zeros(1, length(sz)-1); 42 | for i = 1:length(sz)-1 43 | szProd(i) = prod(sz(1:i)); 44 | end 45 | linearIdx = fisrtSub+sum(subscript.*szProd); 46 | end 47 | 48 | -------------------------------------------------------------------------------- /Matlab/+HAT/+TensorSimilarity/tmpTenEval.m: -------------------------------------------------------------------------------- 1 | function [jacob, polyv, polyt] = tmpTenEval(x, pCoef, s) 2 | 3 | m = zeros(83,1); 4 | m(1) =x(2)*x(2); 5 | m(2) =x(2)*x(3); 6 | m(3) =x(2)*x(4); 7 | m(4) =x(2)*x(5); 8 | m(5) =x(3)*x(3); 9 | m(6) =x(3)*x(4); 10 | m(7) =x(3)*x(5); 11 | m(8) =x(4)*x(4); 12 | m(9) =x(4)*x(5); 13 | m(10) =x(5)*x(5); 14 | m(11) =x(2)*m(1); 15 | m(12) =m(1)*x(3); 16 | m(13) =m(1)*x(5); 17 | m(14) =x(3)*m(2); 18 | m(15) =m(2)*x(4); 19 | m(16) =m(2)*x(5); 20 | m(17) =m(2)*x(6); 21 | m(18) =x(5)*m(3); 22 | m(19) =m(3)*x(6); 23 | m(20) =x(5)*m(4); 24 | m(21) =m(4)*x(6); 25 | m(22) =x(3)*m(5); 26 | m(23) =m(5)*x(4); 27 | m(24) =m(5)*x(5); 28 | m(25) =x(4)*m(6); 29 | m(26) =m(6)*x(5); 30 | m(27) =m(6)*x(6); 31 | m(28) =x(5)*m(7); 32 | m(29) =m(7)*x(6); 33 | m(30) =x(4)*m(8); 34 | m(31) =m(8)*x(5); 35 | m(32) =m(8)*x(6); 36 | m(33) =x(5)*m(9); 37 | m(34) =m(9)*x(6); 38 | m(35) =x(6)*x(4)*x(6); 39 | m(36) =x(5)*m(10); 40 | m(37) =m(10)*x(6); 41 | m(38) =x(6)*x(5)*x(6); 42 | m(39) =x(6)*x(6)*x(6); 43 | m(40) =m(11)*x(1); 44 | m(41) =m(22)*x(1); 45 | m(42) =m(30)*x(1); 46 | m(43) =m(36)*x(1); 47 | m(44) =m(39)*x(1); 48 | m(45) =m(11)*x(2); 49 | m(46) =m(12)*x(5); 50 | m(47) =m(14)*x(5); 51 | m(48) =m(16)*x(5); 52 | m(49) =m(22)*x(3); 53 | m(50) =m(22)*x(4); 54 | m(51) =m(22)*x(5); 55 | m(52) =m(23)*x(4); 56 | m(53) =m(24)*x(5); 57 | m(54) =m(25)*x(4); 58 | m(55) =m(28)*x(5); 59 | m(56) =m(30)*x(4); 60 | m(57) =m(30)*x(5); 61 | m(58) =m(31)*x(5); 62 | m(59) =m(31)*x(6); 63 | m(60) =m(33)*x(5); 64 | m(61) =m(33)*x(6); 65 | m(62) =m(34)*x(6); 66 | m(63) =m(36)*x(5); 67 | m(64) =m(39)*x(6); 68 | m(65) =pCoef(2)*m(13)+pCoef(4)*m(20)+pCoef(7)*m(34)+pCoef(8)*m(36); 69 | m(66) =pCoef(3)*m(16)+pCoef(6)*m(28); 70 | m(67) =pCoef(5)*m(24); 71 | m(68) =pCoef(11)*m(13)+pCoef(14)*m(20)+pCoef(22)*m(30)+pCoef(23)*m(36); 72 | m(69) =pCoef(13)*m(16)+pCoef(20)*m(25)+pCoef(21)*m(28); 73 | m(70) =pCoef(18)*m(23)+pCoef(19)*m(24); 74 | m(71) =pCoef(17)*m(22)+pCoef(26)*m(41); 75 | m(72) =pCoef(29)*m(22)+pCoef(36)*m(36)+pCoef(37)*m(37)+pCoef(38)*m(38); 76 | m(73) =pCoef(30)*m(23)+pCoef(34)*m(33)+pCoef(35)*m(34); 77 | m(74) =pCoef(31)*m(25)+pCoef(33)*m(31); 78 | m(75) =pCoef(32)*m(30)+pCoef(43)*m(42); 79 | m(76) =pCoef(46)*m(12)+pCoef(48)*m(14)+pCoef(52)*m(22)+pCoef(56)*m(30)+pCoef(59)*m(32)+pCoef(63)*m(35); 80 | m(77) =pCoef(50)*m(16)+pCoef(53)*m(24)+pCoef(58)*m(31)+pCoef(62)*m(34); 81 | m(78) =pCoef(54)*m(28)+pCoef(61)*m(33); 82 | m(79) =pCoef(65)*m(36)+pCoef(66)*m(43); 83 | m(80) =pCoef(67)*m(16)+pCoef(71)*m(36)+pCoef(72)*m(37)+pCoef(73)*m(38); 84 | m(81) =pCoef(69)*m(33)+pCoef(70)*m(34); 85 | m(82) =pCoef(68)*m(31); 86 | m(83) =pCoef(76); 87 | polyv = zeros(6,1); 88 | polyv(1) =x(3)*m(65)+x(3)*m(66)+x(3)*m(67)+pCoef(1)*m(45)+pCoef(9)*m(40)*x(2); 89 | polyv(2) =x(3)*m(68)+x(3)*m(69)+x(3)*m(70)+x(3)*m(71)+pCoef(10)*m(11)*x(5)+pCoef(12)*m(13)*x(5)+pCoef(15)*m(18)*x(6)+pCoef(16)*m(20)*x(5)+pCoef(24)*m(56)+pCoef(25)*m(63); 90 | polyv(3) =x(4)*m(72)+x(4)*m(73)+x(4)*m(74)+x(4)*m(75)+pCoef(27)*m(16)*x(6)+pCoef(28)*m(49)+pCoef(39)*m(63)+pCoef(40)*m(36)*x(6)+pCoef(41)*m(37)*x(6)+pCoef(42)*m(38)*x(6); 91 | polyv(4) =x(5)*m(76)+x(5)*m(77)+x(5)*m(78)+x(5)*m(79)+pCoef(44)*m(11)*x(3)+pCoef(45)*m(12)*x(3)+pCoef(47)*m(14)*x(3)+pCoef(49)*m(15)*x(6)+pCoef(51)*m(49)+pCoef(55)*m(56)+pCoef(57)*m(30)*x(6)+pCoef(60)*m(32)*x(6)+pCoef(64)*m(35)*x(6); 92 | polyv(5) =x(4)*m(80)+x(4)*m(81)+x(4)*m(82)+pCoef(74)*m(64)+pCoef(75)*m(44)*x(6); 93 | polyv(6) =x(2)*m(83)+pCoef(77)*x(3)+pCoef(78)*x(4)+pCoef(79)*x(5)+pCoef(80)*x(6)+pCoef(81); 94 | jacob = zeros(6,6); 95 | jacob(1,1) = pCoef(9)*m(45); 96 | jacob(1,2) = pCoef(1)*4*m(11) + pCoef(2)*2*m(16) + pCoef(3)*m(24) + pCoef(4)*m(28) + pCoef(9)*4*m(40); 97 | jacob(1,3) =m(65)+2*m(66)+3*m(67); 98 | jacob(1,4) = pCoef(7)*m(29); 99 | jacob(1,5) = pCoef(2)*m(12) + pCoef(3)*m(14) + pCoef(4)*2*m(16) + pCoef(5)*m(22) + pCoef(6)*2*m(24) + pCoef(7)*m(27) + pCoef(8)*3*m(28); 100 | jacob(1,6) = pCoef(7)*m(26); 101 | jacob(2,1) = pCoef(26)*m(49); 102 | jacob(2,2) = pCoef(10)*3*m(13) + pCoef(11)*2*m(16) + pCoef(12)*2*m(20) + pCoef(13)*m(24) + pCoef(14)*m(28) + pCoef(15)*m(34) + pCoef(16)*m(36); 103 | jacob(2,3) =m(68)+2*m(69)+3*m(70)+4*m(71); 104 | jacob(2,4) = pCoef(15)*m(21) + pCoef(18)*m(22) + pCoef(20)*2*m(23) + pCoef(22)*3*m(25) + pCoef(24)*4*m(30); 105 | jacob(2,5) = pCoef(10)*m(11) + pCoef(11)*m(12) + pCoef(12)*2*m(13) + pCoef(13)*m(14) + pCoef(14)*2*m(16) + pCoef(15)*m(19) + pCoef(16)*3*m(20) + pCoef(19)*m(22) + pCoef(21)*2*m(24) + pCoef(23)*3*m(28) + pCoef(25)*4*m(36); 106 | jacob(2,6) = pCoef(15)*m(18); 107 | jacob(3,1) = pCoef(43)*m(56); 108 | jacob(3,2) = pCoef(27)*m(29); 109 | jacob(3,3) = pCoef(27)*m(21) + pCoef(28)*4*m(22) + pCoef(29)*3*m(23) + pCoef(30)*2*m(25) + pCoef(31)*m(30); 110 | jacob(3,4) =m(72)+2*m(73)+3*m(74)+4*m(75); 111 | jacob(3,5) = pCoef(27)*m(17) + pCoef(33)*m(30) + pCoef(34)*2*m(31) + pCoef(35)*m(32) + pCoef(36)*3*m(33) + pCoef(37)*2*m(34) + pCoef(38)*m(35) + pCoef(39)*4*m(36) + pCoef(40)*3*m(37) + pCoef(41)*2*m(38) + pCoef(42)*m(39); 112 | jacob(3,6) = pCoef(27)*m(16) + pCoef(35)*m(31) + pCoef(37)*m(33) + pCoef(38)*2*m(34) + pCoef(40)*m(36) + pCoef(41)*2*m(37) + pCoef(42)*3*m(38); 113 | jacob(4,1) = pCoef(66)*m(63); 114 | jacob(4,2) = pCoef(44)*3*m(12) + pCoef(45)*2*m(14) + pCoef(46)*2*m(16) + pCoef(47)*m(22) + pCoef(48)*m(24) + pCoef(49)*m(27) + pCoef(50)*m(28); 115 | jacob(4,3) = pCoef(44)*m(11) + pCoef(45)*2*m(12) + pCoef(46)*m(13) + pCoef(47)*3*m(14) + pCoef(48)*2*m(16) + pCoef(49)*m(19) + pCoef(50)*m(20) + pCoef(51)*4*m(22) + pCoef(52)*3*m(24) + pCoef(53)*2*m(28) + pCoef(54)*m(36); 116 | jacob(4,4) = pCoef(49)*m(17) + pCoef(55)*4*m(30) + pCoef(56)*3*m(31) + pCoef(57)*3*m(32) + pCoef(58)*2*m(33) + pCoef(59)*2*m(34) + pCoef(60)*2*m(35) + pCoef(61)*m(36) + pCoef(62)*m(37) + pCoef(63)*m(38) + pCoef(64)*m(39); 117 | jacob(4,5) =m(76)+2*m(77)+3*m(78)+4*m(79); 118 | jacob(4,6) = pCoef(49)*m(15) + pCoef(57)*m(30) + pCoef(59)*m(31) + pCoef(60)*2*m(32) + pCoef(62)*m(33) + pCoef(63)*2*m(34) + pCoef(64)*3*m(35); 119 | jacob(5,1) = pCoef(75)*m(64); 120 | jacob(5,2) = pCoef(67)*m(26); 121 | jacob(5,3) = pCoef(67)*m(18); 122 | jacob(5,4) =m(80)+2*m(81)+3*m(82); 123 | jacob(5,5) = pCoef(67)*m(15) + pCoef(68)*m(30) + pCoef(69)*2*m(31) + pCoef(70)*m(32) + pCoef(71)*3*m(33) + pCoef(72)*2*m(34) + pCoef(73)*m(35); 124 | jacob(5,6) = pCoef(70)*m(31) + pCoef(72)*m(33) + pCoef(73)*2*m(34) + pCoef(74)*4*m(39) + pCoef(75)*4*m(44); 125 | jacob(6,2) =m(83); 126 | jacob(6,3) = pCoef(77); 127 | jacob(6,4) = pCoef(78); 128 | jacob(6,5) = pCoef(79); 129 | jacob(6,6) = pCoef(80); 130 | polyt = zeros(6,1); 131 | if(s<-1e-10) 132 | [Q, DQ] = tmpEvalQDQ(x); 133 | polyt = exp(s)*(polyv-Q); 134 | polyv = Q+polyt; 135 | jacob = DQ+exp(s)*(jacob-DQ); 136 | end 137 | 138 | end 139 | 140 | function [Q, DQ] = tmpEvalQDQ(x) 141 | 142 | a = [ (0.395600-0.918400i); (0.829900-0.558000i); (0.698200+0.715900i); (0.855500-0.517800i); (-0.673700-0.739000i); ]; 143 | b = [(0.818000+0.575200i); (-0.178100+0.984000i); (-0.956900-0.290300i); (0.964600-0.263800i); (0.975800-0.218800i); ]; 144 | L = [(0.628200+0.778000i); (-0.881600+0.472000i); (0.863100-0.505100i); (0.262100-0.965000i); (0.967800-0.251800i); ]; 145 | C = [(0.548400+0.836200i) (0.983000-0.183700i) (0.964000-0.265900i) (-0.995800+0.091800i) (0.310700-0.950500i) ]; 146 | xm_2=x(2:end).^3; 147 | xm_1_b=x(2:end).*xm_2-b; 148 | ax1_L=a.*(x(1)-L); 149 | Q=ax1_L.*xm_1_b; 150 | Q(6) = C*x(2:6)-1; 151 | DQ = zeros(6); 152 | for ia=1:5 153 | DQ(ia, ia+1) = 4*ax1_L(ia)*xm_2(ia); 154 | end 155 | DQ(1:5, 1) = a.*xm_1_b; 156 | DQ(6,2:6)=C; 157 | end 158 | 159 | -------------------------------------------------------------------------------- /Matlab/+HAT/+simpleHypergraphs/hyperchain.m: -------------------------------------------------------------------------------- 1 | function [HG] = hyperchain(V, k) 2 | %HYPERRING This function returns a hyperchain hypergraph 3 | % 4 | % See definition 2 in Controllability of Hypergraphs 5 | % 6 | % Auth: Joshua Pickard 7 | % jpic@umich.edu 8 | % Date: February 20, 2023 9 | 10 | IM = zeros(V, V-k+1); 11 | for e=1:V-k+1 12 | IM(e:e+k-1, e)=1; 13 | end 14 | HG = Hypergraph('IM', sparse(IM)); 15 | 16 | end 17 | 18 | -------------------------------------------------------------------------------- /Matlab/+HAT/+simpleHypergraphs/hyperring.m: -------------------------------------------------------------------------------- 1 | function [HG] = hyperring(V, k) 2 | %HYPERRING This function returns a hyperring hypergraph 3 | % 4 | % See definition 3 in Controllability of Hypergraphs 5 | % 6 | % Auth: Joshua Pickard 7 | % jpic@umich.edu 8 | % Date: February 20, 2023 9 | 10 | if V == k 11 | IM = ones(V,1); 12 | HG = Hypergraph('IM', sparse(IM)); 13 | return 14 | end 15 | 16 | IM = zeros(V, V); 17 | for e=1:V-k+1 18 | IM(e:e+k-1, e) = 1; 19 | end 20 | for e=V-k+2:V 21 | f = 1:e-(V-k+2-1); 22 | b = e:V; 23 | IM([f b] ,e) = 1; 24 | end 25 | HG = Hypergraph('IM', sparse(IM)); 26 | 27 | end 28 | 29 | -------------------------------------------------------------------------------- /Matlab/+HAT/+simpleHypergraphs/hyperstar.m: -------------------------------------------------------------------------------- 1 | function [HG] = hyperstar(V, k) 2 | %HYPERRING This function returns a hyperstar hypergraph 3 | % 4 | % See definition 4 in Controllability of Hypergraphs 5 | % 6 | % Auth: Joshua Pickard 7 | % jpic@umich.edu 8 | % Date: February 20, 2023 9 | 10 | IM = zeros(V, V-k+1); 11 | for e=1:V-k+1 12 | IM([1:k-1 (k-1+e)], e) = 1; 13 | end 14 | HG = Hypergraph('IM', IM); 15 | 16 | end 17 | 18 | -------------------------------------------------------------------------------- /Matlab/+HAT/A32IM.m: -------------------------------------------------------------------------------- 1 | function IM = A32IM(A) 2 | %HYPEREDGE2IM This function returns an incidence matrix corresponding to an 3 | % adjacency tensor for a 3-uniform hypergraph. 4 | % 5 | % Auth: Joshua Pickard 6 | % Date: April 11, 2022 7 | 8 | idxs = find(A ~= 0); 9 | [x,y,z] = ind2sub(size(A),idxs); 10 | E = sort([x y z]')'; 11 | E = unique(E, 'rows'); 12 | IM = HAT.hyperedges2IM(E); 13 | 14 | end 15 | 16 | -------------------------------------------------------------------------------- /Matlab/+HAT/A42IM.m: -------------------------------------------------------------------------------- 1 | function IM = A42IM(A) 2 | %HYPEREDGE2IM This function returns an incidence matrix corresponding to an 3 | % adjacency tensor for a 3-uniform hypergraph. 4 | % 5 | % Auth: Joshua Pickard 6 | % Date: April 11, 2022 7 | 8 | idxs = find(A ~= 0); 9 | [w,x,y,z] = ind2sub(size(A),idxs); 10 | E = sort([w x y z]')'; 11 | E = unique(E, 'rows'); 12 | IM = HAT.hyperedges2IM(E); 13 | 14 | end 15 | 16 | -------------------------------------------------------------------------------- /Matlab/+HAT/averageDistance.m: -------------------------------------------------------------------------------- 1 | %% Computations.averageDistance 2 | % Computes the mean pair-wise path distance between nodes in the 3 | % hypergraph. 4 | %% Syntax 5 | % d = averageDistance(HG) 6 | % [d, dmax] = averageDistance(HG) 7 | %% Input 8 | % * HG - Hypergraph object. HG must represent a k-uniform hypergraph. 9 | %% Output 10 | % * d - Average distance between two nodes in the hypergraph. 11 | % * dmax - Maximum distance between two nodes in the hypergraph. 12 | %% Disclaimer 13 | % The formula for average distance was obtained from equation 30 of the 14 | % paper below. 15 | % 16 | % Amit Surana, Can Chen, and Indika Rajapakse. "Hypergraph dissimilarity measures." arXiv preprint arXiv:2106.08206 (2021). 17 | %% Code 18 | function [d, dmax] = averageDistance(HG) 19 | 20 | A = HG.cliqueGraph; 21 | G = graph(A); 22 | D = distances(G); 23 | 24 | n = size(HG.IM,1); 25 | 26 | dmax=max(D(:)); 27 | d = sum(D, 'all')/2; 28 | d = d/(n*(n-1)/2); 29 | 30 | end 31 | 32 | -------------------------------------------------------------------------------- /Matlab/+HAT/centrality.m: -------------------------------------------------------------------------------- 1 | %% HAT.centrality 2 | % Computes node and edge eigenvector centrality for a hypergraph. 3 | %% Syntax 4 | % [N, E] = hypergraphCentrality(HG) 5 | % [N, E] = hypergraphCentrality(HG, 'Tolerance', tol) 6 | % [N, E] = hypergraphCentrality(HG, 'Tolerance', tol, 'MaxIter', maxIter) 7 | % [N, E] = hypergraphCentrality(HG, 'Model', modelName) 8 | % [N, E] = hypergraphCentrality(HG, 'Model', modelStruct) 9 | % [N, E] = hypergraphCentrality(HG, 'Model', 'Max', 'Alpha', alpha) 10 | %% Input 11 | % * HG - Hypergraph object. 12 | %% Name-Value Arguments 13 | % * Tolerance - Convergence tolerance. *Default* : 10e-4 14 | % * MaxIter - Maximum number of iterations of the eigenvector centrality 15 | % algorithm that the function will run before stopping before convergence. 16 | % *Default* : 3000 17 | % * Model: {'Linear', 'LogExp', 'Max'} or cell array of four anonymous 18 | % funcions. The three string options represent three presets based on the 19 | % models used in Tudisco's paper. A user can input any four functions for 20 | % f, g, phi, and psi by passing those functions as a (1,4) cell array of 21 | % anonymous functions. *Default*: 'LogExp'. 22 | % * Alpha: decimal value used in the 'Max' preset model. *Deafult* : 10. 23 | %% Output 24 | % * nodeCentrality - Node centrality scores. 25 | % * edgeCentrality - Edge centrality scores. 26 | %% References 27 | % This hypergraph centrality algorithm was obtained from Algorithm (1) in 28 | % the paper below. 29 | % 30 | % Tudisco, F., Higham, D.J. Node and edge nonlinear eigenvector centrality for hypergraphs. Commun Phys 4, 201 (2021). https://doi.org/10.1038/s42005-021-00704-2 31 | %% Code 32 | function [nodeCentrality, edgeCentrality] = centrality(HG, NameValueArgs) 33 | arguments 34 | HG 35 | NameValueArgs.Tolerance = 1e-4 36 | NameValueArgs.MaxIter = 3000 37 | NameValueArgs.Model = 'LogExp' 38 | NameValueArgs.Alpha = 10 39 | end 40 | presetModels = {'Linear', 'LogExp', 'Max'}; 41 | 42 | % default parameters 43 | tol = NameValueArgs.Tolerance; 44 | maxiter = NameValueArgs.MaxIter; 45 | a = NameValueArgs.Alpha; % parameter for 'Max' preset model 46 | 47 | % nonlinear functions for f, g, phi, psi. Default is the log-exp scheme 48 | % described in Tudisco's paper. 49 | model = NameValueArgs.Model; 50 | if class(model) == "cell" 51 | f = model{1}; 52 | g = model{2}; 53 | phi = model{3}; 54 | psi = model{4}; 55 | else 56 | preset = validatestring(model, presetModels); 57 | switch preset % three presets from the paper. 58 | case 'Linear' 59 | f = @(x) x; 60 | g = @(x) x; 61 | phi = @(x) x; 62 | psi = @(x) x; 63 | case 'LogExp' 64 | f = @(x) x; 65 | g = @(x) sqrt(x); 66 | phi = @(x) log(x); 67 | psi = @(x) exp(x); 68 | case 'Max' 69 | f = @(x) x; 70 | g = @(x) x; 71 | phi = @(x) x.^a; 72 | psi = @(x) x.^(1/a); 73 | end 74 | end 75 | 76 | B = HG.IM; 77 | W = HG.edgeWeights; 78 | N = HG.nodeWeights; 79 | 80 | B = sparse(B); 81 | [n, m] = size(B); 82 | 83 | x0 = ones(n,1)./n; 84 | y0 = ones(m,1)./m; 85 | nodeCentrality = nan; 86 | edgeCentrality = nan; 87 | 88 | W = sparse(diag(W)); 89 | N = sparse(diag(N)); 90 | 91 | for i = 1:maxiter 92 | if i<10 || mod(i, 10)==0 93 | %disp(i); 94 | end 95 | u = sqrt(x0.*g(B*W*f(y0))); 96 | v = sqrt(y0.*psi(B'*N*phi(x0))); 97 | x = u./norm(u, 1); 98 | y = v./norm(v, 1); 99 | 100 | check = norm(x-x0, 1)+norm(y-y0, 1); 101 | if check < tol 102 | nodeCentrality = full(x); 103 | edgeCentrality = full(y); 104 | return 105 | else 106 | x0 = x; 107 | y0 = y; 108 | end 109 | end 110 | 111 | end 112 | 113 | -------------------------------------------------------------------------------- /Matlab/+HAT/clusteringCoefficient.m: -------------------------------------------------------------------------------- 1 | %% HAT.clusteringCoefficient 2 | % Computes the generalized clustering coefficient on a k-uniform hypergraph. 3 | %% Syntax 4 | % p = HG.clusteringCoefficient() 5 | %% Input 6 | % * HG - Hypergraph object. HG must represent a k-uniform hypergraph. 7 | %% Output 8 | % * p - Average clustering coefficient of HG. 9 | %% Disclaimer 10 | % The formula for average distance was obtained from equation 31 of the 11 | % paper below. 12 | % 13 | % Surana, Amit, Can Chen, and Indika Rajapakse. "Hypergraph Similarity Measures." IEEE Transactions on Network Science and Engineering (2022). 14 | %% Code 15 | function p = clusteringCoefficient(HG) 16 | 17 | A = HAT.uniformEdgeSet(HG); 18 | n = size(A,2); 19 | 20 | pp = zeros(n, 1); 21 | for i = 1:n 22 | [id1, ~] = find(A == i); 23 | N = unique(A(id1, :)); 24 | N(N == i) = []; 25 | C = nchoosek(N, size(A, 2)); 26 | C = sort(C, 2); 27 | A = sort(A, 2); 28 | [~, loc] = ismember(C, A, 'rows'); 29 | q = length(find(loc>0)); 30 | pp(i) = q/size(C, 1); 31 | end 32 | 33 | pp(isnan(pp))=0; 34 | p = mean(pp); 35 | 36 | end 37 | 38 | -------------------------------------------------------------------------------- /Matlab/+HAT/ctrbk.m: -------------------------------------------------------------------------------- 1 | function ctrbMatrix = ctrbk(HG, inputNodesVector) 2 | 3 | % Compute the reduced controllability matrix for k-uniform hypergraphs 4 | % edgeSet is a m by k matrix such that each row is a hyperedge 5 | % numNodes is an integer 6 | % inputNodesVector is a vector containing the nodes are controlled 7 | % Examples: 8 | % C = ctrbk([1 2 3; 2 3 4; 3 4 5], 5, [1 2]) 9 | % C = ctrbk([1 2 3 4; 2 3 4 5; 3 4 5 6; 1 4 5 6;], 6, [1 2 3]) 10 | % by Can Chen, Rahmy Salman 11 | 12 | adjacencyTensor = HG.adjTensor; 13 | numNodes = size(adjacencyTensor, 1); 14 | k = length(size(adjacencyTensor)); 15 | adjacencyUnfold = reshape(adjacencyTensor, numNodes, numNodes^(k-1)); 16 | 17 | ctrbMatrix = HAT.getBmatrix(inputNodesVector, numNodes); 18 | 19 | j = 0; 20 | while rank(ctrbMatrix) < numNodes && j < numNodes 21 | kprod = kronExponentiation(ctrbMatrix, k-1); 22 | nextCtrbMatrix = adjacencyUnfold*kprod; 23 | ctrbMatrix = [ctrbMatrix, nextCtrbMatrix]; %#ok 24 | rankCtrbMatrix = rank(ctrbMatrix); 25 | [U, ~, ~] = svd(ctrbMatrix, 'econ'); 26 | ctrbMatrix = U(:, 1:rankCtrbMatrix); 27 | j = j+1; 28 | end 29 | 30 | end 31 | 32 | function mat = kronExponentiation(mat1, x) 33 | mat = mat1; 34 | for i = 1:x-1 35 | mat = kron(mat, mat1); 36 | end 37 | end -------------------------------------------------------------------------------- /Matlab/+HAT/directSimilarity.m: -------------------------------------------------------------------------------- 1 | function d=directSimilarity(HG1, HG2,type,NameValueArgs) 2 | %computes tensor based distance based on g1, g2 datastructure generated by 3 | %createTensorRepresentation for two given hypergraphs 4 | %type is what distance measure to use 5 | %params are parameters related to specific distance 6 | arguments 7 | HG1 8 | HG2 9 | type = 'Hamming' 10 | NameValueArgs.Tolerance = 1e-4 11 | NameValueArgs.MaxIter = 3000 12 | NameValueArgs.Model = 'LogExp' 13 | NameValueArgs.Alpha = 10 14 | end 15 | 16 | mat1 = HG1.adjTensor; 17 | mat2 = HG2.adjTensor; 18 | 19 | d=NaN; 20 | switch type 21 | 22 | case 'Hamming' 23 | 24 | if ~isempty(mat1) && ~isempty(mat2) 25 | d = HAT.TensorSimilarity.Hamming(mat1, mat2); 26 | end 27 | 28 | case 'Spectral-S' 29 | 30 | if ~isempty(mat1) && ~isempty(mat2) 31 | d = HAT.TensorSimilarity.SpectralS(mat1, mat2); 32 | end 33 | 34 | case 'Spectral-H' 35 | 36 | if ~isempty(mat1) && ~isempty(mat2) 37 | d = HAT.TensorSimilarity.SpectralH(mat1, mat2); 38 | end 39 | 40 | case 'Centrality' 41 | % mat1 and mat2 are incidence matrices 42 | %{ 43 | W1=ones(size(mat1,2),1); 44 | N1=ones(size(mat1,1),1); 45 | W2=ones(size(mat2,2),1); 46 | N2=ones(size(mat2,1),1); 47 | 48 | HG1.IM = mat1; 49 | HG1.edgeWeights = W1; 50 | HG1.nodeWeights = N1; 51 | 52 | HG2.IM = mat2; 53 | HG2.edgeWeights = W2; 54 | HG2.nodeWeights = N2; 55 | %} 56 | 57 | tol = NameValueArgs.Tolerance; 58 | maxIter = NameValueArgs.MaxIter; 59 | model = NameValueArgs.Model; 60 | alpha = NameValueArgs.Alpha; 61 | 62 | cenArgs = {'Tolerance', tol, 'MaxIter', maxIter, 'Model', model, 'Alpha', alpha}; 63 | [nodeCentrality1, ~] = HAT.centrality(HG1, cenArgs{:}); 64 | [nodeCentrality2, ~] = HAT.centrality(HG2, cenArgs{:}); 65 | nodeCentrality1=nodeCentrality1/norm(nodeCentrality1); 66 | nodeCentrality2=nodeCentrality2/norm(nodeCentrality2); 67 | d=norm(nodeCentrality1-nodeCentrality2)/length(nodeCentrality1); 68 | end 69 | -------------------------------------------------------------------------------- /Matlab/+HAT/getBmatrix.m: -------------------------------------------------------------------------------- 1 | function B = getBmatrix(v, n) 2 | 3 | B = zeros(n, length(v)); 4 | for i = 1:length(v) 5 | B(v(i), i) = 1; 6 | end -------------------------------------------------------------------------------- /Matlab/+HAT/hyperedges2IM.m: -------------------------------------------------------------------------------- 1 | function IM = hyperedges2IM(edgeSet) 2 | %HYPEREDGE2IM This function returns an incidence matrix corresponding to an 3 | % edge set. 4 | % 5 | % Auth: Joshua Pickard 6 | % Date: November 28, 2022 7 | 8 | n = max(max(edgeSet)); 9 | e = size(edgeSet,1); 10 | IM = zeros(n, e); 11 | 12 | for e=1:size(IM,2) 13 | IM(edgeSet(e,:), e) = 1; 14 | end 15 | 16 | end 17 | 18 | -------------------------------------------------------------------------------- /Matlab/+HAT/indirectSimilarity.m: -------------------------------------------------------------------------------- 1 | function d = indirectSimilarity(mat1,mat2,NameValueArgs) 2 | % This function computes the graph-based dissimilarity between two 3 | % hypergraphs. 4 | % 5 | % Inputs 6 | % mat1 and mat2: matrices representing the two hypergraphs to compare. 7 | % Depending on the type input, these can either be the graph adjacency 8 | % matrices or the graph laplacian matrices. 9 | % 10 | % type: {'Hamming', 'Jaccard', 'deltaCon', 'centrality', 'heatKer', ... 11 | % 'spanTree', 'Spectral'}. Specifies the dissimilarity measure to be 12 | % used. 'Hamming', 'Jaccard', 'deltaCon', and 'centrality' take adjacency 13 | % matrices for mat1 and mat2 while the last three types take Laplacian 14 | % matrices for mat1 and mat2. 15 | % 16 | % varargin: arguments for 'deltaCon', 'heatKer', and 'centrality'. 17 | % 'deltaCon': a single float to represent epsilon in the deltaCon 18 | % algorithm 19 | % 'heatKer': a single float ot represent tau. 20 | % 'centrality': single string or character vector representing the 21 | % centrality type. See MATLAB's centrality function for 22 | % details. 23 | % 24 | % Output 25 | % d: double representing computed dissimilarity between the hypergraphs 26 | % represented by mat1 and mat2. 27 | % 28 | 29 | arguments 30 | mat1 31 | mat2 32 | NameValueArgs.type = "Hamming" 33 | NameValueArgs.eps = 10e-3 34 | NameValueArgs.tau = 10e-3 35 | NameValueArgs.centrality = 'eigenvector' 36 | end 37 | d=NaN; 38 | 39 | type = NameValueArgs.type; 40 | eps = NameValueArgs.eps; % parameter for deltaCon 41 | tau = NameValueArgs.tau; % parameter for heatKer 42 | cenType = NameValueArgs.centrality; 43 | 44 | 45 | types = {'Hamming', 'Jaccard', 'deltaCon', 'centrality', 'heatKer', ... 46 | 'spanTree', 'Spectral'}; 47 | type = validatestring(type, types); 48 | 49 | 50 | switch type 51 | 52 | case 'Hamming' 53 | % mat1 and mat2 are adjacency matrices 54 | if ~isempty(mat1) && ~isempty(mat2) 55 | n=size(mat1,1); 56 | d=norm(mat1-mat2,1)/(n*(n-1)); 57 | end 58 | 59 | case 'Jaccard' 60 | % mat1 and mat2 are adjacency matrices 61 | if ~isempty(mat1) && ~isempty(mat2) 62 | mat1=mat1(:); mat2=mat2(:); 63 | minA=min([mat1 mat2],[],2); 64 | maxA=max([mat1 mat2],[],2); 65 | d=1-sum(minA)/sum(maxA); 66 | end 67 | 68 | 69 | case 'deltaCon' 70 | % Algorithm 1: https://web.eecs.umich.edu/~dkoutra/papers/DeltaCon_KoutraVF_withAppendix.pdf 71 | % mat1 and mat2 are adjacency matrices 72 | if ~isempty(mat1) && ~isempty(mat2) 73 | D1=diag(sum(mat1,1)); 74 | D2=diag(sum(mat2,1)); 75 | S1=inv(eye(size(mat1))+eps^2*D1-eps*mat1); 76 | S2=inv(eye(size(mat2))+eps^2*D2-eps*mat2); 77 | n1=size(mat1,1); 78 | n2=size(mat2,1); 79 | d1=(sqrt(S1)-sqrt(S2)).^2; 80 | d=(1/(n1*n2))*sqrt(sum(d1(:))); 81 | end 82 | 83 | case 'centrality' 84 | % mat1 and mat2 are adjacency matrices 85 | if ~isempty(mat1) && ~isempty(mat2) 86 | G1 = graph(mat1,'omitselfloops','upper'); 87 | G2 = graph(mat2,'omitselfloops','upper'); 88 | switch cenType 89 | case 'eigenvector' 90 | c1=centrality(G1,cenType,'Importance',G1.Edges.Weight); 91 | c2=centrality(G2,cenType,'Importance',G2.Edges.Weight); 92 | otherwise 93 | c1=centrality(G1,cenType,'Cost',G1.Edges.Weight); 94 | c1=c1/norm(c1); 95 | c2=centrality(G2,cenType,'Cost',G2.Edges.Weight); 96 | c2=c2/norm(c2); 97 | end 98 | n1=size(mat1,1); 99 | n2=size(mat2,1); 100 | d=1/(n1)*norm(c1-c2); 101 | end 102 | 103 | case 'heatKer' 104 | % mat1 and mat2 are Laplacian matrices 105 | [U1, lam1] = eig(full(mat1)); 106 | [U2, lam2] = eig(full(mat2)); 107 | lam1 = diag(lam1); 108 | lam2 = diag(lam2); 109 | if ~isempty(mat1) && ~isempty(mat2) 110 | n=size(mat1,1); 111 | [lam1,ind1]=sort(lam1); 112 | [lam2,ind2]=sort(lam2); 113 | U1=U1(:,ind1); U2=U2(:,ind2); 114 | eLam1=diag(exp(-lam1*tau)); 115 | eLam2=diag(exp(-lam2*tau)); 116 | hW1=U1*eLam1*U1'; 117 | hW2=U2*eLam2*U2'; 118 | delta=hW1-hW2; 119 | d=1/n*trace(delta'*delta); 120 | end 121 | 122 | case 'spanTree' 123 | % mat1 and mat2 are Laplacian matrices 124 | if ~isempty(mat1) && ~isempty(mat2) 125 | [~, lam1] = eig(full(mat1)); 126 | [~, lam2] = eig(full(mat2)); 127 | lam1 = diag(lam1); 128 | lam2 = diag(lam2); 129 | lam1=sort(lam1); 130 | lam2=sort(lam2); 131 | log1=sum(log(abs(lam1(2:end)))); 132 | log2=sum(log(abs(lam2(2:end)))); 133 | d=abs(log1-log2); 134 | end 135 | 136 | case 'Spectral' 137 | % mat1 and mat2 are Laplacian matrices 138 | if ~isempty(mat1) && ~isempty(mat2) 139 | n=size(mat1,1); 140 | lam1=eig(mat1); 141 | lam2=eig(mat2); 142 | lam1=sort(lam1); 143 | lam2=sort(lam2); 144 | d=1/n*norm(lam1-lam2); 145 | end 146 | end 147 | -------------------------------------------------------------------------------- /Matlab/+HAT/load.asv: -------------------------------------------------------------------------------- 1 | function [N, DS] = load(dataset) 2 | %LOAD Returns a builtin dataset of HAT 3 | % 4 | % Parameters: 5 | % * dataset: which dataset to load 6 | % 7 | % Returns: 8 | % * N: network structure as either incidence matrix for hypergraph or 9 | % adjaccency matrix for graphs 10 | % * DS: additional information about the network that may be relevant to 11 | % working with this data 12 | % 13 | % Auth: Joshua Pickard 14 | % Date: November 28, 2022 15 | 16 | [current_path,~,~] = fileparts(mfilename('fullpath')) 17 | len = length(current_path); 18 | current_path(len-3:end) = []; 19 | dp = string(current_path) + "+Data/"; 20 | 21 | switch dataset 22 | case 'karate' 23 | load(dp + "karate.mat"); 24 | DS = Problem; 25 | N = DS.A; 26 | case 'ArnetMiner Citation' 27 | load(dp + "aminer_cocitation.mat"); 28 | N = S; 29 | DS = []; 30 | case 'ArnetMiner Reference' 31 | load(dp + "aminer_coreference.mat"); 32 | N = S; 33 | DS = []; 34 | case 'ArnetMiner Citation' 35 | load(dp + "aminer_cocitation.mat"); 36 | N = S; 37 | DS = []; 38 | case 'ArnetMiner Reference' 39 | load(dp + "aminer_coreference.mat"); 40 | N = S; 41 | DS = []; 42 | end 43 | 44 | end 45 | 46 | 47 | -------------------------------------------------------------------------------- /Matlab/+HAT/load.m: -------------------------------------------------------------------------------- 1 | function [N, DS] = load(dataset) 2 | %LOAD Returns a builtin dataset of HAT 3 | % 4 | % Parameters: 5 | % * dataset: which dataset to load 6 | % 7 | % Returns: 8 | % * N: network structure as either incidence matrix for hypergraph or 9 | % adjaccency matrix for graphs 10 | % * DS: additional information about the network that may be relevant to 11 | % working with this data 12 | % 13 | % Auth: Joshua Pickard 14 | % Date: November 28, 2022 15 | 16 | [current_path,~,~] = fileparts(mfilename('fullpath')) 17 | len = length(current_path); 18 | current_path(len-3:end) = []; 19 | dp = string(current_path) + "+Data/"; 20 | 21 | switch dataset 22 | case 'karate' 23 | load(dp + "karate.mat"); 24 | DS = Problem; 25 | N = DS.A; 26 | case 'ArnetMiner Citation' 27 | load(dp + "aminer_cocitation.mat"); 28 | N = S; 29 | DS = []; 30 | case 'ArnetMiner Reference' 31 | load(dp + "aminer_coreference.mat"); 32 | N = S; 33 | DS = []; 34 | case 'Citeseer Citation' 35 | load(dp + "citeseer_cocitation.mat"); 36 | N = S; 37 | DS = []; 38 | case 'Citeseer Reference' 39 | load(dp + "citeseer_coreference.mat"); 40 | N = S; 41 | DS = []; 42 | case 'Cora Citation' 43 | load(dp + "cora_cocitation.mat"); 44 | N = S; 45 | DS = []; 46 | case 'Cora Reference' 47 | load(dp + "cora_coreference.mat"); 48 | N = S; 49 | DS = []; 50 | case 'DBLP' 51 | load(dp + "dblp.mat"); 52 | N = S; 53 | DS = []; 54 | end 55 | 56 | end 57 | 58 | 59 | -------------------------------------------------------------------------------- /Matlab/+HAT/matrixEntropy.m: -------------------------------------------------------------------------------- 1 | %% HAT.matrixEntropy 2 | % Computes the entropy score of a uniform hypergraph based on the 3 | % generalized singular value decomposition of the Laplacian tensor of that hypergraph. 4 | %% Syntax 5 | % entropy = hypergraphEntropy(HG, false) 6 | %% Input 7 | % * HG - Hypergraph object. HG must represent a k-uniform hypergraph. 8 | % * normalized - bool, indicated whether to normalize the Laplacian matrix or 9 | % not. *Default*: false. 10 | %% Output 11 | % * entropy - Entropy score for the hypergraph. 12 | %% References 13 | % * Dotson, Gabrielle A., et al. "Deciphering multi-way interactions in the human genome." Nature communications 13.1 (2022): 1-15. 14 | % 15 | %% Code 16 | function entropy = matrixEntropy(HG, normalized) 17 | if nargin < 2 18 | normalized = false; 19 | end 20 | H = HG.IM; 21 | H(sum(H, 2)==0, :) = []; 22 | D = diag(sum(H, 2)); 23 | E = diag(sum(H, 1)); 24 | if normalized 25 | L = eye(size(H, 1))-(D^(-1/2)*H*E^(-1)*H'*D^(-1/2)); 26 | else 27 | L = D-H*E^(-1)*H'; 28 | end 29 | eigValues = eig(L); 30 | nonzeroEigVal = eigValues(eigValues>1e-8); 31 | normalizedEig = nonzeroEigVal/sum(nonzeroEigVal); 32 | entropy = -sum(normalizedEig.*log(normalizedEig)); 33 | end -------------------------------------------------------------------------------- /Matlab/+HAT/multicorrelations.asv: -------------------------------------------------------------------------------- 1 | function [M, idxs] = multicorrelations(D, order, type, idxs) 2 | %MULTIWAYCORRELATIONS This function computes multi-correlations among data 3 | % * D is m x n data matrix 4 | % * order is the number of variables considered for multicorrelations 5 | % * type denotes the multicorrelation measures: 'Drezner', 'Wang', 'Taylor' 6 | % Auth: Joshua Pickard 7 | % Date: November 2022 8 | 9 | R = corrcoef(D); 10 | 11 | [m, n] = size(D); 12 | if nargin == 3 13 | idxs = nchoosek(1:n, order); 14 | end 15 | 16 | M = zeros(length(idxs), 1); 17 | 18 | if strcmp(type, 'Taylor') 19 | w = (1/sqrt(order)); 20 | end 21 | 22 | for i=1:length(idxs) 23 | minor = R(idxs(i,:), idxs(i,:)); 24 | if strcmp(type,'Drezner') 25 | M(i) = 1 - min(eig(minor)); 26 | elseif strcmp(type, 'Wang') 27 | M(i) = (1-det(minor))^0.5; 28 | elseif strcmp(type, 'Taylor') 29 | M(i) = w * std(eig(corrcoef(minor))); 30 | end 31 | end 32 | 33 | end 34 | 35 | -------------------------------------------------------------------------------- /Matlab/+HAT/multicorrelations.m: -------------------------------------------------------------------------------- 1 | function [M, idxs] = multicorrelations(D, order, type, idxs) 2 | %MULTIWAYCORRELATIONS This function computes multi-correlations among data 3 | % * D is m x n data matrix 4 | % * order is the number of variables considered for multicorrelations 5 | % * type denotes the multicorrelation measures: 'Drezner', 'Wang', 'Taylor' 6 | % * idxs denotes pairs of indices to have mutli-correlations computed to 7 | % avoid the combinatorial complexity of trying all n choose k pairs. 8 | % Auth: Joshua Pickard 9 | % Date: November 2022 10 | 11 | R = corrcoef(D); 12 | 13 | [m, n] = size(D); 14 | if nargin == 3 15 | idxs = nchoosek(1:n, order); 16 | end 17 | 18 | M = zeros(length(idxs), 1); 19 | 20 | if strcmp(type, 'Taylor') 21 | w = (1/sqrt(order)); 22 | end 23 | 24 | for i=1:length(idxs) 25 | minor = R(idxs(i,:), idxs(i,:)); 26 | if strcmp(type,'Drezner') 27 | M(i) = 1 - min(eig(minor)); 28 | elseif strcmp(type, 'Wang') 29 | M(i) = (1-det(minor))^0.5; 30 | elseif strcmp(type, 'Taylor') 31 | M(i) = w * std(eig(corrcoef(minor))); 32 | end 33 | end 34 | 35 | end 36 | 37 | -------------------------------------------------------------------------------- /Matlab/+HAT/plotIncidenceMatrix.m: -------------------------------------------------------------------------------- 1 | function ax = plotIncidenceMatrix(HG, nodeshape, lineargs, show_h_bars, NameValueArgs) 2 | %PLOT_INCIDENCE_MATRIX creates a new figure and plots the incidence matrix 3 | %onto it. Returns the axes on which the incidence matrix is plotted. 4 | % HG: (n,m) double. Incidence matrix. 5 | 6 | arguments 7 | HG(:,:) 8 | nodeshape = '.' 9 | lineargs = num2cell("-k") 10 | show_h_bars = true 11 | NameValueArgs.sort (1,1) logical = true 12 | end 13 | 14 | % The gray bars need to go underneath the line plot, which needs to go 15 | % underneath the scatter plot. But we need to make the scatter and line 16 | % plots before the bar plot use the padded ax.XLim to set the base of 17 | % the bar plot. So, we plot in this order: 18 | % 1. Scatter 19 | % 2. Line Plot 20 | % 3. Barh 21 | % Then we flip the graphics array of the axes. 22 | % 23 | 24 | A = HG.IM; 25 | if NameValueArgs.sort 26 | A = HAT.SortIM.cardinalitySort(A); 27 | A = HAT.SortIM.min_max_sort(A); 28 | end 29 | 30 | ax = gca; 31 | ax.XLimitMethod = 'padded'; 32 | ax.YLimitMethod = 'padded'; 33 | 34 | %% Scatter 35 | s = HAT.ScatterIM.scatterIM(A, ax); 36 | s.Marker = nodeshape; 37 | s.CData = [0 0 0]; 38 | hold on; 39 | 40 | %% Line Plot 41 | if class(lineargs) == "cell" 42 | p = HAT.LinePlotIM.lineplotIM(ax, A, lineargs); 43 | end 44 | 45 | %% Barh 46 | if show_h_bars 47 | HAT.BarhIM.barhIM(ax, A); 48 | end 49 | hold off; 50 | 51 | %% Axes 52 | ax.XLim = [0, size(A,2) + 1]; 53 | ax.YLim = [0.5, size(A,1) + 0.5]; 54 | ax.YDir = 'reverse'; 55 | 56 | chi = get(ax, 'Children'); 57 | set(ax, 'Children', flipud(chi)); 58 | end -------------------------------------------------------------------------------- /Matlab/+HAT/tensorEntropy.m: -------------------------------------------------------------------------------- 1 | function tensorEntropy = tensorEntropy(HG) %edgeSet, numNodes) 2 | %% Tensor Entropy 3 | % Compute the tensor entropy for k-uniform hypergraphs 4 | % edgeSet is a m by k matrix such that each row is a hyperedge 5 | % numNodes is an integer 6 | % 7 | %% Examples: 8 | % e = entropyk([1 2 3; 2 3 4; 3 4 5], 5) 9 | % e = entropyk([2 3 5; 6 7 8; 5 8 9; 2 6 8], 10) 10 | %% Authors 11 | % Can Chen 12 | % Rahmy Salman 13 | 14 | % adjacencyTensor = hypergraphk(edgeSet, numNodes); 15 | % degreeTensor = degreek(edgeSet, numNodes); 16 | % laplacianTensor = degreeTensor-adjacencyTensor; 17 | laplacianTensor = HG.laplacianTensor; 18 | numNodes = size(HG.IM, 1); 19 | 20 | k = ndims(laplacianTensor); 21 | 22 | laplacianUnfold = reshape(laplacianTensor, numNodes, numNodes^(k-1)); 23 | 24 | singularValues = svd(laplacianUnfold, 'econ'); 25 | normalizedValues = singularValues./sum(singularValues); 26 | normalizedValues = normalizedValues(normalizedValues > 1e-8); 27 | tensorEntropy = -sum(normalizedValues.*log(normalizedValues)); 28 | 29 | end 30 | 31 | -------------------------------------------------------------------------------- /Matlab/+HAT/tmpTenEval.m: -------------------------------------------------------------------------------- 1 | function [jacob, polyv, polyt] = tmpTenEval(x, pCoef, s) 2 | 3 | m = zeros(17,1); 4 | m(1) =x(2)*x(1); 5 | m(2) =x(1)*x(3); 6 | m(3) =x(1)*x(4); 7 | m(4) =x(1)*x(5); 8 | m(5) =x(1)*x(6); 9 | m(6) =x(2)*x(2); 10 | m(7) =x(2)*x(3); 11 | m(8) =x(3)*x(3); 12 | m(9) =x(4)*x(4); 13 | m(10) =x(5)*x(5); 14 | m(11) =x(6)*x(6); 15 | m(12) =pCoef(2)*x(4)+pCoef(3)*x(5); 16 | m(13) =pCoef(5)*x(4)+pCoef(6)*x(5); 17 | m(14) =pCoef(12)*m(9); 18 | m(15) =pCoef(16)*m(10); 19 | m(16) =pCoef(19)*m(11); 20 | m(17) =pCoef(20); 21 | polyv = zeros(6,1); 22 | polyv(1) =x(3)*m(12)+pCoef(1)*m(6)+pCoef(4)*m(1)*x(2); 23 | polyv(2) =x(2)*m(13)+pCoef(7)*m(8)+pCoef(8)*m(2)*x(3); 24 | polyv(3) =x(1)*m(14)+pCoef(9)*m(7)+pCoef(10)*m(9)+pCoef(11)*x(5)*x(6); 25 | polyv(4) =x(1)*m(15)+pCoef(13)*m(7)+pCoef(14)*x(4)*x(6)+pCoef(15)*m(10); 26 | polyv(5) =x(1)*m(16)+pCoef(17)*x(4)*x(5)+pCoef(18)*m(11); 27 | polyv(6) =x(2)*m(17)+pCoef(21)*x(3)+pCoef(22)*x(4)+pCoef(23)*x(5)+pCoef(24)*x(6)+pCoef(25); 28 | jacob = zeros(6,6); 29 | jacob(1,1) = pCoef(4)*m(6); 30 | jacob(1,2) = pCoef(1)*2*x(2) + pCoef(4)*2*m(1); 31 | jacob(1,3) =m(12); 32 | jacob(1,4) = pCoef(2)*x(3); 33 | jacob(1,5) = pCoef(3)*x(3); 34 | jacob(2,1) = pCoef(8)*m(8); 35 | jacob(2,2) =m(13); 36 | jacob(2,3) = pCoef(7)*2*x(3) + pCoef(8)*2*m(2); 37 | jacob(2,4) = pCoef(5)*x(2); 38 | jacob(2,5) = pCoef(6)*x(2); 39 | jacob(3,1) =m(14); 40 | jacob(3,2) = pCoef(9)*x(3); 41 | jacob(3,3) = pCoef(9)*x(2); 42 | jacob(3,4) = pCoef(10)*2*x(4) + pCoef(12)*2*m(3); 43 | jacob(3,5) = pCoef(11)*x(6); 44 | jacob(3,6) = pCoef(11)*x(5); 45 | jacob(4,1) =m(15); 46 | jacob(4,2) = pCoef(13)*x(3); 47 | jacob(4,3) = pCoef(13)*x(2); 48 | jacob(4,4) = pCoef(14)*x(6); 49 | jacob(4,5) = pCoef(15)*2*x(5) + pCoef(16)*2*m(4); 50 | jacob(4,6) = pCoef(14)*x(4); 51 | jacob(5,1) =m(16); 52 | jacob(5,4) = pCoef(17)*x(5); 53 | jacob(5,5) = pCoef(17)*x(4); 54 | jacob(5,6) = pCoef(18)*2*x(6) + pCoef(19)*2*m(5); 55 | jacob(6,2) =m(17); 56 | jacob(6,3) = pCoef(21); 57 | jacob(6,4) = pCoef(22); 58 | jacob(6,5) = pCoef(23); 59 | jacob(6,6) = pCoef(24); 60 | polyt = zeros(6,1); 61 | if(s<-1e-10) 62 | [Q, DQ] = tmpEvalQDQ(x); 63 | polyt = exp(s)*(polyv-Q); 64 | polyv = Q+polyt; 65 | jacob = DQ+exp(s)*(jacob-DQ); 66 | end 67 | 68 | end 69 | 70 | function [Q, DQ] = tmpEvalQDQ(x) 71 | 72 | a = [ (0.395600-0.918400i); (0.829900-0.558000i); (0.698200+0.715900i); (0.855500-0.517800i); (-0.673700-0.739000i); ]; 73 | b = [(0.818000+0.575200i); (-0.178100+0.984000i); (-0.956900-0.290300i); (0.964600-0.263800i); (0.975800-0.218800i); ]; 74 | L = [(0.628200+0.778000i); (-0.881600+0.472000i); (0.863100-0.505100i); (0.262100-0.965000i); (0.967800-0.251800i); ]; 75 | C = [(0.548400+0.836200i) (0.983000-0.183700i) (0.964000-0.265900i) (-0.995800+0.091800i) (0.310700-0.950500i) ]; 76 | xm_2=x(2:end).^1; 77 | xm_1_b=x(2:end).*xm_2-b; 78 | ax1_L=a.*(x(1)-L); 79 | Q=ax1_L.*xm_1_b; 80 | Q(6) = C*x(2:6)-1; 81 | DQ = zeros(6); 82 | for ia=1:5 83 | DQ(ia, ia+1) = 2*ax1_L(ia)*xm_2(ia); 84 | end 85 | DQ(1:5, 1) = a.*xm_1_b; 86 | DQ(6,2:6)=C; 87 | end 88 | 89 | -------------------------------------------------------------------------------- /Matlab/+HAT/toyHG.m: -------------------------------------------------------------------------------- 1 | function [HG] = toyHG(n, k, t) 2 | %TOYHG This function returns a toy hypergraph 3 | % 4 | % PARAMETERS: 5 | % n: number of vertices 6 | % k: order of hypergraph 7 | % t: type of hypergraph: ['ring', 'chain', 'star','complete'] 8 | % 9 | % Auth: Joshua Pickard 10 | % jpic@umich.edu 11 | % Date: February 2023 12 | switch t 13 | case "hyperring" 14 | HG = HAT.simpleHypergraphs.hyperring(n, k); 15 | case "hyperchain" 16 | HG = HAT.simpleHypergraphs.hyperchain(n, k); 17 | case "hyperstar" 18 | HG = HAT.simpleHypergraphs.hyperstar(n, k); 19 | case "complete" 20 | HG = HAT.simpleHypergraphs.completeHG(n, k); 21 | otherwise 22 | error('invalid type of hypergraph') 23 | end 24 | end 25 | 26 | -------------------------------------------------------------------------------- /Matlab/+HAT/uniformEdgeSet.m: -------------------------------------------------------------------------------- 1 | %% Decompositions.TensorDecomp.uniformEdgeSet 2 | % takes the incidence matrix of a hypergraph and returns a matrix 3 | % representing the hyperedge set of the hypergraph. Each row is a 4 | % hyperedge. 5 | %% Syntax 6 | % 7 | %% Input 8 | % 9 | %% Output 10 | % 11 | %% Disclaimer 12 | % 13 | %% Code 14 | function hyperedgeSet = uniformEdgeSet(HG) 15 | H = HG.IM; 16 | k = sum(H(:,1), 1); 17 | hyperedgeSet=ones(size(H,2), k); 18 | for i=1:size(H,2) 19 | e=H(:,i); 20 | ind=find(e>0); 21 | hyperedgeSet(i, :) = ind; 22 | end 23 | 24 | end 25 | 26 | -------------------------------------------------------------------------------- /Matlab/+HAT/uniformErdosRenyi.m: -------------------------------------------------------------------------------- 1 | function HG = uniformErdosRenyi(v, e, k) 2 | %UNIFORMERDOSRENYI This function constructs a k-uniform Erdos-Renyi 3 | % (random) hypergraph. 4 | % Inputs 5 | % * v: number of vertices 6 | % * e: number of edges 7 | % * k: order of hypergraph 8 | % Auth: Joshua Pickard 9 | % jpic@umich.edu 10 | 11 | IM = zeros(v, e); 12 | for i=1:e 13 | idx = randsample(v, k); 14 | IM(idx, i) = 1; 15 | end 16 | HG = Hypergraph('IM', IM); 17 | 18 | end 19 | 20 | -------------------------------------------------------------------------------- /Matlab/@Hypergraph/Hypergraph.m: -------------------------------------------------------------------------------- 1 | classdef Hypergraph 2 | %HYPERGRAPH Class to store a hypergraph, summarize it, make 3 | % computations on it, and plot it. 4 | 5 | % This class treats rows of the incidence matrix as nodes and the 6 | % columns as hyperedges. 7 | properties 8 | IM (:,:) % incidence matrix 9 | edgeWeights 10 | nodeWeights 11 | end 12 | 13 | methods 14 | function obj = Hypergraph(nameValueArgs) 15 | %HYPERGRAPH Construct an instance of this class. 16 | % Takes in any 2D array representing an incidence matrix and 17 | % stores it in sparse format. Also can store the hyperedge 18 | % set for uniform hypergraphs. 19 | arguments 20 | nameValueArgs.IM = sparse(1); 21 | nameValueArgs.edgeWeights = 0; 22 | nameValueArgs.nodeWeights = 0; 23 | end 24 | obj.IM = sparse(nameValueArgs.IM); 25 | if nameValueArgs.edgeWeights == 0 26 | nameValueArgs.edgeWeights = ones(size(obj.IM, 2), 1); 27 | end 28 | if nameValueArgs.nodeWeights== 0 29 | nameValueArgs.nodeWeights = ones(size(obj.IM, 1), 1); 30 | end 31 | obj.edgeWeights = nameValueArgs.edgeWeights; 32 | obj.nodeWeights = nameValueArgs.nodeWeights; 33 | end 34 | 35 | %% Summarization 36 | function m = numRows(obj) 37 | %NUMROWS Get the number of rows in the incidence matrix. 38 | m = size(obj.IM, 1); 39 | end 40 | 41 | function n = numCols(obj) 42 | %NUMCOLS Get the number of columns in the incidence matrix. 43 | n = size(obj.IM, 2); 44 | end 45 | 46 | function d = density(obj) 47 | %DENSITY Gets the density of the underlying incidence matrix. 48 | %If this is less than (m*(n-1)-1)/2, then the matrix is so 49 | %dense that storing it in CSC format takes up more memory than 50 | %dense format. 51 | d = nnz(obj.IM)/(obj.numCols * obj.numRows); 52 | end 53 | 54 | function t = CSCThreshold(obj) 55 | %CSCTHRESHOLD Gets the density threshold over which it saves 56 | %space to store the matrix in dense format. 57 | m = obj.numRows; 58 | n = obj.numCols; 59 | t = (m*(n-1)-1)/(2*m*n); 60 | end 61 | 62 | function sz = edgeSizes(obj) 63 | %EDGESIZES Get the number of nodes in each edge. 64 | sz = sum(obj.IM, 1); 65 | end 66 | 67 | function dg = nodeDegrees(obj) 68 | %NODEDEGREES Get the degree of each node. 69 | dg = sum(obj.IM, 2); 70 | end 71 | 72 | % fun decls 73 | 74 | % Returns the s-connected components of the hypergraph. 75 | % s: the minimum connecting edge size. When s=1, this function 76 | % returns the connected components of the clique expansion. 77 | % outputForm {"vector" (default), "cell"}: arg to MATLAB's 78 | % conncomp function. Specifies the output form of the connected 79 | % components. 80 | [bins, binSize] = sConnectedComponents(obj, s, outputForm) 81 | 82 | r = sRadius(obj, s); 83 | 84 | d = sDiameter(obj, s); 85 | 86 | %% Representation 87 | function A = adjTensor(obj) 88 | A = HAT.TensorRepresentation.adjacencyTensor(obj); 89 | end 90 | 91 | function D = degreeTensor(obj) 92 | D = HAT.TensorRepresentation.degreeTensor(obj); 93 | end 94 | 95 | function L = laplacianTensor(obj) 96 | L = obj.degreeTensor - obj.adjTensor; 97 | end 98 | 99 | function C = cliqueGraph(obj) 100 | C = HAT.GraphRepresentation.cliqueGraph(obj); 101 | end 102 | 103 | function S = starGraph(obj) 104 | S = HAT.GraphRepresentation.starGraph(obj); 105 | end 106 | 107 | function L = lineGraph(obj) 108 | L = HAT.GraphRepresentation.lineGraph(obj); 109 | end 110 | 111 | function HG = dual(obj) 112 | HG = Hypergraph(obj.IM'); 113 | end 114 | 115 | function [A, L] = laplacianMatrix(obj, type) 116 | if nargin == 1 117 | warning("Enter Matrix Laplacian Type: Bolla, Rodriguez or Zhou"); 118 | return 119 | end 120 | if strcmp(type, "Bolla") 121 | [A, L] = HAT.GraphRepresentation.BollaLaplacian(obj); 122 | elseif strcmp(type, "Rodriguez") 123 | [A, L] = HAT.GraphRepresentation.RodriguezLaplacian(obj); 124 | elseif strcmp(type, "Zhou") 125 | [A, L] = HAT.GraphRepresentation.ZhouLaplacian(obj); 126 | end 127 | end 128 | 129 | %% Computation 130 | function E = tensorEntropy(obj) 131 | E = HAT.tensorEntropy(obj); 132 | end 133 | 134 | function M = matrixEntropy(obj) 135 | M = HAT.matrixEntropy(obj); 136 | end 137 | 138 | function B = ctrbk(obj, driverNodes) 139 | B = HAT.ctrbk(obj, driverNodes); 140 | end 141 | 142 | function A = avgDistance(obj) 143 | A = HAT.averageDistance(obj); 144 | end 145 | 146 | function c = clusteringCoef(obj) 147 | c = HAT.clusteringCoefficient(obj); 148 | end 149 | 150 | %{ 151 | function c = centrality(obj, NameValueArgs) 152 | c = HAT.centrality(obj, NameValueArgs); 153 | end 154 | %} 155 | 156 | %% Visualization 157 | function ax = plot(obj) 158 | ax = HAT.plotIncidenceMatrix(obj); 159 | end 160 | 161 | end 162 | end 163 | 164 | -------------------------------------------------------------------------------- /Matlab/@Hypergraph/sConnectedComponents.m: -------------------------------------------------------------------------------- 1 | function [bins, binSize] = sConnectedComponents(obj, s, outputForm) 2 | %SCONNECTEDCOMPONENTS Returns the s-connected components of the hypergraph 3 | %specified by the incidence matrix. 4 | % 5 | arguments 6 | obj 7 | s = 1 8 | outputForm = "vector" 9 | end 10 | I = obj.IM; 11 | I(:, sum(I,1) < s) = 0; % remove edges that are smaller than s 12 | A = I*I'; % get clique-expanded adjacency matrix 13 | 14 | [bins, binSize] = conncomp(graph(A), "OutputForm", outputForm); 15 | end 16 | 17 | -------------------------------------------------------------------------------- /Matlab/@Hypergraph/sRadius.m: -------------------------------------------------------------------------------- 1 | function r = sRadius(obj, s) 2 | %SRADIUS Summary of this function goes here 3 | % Detailed explanation goes here 4 | I = obj.IM; 5 | I(:, sum(I,1) < s) = 0; % remove edges that are smaller than s 6 | A = I*I'; % get clique-expanded adjacency matrix 7 | 8 | r = min(distances(graph(A), 'Method', 'unweighted'), 1); 9 | end 10 | 11 | -------------------------------------------------------------------------------- /Matlab/README.md: -------------------------------------------------------------------------------- 1 | # Hypergraph Analysis Toolbox: Matlab Implementation 2 | 3 | --- 4 | 5 | This directory manages the Matlab implenentation of HAT. 6 | -------------------------------------------------------------------------------- /Python/HAT/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | __all__ = ['hypergraph', 'HAT', 'draw'] 3 | 4 | from .hypergraph import Hypergraph 5 | # from .HAT import * 6 | # from .draw import * 7 | -------------------------------------------------------------------------------- /Python/HAT/__pycache__/GraphDecompositions.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Python/HAT/__pycache__/GraphDecompositions.cpython-38.pyc -------------------------------------------------------------------------------- /Python/HAT/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Python/HAT/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /Python/HAT/__pycache__/graph.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Python/HAT/__pycache__/graph.cpython-38.pyc -------------------------------------------------------------------------------- /Python/HAT/data/aminer_cocitation.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Python/HAT/data/aminer_cocitation.mat -------------------------------------------------------------------------------- /Python/HAT/data/aminer_coreference.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Python/HAT/data/aminer_coreference.mat -------------------------------------------------------------------------------- /Python/HAT/data/citeseer_cocitation.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Python/HAT/data/citeseer_cocitation.mat -------------------------------------------------------------------------------- /Python/HAT/data/citeseer_coreference.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Python/HAT/data/citeseer_coreference.mat -------------------------------------------------------------------------------- /Python/HAT/data/cora_cocitation.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Python/HAT/data/cora_cocitation.mat -------------------------------------------------------------------------------- /Python/HAT/data/cora_coreference.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Python/HAT/data/cora_coreference.mat -------------------------------------------------------------------------------- /Python/HAT/data/dblp.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/Python/HAT/data/dblp.mat -------------------------------------------------------------------------------- /Python/HAT/draw.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import networkx as nx 3 | 4 | from scipy.spatial.distance import pdist 5 | 6 | import matplotlib.pyplot as plt 7 | from matplotlib.collections import PolyCollection 8 | from matplotlib import colormaps 9 | from itertools import combinations 10 | from collections import Counter 11 | 12 | 13 | from HAT.export import to_hypernetx 14 | # from HAT.graph import graph 15 | # from HAT.Hypergraph import Hypergraph as HG 16 | 17 | def bipartite( 18 | HG, 19 | ax=None 20 | ): 21 | G = HG.star_graph 22 | pos = nx.layout.bipartite_layout(G, nodes=np.arange(HG.nedges)) 23 | ax = ax or plt.gca() 24 | nx.draw(G, pos=pos, ax=ax) 25 | return ax 26 | 27 | def pairwise( 28 | HG, 29 | labels=True, 30 | ax=None 31 | ): 32 | # TODO: get information from HG.nodes into networkx graph G nodes so that it is drawn with the node names 33 | G = HG.clique_graph 34 | pos = nx.layout.spring_layout(G) 35 | ax = ax or plt.gca() 36 | nx.draw(G, pos=pos, with_labels=False) 37 | if labels: 38 | labels = {node: str(HG.nodes['Names'].values[node]) for node in range(len(G.nodes))} 39 | nx.draw_networkx_labels(G, pos, labels, ax=ax, font_size=10) 40 | return ax 41 | 42 | 43 | def clique(HG, ax=None, node_size=20, marker='o', cmap='viridis', edgewidth=5, labels=True): 44 | """ 45 | Plot the clique graph of a hypergraph, with edges of each clique sharing the same color. 46 | 47 | Parameters: 48 | - HG: Hypergraph object with attributes `clique_graph` (Graph) and `edges['Nodes']` (DataFrame). 49 | - ax: matplotlib.axes.Axes, optional. Axes to plot on. 50 | - node_size: int, optional. Size of the scatter plot points (default: 10). 51 | - marker: str, optional. Marker style for scatter plot points (default: 'o'). 52 | - cmap: str or Colormap, optional. Colormap for clique edges (default: 'viridis'). 53 | 54 | Returns: 55 | - ax: matplotlib.axes.Axes with the plot. 56 | """ 57 | zorder_offset = -1000 58 | 59 | G = HG.clique_graph 60 | pos = np.array(list(nx.layout.spring_layout(G).values())) # Positions as an array 61 | 62 | ax = ax or plt.gca() 63 | cmap = colormaps[cmap] if isinstance(cmap, str) else cmap # Resolve colormap 64 | 65 | edge_counter = Counter() 66 | for nodes in HG.edges['Nodes']: 67 | for nodei, nodej in combinations(nodes, 2): 68 | edge_counter[tuple(sorted((nodei, nodej)))] += edgewidth 69 | 70 | for edge_idx, nodes in enumerate(HG.edges['Nodes']): 71 | color = cmap(edge_idx / HG.nedges) # Normalize edge_idx to [0, 1] for colormap 72 | for nodei, nodej in combinations(nodes, 2): # All pairs in the clique 73 | linewidth = edge_counter[tuple(sorted((nodei, nodej)))] 74 | edge_counter[tuple(sorted((nodei, nodej)))] -= edgewidth 75 | ax.plot( 76 | [pos[nodei, 0], pos[nodej, 0]], 77 | [pos[nodei, 1], pos[nodej, 1]], 78 | color=color, 79 | linewidth=linewidth, 80 | zorder=edge_idx+zorder_offset, 81 | ) 82 | 83 | # Scatter plot for nodes 84 | ax.scatter( 85 | pos[:, 0], 86 | pos[:, 1], 87 | s=node_size, 88 | marker=marker, 89 | zorder=HG.nedges + 1+zorder_offset, 90 | color="black" 91 | ) 92 | 93 | # Remove axis ticks 94 | ax.set_xticks([]) 95 | ax.set_yticks([]) 96 | 97 | if labels: 98 | labels = {node: str(HG.nodes['Names'].values[node]) for node in range(len(G.nodes))} 99 | nx.draw_networkx_labels(G, pos, labels, ax=ax, font_size=10, 100 | bbox=dict(facecolor='white', edgecolor='none')) # , alpha=0.7)) 101 | 102 | return ax 103 | 104 | 105 | 106 | def incidence_plot(HG, shade_rows=True, connect_nodes=True, dpi=200, edge_colors=None, node_labels=None): 107 | """Plot the incidence matrix of a hypergraph. 108 | 109 | :param H: a HAT.hypergraph object 110 | :param shade_rows: shade rows (bool) 111 | :param connect_nodes: connect nodes in each hyperedge (bool) 112 | :param dpi: the resolution of the image (int) 113 | :param edge_colors: The colors of edges represented in the incidence matrix. This is random by default 114 | 115 | :return: matplotlib axes with figure drawn on to it 116 | """ 117 | # dpi spec 118 | plt.rcParams['figure.dpi'] = dpi 119 | 120 | n, m = HG.nnodes, HG.nedges 121 | 122 | # plot the incidence matrix 123 | y, x = np.where(HG.incidence_matrix != 0) 124 | plt.scatter(x, y, 125 | edgecolor='k', 126 | zorder=2) 127 | 128 | for i in range(m): 129 | y = np.where(HG.incidence_matrix[:,i] != 0)[0] 130 | x = i * np.ones(len(y),) 131 | if edge_colors is None: 132 | c = None 133 | else: 134 | c = edge_colors[i] 135 | plt.scatter(x, y, 136 | color=c, 137 | edgecolor='k', 138 | zorder=2) 139 | 140 | y, x = np.where(HG.incidence_matrix != 0) 141 | 142 | # create row shading 143 | if shade_rows: 144 | yBar = np.arange(n) 145 | xBar = np.zeros(n) 146 | xBar[::2] = m - 0.5 147 | 148 | plt.barh(yBar, 149 | xBar, 150 | height=1.0, 151 | color='grey', 152 | left=-0.25, 153 | alpha=0.5, 154 | zorder=1) 155 | 156 | # plot each hyperedge with a black connector 157 | if connect_nodes: 158 | for i in range(len(HG.incidence_matrix[0])): 159 | i_pts = np.where(x == i) 160 | plt.plot([i,i], 161 | [np.min(y[i_pts]), 162 | np.max(y[i_pts])], 163 | c='k', 164 | lw=1, 165 | zorder=1) 166 | 167 | # plot range spec 168 | plt.xlim([-0.5, m - 0.5]) 169 | 170 | # Turn of axis ticks. Keep labels on 171 | if node_labels is not None: 172 | y_positions = list(np.arange(HG.nodes.shape[0])) 173 | print(f"{y_positions=}") 174 | plt.yticks(y_positions, list(HG.nodes[node_labels].values)) 175 | else: 176 | plt.yticks([]) 177 | plt.xticks([]) 178 | 179 | return plt.gca() 180 | 181 | def rubber_bands( 182 | HG, 183 | pos=None, 184 | with_color=True, 185 | with_node_counts=False, 186 | with_edge_counts=False, 187 | layout=nx.spring_layout, 188 | layout_kwargs={}, 189 | ax=None, 190 | node_radius=None, 191 | edges_kwargs={}, 192 | nodes_kwargs={}, 193 | edge_labels_on_edge=True, 194 | edge_labels={}, 195 | edge_labels_kwargs={}, 196 | node_labels={}, 197 | node_labels_kwargs={}, 198 | with_edge_labels=True, 199 | with_node_labels=True, 200 | node_label_alpha=0.35, 201 | edge_label_alpha=0.35, 202 | with_additional_edges=None, 203 | contain_hyper_edges=False, 204 | additional_edges_kwargs={}, 205 | return_pos=False 206 | ): 207 | try: 208 | import hypernetx as hnx 209 | except ImportError as e: 210 | raise ImportError( 211 | "The 'hypernetx' library is required to use the 'rubber_bands' function. " 212 | "Please install it using `pip install hypernetx`." 213 | ) from e 214 | HG_hnx = to_hypernetx(HG) 215 | hnx.draw( 216 | HG_hnx, 217 | pos=pos, 218 | # with_color=with_color, 219 | # with_node_counts=with_node_counts, 220 | # with_edge_counts=with_edge_counts, 221 | layout=layout, 222 | layout_kwargs=layout_kwargs, 223 | ax=ax, 224 | node_radius=node_radius, 225 | edges_kwargs=edges_kwargs, 226 | nodes_kwargs=nodes_kwargs, 227 | edge_labels_on_edge=edge_labels_on_edge, 228 | edge_labels=edge_labels, 229 | edge_labels_kwargs=edge_labels_kwargs, 230 | node_labels=node_labels, 231 | node_labels_kwargs=node_labels_kwargs, 232 | with_edge_labels=with_edge_labels, 233 | with_node_labels=with_node_labels, 234 | node_label_alpha=node_label_alpha, 235 | edge_label_alpha=edge_label_alpha, 236 | with_additional_edges=with_additional_edges, 237 | contain_hyper_edges=contain_hyper_edges, 238 | additional_edges_kwargs=additional_edges_kwargs, 239 | return_pos=return_pos 240 | ) 241 | 242 | -------------------------------------------------------------------------------- /Python/HAT/dynamics.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy as sp 3 | 4 | # from HAT import Hypergraph 5 | from HAT import multilinalg as mla 6 | 7 | 8 | """ 9 | This contains miscilaneous methods related to hypergraph dynamics, controllability, and observability. 10 | """ 11 | 12 | def ctrbk(HG, inputVxc): 13 | """Compute the reduced controllability matrix for :math:`k-` uniform hypergraphs. 14 | 15 | :param inputVxc: List of vertices that may be controlled 16 | :type inputVxc: *ndarray* 17 | :return: Controllability matrix 18 | :rtype: *ndarray* 19 | 20 | References 21 | ========== 22 | - Chen C, Surana A, Bloch A, Rajapakse I. "Controllability of Hypergraphs." 23 | IEEE Transactions on Network Science and Engineering, 2021. https://drive.google.com/file/d/12aReE7mE4MVbycZUxUYdtICgrAYlzg8o/view 24 | """ 25 | # Auth: Joshua Pickard 26 | # jpic@umich.edu 27 | # Date: Nov 30, 2022 28 | A = HG.adjacency_tensor 29 | modes = A.shape 30 | n = modes[0] 31 | order = len(modes) 32 | Aflat = np.reshape(A, (n, n**(order-1))) 33 | ctrbMatrix = b_matrix(HG, inputVxc) 34 | j = 0 35 | while j < n and np.linalg.matrix_rank(ctrbMatrix) < n: 36 | kprod = mla.kronecker_exponentiation(ctrbMatrix, len(modes)-1) 37 | nextCtrbMatrix = Aflat @ kprod; 38 | ctrbMatrix = np.concatenate((ctrbMatrix, nextCtrbMatrix), axis=1) 39 | r = np.linalg.matrix_rank(ctrbMatrix) 40 | U, _, _ = sp.linalg.svd(ctrbMatrix) 41 | ctrbMatrix = U[:,0:r] 42 | j += 1 43 | return ctrbMatrix 44 | 45 | def b_matrix(HG, inputVxc): 46 | """Constructs controllability :math:`B` matrix commonly used in the linear control system 47 | 48 | .. math:: 49 | \\frac{dx}{dt} = Ax+Bu 50 | 51 | :param inputVxc: a list of input control nodes 52 | :type inputVxc: *ndarray* 53 | :return: control matrix 54 | :rtype: *ndarray* 55 | 56 | References 57 | ========== 58 | - Can Chen, Amit Surana, Anthony M Bloch, and Indika Rajapakse. Controllability of hypergraphs. IEEE Transactions 59 | on Network Science and Engineering, 8(2):1646–1657, 2021. https://drive.google.com/file/d/12aReE7mE4MVbycZUxUYdtICgrAYlzg8o/view 60 | """ 61 | # Auth: Joshua Pickard 62 | # jpic@umich.edu 63 | # Date: Nov 30, 2022 64 | B = np.zeros((HG.nnodes, len(inputVxc))) 65 | for i in range(len(inputVxc)): 66 | B[inputVxc[i], i] = 1 67 | return B -------------------------------------------------------------------------------- /Python/HAT/export.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | def to_hypernetx(HG): 4 | """ 5 | Converts a HAT hypergraph to a HyperNetX hypergraph. 6 | 7 | :param HG: The hypergraph object from the HAT library. 8 | :type HG: HAT.Hypergraph 9 | :return: A HyperNetX hypergraph object. 10 | :rtype: hypernetx.Hypergraph 11 | 12 | This function converts a hypergraph represented in the HAT library 13 | to the HyperNetX library's `Hypergraph` format. It creates the HyperNetX 14 | hypergraph using the node-edge relationships defined in the HAT hypergraph. 15 | 16 | **Parameters** 17 | - **HG** (*HAT.Hypergraph*): The input hypergraph in HAT format. 18 | 19 | **Returns** 20 | - (*hypernetx.Hypergraph*): The hypergraph in HyperNetX format. 21 | 22 | **Features** 23 | - Explodes the `edges` DataFrame to create a long-form representation of 24 | the hypergraph, where each row associates a node with an edge. 25 | - Automatically assigns a column for edge identifiers (`Edges`) to maintain 26 | the edge-node mappings required by HyperNetX. 27 | 28 | **Dependencies** 29 | This function requires the `hypernetx` library. If the library is not 30 | installed, an `ImportError` will be raised with instructions to install it. 31 | 32 | **Raises** 33 | - `ImportError`: If the `hypernetx` library is not installed. 34 | 35 | **Notes** 36 | - Ensure that the input HAT hypergraph has a well-structured `edges` DataFrame 37 | with a `Nodes` column containing lists of nodes in each edge. 38 | - The output HyperNetX hypergraph will preserve the original node and edge 39 | relationships from the input HAT hypergraph. 40 | """ 41 | try: 42 | import hypernetx as hnx 43 | except ImportError as e: 44 | raise ImportError( 45 | "The 'hypernetx' library is required to use the 'to_hypernetx' function. " 46 | "Please install it using `pip install hypernetx`." 47 | ) from e 48 | 49 | HG_df = HG.edges.explode('Nodes') 50 | HG_df['Edges'] = HG_df.index 51 | return hnx.Hypergraph(HG_df, edge_col='Edges', node_col='Nodes') 52 | 53 | def to_hypergraphx(HG): 54 | """ 55 | Converts a HAT hypergraph to a HypergraphX hypergraph. 56 | 57 | :param HG: The hypergraph object from the HAT library. 58 | :type HG: HAT.Hypergraph 59 | :return: A HypergraphX hypergraph object. 60 | :rtype: hypergraphx.core.hypergraph.Hypergraph 61 | 62 | This function converts a hypergraph represented in the HAT library 63 | to the HypergraphX library's `Hypergraph` format. It transfers node and edge 64 | metadata, as well as weights if the original hypergraph is weighted. 65 | 66 | **Parameters** 67 | - **HG** (*HAT.Hypergraph*): The input hypergraph in HAT format. 68 | 69 | **Returns** 70 | - (*hypergraphx.core.hypergraph.Hypergraph*): The hypergraph in HypergraphX format. 71 | 72 | **Features** 73 | - If the HAT hypergraph contains a `Weights` column in its `edges` DataFrame, 74 | these weights are transferred to the HypergraphX hypergraph. 75 | - Transfers node metadata from the `nodes` DataFrame as a dictionary where 76 | keys are node identifiers and values are metadata dictionaries. 77 | - Transfers edge metadata from the `edges` DataFrame as a dictionary where 78 | keys are edge identifiers and values are metadata dictionaries. 79 | 80 | **Dependencies** 81 | This function requires the `hypergraphx` library. If the library is not 82 | installed, an `ImportError` will be raised with instructions to install it. 83 | 84 | **Raises** 85 | - `ImportError`: If the `hypergraphx` library is not installed. 86 | 87 | **Notes** 88 | - Ensure that the input HAT hypergraph has properly defined `nodes` 89 | and `edges` DataFrames with necessary metadata if applicable. 90 | """ 91 | try: 92 | from hypergraphx.core import hypergraph as hgx 93 | except ImportError as e: 94 | raise ImportError( 95 | "The 'hypergraphx' library is required to use the 'to_hypergraphx' function. " 96 | "Please install it using `pip install hypergraphx`." 97 | ) from e 98 | weighted = ('Weights' in HG.edges.columns) 99 | weights = None 100 | if weighted: 101 | weights = list(HG.edges['Weights'].values) 102 | G = hgx.Hypergraph( 103 | HG.edge_list, 104 | weighted = weighted, 105 | weights = weights, 106 | node_metadata=HG.nodes.to_dict(orient='index'), 107 | edge_metadata=HG.edges.to_dict(orient='index') 108 | ) 109 | return G 110 | 111 | def to_hif(HG): 112 | """Converts HAT.Hypergraph to Hypergraph Interchange Format (HIF) 113 | """ 114 | network_type = 'HAT' 115 | metadata = { 116 | 'uniform' : HG.uniform, 117 | 'order' : HG.order, 118 | 'directed' : HG.directed 119 | } 120 | incidence, nodes, edges = [], [], [] 121 | for inode in range(HG.nodes.shape[0]): 122 | node = {'node': inode} 123 | for property in HG.nodes.columns: 124 | if property in ['Nodes']: 125 | continue 126 | else: 127 | node[property] = HG.nodes[property].iloc[inode] 128 | nodes.append(node) 129 | for iedge in range(HG.edges.shape[0]): 130 | incident_nodes = list(HG.edges['Nodes'].iloc[iedge]) 131 | edge = { 132 | 'edge' : iedge, 133 | 'nodes' : incident_nodes 134 | } 135 | edge_incidence = { 136 | 'edge' : iedge, 137 | 'node' : None 138 | } 139 | for property in HG.edges.columns: 140 | if property in ['Nodes']: 141 | continue 142 | else: 143 | edge[property] = HG.edges[property].iloc[iedge] 144 | edge_incidence[property] = HG.edges[property].iloc[iedge] 145 | edges.append(edge) 146 | for node in incident_nodes: 147 | edge_incidence['node'] = node 148 | incidence.append(edge_incidence.copy()) 149 | hif = { 150 | 'network-type': network_type, 151 | 'metadata': metadata, 152 | 'nodes': nodes, 153 | 'edges': edges, 154 | 'incidences': incidence 155 | } 156 | return hif 157 | 158 | -------------------------------------------------------------------------------- /Python/HAT/graph.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy as sp 3 | import networkx as nx 4 | 5 | """ 6 | This file interfaces HAT with networkx. It provides several methods to create graph representations from hypergraphs. 7 | """ 8 | 9 | 10 | def clique_graph(HG): 11 | """The clique expansion graph is constructed. 12 | 13 | :return: Clique expanded graph 14 | :rtype: *networkx.graph* 15 | 16 | The clique expansion algorithm constructs a *graph* on the same set of vertices as the hypergraph by defining an 17 | edge set where every pair of vertices contained within the same edge in the hypergraph have an edge between them 18 | in the graph. Given a hypergraph :math:`H=(V,E_h)`, then the corresponding clique graph is :math:`C=(V,E_c)` where 19 | :math:`E_c` is defined 20 | 21 | .. math:: 22 | 23 | E_c = \{(v_i, v_j) |\ \exists\ e\in E_h \\text{ where } v_i, v_j\in e\}. 24 | 25 | This is called clique expansion because the vertices contained in each :math:`h\in E_h` forms a clique in :math:`C`. 26 | While the map from :math:`H` to :math:`C` is well-defined, the transformation to a clique graph is a lossy process, 27 | so the hypergraph structure of :math:`H` cannot be uniquely recovered from the clique graph :math:`C` alone [1]. 28 | 29 | References 30 | ---------- 31 | - Amit Surana, Can Chen, and Indika Rajapakse. Hypergraph similarity measures. IEEE Transactions on Network Science and Engineering, pages 1-16, 2022. 32 | - Yang, Chaoqi, et al. "Hypergraph learning with line expansion." arXiv preprint arXiv:2005.04843 (2020). 33 | """ 34 | # Auth: Joshua Pickard 35 | # jpic@umich.edu 36 | # Date: Nov 30, 2022 37 | 38 | A = HG.incidence_matrix @ HG.incidence_matrix.T 39 | np.fill_diagonal(A,0) # Omit self loops 40 | return nx.from_numpy_array(A) 41 | 42 | def lineGraph(HG): 43 | """The line graph, which is the clique expansion of the dual graph, is constructed. 44 | 45 | :return: Line graph 46 | :rtype: *networkx.graph* 47 | 48 | References 49 | ---------- 50 | - Yang, Chaoqi, et al. "Hypergraph learning with line expansion." arXiv preprint arXiv:2005.04843 (2020). 51 | """ 52 | # Auth: Joshua Pickard 53 | # jpic@umich.edu 54 | # Date: Nov 30, 2022 55 | D = HG.dual() 56 | return D.cliqueGraph() 57 | 58 | def star_graph(HG): 59 | """The star graph representation is constructed. 60 | 61 | :return: Star graph 62 | :rtype: *networkx.graph* 63 | 64 | The star expansion of :math:`{H}=({V},{E}_h)` constructs a bipartite graph :math:`{S}=\{{V}_s,{E}_s\}` 65 | by introducing a new set of vertices :math:`{V}_s={V}\cup {E}_h` where some vertices in the star graph 66 | represent hyperedges of the original hypergraph. There exists an edge between each vertex :math:`v,e\in {V}_s` 67 | when :math:`v\in {V}`, :math:`e\in {E}_h,` and :math:`v\in e`. Each hyperedge in :math:`{E}_h` induces 68 | a star in :math:`S`. This is a lossless process, so the hypergraph structure of :math:`H` is well-defined] 69 | given a star graph :math:`S`. 70 | 71 | References 72 | ---------- 73 | - Yang, Chaoqi, et al. "Hypergraph learning with line expansion." arXiv preprint arXiv:2005.04843 (2020). 74 | """ 75 | # Auth: Joshua Pickard 76 | # jpic@umich.edu 77 | # Date: Nov 30, 2022 78 | n = len(HG.incidence_matrix) + len(HG.incidence_matrix[0]) 79 | A = np.zeros((n,n)) 80 | A[len(A) - len(HG.incidence_matrix):len(A),0:len(HG.incidence_matrix[0])] = HG.incidence_matrix 81 | A[0:len(HG.incidence_matrix[0]),len(A) - len(HG.incidence_matrix):len(A)] = HG.incidence_matrix.T 82 | return nx.from_numpy_array(A) 83 | 84 | 85 | -------------------------------------------------------------------------------- /Python/HAT/laplacian.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy as sp 3 | # from HAT import Hypergraph 4 | 5 | """ 6 | This file implements hypergraph laplacian methods. 7 | """ 8 | 9 | def laplacian_matrix(HG, laplacian_type='Bolla'): 10 | """This function returns a version of the higher order Laplacian matrix of the hypergraph. 11 | 12 | :param type: Indicates which version of the Laplacin matrix to return. It defaults to ``Bolla`` [1], but ``Rodriguez`` [2,3] and ``Zhou`` [4] are valid arguments as well. 13 | :type type: str, optional 14 | :return: Laplacian matrix 15 | :rtype: *ndarray* 16 | 17 | Several version of the hypergraph Laplacian are defined in [1-4]. These aim to capture 18 | the higher order structure as a matrix. This function serves as a wrapper to call functions 19 | that generate different specific Laplacians (See ``bolla_laplacian()``, ``rodriguez_laplacian()``, 20 | and ``zhou_laplacian()``). 21 | 22 | References 23 | ---------- 24 | - Bolla, M. (1993). Spectra, euclidean representations and clusterings of hypergraphs. Discrete Mathematics, 117. 25 | https://www.sciencedirect.com/science/article/pii/0012365X9390322K 26 | - Rodriguez, J. A. (2002). On the Laplacian eigenvalues and metric parameters of hypergraphs. Linear and Multilinear Algebra, 50(1), 1-14. 27 | https://www.tandfonline.com/doi/abs/10.1080/03081080290011692 28 | - Rodriguez, J. A. (2003). On the Laplacian spectrum and walk-regular hypergraphs. Linear and Multilinear Algebra, 51, 285–297. 29 | https://www.tandfonline.com/doi/abs/10.1080/0308108031000084374 30 | - Zhou, D., Huang, J., & Schölkopf, B. (2005). Beyond pairwise classification and clustering using hypergraphs. (Equation 3.3) 31 | https://dennyzhou.github.io/papers/hyper_tech.pdf 32 | """ 33 | # Auth: Joshua Pickard 34 | # jpic@umich.edu 35 | # Date: Nov 30, 2022 36 | if laplacian_type.lower() == 'bolla': 37 | return bolla_laplacian(HG) 38 | elif laplacian_type.lower() == 'rodriguez': 39 | return rodriguez_laplacian(HG) 40 | elif laplacian_type.lower() == 'zhou': 41 | return zhou_laplacian(HG) 42 | 43 | def bolla_laplacian(HG): 44 | """This function constructs the hypergraph Laplacian according to [1]. 45 | 46 | :return: Bolla Laplacian matrix 47 | :rtype: *ndarray* 48 | 49 | References 50 | ---------- 51 | - Bolla, M. (1993). Spectra, euclidean representations and clusterings of hypergraphs. Discrete Mathematics, 117. 52 | https://www.sciencedirect.com/science/article/pii/0012365X9390322K 53 | """ 54 | # Auth: Joshua Pickard 55 | # jpic@umich.edu 56 | # Date: Nov 30, 2022 57 | dv = np.sum(HG.incidence_matrix, axis=1) 58 | Dv = np.zeros((len(dv), len(dv))) 59 | np.fill_diagonal(Dv, dv) 60 | de = np.sum(HG.incidence_matrix, axis=0) 61 | De = np.zeros((len(de), len(de))) 62 | np.fill_diagonal(De, de) 63 | DeInv = sp.linalg.inv(De, overwrite_a=True) 64 | L = Dv - (HG.incidence_matrix @ DeInv @ HG.incidence_matrix.T) 65 | return L 66 | 67 | def rodriguez_laplacian(HG): 68 | """This function constructs the hypergraph Laplacian according to [1, 2]. 69 | 70 | :return: Rodriguez Laplacian matrix 71 | :rtype: *ndarray* 72 | 73 | References 74 | ---------- 75 | - Rodriguez, J. A. (2002). On the Laplacian eigenvalues and metric parameters of hypergraphs. Linear and Multilinear Algebra, 50(1), 1-14. 76 | https://www.tandfonline.com/doi/abs/10.1080/03081080290011692 77 | - Rodriguez, J. A. (2003). On the Laplacian spectrum and walk-regular hypergraphs. Linear and Multilinear Algebra, 51, 285–297. 78 | https://www.tandfonline.com/doi/abs/10.1080/0308108031000084374 79 | """ 80 | # Auth: Joshua Pickard 81 | # jpic@umich.edu 82 | # Date: Nov 30, 2022 83 | A = HG.incidence_matrix @ HG.incidence_matrix.T 84 | np.fill_diagonal(A, 0) 85 | L = np.diag(sum(A)) - A 86 | return L 87 | 88 | def zhou_laplacian(HG): 89 | """This function constructs the hypergraph Laplacian according to [1]. 90 | 91 | :return: Zhou Laplacian matrix 92 | :rtype: *ndarray* 93 | 94 | References 95 | ---------- 96 | - Zhou, D., Huang, J., & Schölkopf, B. (2005). Beyond pairwise classification and clustering using hypergraphs. (Equation 3.3) 97 | https://dennyzhou.github.io/papers/hyper_tech.pdf 98 | """ 99 | # Auth: Joshua Pickard 100 | # jpic@umich.edu 101 | # Date: Nov 30, 2022 102 | Dvinv = np.diag(1/np.sqrt(HG.incidence_matrix @ HG.edge_weights)) 103 | Deinv = np.diag(1/np.sum(HG.incidence_matrix, axis=0)) 104 | W = np.diag(HG.edge_weights) 105 | L = np.eye(len(HG.incidence_matrix)) - Dvinv @ HG.incidence_matrix @ W @ Deinv @ HG.incidence_matrix.T @ Dvinv 106 | return L 107 | 108 | -------------------------------------------------------------------------------- /Python/HAT/metrics.py: -------------------------------------------------------------------------------- 1 | """ 2 | Hypergraph metrics: 3 | 4 | 1. matrix entropy 5 | 2. average distance 6 | 3. clustering coefficient 7 | 4. nonlinear_eigenvector_centrality 8 | """ 9 | 10 | import numpy as np 11 | import networkx as nx 12 | import scipy as sp 13 | from tqdm import tqdm 14 | 15 | def matrix_entropy(HG, laplacian_type='Rodriguez'): 16 | """Computes hypergraph entropy based on the eigenvalues values of the Laplacian matrix. 17 | 18 | :param laplacian_type: Type of hypergraph Laplacian matrix. This defaults to 'Rodriguez' and other 19 | choices inclue ``Bolla`` and ``Zhou`` (See: ``laplacianMatrix()``). 20 | :type laplacian_type: *str, optional* 21 | :return: Matrix based hypergraph entropy 22 | :rtype: *float* 23 | 24 | Matrix entropy of a hypergraph is defined as the entropy of the eigenvalues of the 25 | hypergraph Laplacian matrix [1]. This may be applied to any version of the Laplacian matrix. 26 | 27 | References 28 | ========== 29 | - C. Chen and I. Rajapakse, Tensor Entropy for Uniform Hypergraphs, IEEE TRANSACTIONS ON NETWORK SCIENCE AND ENGINEERING (2020) 30 | (Equation 1) https://arxiv.org/pdf/1912.09624.pdf 31 | """ 32 | # Auth: Joshua Pickard 33 | # jpic@umich.edu 34 | # Date: Nov 30, 2022 35 | L = HG.laplacianMatrix(laplacian_type) 36 | U, V = np.linalg.eig(L) 37 | return sp.stats.entropy(U) 38 | 39 | def avgerage_distance(HG): 40 | """Computes the average pairwise distance between any 2 vertices in the hypergraph. 41 | 42 | :return: avgDist 43 | :rtype: *float* 44 | 45 | The hypergraph is clique expanded to a graph object, and the average shortest path on 46 | the clique expanded graph is returned. 47 | """ 48 | # Auth: Joshua Pickard 49 | # jpic@umich.edu 50 | # Date: Nov 30, 2022 51 | G = HG.cliqueGraph() 52 | avgDist = nx.average_shortest_path_length(G) 53 | return avgDist 54 | 55 | def clustering_coefficient(HG): 56 | """Computes clustering average clustering coefficient of the hypergraph. 57 | 58 | :return: average clustering coefficient 59 | :rtype: *float* 60 | 61 | For a uniform hypergraph, the clustering coefficient of a vertex :math:`v_i` 62 | is defined as the number of edges the vertex participates in (i.e. :math:`deg(v_i)`) divided 63 | by the number of :math:`k-`way edges that could exist among vertex :math:`v_i` and its neighbors 64 | (See equation 31 in [1]). This is written 65 | 66 | .. math:: 67 | C_i = \\frac{deg(v_i)}{\\binom{|N_i|}{k}} 68 | 69 | where :math:`N_i` is the set of neighbors or vertices adjacent to :math:`v_i`. The hypergraph 70 | clustering coefficient computed here is the average clustering coefficient for all vertices, 71 | written 72 | 73 | .. math:: 74 | C=\sum_{i=1}^nC_i 75 | 76 | References 77 | ========== 78 | - Surana, Amit, Can Chen, and Indika Rajapakse. "Hypergraph Similarity Measures." 79 | IEEE Transactions on Network Science and Engineering (2022). 80 | https://drive.google.com/file/d/1JUYIQ2_u9YX7ky0U7QptUbJyjEMSYNNR/view 81 | """ 82 | # Auth: Joshua Pickard 83 | # jpic@umich.edu 84 | # Date: Nov 30, 2022 85 | n, e = HG.nnodes, HG.nedges 86 | order = sum(HG.incidence_matrix[:,0]) 87 | avgClusterCoef = 0 88 | for v in range(n): 89 | edges = np.where(HG.IM[v,:] > 0)[0] 90 | neighbors = np.where(np.sum(HG.IM[:, edges], axis=1) > 0)[0] 91 | avgClusterCoef += (len(edges) / sp.special.comb(len(neighbors), order)) 92 | avgClusterCoef /= n 93 | return avgClusterCoef 94 | 95 | def nonlinear_eigenvector_centrality(HG, tol=1e-4, maxIter=3000, model='LogExp', alpha=10): 96 | """Computes node and edge centralities. 97 | 98 | :param tol: threshold tolerance for the convergence of the centrality measures, defaults to 1e-4 99 | :type tol: *int*, optional 100 | :param maxIter: maximum number of iterations for the centrality measures to converge in, defaults to 3000 101 | :type maxIter: int, optional 102 | :param model: the set of functions used to compute centrality. This defaults to 'LogExp', and other choices include 103 | 'Linear', 'Max' or a list of 4 custom function handles (See [1]). 104 | :type model: str, optional 105 | :param alpha: Hyperparameter used for computing centrality (See [1]), defaults to 10 106 | :type alpha: int, optional 107 | 108 | :return: vxcCentrality 109 | :rtype: *ndarray* containing centrality scores for each vertex in the hypergraph 110 | :return: edgeCentrality 111 | :rtype: *ndarray* containing centrality scores for each edge in the hypergraph 112 | 113 | References 114 | ---------- 115 | - Tudisco, F., Higham, D.J. Node and edge nonlinear eigenvector centrality for hypergraphs. Commun Phys 4, 201 (2021). https://doi.org/10.1038/s42005-021-00704-2 116 | """ 117 | # Auth: Joshua Pickard 118 | # jpic@umich.edu 119 | # Date: Nov 30, 2022 120 | if model=='Linear': 121 | f = lambda x : x 122 | g = lambda x : x 123 | phi = lambda x : x 124 | psi = lambda x : x 125 | elif model=='LogExp': 126 | f = lambda x : x 127 | g = lambda x : np.sqrt(x) 128 | phi = lambda x : np.log(x) 129 | psi = lambda x : np.exp(x) 130 | elif model=='Max': 131 | f = lambda x : x 132 | g = lambda x : x 133 | phi = lambda x : x**alpha 134 | psi = lambda x : x**(1/alpha) 135 | elif isinstance(model, list): 136 | f = model[0] 137 | g = model[1] 138 | phi = model[2] 139 | psi = model[3] 140 | else: 141 | print('Enter a valid centrality model') 142 | 143 | B = HG.incidence_matrix 144 | W = HG.edge_weights 145 | N = HG.node_weights 146 | W = np.diag(W) 147 | N = np.diag(N) 148 | n, m = B.shape 149 | x0 = np.ones(n,) / n 150 | y0 = np.ones(m,) / m 151 | 152 | for _ in tqdm(range(maxIter), desc='Iterations'): 153 | u = np.sqrt(np.multiply(np.array(x0),np.array(g(B @ W @ f(y0))))) 154 | v = np.sqrt(np.multiply(np.array(y0),np.array(psi(B.T @ N @ phi(x0))))) 155 | x = u / sum(u) 156 | y = v / sum(v) 157 | 158 | check = sum(np.abs(x - x0)) + sum(np.abs(y - y0)) 159 | if check < tol: 160 | break 161 | else: 162 | x0 = x 163 | y0 = y 164 | 165 | vertex_centrality = x 166 | edge_centrality = y 167 | 168 | HG.nodes['NLEC'] = vertex_centrality 169 | HG.edges['NLEC'] = edge_centrality 170 | 171 | return vertex_centrality, edge_centrality 172 | 173 | -------------------------------------------------------------------------------- /Python/HAT/multilinalg.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy as sp 3 | 4 | def hosvd(T, M=True, uniform=False, sym=False): 5 | """ Higher Order Singular Value Decomposition 6 | 7 | :param uniform: Indicates if T is a uniform tensor 8 | :param sym: Indicates if T is a super symmetric tensor 9 | :param M: Indicates if the factor matrices are required as well as the core tensor 10 | 11 | :return: The singular values of the core diagonal tensor and the factor matrices. 12 | """ 13 | # Auth: Joshua Pickard 14 | # jpic@umich.edu 15 | # Date: Dec 2, 2022 16 | if uniform and not M: 17 | return supersymHosvd(T) 18 | else: 19 | print('Nonuniform SVD not implemented') 20 | 21 | def supersymHosvd(T): 22 | """ Computes the singular values of a uniform, symetric tensor. See Algorithm 1 in [1]. 23 | 24 | :param T: A uniform, symmetric multidimensional array 25 | 26 | :return: The singular values that compose the core tensor of the HOSVD on T. 27 | 28 | References 29 | ---------- 30 | - C. Chen and I. Rajapakse, Tensor Entropy for Uniform Hypergraphs, IEEE TRANSACTIONS ON NETWORK SCIENCE AND ENGINEERING (2020) 31 | """ 32 | # Auth: Joshua Pickard 33 | # jpic@umich.edu 34 | # Date: Dec 2, 2022 35 | d = T.shape[0] 36 | m = len(T.shape) 37 | M = np.reshape(T, (d, d**(m-1))) 38 | return sp.linalg.svd(M) 39 | 40 | def HammingSimilarity(A1, A2): 41 | """Computes the Spectral-S similarity of 2 Adjacency tensors [1]. 42 | 43 | :param A1: adjacency tensor 1 44 | :type A1: *ndarray* 45 | :param A2: adjacency tensor 2 46 | :type A2: *ndarray* 47 | :return: Hamming similarity measure 48 | :rtype: *float* 49 | 50 | References 51 | ========== 52 | - Amit Surana, Can Chen, and Indika Rajapakse. Hypergraph similarity measures. IEEE Transactions on Network Science and Engineering, pages 1-16, 2022. 53 | 54 | """ 55 | # Auth: Joshua Pickard 56 | # jpic@umich.edu 57 | # Date: Dec 2, 2022 58 | modes = A1.shape 59 | order = len(modes) 60 | s = sum(abs(A1 - A2)) 61 | while len(s.shape) != 1: 62 | s = sum(s) 63 | s = sum(s) 64 | return s / (modes[0]**order - modes[0]) 65 | 66 | def SpectralHSimilarity(L1, L2): 67 | """Computes the Spectral-S similarity of 2 Laplacian tensors [1]. 68 | 69 | :param L1: Laplacian tensor 1 70 | :type L1: *ndarray* 71 | :param L2: Laplacian tensor 2 72 | :type L2: *ndarray* 73 | :return: Spectral-S similarity measure 74 | :rtype: *float* 75 | 76 | References 77 | ========== 78 | - Amit Surana, Can Chen, and Indika Rajapakse. Hypergraph similarity measures. IEEE Transactions on Network Science and Engineering, pages 1-16, 2022. 79 | """ 80 | # Auth: Joshua Pickard 81 | # jpic@umich.edu 82 | # Date: Dec 2, 2022 83 | _, S1, _ = supersymHosvd(L1) 84 | _, S2, _ = supersymHosvd(L2) 85 | S1 = (1/sum(S1)) * S1 86 | S2 = (1/sum(S1)) * S2 87 | S = sum(abs(S1 - S2)**2)/len(S1) 88 | return S 89 | 90 | def kronecker_exponentiation(M, x): 91 | """Kronecker Product Exponential. 92 | 93 | :param M: a matrix 94 | :type M: *ndarray* 95 | :param x: power of exponentiation 96 | :type x: *int* 97 | :return: Krnoecker Product exponentiation of **M** a total of **x** times 98 | :rtype: *ndarray* 99 | 100 | This function performs the Kronecker Product on a matrix :math:`M` a total of 101 | :math:`x` times. The Kronecker product is defined for two matrices 102 | :math:`A\in\mathbf{R}^{l \\times m}, B\in\mathbf{R}^{m \\times n}` as the matrix 103 | 104 | .. math:: 105 | A \\bigotimes B= \\begin{pmatrix} A_{1,1}B & A_{1,2}B & \dots & A_{1,m}B \\\\ A_{2,1}B & A_{2,2}B & \dots & A_{2,m}B \\\\ \\vdots & \\vdots & \\ddots & \\vdots \\\\ A_{l,1}B & A_{l,2}B & \dots & A_{l,n}B \\end{pmatrix} 106 | 107 | """ 108 | # Auth: Joshua Pickard 109 | # jpic@umich.edu 110 | # Date: Dec 2, 2022 111 | 112 | # Base cases 113 | if x == 1: 114 | return M 115 | elif x % 2 == 0: 116 | half_kron = kronecker_exponentiation(M, x // 2) 117 | return np.kron(half_kron, half_kron) 118 | else: 119 | return np.kron(M, kronecker_exponentiation(M, x - 1)) 120 | 121 | 122 | -------------------------------------------------------------------------------- /Python/HAT/tensors.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy as sp 3 | import scipy.linalg 4 | from itertools import permutations 5 | import networkx as nx 6 | 7 | import multilinalg as mla 8 | import hypergraph 9 | 10 | """ 11 | This file implements tensor representations of hypergraph 12 | """ 13 | 14 | 15 | def adjTensor(HG): 16 | """This constructs the adjacency tensor for uniform hypergraphs. 17 | 18 | :return: Adjacency Tensor 19 | :rtype: *ndarray* 20 | 21 | The adjacency tensor :math:`A` of a :math:`k-`order hypergraph :math:`H` is the multi-way, hypergraph analog of the pairwise, graph 22 | adjacency matrix. It is defined as a :math:`k-` mode tensor ( :math:`k-` dimensional matrix): 23 | 24 | .. math:: 25 | A \in \mathbf{R}^{ \overbrace{n \\times \dots \\times n}^{k \\text{ times}}} \\text{ where }{A}_{j_1\dots j_k} = \\begin{cases} \\frac{1}{(k-1)!} & \\text{if }(j_1,\dots,j_k)\in {E}_h \\\\ 0 & \\text{otherwise} \end{cases}, 26 | 27 | as found in equation 8 of [1]. 28 | 29 | References 30 | ========== 31 | - C. Chen and I. Rajapakse, Tensor Entropy for Uniform Hypergraphs, IEEE TRANSACTIONS ON NETWORK SCIENCE AND ENGINEERING (2020) 32 | (Equation 8) https://arxiv.org/pdf/1912.09624.pdf 33 | """ 34 | # Auth: Joshua Pickard 35 | # jpic@umich.edu 36 | # Date: Nov 30, 2022 37 | order = int(sum(HG.IM[:,0])) 38 | denom = np.math.factorial(order - 1) 39 | modes = len(HG.IM) * np.ones(order) 40 | A = np.zeros(modes.astype(int)) 41 | for e in range(len(HG.IM[0])): 42 | vxc = np.where(HG.IM[:, e] == 1)[0] 43 | vxc = list(permutations(vxc)) 44 | for p in vxc: 45 | A[p] = 1 / denom 46 | return A 47 | 48 | def degreeTensor(HG): 49 | """This constructs the degree tensor for uniform hypergraphs. 50 | 51 | :return: Degree Tensor 52 | :rtype: *ndarray* 53 | 54 | The degree tensor :math:`D` is the hypergraph analog of the degree matrix. For a :math:`k-` order hypergraph 55 | :math:`H=(V,E)` the degree tensor :math:`D` is a diagonal supersymmetric tensor defined 56 | 57 | .. math:: 58 | D \in \mathbf{R}^{ \overbrace{n \\times \dots \\times n}^{k \\text{ times}}} \\text{ where }{D}_{i\dots i} = degree(v_i) \\text{ for all } v_i\in V 59 | 60 | References 61 | ---------- 62 | - C. Chen and I. Rajapakse, Tensor Entropy for Uniform Hypergraphs, IEEE TRANSACTIONS ON NETWORK SCIENCE AND ENGINEERING (2020) 63 | https://arxiv.org/pdf/1912.09624.pdf 64 | """ 65 | # Auth: Joshua Pickard 66 | # jpic@umich.edu 67 | # Date: Nov 30, 2022 68 | order = int(sum(HG.IM[:,0])) 69 | modes = len(HG.IM) * np.ones(order) 70 | D = np.zeros(modes.astype(int)) 71 | for vx in range(len(HG.IM)): 72 | D[tuple((np.ones(order) * vx).astype(int))] = sum(HG.IM[vx]) 73 | return D 74 | 75 | 76 | 77 | def laplacianTensor(HG): 78 | """This constructs the Laplacian tensor for uniform hypergraphs. 79 | 80 | :return: Laplcian Tensor 81 | :rtype: *ndarray* 82 | 83 | The Laplacian tensor is the tensor analog of the Laplacian matrix for graphs, and it is 84 | defined equivalently. For a hypergraph :math:`H=(V,E)` with an adjacency tensor :math:`A` 85 | and degree tensor :math:`D`, the Laplacian tensor is 86 | 87 | .. math:: 88 | L = D - A 89 | 90 | References 91 | ========== 92 | - C. Chen and I. Rajapakse, Tensor Entropy for Uniform Hypergraphs, IEEE TRANSACTIONS ON NETWORK SCIENCE AND ENGINEERING (2020) 93 | (Equation 9) https://arxiv.org/pdf/1912.09624.pdf 94 | """ 95 | # Auth: Joshua Pickard 96 | # jpic@umich.edu 97 | # Date: Nov 30, 2022 98 | D = HG.degreeTensor() 99 | A = HG.adjTensor() 100 | L = D - A 101 | return L 102 | 103 | 104 | 105 | def tensorEntropy(HG): 106 | """Computes hypergraph entropy based on the singular values of the Laplacian tensor. 107 | 108 | :return: tensor entropy 109 | :rtype: *float* 110 | 111 | Uniform hypergraph entropy is defined as the entropy of the higher order singular 112 | values of the Laplacian matrix [1]. 113 | 114 | References 115 | ---------- 116 | - C. Chen and I. Rajapakse, Tensor Entropy for Uniform Hypergraphs, IEEE TRANSACTIONS 117 | ON NETWORK SCIENCE AND ENGINEERING (2020) (Definition 7, Algorithm 1) 118 | https://arxiv.org/pdf/1912.09624.pdf 119 | """ 120 | # Auth: Joshua Pickard 121 | # jpic@umich.edu 122 | # Date: Nov 30, 2022 123 | L = HG.laplacianTensor() 124 | _, S, _ = mla.hosvd(L, M=False, uniform=True) 125 | return sp.stats.entropy(S) 126 | 127 | -------------------------------------------------------------------------------- /Python/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Joshua Pickard 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 | -------------------------------------------------------------------------------- /Python/PYPIREADME.md: -------------------------------------------------------------------------------- 1 | # Hypergraph Analysis Toolbox (HAT) 2 | 3 | Principle Author: Joshua Pickard (jpic@umich.edu) 4 | 5 | --- 6 | 7 | Hypergraph Analysis Toolbox (HAT) is a general purpose software for hypergraph analytics. HAT is implemented in both Python and MATLAB. Information on the broader projcet is available at the below links: 8 | 9 | * Website: https://hypergraph-analysis-toolbox.readthedocs.io/ 10 | * Source Code: https://github.com/Jpickard1/Hypergraph-Analysis-Toolbox 11 | * Bug Reports: https://github.com/Jpickard1/Hypergraph-Analysis-Toolbox/issues 12 | * Publication: https://arxiv.org/abs/2211.11166 13 | 14 | -------------------------------------------------------------------------------- /Python/README.md: -------------------------------------------------------------------------------- 1 | # Hypergraph Analysis Toolbox (HAT): Python Implementation 2 | 3 | --- 4 | 5 | This directory manages the Python implenentation of HAT. 6 | 7 | ## Hypergraph Class: 8 | 9 | **Numerical Representation** 10 | - edge_list 11 | - adjacency_tensor 12 | - incidence_matrix 13 | 14 | **Annotated Features** 15 | - nodes 16 | - edges 17 | 18 | **Hyeprgraph Attributes** 19 | - uniform 20 | - order 21 | - directed 22 | 23 | **Construction** 24 | 25 | *Criteria to be directed* 26 | - We assume adjacency tensors are directed 27 | - Signed incidence matrices are directed, else undirected 28 | - head tail edge lists are directed 29 | 30 | ### Data Schema: 31 | 32 | **Numerical Representation** 33 | - edge_list: 34 | ``` 35 | # Undirected 36 | HG.edge_list = [ 37 | [0,1,2], 38 | [0,1,3] 39 | ] 40 | 41 | # Directed 42 | HG.edge_list = [ 43 | [[head], [tail]], 44 | [[0],[1,2]], 45 | [[0],[1,3]] 46 | ] 47 | ``` 48 | 49 | - incidence_matrix 50 | ``` 51 | # Undirected 52 | HG.incidence_matrix = np.array( 53 | [[1, 1], 54 | [1, 1], 55 | [1, 0], 56 | [0, 1] 57 | ] 58 | ) 59 | # Directed 60 | HG.incidence_matrix = np.array( 61 | [[ 1, 1], 62 | [-1, -1], 63 | [-1, 0], 64 | [ 0, -1] 65 | ] 66 | ) 67 | ``` 68 | - adjacency_tensor (only directed) 69 | ``` 70 | # Directed 71 | HG.adjacency_tensor = np.array( 72 | [ 73 | [ 74 | [0, 0, 0, 0], 75 | [0, 0, 1, 1], 76 | [0, 1, 0, 0], 77 | [0, 1, 0, 0] 78 | ], 79 | [ 80 | [0, 0, 1, 1], 81 | [0, 0, 0, 0], 82 | [1, 0, 0, 0], 83 | [1, 0, 0, 0] 84 | ], 85 | [ 86 | [0, 1, 0, 0], 87 | [1, 0, 0, 0], 88 | [0, 0, 0, 0], 89 | [0, 0, 0, 0] 90 | ], 91 | [ 92 | [0, 1, 0, 0], 93 | [1, 0, 0, 0], 94 | [0, 0, 0, 0], 95 | [0, 0, 0, 0] 96 | ] 97 | ] 98 | ) 99 | ``` 100 | 101 | **Annotated Features** 102 | - nodes 103 | - edges 104 | 105 | **Hyeprgraph Attributes** 106 | - uniform (bool): True if HG is *k-*uniform (undirected) or *k-*tail-uniform (directed) 107 | - order (int, None): the order of the uniformity 108 | - directed (bool): if hyperedges have direction associated with them 109 | - weighted (bool): if hyperedges have associated weights 110 | 111 | 112 | ## TODO: 113 | 114 | 1. decide to remove setters of incidence matrix, adjacency tensors, and edge sets. 115 | Argument for: this should be supplied at creation or by modifiation of adding new vertices. If it is already set, why would we reset it? 116 | Argument against: not sure. 117 | 118 | 2. Testing: 119 | 120 | ``` 121 | python -m unittest -v .\tests\hypergraph_constructors.py 122 | ``` -------------------------------------------------------------------------------- /Python/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ "hatchling",] 3 | build-backend = "hatchling.build" 4 | 5 | [project] 6 | name = "HypergraphAnalysisToolbox" 7 | version = "1.1.13" 8 | description = "This package performes hypergraph analysis." 9 | readme = "PYPIREADME.md" 10 | requires-python = ">=3.11" 11 | classifiers = [ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent",] 12 | dependencies = [ 13 | 'numpy', 14 | 'scipy', 15 | 'matplotlib', 16 | 'pandas', 17 | 'networkx', 18 | 'rich', 19 | 'tqdm' 20 | ] 21 | 22 | [[project.authors]] 23 | name = "Joshua Pickard" 24 | email = "jpic@umich.edu" 25 | 26 | 27 | [project.urls] 28 | Homepage = "https://hypergraph-analysis-toolbox.readthedocs.io/en/latest/" 29 | "Bug Tracker" = "https://github.com/Jpickard1/Hypergraph-Analysis-Toolbox/issues" 30 | 31 | [tool.hatch.build.targets.wheel] 32 | packages = [ "HAT",] 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hypergraph-Analysis-Toolbox (HAT) 2 | 3 | [![Documentation Status](https://readthedocs.org/projects/hypergraph-analysis-toolbox/badge/?version=latest)](https://hypergraph-analysis-toolbox.readthedocs.io/en/latest/?badge=latest) 4 | [![View Hypergraph Analysis Toolbox on File Exchange](https://www.mathworks.com/matlabcentral/images/matlab-file-exchange.svg)](https://www.mathworks.com/matlabcentral/fileexchange/121013-hypergraph-analysis-toolbox) 5 | 6 | The [Hypergraph Analysis Toolbox](https://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1011190) is a general purpose software for analyzing the structure and dynamics of Hypergraphs. 7 | 8 | Hypergraph Analysis Toolbox (HAT) is a software suite for the analysis and visualization of hypergraphs and higher order structures. Motivated to investigate Pore-C data, HAT is intended as a general prupose, versatile software for hypergraph construction, visualization, and analysis. HAT's main features include: 9 | 10 | - Controllability and observability of higher order systems 11 | - Hypergraph metrics: centrality, similarity, entropy, etc. 12 | - Tensor based analysis: eigenvalues, decompositions, Kronecker products, etc. 13 | 14 | Documentation for HAT is found [here](https://hypergraph-analysis-toolbox.readthedocs.io/en/latest/index.html) at: https://hypergraph-analysis-toolbox.readthedocs.io/en/latest/index.html 15 | 16 | **Papers by the HAT Team** 17 | HAT was developed to consolidate and facilitate the development of new hypergraph methods. Select papers that motivated this development and whose methods are part of HAT include: 18 | 19 | - Scalable Hypergraph Algorithms for Observability of Gene Regulation (*coming soon*) 20 | - [Kronecker Products of Tensors and Hypergraphs](https://epubs.siam.org/doi/full/10.1137/23M1592547) 21 | - [Observability of Hypergraphs](https://drive.google.com/file/d/1FQxRj5VdPkY-P64ek7rq4lp9jQW9MLFP/view) 22 | - [Geometric Apsects of Observability of Hypergraphs](https://drive.google.com/file/d/1-5AL_rOvAm-aUClSfyy9MpED7h7_L76o/view) 23 | - [HAT: Hypergraph Analysis Toolbox](https://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1011190) 24 | - [Deciphering Multiway Interactions in the Human Genome](https://drive.google.com/file/d/1rp6ZtKf_DxUL0xOpcUzRg1rJGA6xlu-f/view) 25 | - [Hypergraph Similarity Measures](https://drive.google.com/file/d/1Dc4nSkkZyk4axOAshdRDXo8Gx24h4M-d/view) 26 | - [Controllability of Hypergraphs](https://drive.google.com/file/d/12aReE7mE4MVbycZUxUYdtICgrAYlzg8o/view) 27 | - [Tensor Entropy for Uniform Hypergraphs](https://drive.google.com/file/d/1-d4uR5KT3iDpOd69aCQVjNZzMyILXp5E/view) 28 | - [Multilinear Control Systems Theory](https://drive.google.com/file/d/1F0ZGoVWeKSWemXvSp6ilTwLS8N7j6n71/view) 29 | 30 | HAT_logo_v2 31 | 32 | -------------------------------------------------------------------------------- /Tests/README.md: -------------------------------------------------------------------------------- 1 | # HAT TESTS 2 | 3 | This directory contains a series of tests for HAT. Every test can be run through either the Matlab or Python implementations. I would like to have a series of tests with defined inputs and outputs that should run pass on all implementations. 4 | -------------------------------------------------------------------------------- /Tests/control_can.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.append('../') 3 | from HAT import Hypergraph, dynamics 4 | import numpy as np 5 | import unittest 6 | import logging 7 | 8 | class HypergraphControlTests(unittest.TestCase): 9 | def test_bmatrix_1(self): 10 | """ 11 | Test construction of control configuration matrix 12 | """ 13 | incidence_matrix=np.array( 14 | [[1, 1], 15 | [1, 1], 16 | [1, 0], 17 | [0, 1]] 18 | ) 19 | HG = Hypergraph(incidence_matrix=incidence_matrix) 20 | 21 | B1 = dynamics.b_matrix(HG, [0]) 22 | correct_b_matrix_1 = np.array([[1], [0], [0], [0]]) 23 | B2 = dynamics.b_matrix(HG, [0, 1]) 24 | correct_b_matrix_2 = np.array([[1, 0], [0, 1], [0, 0], [0, 0]]) 25 | B3 = dynamics.b_matrix(HG, [1, 0]) 26 | correct_b_matrix_3 = np.array([[0, 1], [1, 0], [0, 0], [0, 0]]) 27 | 28 | np.testing.assert_array_equal(B1, correct_b_matrix_1, "B1 matrix does not match the expected output.") 29 | np.testing.assert_array_equal(B2, correct_b_matrix_2, "B2 matrix does not match the expected output.") 30 | np.testing.assert_array_equal(B3, correct_b_matrix_3, "B3 matrix does not match the expected output.") 31 | 32 | def test_ctrbk(self): 33 | """ 34 | Test construction of control configuration matrix 35 | """ 36 | logging.info('test_constructor_edge_set_1') 37 | incidence_matrix=np.array( 38 | [[1, 1], 39 | [1, 1], 40 | [1, 0], 41 | [0, 1]] 42 | ) 43 | HG = Hypergraph(incidence_matrix=incidence_matrix) 44 | C1 = dynamics.ctrbk(HG, [0,1,2,3]) 45 | correct_C_matrix_1 = np.array( 46 | [ 47 | [1, 0, 0, 0], 48 | [0, 1, 0, 0], 49 | [0, 0, 1, 0], 50 | [0, 0, 0, 1] 51 | ] 52 | ) 53 | incidence_matrix=np.array( 54 | [[1], 55 | [1], 56 | [1], 57 | [1]] 58 | ) 59 | HG = Hypergraph(incidence_matrix=incidence_matrix) 60 | C2 = dynamics.ctrbk(HG, [0,1,2]) 61 | correct_C_matrix_2 = np.array( 62 | [[0., 0., 0., 1.], 63 | [0., 1., 0., 0.], 64 | [0., 0., 1., 0.], 65 | [1., 0., 0., 0.]] 66 | ) 67 | np.testing.assert_array_equal(C1, correct_C_matrix_1, "C1 matrix does not match the expected output.") 68 | np.testing.assert_array_equal(C2, correct_C_matrix_2, "C2 matrix does not match the expected output.") 69 | 70 | if __name__ == '__main__': 71 | unittest.main() 72 | 73 | -------------------------------------------------------------------------------- /Tests/hypergraph_constructors.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.append('../') 3 | from HAT import Hypergraph 4 | import numpy as np 5 | import pandas as pd 6 | from pandas.testing import assert_frame_equal 7 | import unittest 8 | import logging 9 | 10 | def are_nested_lists_equivalent(list1, list2): 11 | # Check if both are lists of lists 12 | if not all(isinstance(sublist, list) for sublist in list1 + list2): 13 | return False 14 | 15 | # Sort each sublist and then sort the outer list 16 | sorted_list1 = sorted([sorted(sublist) for sublist in list1]) 17 | sorted_list2 = sorted([sorted(sublist) for sublist in list2]) 18 | 19 | # Compare the sorted lists 20 | return sorted_list1 == sorted_list2 21 | 22 | class HypergraphConstructorTestCase1(unittest.TestCase): 23 | """Tests hypergraph construction from three basic, numerical representations of the hypergraph. 24 | """ 25 | def setUp(self): 26 | """Set up shared resources for edge_list-based tests.""" 27 | self.edge_list = [[0, 1, 2], [0, 1, 3]] 28 | self.expected_node_df = pd.DataFrame({'Nodes': [0, 1, 2, 3]}) 29 | self.expected_edges_df = pd.DataFrame( 30 | { 31 | 'Nodes': [[0,1,2], 32 | [0,1,3]] 33 | } 34 | ) 35 | self.expected_incidence_matrix = np.array([ 36 | [1, 1], 37 | [1, 1], 38 | [1, 0], 39 | [0, 1] 40 | ]) 41 | self.expected_adjacency_tensor = np.array([ 42 | [[0, 0, 0, 0], 43 | [0, 0, 1, 1], 44 | [0, 1, 0, 0], 45 | [0, 1, 0, 0]], 46 | [[0, 0, 1, 1], 47 | [0, 0, 0, 0], 48 | [1, 0, 0, 0], 49 | [1, 0, 0, 0]], 50 | [[0, 1, 0, 0], 51 | [1, 0, 0, 0], 52 | [0, 0, 0, 0], 53 | [0, 0, 0, 0]], 54 | [[0, 1, 0, 0], 55 | [1, 0, 0, 0], 56 | [0, 0, 0, 0], 57 | [0, 0, 0, 0]] 58 | ]) 59 | 60 | def test_constructor_edge_set_1(self): 61 | """ 62 | Test construction from edge_list. 63 | 64 | Validation of 3 numerical representations and other properties 65 | """ 66 | logging.info('test_constructor_edge_set_1') 67 | HG = Hypergraph(edge_list=self.edge_list) 68 | incidence_matrix=np.array( 69 | [[1, 1], 70 | [1, 1], 71 | [1, 0], 72 | [0, 1]] 73 | ) 74 | 75 | # Validate hypergraph properties 76 | assert HG.order == 3 77 | assert HG.uniform == True 78 | assert HG.directed == False 79 | np.testing.assert_array_equal(HG.incidence_matrix, incidence_matrix) 80 | np.testing.assert_array_equal(HG.adjacency_tensor, self.expected_adjacency_tensor) 81 | 82 | # Validate dataframes 83 | try: 84 | assert_frame_equal(self.expected_node_df, HG.nodes, check_dtype=False) 85 | except AssertionError as e: 86 | logging.info(f"DataFrames are not equal: {e}") 87 | 88 | try: 89 | assert_frame_equal(self.expected_edges_df, HG.edges, check_dtype=False) 90 | except AssertionError as e: 91 | logging.info(f"DataFrames are not equal: {e}") 92 | 93 | assert are_nested_lists_equivalent(HG.edge_list, self.edge_list) == True 94 | assert np.sum(HG.adjacency_tensor - self.expected_adjacency_tensor) < 1e-5 95 | 96 | logging.info('constructor_1 complete') 97 | 98 | def test_constructor_incidence_matrix_1(self): 99 | """ 100 | Test construction from incidence_matrix. 101 | 102 | Validation of 3 numerical representations and other properties 103 | """ 104 | edge_list = [[0,1,2], 105 | [0,1,3]] 106 | incidence_matrix=np.array( 107 | [[1, 1], 108 | [1, 1], 109 | [1, 0], 110 | [0, 1]] 111 | ) 112 | adjacency_tensor = np.array( 113 | [[[0, 0, 0, 0], 114 | [0, 0, 1, 1], 115 | [0, 1, 0, 0], 116 | [0, 1, 0, 0]], 117 | [[0, 0, 1, 1], 118 | [0, 0, 0, 0], 119 | [1, 0, 0, 0], 120 | [1, 0, 0, 0]], 121 | [[0, 1, 0, 0], 122 | [1, 0, 0, 0], 123 | [0, 0, 0, 0], 124 | [0, 0, 0, 0]], 125 | [[0, 1, 0, 0], 126 | [1, 0, 0, 0], 127 | [0, 0, 0, 0], 128 | [0, 0, 0, 0]]] 129 | ) 130 | HG = Hypergraph(incidence_matrix=incidence_matrix) 131 | 132 | # Validate hypergraph properties 133 | assert HG.order == 3 134 | assert HG.uniform == True 135 | assert HG.directed == False 136 | np.testing.assert_array_equal(HG.incidence_matrix, incidence_matrix) 137 | np.testing.assert_array_equal(HG.adjacency_tensor, adjacency_tensor) 138 | 139 | # Validate dataframes 140 | try: 141 | assert_frame_equal(self.expected_node_df, HG.nodes, check_dtype=False) 142 | except AssertionError as e: 143 | logging.info(f"DataFrames are not equal: {e}") 144 | 145 | try: 146 | assert_frame_equal(self.expected_edges_df, HG.edges, check_dtype=False) 147 | except AssertionError as e: 148 | logging.info(f"DataFrames are not equal: {e}") 149 | 150 | assert are_nested_lists_equivalent(HG.edge_list, edge_list) == True 151 | assert np.sum(HG.adjacency_tensor - adjacency_tensor) < 1e-5 152 | 153 | logging.info('constructor_2 complete') 154 | 155 | def test_constructor_adjacency_tensor_1(self): 156 | """ 157 | Test construction from adjacency_tensor. 158 | 159 | Validation of 3 numerical representations and other properties 160 | """ 161 | logging.info('constructor_3 start') 162 | edge_list= [ 163 | [[0], [1, 2]], 164 | [[0], [1, 3]], 165 | [[1], [0, 2]], 166 | [[1], [0, 3]], 167 | [[2], [0, 1]], 168 | [[3], [0, 1]] 169 | ] 170 | node_df = pd.DataFrame({'Nodes': [0,1,2,3]}) 171 | data = { 172 | 'Nodes': [[0, 1, 2], [0, 1, 3], [0, 1, 2], [0, 1, 3], [0, 1, 2], [0, 1, 3]], 173 | 'Head': [[0], [0], [1], [1], [2], [3]], 174 | 'Tail': [[1, 2], [1, 3], [0, 2], [0, 3], [0, 1], [0, 1]], 175 | 'Edges':[0,1,2,3,4,5] 176 | } 177 | 178 | # Create the DataFrame with specified indices 179 | edges_df = pd.DataFrame(data, index=[0, 1, 4, 5, 8, 10]) 180 | 181 | incidence_matrix = np.array( 182 | [[1, 1, -1, -1, -1, -1], 183 | [ -1, -1, 1, 1, -1, -1], 184 | [ -1, 0, -1, 0, 1, 0], 185 | [ 0, -1, 0, -1, 0, 1]] 186 | ) 187 | adjacency_tensor = np.array( 188 | [[[0, 0, 0, 0], 189 | [0, 0, 1, 1], 190 | [0, 1, 0, 0], 191 | [0, 1, 0, 0]], 192 | [[0, 0, 1, 1], 193 | [0, 0, 0, 0], 194 | [1, 0, 0, 0], 195 | [1, 0, 0, 0]], 196 | [[0, 1, 0, 0], 197 | [1, 0, 0, 0], 198 | [0, 0, 0, 0], 199 | [0, 0, 0, 0]], 200 | [[0, 1, 0, 0], 201 | [1, 0, 0, 0], 202 | [0, 0, 0, 0], 203 | [0, 0, 0, 0]]] 204 | ) 205 | HG = Hypergraph(adjacency_tensor=adjacency_tensor) 206 | 207 | # Validate hypergraph properties 208 | assert HG.order == 3 209 | assert HG.uniform == True 210 | assert HG.directed == True 211 | np.testing.assert_array_equal(HG.adjacency_tensor, adjacency_tensor) 212 | 213 | # Validate dataframes 214 | try: 215 | assert_frame_equal(node_df, HG.nodes, check_dtype=False) 216 | except AssertionError as e: 217 | logging.info(f"DataFrames are not equal: {e}") 218 | 219 | try: 220 | print(f"{HG.edges=}") 221 | print(f"{edges_df=}") 222 | assert_frame_equal(edges_df, HG.edges, check_dtype=False) 223 | except AssertionError as e: 224 | logging.info(f"DataFrames are not equal: {e}") 225 | 226 | assert np.sum(HG.adjacency_tensor - adjacency_tensor) < 1e-5 227 | 228 | np.testing.assert_array_equal(HG.incidence_matrix, incidence_matrix) 229 | assert are_nested_lists_equivalent(HG.edge_list, edge_list) == True 230 | 231 | logging.info('constructor_3 complete') 232 | 233 | class HypergraphConstructorTestCase2(unittest.TestCase): 234 | def test_add_node_1(self): 235 | incidence_matrix=np.array( 236 | [[1, 1], 237 | [1, 1], 238 | [1, 0], 239 | [0, 1]] 240 | ) 241 | HG = Hypergraph(incidence_matrix=incidence_matrix) 242 | HG.add_node() 243 | 244 | node_df = pd.DataFrame({'Nodes': [0,1,2,3,4]}) 245 | assert_frame_equal(node_df, HG.nodes, check_dtype=False) 246 | 247 | def test_add_node_2(self): 248 | incidence_matrix=np.array( 249 | [[1, 1], 250 | [1, 1], 251 | [1, 0], 252 | [0, 1]] 253 | ) 254 | HG = Hypergraph(incidence_matrix=incidence_matrix) 255 | HG.nodes['key'] = ['a', 'b', 'c', 'd'] 256 | HG.add_node(properties={'key':'e'}) 257 | 258 | node_df = pd.DataFrame({'Nodes': [0,1,2,3,4], 259 | 'key':['a','b','c','d','e']}) 260 | assert_frame_equal(node_df, HG.nodes, check_dtype=False) 261 | 262 | def test_add_node_3(self): 263 | incidence_matrix=np.array( 264 | [[1, 1], 265 | [1, 1], 266 | [1, 0], 267 | [0, 1]] 268 | ) 269 | HG = Hypergraph(incidence_matrix=incidence_matrix) 270 | HG.nodes['key'] = ['a', 'b', 'c', 'd'] 271 | HG.add_node(properties={'key':'e', 'value':'z'}) 272 | 273 | node_df = pd.DataFrame({'Nodes': [0,1,2,3,4], 274 | 'key':['a','b','c','d','e'], 275 | 'value':[pd.NA, pd.NA, pd.NA, pd.NA, 'z']}) 276 | assert_frame_equal(node_df, HG.nodes, check_dtype=False) 277 | 278 | def test_add_node_4(self): 279 | incidence_matrix=np.array( 280 | [[1, 1], 281 | [1, 1], 282 | [1, 0], 283 | [0, 1]] 284 | ) 285 | HG = Hypergraph(incidence_matrix=incidence_matrix) 286 | HG.nodes['key'] = ['a', 'b', 'c', 'd'] 287 | HG.nodes['value'] = ['w','x','y','z'] 288 | HG.add_node(properties={'key':'e'}) 289 | 290 | node_df = pd.DataFrame({'Nodes': [0,1,2,3,4], 291 | 'key':['a','b','c','d','e'], 292 | 'value':['w','x','y','z',pd.NA]}) 293 | assert_frame_equal(node_df, HG.nodes, check_dtype=False) 294 | 295 | def test_add_edge_1(self): 296 | incidence_matrix = np.array( 297 | [[1, 1], 298 | [1, 1], 299 | [1, 0], 300 | [0, 1]] 301 | ) 302 | HG = Hypergraph(incidence_matrix=incidence_matrix) 303 | 304 | # Add properties to nodes and edges 305 | HG.edges['weight'] = [1.5, 2.5] 306 | 307 | # Add an edge 308 | HG.add_edge(nodes=[2, 3], properties={'weight': 3.0}) 309 | 310 | # Define expected edge DataFrame 311 | edge_df = pd.DataFrame({ 312 | 'Nodes': [[0, 1, 2], [0, 1, 3], [2, 3]], 313 | 'Edges': [0,1,2], 314 | 'weight': [1.5, 2.5, 3.0] 315 | }) 316 | 317 | # Assert the edges match 318 | assert_frame_equal(edge_df, HG.edges, check_dtype=False) 319 | 320 | def test_add_edge_2(self): 321 | incidence_matrix = np.array( 322 | [[1, 1], 323 | [1, 1], 324 | [1, 0], 325 | [0, 1]] 326 | ) 327 | HG = Hypergraph(incidence_matrix=incidence_matrix) 328 | 329 | # Add properties to nodes and edges 330 | HG.edges['weight'] = [1.5, 2.5] 331 | 332 | # Add an edge 333 | HG.add_edge(nodes=[2, 3]) 334 | 335 | # Define expected edge DataFrame 336 | edge_df = pd.DataFrame({ 337 | 'Nodes': [[0, 1, 2], [0, 1, 3], [2, 3]], 338 | 'Edges': [0,1,2], 339 | 'weight': [1.5, 2.5, pd.NA] 340 | }) 341 | 342 | # Assert the edges match 343 | assert_frame_equal(edge_df, HG.edges, check_dtype=False) 344 | 345 | def test_add_edge_3(self): 346 | incidence_matrix = np.array( 347 | [[1, 1], 348 | [1, 1], 349 | [1, 0], 350 | [0, 1]] 351 | ) 352 | HG = Hypergraph(incidence_matrix=incidence_matrix) 353 | 354 | # Add an edge 355 | HG.add_edge(nodes=[2, 3], properties={'weight': 3.0}) 356 | 357 | # Define expected edge DataFrame 358 | edge_df = pd.DataFrame({ 359 | 'Nodes': [[0, 1, 2], [0, 1, 3], [2, 3]], 360 | 'Edges': [0,1,2], 361 | 'weight': [pd.NA, pd.NA, 3.0] 362 | }) 363 | 364 | # Assert the edges match 365 | print(f"{HG.edges=}") 366 | assert_frame_equal(edge_df, HG.edges, check_dtype=False) 367 | 368 | logging.basicConfig( 369 | level=logging.INFO, 370 | format='%(asctime)s\t - %(message)s', 371 | datefmt='%Y-%m-%d %H:%M:%S' 372 | ) 373 | 374 | if __name__ == '__main__': 375 | unittest.main() 376 | 377 | -------------------------------------------------------------------------------- /Tests/laplacians.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.append('../') 3 | from HAT import Hypergraph, laplacian 4 | import numpy as np 5 | import unittest 6 | import logging 7 | 8 | class Laplacians(unittest.TestCase): 9 | def test_bolla(self): 10 | incidence_matrix=np.array( 11 | [[1, 1], 12 | [1, 1], 13 | [1, 0], 14 | [0, 1]] 15 | ) 16 | HG = Hypergraph(incidence_matrix=incidence_matrix) 17 | L1 = laplacian.laplacian_matrix(HG) 18 | L2 = laplacian.laplacian_matrix(HG, laplacian_type='Bolla') 19 | L3 = laplacian.bolla_laplacian(HG) 20 | # print(f"{type(HG)=}") 21 | # L4 = HG.laplacian_matrix(laplacian_type='bolla') 22 | 23 | L1_correct = np.array([[ 1.33333333, -0.66666667, -0.33333333, -0.33333333], 24 | [-0.66666667, 1.33333333, -0.33333333, -0.33333333], 25 | [-0.33333333, -0.33333333, 0.66666667, 0. ], 26 | [-0.33333333, -0.33333333, 0. , 0.66666667]]) 27 | 28 | np.testing.assert_allclose(L1, L1_correct, atol=1e-5, err_msg="L1 matrix does not match the expected output.") 29 | np.testing.assert_allclose(L2, L1_correct, atol=1e-5, err_msg="L2 matrix does not match the expected output.") 30 | np.testing.assert_allclose(L3, L1_correct, atol=1e-5, err_msg="L3 matrix does not match the expected output.") 31 | 32 | 33 | ''' 34 | def test_rodriguez(self): 35 | pass 36 | 37 | def test_zhou(self): 38 | pass 39 | ''' 40 | 41 | if __name__ == '__main__': 42 | unittest.main() 43 | 44 | -------------------------------------------------------------------------------- /Tests/matlab_basic_tests.m: -------------------------------------------------------------------------------- 1 | %% MATLAB Basic Tests 2 | % This script is intended to test the ability to call every function in the 3 | % package as intended. 4 | % 5 | % NOTE: This script does not test that functions produce the intended 6 | % output. 7 | % 8 | % Auth: Joshua Pickard 9 | % jpic@umich.edu 10 | % Date: September 23, 2022 11 | 12 | %% Preamble 13 | clear all; 14 | close all; 15 | % I = randi([0 1], 5, 10) 16 | 17 | I = [ 1 1 1 1 1 1 0 0 0 0; 18 | 1 1 1 0 0 0 1 1 1 0; 19 | 1 0 0 1 1 0 1 1 0 1; 20 | 0 1 0 1 0 1 1 0 1 1; 21 | 0 0 1 0 1 1 0 1 1 1;] 22 | 23 | %% Visualization 24 | ax = figure; 25 | PlotIM.plotIncidenceMatrix(I); 26 | %% Hypergraph dir 27 | H = Hypergraph('H', I); % Constructor 28 | 29 | [a,b] = sConnectedComponents(H, 1) % Function 30 | a = sRadius(H, 1) % Function 31 | 32 | %% Computations dir 33 | [d, dmax] = Computations.averageDistance(H) 34 | p = Computations.clusteringCoefficient(H) 35 | 36 | % This function is curently broken 37 | % [nodeCentrality, edgeCentrality] = Computations.hypergraphCentrality(H) 38 | entropy = Computations.hypergraphEntropy(H); 39 | 40 | %% Decompositions 41 | 42 | % Tensor decompositions 43 | A = Decompositions.TensorDecomp.adjacencyTensor(H); 44 | A = Decompositions.TensorDecomp.dualAdjacencyTensor(H); 45 | hyperedgeSet = Decompositions.TensorDecomp.uniformEdgeSet(H); 46 | E = Decompositions.TensorDecomp.edgeSetToIncidenceMatrix(hyperedgeSet); 47 | % This function should be refactored to accept the hypergraph object rather 48 | % than the hyperedgeSet 49 | 50 | % Graph decompositions 51 | [adjMat,lapMat] = Decompositions.GraphDecomp.BollaLaplacian(H); 52 | [adjMat,lapMat] = Decompositions.GraphDecomp.cliqueGraph(H); 53 | [adjMat,lapMat] = Decompositions.GraphDecomp.dualGraph(H); 54 | [adjMat,lapMat] = Decompositions.GraphDecomp.lineGraph(H); 55 | [adjMat,lapMat] = Decompositions.GraphDecomp.RodriguezLaplacian(H); 56 | [adjMat,lapMat] = Decompositions.GraphDecomp.starGraph(H); 57 | [adjMat,lapMat] = Decompositions.GraphDecomp.ZhouLaplacian(H); 58 | 59 | %% Dissimilarity measures 60 | d = DissimilarityMeasures.graphDissimilarity(randi([0 1], 5, 5), randi([0 1], 5, 5)); 61 | d = DissimilarityMeasures.hypergraphDissimilarity(randi([0 1], 5, 5), randi([0 1], 5, 5)); 62 | 63 | % Tensor Dissimilarity 64 | A1 = randi([0 1], 5, 5, 5); 65 | A2 = randi([0 1], 5, 5, 5); 66 | d = DissimilarityMeasures.TensorDis.Hamming(A1, A2); 67 | d = DissimilarityMeasures.TensorDis.SpectralH(A1, A2); 68 | d = DissimilarityMeasures.TensorDis.SpectralS(A1, A2); 69 | 70 | %% Controllability 71 | -------------------------------------------------------------------------------- /Tests/metrics.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.append('../') 3 | from HAT import Hypergraph, laplacian 4 | import numpy as np 5 | import unittest 6 | import logging 7 | 8 | class metric_tests(unittest.TestCase): 9 | 10 | def test_matrix_entropy(self): 11 | pass 12 | 13 | 14 | 15 | def test_avgerage_distance(self): 16 | pass 17 | 18 | 19 | 20 | def test_clustering_coefficient(self): 21 | pass 22 | 23 | 24 | 25 | def test_nonlinear_eigenvector_centrality(self): 26 | pass 27 | 28 | if __name__ == '__main__': 29 | unittest.main() 30 | -------------------------------------------------------------------------------- /Tests/run_tests.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | from concurrent.futures import ThreadPoolExecutor 3 | 4 | print('Executing: run_tests.py') 5 | 6 | # Define the test commands 7 | test_commands = [ 8 | ["python", "-m", "unittest", "-v", "./Tests/hypergraph_constructors.py"], 9 | ["python", "-m", "unittest", "-v", "./Tests/control_can.py"], 10 | ["python", "-m", "unittest", "-v", "./Tests/laplacians.py"], 11 | ] 12 | 13 | # Function to run a test command 14 | def run_test(command): 15 | subprocess.run(command) 16 | 17 | # Run the tests simultaneously using ThreadPoolExecutor 18 | with ThreadPoolExecutor() as executor: 19 | executor.map(run_test, test_commands) 20 | -------------------------------------------------------------------------------- /demos/MATLAB Documentation/IntroToHAT.asv: -------------------------------------------------------------------------------- 1 | % Constructor 2 | I = randi([0,1], 5, 10) 3 | HG = Hypergraph('IM',I) 4 | 5 | % Visualize 6 | p = HG.plot() 7 | 8 | % Tensor representations 9 | I = [1 1 1 0; 10 | 1 1 0 1; 11 | 1 0 1 1; 12 | 0 1 1 1]; 13 | 14 | HG = Hypergraph('IM',I) 15 | A = HG.adjTensor 16 | D = HG.degreeTensor 17 | L = HG.laplacianTensor 18 | 19 | % Graph Expansions 20 | I = [1 1 1 0; 21 | 1 1 0 1; 22 | 1 0 1 1] 23 | HG = Hypergraph('IM',I) 24 | 25 | C = full(HG.cliqueGraph()) 26 | S = full(HG.starGraph()) 27 | L = full(HG.lineGraph()) 28 | 29 | % Laplacians 30 | [A1, L1] = (HG.laplacianMatrix("Bolla")) 31 | [A2, L2] = (HG.laplacianMatrix("Rodriguez")) 32 | [A3, L3] = (HG.laplacianMatrix("Zhou")) 33 | 34 | % Hypergraph Similarity 35 | HG1 = HAT.uniformErdosRenyi(6,8,3); 36 | HG2 = HAT.uniformErdosRenyi(6,8,3); 37 | 38 | D1 = HAT.directSimilarity(HG1,HG2,'Hamming') 39 | D2 = HAT.directSimilarity(HG1,HG2,'Spectral-S') 40 | D3 = HAT.directSimilarity(HG1,HG2,'Spectral-H') 41 | D4 = HAT.directSimilarity(HG1,HG2,'Centrality') 42 | 43 | A1 = HG1.cliqueGraph(); 44 | A2 = HG2.cliqueGraph(); 45 | 46 | ID1 = HAT.indirectSimilarity(A1, A2, 'type', 'centrality') 47 | ID2 = HAT.indirectSimilarity(A1, A2, 'type', 'Hamming') 48 | ID3 = HAT.indirectSimilarity(A1, A2, 'type', 'Jaccard') 49 | ID4 = HAT.indirectSimilarity(A1, A2, 'type', 'deltaCon') 50 | ID5 = HAT.indirectSimilarity(A1, A2, 'type', 'heatKer') 51 | ID6 = HAT.indirectSimilarity(A1, A2, 'type', 'spanTree') 52 | ID7 = HAT.indirectSimilarity(A1, A2, 'type', 'Spectral') 53 | 54 | % Entropy 55 | HG = HAT.uniformErdosRenyi(6,8,3); 56 | E = HG.tensorEntropy() 57 | M = HG.matrixEntropy() 58 | 59 | % Controllability 60 | I = randi([0,1], 5, 10); 61 | HG = Hypergraph('IM',I); 62 | B = HAT.ctrbk(HG,[1]) 63 | 64 | % Other Properties 65 | HG = HAT.uniformErdosRenyi(6,8,3); 66 | avg = HG.avgDistance 67 | clusterCoef = HG.clusteringCoef 68 | centrality = HAT.centrality(HG) 69 | 70 | %% Python Comparison 71 | IM = [1 1 0; 72 | 1 1 0; 73 | 1 0 1; 74 | 0 1 1; 75 | 0 0 1]; 76 | HG = Hypergraph('IM',IM) 77 | [A1, L1] = (HG.laplacianMatrix("Bolla")) 78 | [A2, L2] = (HG.laplacianMatrix("Rodriguez")) 79 | [A3, L3] = (HG.laplacianMatrix("Zhou")) 80 | 81 | A = HG.adjTensor 82 | HAT.directSimilarity(HG, HG, 'Spectral-S') 83 | 84 | %% Doc 2 85 | % 1. Construction 86 | IM = [1 1 0; 87 | 1 1 0; 88 | 1 0 1; 89 | 0 1 1; 90 | 0 0 1]; 91 | HG = Hypergraph('IM',IM) 92 | 93 | % 2. Visualization 94 | HG.plot() 95 | 96 | % 3. Expansion 97 | C = HG.cliqueGraph; 98 | figure; plot(graph(C)); 99 | title('Clique Expansion'); 100 | 101 | S = HG.starGraph; 102 | figure; plot(graph(S)); 103 | title('Star Expansion'); 104 | 105 | % 4. Structural Properties 106 | avgDist = HG.avgDistance 107 | clusterCoef = HG.clusteringCoef 108 | C = HG.centrality() 109 | 110 | % 5. Similarity 111 | IM = [1 1 0; 112 | 0 1 1; 113 | 1 0 0; 114 | 0 1 1; 115 | 1 0 1]; 116 | HG2 = Hypergraph('IM',IM) 117 | D1 = HAT.directSimilarity(HG, HG2, 'Hamming') 118 | D2 = HAT.directSimilarity(HG, HG2, 'Centrality') 119 | D3 = HAT.directSimilarity(HG, HG2, 'Spectral-S') 120 | D4 = HAT.directSimilarity(HG, HG2, 'Spectral-H') 121 | 122 | I1 = HAT.indirectSimilarity(HG.cliqueGraph, HG2.cliqueGraph, "type",1) 123 | 124 | % 6. Controllability 125 | B = HG.ctrbk([1 3]) 126 | 127 | % 7. Multicorrelation 128 | % 6 rvars. 8 measurements 129 | D = rand(8, 6); 130 | [M, sets] = HAT.multicorrelations(D, 3, 'Drezner'); 131 | 132 | -------------------------------------------------------------------------------- /demos/MATLAB Documentation/IntroToHAT.m: -------------------------------------------------------------------------------- 1 | % Constructor 2 | I = randi([0,1], 5, 10) 3 | HG = Hypergraph('IM',I) 4 | 5 | % Visualize 6 | p = HG.plot() 7 | 8 | % Tensor representations 9 | I = [1 1 1 0; 10 | 1 1 0 1; 11 | 1 0 1 1; 12 | 0 1 1 1]; 13 | 14 | HG = Hypergraph('IM',I) 15 | A = HG.adjTensor 16 | D = HG.degreeTensor 17 | L = HG.laplacianTensor 18 | 19 | % Graph Expansions 20 | I = [1 1 1 0; 21 | 1 1 0 1; 22 | 1 0 1 1] 23 | HG = Hypergraph('IM',I) 24 | 25 | C = full(HG.cliqueGraph()) 26 | S = full(HG.starGraph()) 27 | L = full(HG.lineGraph()) 28 | 29 | % Laplacians 30 | [A1, L1] = (HG.laplacianMatrix("Bolla")) 31 | [A2, L2] = (HG.laplacianMatrix("Rodriguez")) 32 | [A3, L3] = (HG.laplacianMatrix("Zhou")) 33 | 34 | % Hypergraph Similarity 35 | HG1 = HAT.uniformErdosRenyi(6,8,3); 36 | HG2 = HAT.uniformErdosRenyi(6,8,3); 37 | 38 | D1 = HAT.directSimilarity(HG1,HG2,'Hamming') 39 | D2 = HAT.directSimilarity(HG1,HG2,'Spectral-S') 40 | D3 = HAT.directSimilarity(HG1,HG2,'Spectral-H') % Not implemented in Python 41 | D4 = HAT.directSimilarity(HG1,HG2,'Centrality') 42 | 43 | A1 = HG1.cliqueGraph(); 44 | A2 = HG2.cliqueGraph(); 45 | 46 | ID1 = HAT.indirectSimilarity(A1, A2, 'type', 'centrality') 47 | ID2 = HAT.indirectSimilarity(A1, A2, 'type', 'Hamming') 48 | ID3 = HAT.indirectSimilarity(A1, A2, 'type', 'Jaccard') 49 | ID4 = HAT.indirectSimilarity(A1, A2, 'type', 'deltaCon') 50 | ID5 = HAT.indirectSimilarity(A1, A2, 'type', 'heatKer') 51 | ID6 = HAT.indirectSimilarity(A1, A2, 'type', 'spanTree') 52 | ID7 = HAT.indirectSimilarity(A1, A2, 'type', 'Spectral') 53 | 54 | % Entropy 55 | HG = HAT.uniformErdosRenyi(6,8,3); 56 | E = HG.tensorEntropy() 57 | M = HG.matrixEntropy() 58 | 59 | % Controllability 60 | I = randi([0,1], 5, 10); 61 | HG = Hypergraph('IM',I); 62 | B = HAT.ctrbk(HG,[1]) 63 | 64 | % Other Properties 65 | HG = HAT.uniformErdosRenyi(6,8,3); 66 | avg = HG.avgDistance 67 | clusterCoef = HG.clusteringCoef 68 | centrality = HAT.centrality(HG) 69 | 70 | %% Python Comparison 71 | IM = [1 1 0; 72 | 1 1 0; 73 | 1 0 1; 74 | 0 1 1; 75 | 0 0 1]; 76 | HG = Hypergraph('IM',IM) 77 | [A1, L1] = (HG.laplacianMatrix("Bolla")) 78 | [A2, L2] = (HG.laplacianMatrix("Rodriguez")) 79 | [A3, L3] = (HG.laplacianMatrix("Zhou")) 80 | 81 | A = HG.adjTensor 82 | HAT.directSimilarity(HG, HG, 'Spectral-S') 83 | 84 | %% Doc 2 85 | % 1. Construction 86 | IM = [1 1 0; 87 | 1 1 0; 88 | 1 0 1; 89 | 0 1 1; 90 | 0 0 1]; 91 | HG = Hypergraph('IM',IM) 92 | 93 | % 2. Visualization 94 | HG.plot() 95 | 96 | % 3. Expansion 97 | C = HG.cliqueGraph; 98 | figure; plot(graph(C)); 99 | title('Clique Expansion'); 100 | 101 | S = HG.starGraph; 102 | figure; plot(graph(S)); 103 | title('Star Expansion'); 104 | 105 | % 4. Structural Properties 106 | avgDist = HG.avgDistance 107 | clusterCoef = HG.clusteringCoef 108 | C = HG.centrality() 109 | 110 | % 5. Similarity 111 | IM = [1 1 0; 112 | 0 1 1; 113 | 1 0 0; 114 | 0 1 1; 115 | 1 0 1]; 116 | HG2 = Hypergraph('IM',IM) 117 | D1 = HAT.directSimilarity(HG, HG2, 'Hamming') 118 | D2 = HAT.directSimilarity(HG, HG2, 'Centrality') 119 | D3 = HAT.directSimilarity(HG, HG2, 'Spectral-S') 120 | D4 = HAT.directSimilarity(HG, HG2, 'Spectral-H') 121 | 122 | I1 = HAT.indirectSimilarity(HG.cliqueGraph, HG2.cliqueGraph, "type",1) 123 | 124 | % 6. Controllability 125 | B = HG.ctrbk([1 3]) 126 | 127 | % 7. Multicorrelation 128 | % 6 rvars. 8 measurements 129 | D = rand(8, 6); 130 | [M, sets] = HAT.multicorrelations(D, 3, 'Drezner'); 131 | 132 | -------------------------------------------------------------------------------- /demos/MATLAB Documentation/Introduction.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/demos/MATLAB Documentation/Introduction.mlx -------------------------------------------------------------------------------- /demos/MATLAB Documentation/multicorrelation.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/demos/MATLAB Documentation/multicorrelation.mlx -------------------------------------------------------------------------------- /demos/Matlab Development Demos/Development Demo.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/demos/Matlab Development Demos/Development Demo.m -------------------------------------------------------------------------------- /demos/Matlab Development Demos/PHAT_application_note.m: -------------------------------------------------------------------------------- 1 | %% PHAT Application Note 2 | % 3 | % This file contains code used to generate figures for the Bioinformatics 4 | % PoreC Hypergraph Analysis Toolbox Application Note 5 | % 6 | % Auth: Joshua Pickard 7 | % jpic@umich.edu 8 | % Date: September 21, 2022 9 | 10 | %% Preamble 11 | clear all 12 | 13 | %% 14 | 15 | I = randi([0 1], 10, 15) 16 | H = Hypergraph('H', I) 17 | ax = figure; 18 | PlotIM.plotIncidenceMatrix(H, ax) 19 | -------------------------------------------------------------------------------- /demos/Matlab Development Demos/sample_incidence_matrix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/demos/Matlab Development Demos/sample_incidence_matrix.png -------------------------------------------------------------------------------- /demos/Matlab Documentation Examples/IntroToHAT.m: -------------------------------------------------------------------------------- 1 | % Constructor 2 | I = randi([0,1], 5, 10) 3 | HG = Hypergraph('IM',I) 4 | 5 | % Visualize 6 | p = HG.plot() 7 | 8 | % Tensor representations 9 | I = [1 1 1 0; 10 | 1 1 0 1; 11 | 1 0 1 1; 12 | 0 1 1 1]; 13 | 14 | HG = Hypergraph('IM',I) 15 | A = HG.adjTensor 16 | D = HG.degreeTensor 17 | L = HG.laplacianTensor 18 | 19 | % Graph Expansions 20 | I = [1 1 1 0; 21 | 1 1 0 1; 22 | 1 0 1 1] 23 | HG = Hypergraph('IM',I) 24 | 25 | C = full(HG.cliqueGraph()) 26 | S = full(HG.starGraph()) 27 | L = full(HG.lineGraph()) 28 | 29 | % Laplacians 30 | [A1, L1] = (HG.laplacianMatrix("Bolla")) 31 | [A2, L2] = (HG.laplacianMatrix("Rodriguez")) 32 | [A3, L3] = (HG.laplacianMatrix("Zhou")) 33 | 34 | % Hypergraph Similarity 35 | HG1 = HAT.uniformErdosRenyi(6,8,3); 36 | HG2 = HAT.uniformErdosRenyi(6,8,3); 37 | 38 | D1 = HAT.directSimilarity(HG1,HG2,'Hamming') 39 | D2 = HAT.directSimilarity(HG1,HG2,'Spectral-S') 40 | D3 = HAT.directSimilarity(HG1,HG2,'Spectral-H') % Not implemented in Python 41 | D4 = HAT.directSimilarity(HG1,HG2,'Centrality') 42 | 43 | A1 = HG1.cliqueGraph(); 44 | A2 = HG2.cliqueGraph(); 45 | 46 | ID1 = HAT.indirectSimilarity(A1, A2, 'type', 'centrality') 47 | ID2 = HAT.indirectSimilarity(A1, A2, 'type', 'Hamming') 48 | ID3 = HAT.indirectSimilarity(A1, A2, 'type', 'Jaccard') 49 | ID4 = HAT.indirectSimilarity(A1, A2, 'type', 'deltaCon') 50 | ID5 = HAT.indirectSimilarity(A1, A2, 'type', 'heatKer') 51 | ID6 = HAT.indirectSimilarity(A1, A2, 'type', 'spanTree') 52 | ID7 = HAT.indirectSimilarity(A1, A2, 'type', 'Spectral') 53 | 54 | % Entropy 55 | HG = HAT.uniformErdosRenyi(6,8,3); 56 | E = HG.tensorEntropy() 57 | M = HG.matrixEntropy() 58 | 59 | % Controllability 60 | I = randi([0,1], 5, 10); 61 | HG = Hypergraph('IM',I); 62 | B = HAT.ctrbk(HG,[1]) 63 | 64 | % Other Properties 65 | HG = HAT.uniformErdosRenyi(6,8,3); 66 | avg = HG.avgDistance 67 | clusterCoef = HG.clusteringCoef 68 | centrality = HAT.centrality(HG) 69 | 70 | %% Python Comparison 71 | IM = [1 1 0; 72 | 1 1 0; 73 | 1 0 1; 74 | 0 1 1; 75 | 0 0 1]; 76 | HG = Hypergraph('IM',IM) 77 | [A1, L1] = (HG.laplacianMatrix("Bolla")) 78 | [A2, L2] = (HG.laplacianMatrix("Rodriguez")) 79 | [A3, L3] = (HG.laplacianMatrix("Zhou")) 80 | 81 | A = HG.adjTensor 82 | HAT.directSimilarity(HG, HG, 'Spectral-S') 83 | 84 | %% Doc 2 85 | % 1. Construction 86 | IM = [1 1 0; 87 | 1 1 0; 88 | 1 0 1; 89 | 0 1 1; 90 | 0 0 1]; 91 | HG = Hypergraph('IM',IM) 92 | 93 | % 2. Visualization 94 | HG.plot() 95 | 96 | % 3. Expansion 97 | C = HG.cliqueGraph; 98 | figure; plot(graph(C)); 99 | title('Clique Expansion'); 100 | 101 | S = HG.starGraph; 102 | figure; plot(graph(S)); 103 | title('Star Expansion'); 104 | 105 | % 4. Structural Properties 106 | avgDist = HG.avgDistance 107 | clusterCoef = HG.clusteringCoef 108 | C = HG.centrality() 109 | 110 | % 5. Similarity 111 | IM = [1 1 0; 112 | 0 1 1; 113 | 1 0 0; 114 | 0 1 1; 115 | 1 0 1]; 116 | HG2 = Hypergraph('IM',IM) 117 | D1 = HAT.directSimilarity(HG, HG2, 'Hamming') 118 | D2 = HAT.directSimilarity(HG, HG2, 'Centrality') 119 | D3 = HAT.directSimilarity(HG, HG2, 'Spectral-S') 120 | D4 = HAT.directSimilarity(HG, HG2, 'Spectral-H') 121 | 122 | I1 = HAT.indirectSimilarity(HG.cliqueGraph, HG2.cliqueGraph, "type",1) 123 | 124 | % 6. Controllability 125 | B = HG.ctrbk([1 3]) 126 | 127 | % 7. Multicorrelation 128 | % 6 rvars. 8 measurements 129 | D = rand(8, 6); 130 | [M, sets] = HAT.multicorrelations(D, 3, 'Drezner'); 131 | 132 | -------------------------------------------------------------------------------- /demos/Matlab Documentation Examples/Introduction.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/demos/Matlab Documentation Examples/Introduction.mlx -------------------------------------------------------------------------------- /demos/Matlab Documentation Examples/multicorrelation.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/demos/Matlab Documentation Examples/multicorrelation.mlx -------------------------------------------------------------------------------- /demos/Python Documentation/Introduction.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "2f48ab21-01a8-4770-8d61-da411d535187", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import HAT\n", 11 | "import numpy as np\n", 12 | "import scipy as sp\n", 13 | "import networkx as nx" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 2, 19 | "id": "5f7f0aff-3e60-43d8-ae1f-ea6698a6a27d", 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "W = np.random.randint(2,size=(15,20))" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 3, 29 | "id": "fb09d24d-3faf-4517-8b6a-198d5bf42e4c", 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "W = np.random.randint(2,size=(15,20))\n", 34 | "HG = HAT.Hypergraph(W)\n", 35 | "# HG.draw()" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": 4, 41 | "id": "e8865cc0-df39-4607-89e8-a99a4eb027bf", 42 | "metadata": {}, 43 | "outputs": [], 44 | "source": [ 45 | "# HAT.draw.incidencePlot(HG)" 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": 5, 51 | "id": "e3a0e75a-85c3-405b-9565-45063d7b9ad4", 52 | "metadata": {}, 53 | "outputs": [], 54 | "source": [ 55 | "I = np.array([[1, 1, 1, 0],\n", 56 | " [1, 1, 0, 1],\n", 57 | " [1, 0, 1, 1],\n", 58 | " [0, 1, 1, 1]])\n", 59 | "\n", 60 | "HG = HAT.Hypergraph(I)\n", 61 | "A = HG.adjTensor()\n", 62 | "D = HG.degreeTensor()\n", 63 | "L = HG.laplacianTensor()" 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": 6, 69 | "id": "b5cb7bba-0749-4fe7-b78a-3a2e2db1b4c4", 70 | "metadata": {}, 71 | "outputs": [], 72 | "source": [ 73 | "I = np.array([[1, 1, 1, 0],\n", 74 | " [1, 1, 0, 1],\n", 75 | " [1, 0, 1, 1]])\n", 76 | "HG = HAT.Hypergraph(I)\n", 77 | "C = HG.cliqueGraph()\n", 78 | "L = HG.lineGraph()\n", 79 | "S = HG.starGraph()" 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": 7, 85 | "id": "f7592cd3-917e-4ff5-947c-a097ddbc71bc", 86 | "metadata": {}, 87 | "outputs": [], 88 | "source": [ 89 | "B = HG.laplacianMatrix(\"Bolla\")\n", 90 | "R = HG.laplacianMatrix(\"Rodriguez\")\n", 91 | "Z = HG.laplacianMatrix(\"Zhou\")" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": 8, 97 | "id": "b1f2ea60-7b32-471e-9b17-6904f05b3f7d", 98 | "metadata": {}, 99 | "outputs": [], 100 | "source": [ 101 | "HG1 = HAT.uniformErdosRenyi(6,4,3)\n", 102 | "HG2 = HAT.uniformErdosRenyi(6,4,3)" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": 9, 108 | "id": "524e1a82-dc4e-478b-86b7-f52d5e78a170", 109 | "metadata": {}, 110 | "outputs": [ 111 | { 112 | "name": "stdout", 113 | "output_type": "stream", 114 | "text": [ 115 | "0.12380952380952381\n", 116 | "4.8936807962684945\n", 117 | "0.11292370628198518\n" 118 | ] 119 | } 120 | ], 121 | "source": [ 122 | "D1 = HAT.directSimilarity(HG1, HG2, 'Hamming')\n", 123 | "print(D1)\n", 124 | "D2 = HAT.directSimilarity(HG1, HG2, 'Spectral-S')\n", 125 | "print(D2)\n", 126 | "D3 = HAT.directSimilarity(HG1, HG2, 'centrality')\n", 127 | "print(D3)" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": 10, 133 | "id": "64959810-22d2-4bfb-807d-6288f08b941f", 134 | "metadata": {}, 135 | "outputs": [ 136 | { 137 | "name": "stdout", 138 | "output_type": "stream", 139 | "text": [ 140 | "0.26666666666666666\n", 141 | "0.8571428571428572\n", 142 | "0.015531368962205985\n", 143 | "0.24049759969471576\n" 144 | ] 145 | } 146 | ], 147 | "source": [ 148 | "G1 = HG1.cliqueGraph()\n", 149 | "G2 = HG2.cliqueGraph()\n", 150 | "\n", 151 | "D1 = HAT.indirectSimilarity(G1, G2, 'Hamming')\n", 152 | "D2 = HAT.indirectSimilarity(G1, G2, 'Jaccard')\n", 153 | "D3 = HAT.indirectSimilarity(G1, G2, 'deltaCon')\n", 154 | "D4 = HAT.indirectSimilarity(G1, G2, 'Spectral')\n", 155 | "# Centrality D5 = HAT.indirectSimilarity(G1, G2, 'Jaccard')\n", 156 | "# D6 = HAT.indirectSimilarity(G1, G2, 'Jaccard')\n", 157 | "print(D1)\n", 158 | "print(D2)\n", 159 | "print(D3)\n", 160 | "print(D4)\n", 161 | "\n" 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": 12, 167 | "id": "a2d34a7c-a353-453c-a20b-489fe8097621", 168 | "metadata": {}, 169 | "outputs": [ 170 | { 171 | "name": "stdout", 172 | "output_type": "stream", 173 | "text": [ 174 | "2.2068854769292123\n", 175 | "-inf\n", 176 | "0.4503571428571428\n", 177 | "1.5777777777777777\n" 178 | ] 179 | } 180 | ], 181 | "source": [ 182 | "HG = HAT.uniformErdosRenyi(10,9,3)\n", 183 | "print(HG.tensorEntropy())\n", 184 | "print(HG.matrixEntropy())\n", 185 | "print(HG.clusteringCoef())\n", 186 | "print(HG.avgDistance())" 187 | ] 188 | }, 189 | { 190 | "cell_type": "code", 191 | "execution_count": 30, 192 | "id": "816e5e5f-f72c-4ae0-8998-e66f1c32de32", 193 | "metadata": {}, 194 | "outputs": [ 195 | { 196 | "data": { 197 | "text/plain": [ 198 | "(array([0.10499828, 0.112828 , 0.09487666, 0.09487666, 0.12486471,\n", 199 | " 0.112828 , 0.10499828, 0.12486471, 0.12486471]),\n", 200 | " array([0.11111111, 0.11111111, 0.11111111, 0.11111111, 0.11111111,\n", 201 | " 0.11111111, 0.11111111, 0.11111111, 0.11111111]))" 202 | ] 203 | }, 204 | "execution_count": 30, 205 | "metadata": {}, 206 | "output_type": "execute_result" 207 | } 208 | ], 209 | "source": [ 210 | "HG = HAT.uniformErdosRenyi(9,9,4)\n", 211 | "HG.centrality(model='LogExp')" 212 | ] 213 | }, 214 | { 215 | "cell_type": "code", 216 | "execution_count": 31, 217 | "id": "20a9ef4a-c5de-47b4-a196-b1c04214242a", 218 | "metadata": {}, 219 | "outputs": [ 220 | { 221 | "name": "stdout", 222 | "output_type": "stream", 223 | "text": [ 224 | "(9, 2)\n", 225 | "(9, 10)\n", 226 | "(9, 2)\n", 227 | "(9, 10)\n", 228 | "(9, 2)\n", 229 | "(9, 10)\n", 230 | "(9, 2)\n", 231 | "(9, 10)\n", 232 | "(9, 2)\n", 233 | "(9, 10)\n", 234 | "(9, 2)\n", 235 | "(9, 10)\n", 236 | "(9, 2)\n", 237 | "(9, 10)\n", 238 | "(9, 2)\n", 239 | "(9, 10)\n", 240 | "(9, 2)\n", 241 | "(9, 10)\n", 242 | "(9, 2)\n" 243 | ] 244 | }, 245 | { 246 | "data": { 247 | "text/plain": [ 248 | "array([[ 0., 0.],\n", 249 | " [ 0., 1.],\n", 250 | " [ 0., 0.],\n", 251 | " [-1., 0.],\n", 252 | " [ 0., 0.],\n", 253 | " [ 0., 0.],\n", 254 | " [ 0., 0.],\n", 255 | " [ 0., 0.],\n", 256 | " [ 0., 0.]])" 257 | ] 258 | }, 259 | "execution_count": 31, 260 | "metadata": {}, 261 | "output_type": "execute_result" 262 | } 263 | ], 264 | "source": [ 265 | "B = HG.ctrbk([1, 3])\n", 266 | "B" 267 | ] 268 | }, 269 | { 270 | "cell_type": "code", 271 | "execution_count": null, 272 | "id": "eef9b16d-9d50-4988-b72f-e0291ce29d1a", 273 | "metadata": {}, 274 | "outputs": [], 275 | "source": [ 276 | "sp.stats.entropy(np.array([ 6.00000000e+00, -5.33573783e-16, 6.00000000e+00]))" 277 | ] 278 | }, 279 | { 280 | "cell_type": "code", 281 | "execution_count": null, 282 | "id": "b1845972-40d3-457a-a226-7ac635f2ea48", 283 | "metadata": {}, 284 | "outputs": [], 285 | "source": [ 286 | "D3 = HAT.indirectSimilarity(G1, G2, 'deltaCon')" 287 | ] 288 | }, 289 | { 290 | "cell_type": "code", 291 | "execution_count": null, 292 | "id": "d5d8d2d1-4a3a-4f0c-88cb-b9be24f4dbe7", 293 | "metadata": {}, 294 | "outputs": [], 295 | "source": [ 296 | "# HG1.degreeTensor()\n", 297 | "# order = int(sum(HG1.IM[:,0]))\n", 298 | "# np.ones(order)\n", 299 | "M1 = nx.adjacency_matrix(G1).todense()\n", 300 | "print(M1)\n", 301 | "D1 = np.diag(sum(M1))\n", 302 | "print(D1)" 303 | ] 304 | } 305 | ], 306 | "metadata": { 307 | "kernelspec": { 308 | "display_name": "Python 3 (ipykernel)", 309 | "language": "python", 310 | "name": "python3" 311 | }, 312 | "language_info": { 313 | "codemirror_mode": { 314 | "name": "ipython", 315 | "version": 3 316 | }, 317 | "file_extension": ".py", 318 | "mimetype": "text/x-python", 319 | "name": "python", 320 | "nbconvert_exporter": "python", 321 | "pygments_lexer": "ipython3", 322 | "version": "3.9.7" 323 | } 324 | }, 325 | "nbformat": 4, 326 | "nbformat_minor": 5 327 | } 328 | -------------------------------------------------------------------------------- /docs/.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the version of Python and other tools you might need 9 | build: 10 | os: ubuntu-22.04 11 | tools: 12 | python: "3.11" 13 | 14 | # Build documentation in the docs/ directory with Sphinx 15 | sphinx: 16 | configuration: docs/conf.py 17 | 18 | # We recommend specifying your dependencies to enable reproducible builds: 19 | # https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 20 | # python: 21 | # install: 22 | # - requirements: docs/requirements.txt 23 | -------------------------------------------------------------------------------- /docs/HAT.rst: -------------------------------------------------------------------------------- 1 | HAT Documentation 2 | ================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | Hypergraph Class 8 | --------------------- 9 | 10 | .. automodule:: HAT.hypergraph 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Graph Interface 16 | --------------------- 17 | 18 | .. automodule:: HAT.graph 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Hypergraph Metrics 24 | --------------------- 25 | 26 | .. automodule:: HAT.metrics 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | Dynamics and Control 32 | --------------------- 33 | 34 | .. automodule:: HAT.dynamics 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | Tensor Representations 40 | ---------------------- 41 | 42 | .. automodule:: HAT.tensors 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | Laplacians 48 | ---------------------- 49 | 50 | .. automodule:: HAT.laplacian 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | 55 | HAT.HAT module 56 | --------------- 57 | 58 | .. automodule:: HAT.HAT 59 | :members: 60 | :undoc-members: 61 | :show-inheritance: 62 | 63 | 64 | HAT.draw module 65 | --------------- 66 | 67 | .. automodule:: HAT.draw 68 | :members: 69 | :undoc-members: 70 | :show-inheritance: 71 | 72 | HAT.multilinalg module 73 | ---------------------- 74 | 75 | .. automodule:: HAT.multilinalg 76 | :members: 77 | :undoc-members: 78 | :show-inheritance: 79 | 80 | Bug Reporting 81 | ------------- 82 | Please report all bugs or defects in HAT to `this page `_. -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 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 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/_static/GC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/docs/_static/GC.png -------------------------------------------------------------------------------- /docs/_static/GH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/docs/_static/GH.png -------------------------------------------------------------------------------- /docs/_static/GL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/docs/_static/GL.png -------------------------------------------------------------------------------- /docs/_static/GS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/docs/_static/GS.png -------------------------------------------------------------------------------- /docs/_static/IncidenceMatrix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/docs/_static/IncidenceMatrix.png -------------------------------------------------------------------------------- /docs/_static/index_dyadic_decomp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/docs/_static/index_dyadic_decomp.png -------------------------------------------------------------------------------- /docs/_static/vis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jpickard1/Hypergraph-Analysis-Toolbox/7bcd0d57d130aa20db76d7ae385b82b7e96e46a2/docs/_static/vis.png -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | sys.path.insert(0, os.path.abspath('../HAT/')) 4 | sys.path.insert(0, os.path.abspath('..')) 5 | 6 | import mock 7 | 8 | MOCK_MODULES = ['numpy', 9 | 'scipy', 10 | 'scipy.io', 11 | 'scipy.spatial' 12 | 'matplotlib', 13 | 'matplotlib.pyplot', 14 | 'scipy.linalg', 15 | 'networkx', 16 | 'pandas', 17 | 'pd', 18 | 'np', 19 | 'sp' 20 | ] 21 | for mod_name in MOCK_MODULES: 22 | sys.modules[mod_name] = mock.Mock() 23 | 24 | # import HAT.HAT 25 | # import HAT.Hypergraph 26 | # import HAT.multilinalg 27 | # import HAT.draw 28 | # import Hypergraph 29 | # from HAT.HAT import * 30 | 31 | # Configuration file for the Sphinx documentation builder. 32 | # 33 | # For the full list of built-in configuration values, see the documentation: 34 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 35 | 36 | # -- Project information ----------------------------------------------------- 37 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 38 | 39 | project = 'Hypergraph Analysis Toolbox' 40 | copyright = '2022, Joshua Pickard' 41 | author = 'Joshua Pickard' 42 | release = '0.0.1' 43 | 44 | # -- General configuration --------------------------------------------------- 45 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 46 | 47 | extensions = [ 48 | 'sphinx.ext.autosummary', 49 | 'sphinx.ext.autodoc', 50 | 'sphinx.ext.autosummary', 51 | 'sphinx.ext.mathjax', 52 | 'sphinx.ext.viewcode', 53 | 'sphinx.ext.napoleon', 54 | 'sphinx.ext.intersphinx', 55 | 'sphinx.ext.extlinks' 56 | ] 57 | 58 | templates_path = ['_templates'] 59 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 60 | 61 | autodoc_member_order = 'bysource' # Order documentation by order of code in file 62 | 63 | # -- Options for HTML output ------------------------------------------------- 64 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 65 | 66 | html_theme = 'sphinx_rtd_theme' 67 | html_static_path = ['_static'] 68 | -------------------------------------------------------------------------------- /docs/dev.rst: -------------------------------------------------------------------------------- 1 | Development 2 | =========== 3 | 4 | This page contains the goals for the next version of HAT. To contribute, for information on the below, or to request specific features in HAT, please contact us at jpic@umich.edu 5 | 6 | Software Development 7 | ******************** 8 | 1. Automated testing of software 9 | 2. Increased number of tutorial 10 | 3. Increased number of hypergraph visualization methods 11 | 4. Add hyperlink prediction module 12 | 5. Include built-in hypergraphs 13 | 14 | Hypergraph Methods Development 15 | ****************************** 16 | 1. Directed hypergraphs 17 | 2. Nonuniform hypergraphs 18 | 3. Large hypergraph constructions 19 | 20 | Bug Reporting 21 | ------------- 22 | Please report all bugs or defects in HAT to `this page `_. -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. Hypergraph Analysis Toolbox documentation master file, created by 2 | sphinx-quickstart on Mon Oct 3 14:52:46 2022. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Hypergraph Analysis Toolbox 7 | =========================== 8 | 9 | .. image:: _static/index_dyadic_decomp.png 10 | :align: center 11 | 12 | Introduction 13 | ============ 14 | Hypergraph Analysis Toolbox (HAT) is a software suite for the analysis and visualization of hypergraphs and 15 | higher order structures. Motivated to investigate Pore-C data, HAT is intended as a general prupose, versatile 16 | software for hypergraph construction, visualization, and analysis. HAT addresses the following hypergraph 17 | problems: 18 | 19 | 1. Construction 20 | 2. Visualization 21 | 3. Expansion and numeric representation 22 | 4. Structral Properties 23 | 5. Controllability 24 | 6. Similarity Measures 25 | 26 | The capabilities and use cases of HAT are outlined in `this notice `_. 27 | 28 | Contributors 29 | ************ 30 | Joshua Pickard, Can Chen, Rahmy Salman, Cooper Stansbury, Sion Kim, Amit Surana, Anthony Bloch, and Indika Rajapakse 31 | 32 | Bug Reporting 33 | ------------- 34 | Please report all bugs or defects in HAT to `this page `_. 35 | 36 | 37 | .. toctree:: 38 | :maxdepth: 2 39 | :caption: Contents: 40 | 41 | install.rst 42 | tutorials.rst 43 | HAT.rst 44 | dev.rst 45 | ref.rst 46 | 47 | Indices and tables 48 | ================== 49 | 50 | * :ref:`genindex` 51 | * :ref:`modindex` 52 | * :ref:`search` 53 | -------------------------------------------------------------------------------- /docs/install.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | 4 | An instillation guide for the MATLAB, Python, and Development versions of HAT is available here. 5 | 6 | Python Distribution 7 | ******************* 8 | 9 | The `Python distribution `_ of HAT may be installed through pip: 10 | 11 | .. code-block:: Python 12 | 13 | >> pip install HypergraphAnalysisToolbox 14 | 15 | Once installed, HAT may be imported into the Python environment with the command: 16 | 17 | .. code-block:: Python 18 | 19 | import HAT 20 | 21 | The Python distribution has the following dependencies: 22 | 23 | 1. numpy 24 | 2. scipy 25 | 3. matplotlib 26 | 4. itertools 27 | 5. networkx 28 | 29 | MATLAB Distribution 30 | ******************* 31 | 32 | The MATLAB distribution of HAT can be installed through either the `MATLAB Central `_. A MathWorks :code:`.mltbx` file can be downloaded from the site, 33 | and installed through the add on manager in the MATLAB Home environment. Once installed as a toolbox, you will have access to all HAT functionality. 34 | 35 | The MATLAB distribution has the following dependencies which need to be installed separately: 36 | 37 | 1. `TenEig — Tensor Eigenpairs Solver `_ 38 | 39 | Development Distribution 40 | ************************ 41 | 42 | All implementations of HAT are managed through a `common git repository `_. This is public, so it may be 43 | cloned and modified. If interested in modifying or contributing to HAT, please see information on the Development page and contact Joshua Pickard at jpic@umich.edu. 44 | 45 | Bug Reporting 46 | ------------- 47 | Please report all bugs or defects in HAT to `this page `_. -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/ref.rst: -------------------------------------------------------------------------------- 1 | References 2 | ===================== 3 | 4 | - Amit Surana, Can Chen, and Indika Rajapakse. Hypergraph similarity measures. IEEE Transactions on Network Science and Engineering, pages 1-16, 2022. 5 | - Zvi Drezner. Multirelation—a correlation among more than two variables. Computational Statistics & Data Analysis, 19(3):283–292, 1995. 6 | - Jianji Wang and Nanning Zheng. Measures of correlation for multiple variables. arXiv preprint arXiv:1401.4827, 2014. 7 | - Benjamin M Taylor. A multi-way correlation coefficient. arXiv preprint arXiv:2003.02561, 2020. 8 | - Yang, Chaoqi, et al. "Hypergraph learning with line expansion." arXiv preprint arXiv:2005.04843 (2020). 9 | - Bolla, M. (1993). Spectra, euclidean representations and clusterings of hypergraphs. Discrete Mathematics, 117. https://www.sciencedirect.com/science/article/pii/0012365X9390322K 10 | - Rodriguez, J. A. (2002). On the Laplacian eigenvalues and metric parameters of hypergraphs. Linear and Multilinear Algebra, 50(1), 1-14. https://www.tandfonline.com/doi/abs/10.1080/03081080290011692 11 | - Rodriguez, J. A. (2003). On the Laplacian spectrum and walk-regular hypergraphs. Linear and Multilinear Algebra, 51, 285–297. https://www.tandfonline.com/doi/abs/10.1080/0308108031000084374 12 | - Zhou, D., Huang, J., & Schölkopf, B. (2005). Beyond pairwise classification and clustering using hypergraphs. (Equation 3.3) https://dennyzhou.github.io/papers/hyper_tech.pdf 13 | - Can Chen and Indika Rajapakse. Tensor Entropy for Uniform Hypergraphs. IEEE TRANSACTIONS ON NETWORK SCIENCE AND ENGINEERING (2020) https://arxiv.org/pdf/1912.09624.pdf 14 | - Chen C, Surana A, Bloch A, Rajapakse I. "Controllability of Hypergraphs." IEEE Transactions on Network Science and Engineering, 2021. https://drive.google.com/file/d/12aReE7mE4MVbycZUxUYdtICgrAYlzg8o/view 15 | - Tudisco, F., Higham, D.J. Node and edge nonlinear eigenvector centrality for hypergraphs. Commun Phys 4, 201 (2021). https://doi.org/10.1038/s42005-021-00704-2 16 | - Joshua Pickard, Amit Surana, Anthony Bloch, and Indika Rajapakse. Observability of Hypergraphs. arXiv preprint arXiv:2304.04883 (2023). https://arxiv.org/pdf/2304.04883.pdf 17 | 18 | 19 | Bug Reporting 20 | ------------- 21 | Please report all bugs or defects in HAT to `this page `_. 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /docs/tutorials.rst: -------------------------------------------------------------------------------- 1 | Tutorials 2 | ========= 3 | 4 | This page contains a series of tutorials for using HAT. Every tutorial is available in both Python and MATLAB. 5 | 6 | Python 7 | ****** 8 | 9 | Each Python tutorial open as a Google CoLab notebook and can be run online. You need to be logged into a google account in order to 10 | access the notebooks. The links below may open to seemingly large .txt documents, in which case there will be a button near the top 11 | to open the links in CoLab. Additionally, the tutorials can be downloaded from the links and run locally as a jupyter notebook as well. 12 | 13 | 1. `Introduction to HAT in Python `_ 14 | 2. `Constructing Hypergraphs from Multicorrealtions `_ 15 | 16 | MATLAB 17 | ****** 18 | 19 | Each MATLAB tutorial opens to MATLAB Online. If you have a MATLAB account you can run it online. Otherwise, you can download the tutorial file from MATLAB Online and run it as a live script locally. 20 | 21 | 1. `Introduction to HAT in MATLAB `_ 22 | 2. `Constructing Hypergraphs from Multicorrealtions `_ 23 | 24 | Bug Reporting 25 | ------------- 26 | Please report all bugs or defects in HAT to `this page `_. -------------------------------------------------------------------------------- /increment_version.py: -------------------------------------------------------------------------------- 1 | # increment_version.py 2 | import os 3 | import toml 4 | from pathlib import Path 5 | 6 | def increment_version(file_path: str): 7 | ''' 8 | This method updates the patch counter associated with the version of HAT. 9 | Python/pyproject.toml is updated, which contains metadata used for distribution 10 | by PYPI. 11 | ''' 12 | file = Path(file_path) 13 | data = toml.loads(file.read_text()) 14 | 15 | # Extract and increment version 16 | version_parts = data['project']['version'].split('.') 17 | version_parts[-1] = str(int(version_parts[-1]) + 1) 18 | data['project']['version'] = '.'.join(version_parts) 19 | 20 | # Write back updated version 21 | file.write_text(toml.dumps(data)) 22 | print(f"Version updated to {data['project']['version']}") 23 | 24 | if __name__ == "__main__": 25 | increment_version(os.path.join("Python", "pyproject.toml")) 26 | --------------------------------------------------------------------------------