├── .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 | [](https://hypergraph-analysis-toolbox.readthedocs.io/en/latest/?badge=latest)
4 | [](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 |
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 |
--------------------------------------------------------------------------------