├── .cargo └── config.toml ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yaml ├── labels.yaml ├── pull_request_template.md ├── settings.yaml └── workflows │ ├── book.yaml │ ├── release.yaml │ ├── rust.yaml │ └── sync_labels.yaml ├── .gitignore ├── .release-plz.toml ├── .rustfmt.toml ├── .taplo.toml ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── SUMMARY.md ├── book.toml ├── cova-algebra ├── .cargo │ └── config.toml ├── CHANGELOG.md ├── Cargo.toml ├── README.md ├── katex-header.html └── src │ ├── algebras │ ├── boolean.rs │ ├── clifford.rs │ └── mod.rs │ ├── arithmetic │ ├── mod.rs │ ├── modular.rs │ └── primitive.rs │ ├── category.rs │ ├── groups.rs │ ├── lib.rs │ ├── modules │ ├── mod.rs │ ├── trivial.rs │ └── tropical.rs │ ├── rings.rs │ └── tensors │ ├── dynamic │ ├── matrix.rs │ ├── mod.rs │ └── vector.rs │ ├── fixed.rs │ └── mod.rs ├── cova-space ├── .cargo │ └── config.toml ├── CHANGELOG.md ├── Cargo.toml ├── README.md ├── katex-header.html └── src │ ├── cloud.rs │ ├── complexes │ ├── cubical.rs │ ├── mod.rs │ └── simplicial.rs │ ├── definitions.rs │ ├── filtration │ ├── mod.rs │ └── vietoris_rips.rs │ ├── graph.rs │ ├── homology.rs │ ├── lattice.rs │ ├── lib.rs │ ├── set.rs │ └── sheaf.rs ├── cova ├── .cargo │ └── config.toml ├── CHANGELOG.md ├── Cargo.toml ├── README.md ├── katex-header.html └── src │ └── lib.rs ├── examples ├── README.md └── vietoris_web │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── build-optimized.sh │ ├── index.html │ └── src │ ├── lib.rs │ └── main.rs ├── justfile ├── katex-header.html └── rust-toolchain.toml /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | rustdocflags = ["--html-in-header", "./katex-header.html"] 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Report a bug to help us improve 4 | title: 'bug(area): brief description of the bug' 5 | labels: 'type: enhancement' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Title Format** 11 | Please use the following format for your title: 12 | ``` 13 | fix(area): brief description of the bug 14 | ``` 15 | Where `area` is one of: `algebra`, `space` 16 | 17 | **Describe the Bug** 18 | A clear and concise description of what the bug is. 19 | 20 | **To Reproduce** 21 | Steps to reproduce the behavior: 22 | 1. Use function/method '...' 23 | 2. With parameters '....' 24 | 3. See error 25 | 26 | **Expected Behavior** 27 | A clear and concise description of what you expected to happen. 28 | 29 | **Environment** 30 | - OS: [e.g. Ubuntu 20.04] 31 | - Rust Version: [e.g. 1.75.0] 32 | - Crate Version: [e.g. 0.1.0] 33 | 34 | **Additional Context** 35 | Add any other context about the problem here. 36 | 37 | **Labels to Consider** 38 | - `area: algebra` or `area: space` (based on affected component) 39 | - `priority: critical/high/medium/low` (based on impact) 40 | - `tech: performance` (if performance related) 41 | - `tech: security` (if security related) -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Suggest an idea for this project 4 | title: 'feat(area): brief description of the feature' 5 | labels: 'type: enhancement' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Title Format** 11 | Please use the following format for your title: 12 | ``` 13 | feat(area): brief description of the feature 14 | ``` 15 | Where `area` is one of: `algebra`, `space` 16 | 17 | **Feature Description** 18 | A clear and concise description of what you want to happen. 19 | 20 | **Motivation** 21 | Why is this feature needed? What problems does it solve? 22 | 23 | **Implementation Details** 24 | If applicable, describe the technical approach to implementing this feature: 25 | - [ ] Task 1 26 | - [ ] Task 2 27 | - [ ] Task 3 28 | 29 | **Dependencies** 30 | List any dependencies or prerequisites needed for this feature. 31 | 32 | **Additional Context** 33 | Add any other context or screenshots about the feature request here. 34 | 35 | **Labels to Consider** 36 | - `area: algebra` or `area: space` (based on component) 37 | - `priority: critical/high/medium/low` (based on importance) 38 | - `tech: performance` (if performance related) 39 | - `community: help-wanted` (if seeking contributors) -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "cargo" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | # Group all updates together 8 | groups: 9 | all-updates: 10 | patterns: 11 | - "*" 12 | # Specify rules for version updates 13 | open-pull-requests-limit: 10 14 | # Assign reviewers (optional) 15 | reviewers: 16 | - "autoparallel" 17 | # Labels for PRs (optional) 18 | labels: 19 | - "dependencies" 20 | - "automated pr" 21 | # Configure commit message 22 | commit-message: 23 | prefix: "chore" 24 | include: "scope" 25 | # Only allow certain update types (optional) 26 | allow: 27 | # Allow both direct and indirect updates for all packages 28 | - dependency-type: "all" -------------------------------------------------------------------------------- /.github/labels.yaml: -------------------------------------------------------------------------------- 1 | # Priority Levels (Red to Green) 2 | - name: "priority: critical" 3 | color: "b60205" 4 | description: "Must be addressed immediately" 5 | 6 | - name: "priority: high" 7 | color: "d93f0b" 8 | description: "High priority tasks" 9 | 10 | - name: "priority: medium" 11 | color: "fbca04" 12 | description: "Medium priority tasks" 13 | 14 | - name: "priority: low" 15 | color: "0e8a16" 16 | description: "Low priority tasks" 17 | 18 | # Areas of Codebase (Blues) 19 | - name: "area: algebra" 20 | color: "0052cc" 21 | description: "Algebra related changes" 22 | 23 | - name: "area: space" 24 | color: "006b75" 25 | description: "Space related changes" 26 | 27 | # Task Types (Purples) 28 | - name: "type: refactor" 29 | color: "6f42c1" 30 | description: "Code refactoring and restructuring" 31 | 32 | - name: "type: enhancement" 33 | color: "7057ff" 34 | description: "Improvements to existing features" 35 | 36 | - name: "type: maintenance" 37 | color: "8a63d2" 38 | description: "Maintenance and cleanup tasks" 39 | 40 | # Technical Categories (Oranges) 41 | - name: "tech: security" 42 | color: "d93f0b" 43 | description: "Security-related changes" 44 | 45 | - name: "tech: performance" 46 | color: "fbca04" 47 | description: "Performance improvements" 48 | 49 | - name: "tech: testing" 50 | color: "ff7619" 51 | description: "Testing related changes" 52 | 53 | # Process Labels (Greens) 54 | - name: "status: needs-review" 55 | color: "0e8a16" 56 | description: "Needs review from maintainers" 57 | 58 | - name: "status: blocked" 59 | color: "44cc11" 60 | description: "Blocked by other issues" 61 | 62 | - name: "status: in-progress" 63 | color: "1a7f37" 64 | description: "Currently being worked on" 65 | 66 | # Community Labels (Teals) 67 | - name: "community: good-first-issue" 68 | color: "008672" 69 | description: "Good for new contributors" 70 | 71 | - name: "community: help-wanted" 72 | color: "006b75" 73 | description: "Extra attention needed" 74 | 75 | # Documentation (Light Blue) 76 | - name: "docs" 77 | color: "0075ca" 78 | description: "Documentation updates" 79 | 80 | # Dependencies (Pink) 81 | - name: "dependencies" 82 | color: "cb7eed" 83 | description: "Dependency updates and maintenance" 84 | 85 | # CI/CD (Bright Green) 86 | - name: "ci/cd" 87 | color: "44cc11" 88 | description: "Continuous integration and deployment pipeline changes" -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Pull Request 3 | about: Create a pull request 4 | title: 'type(area): brief description of changes' 5 | assignees: '' 6 | --- 7 | 8 | **Title Format** 9 | Please use the following format for your title: 10 | ``` 11 | type(area): brief description of changes 12 | ``` 13 | Where: 14 | - `type` is one of: `feat`, `fix`, `refactor`, `docs`, `test`, `chore` 15 | - `area` is one of: `algebra`, `space` 16 | 17 | **Description** 18 | Please provide a clear description of your changes. If this PR closes any issues, please reference them here. 19 | 20 | **Changes Made** 21 | - [ ] Change 1 22 | - [ ] Change 2 23 | - [ ] Change 3 24 | 25 | **Testing** 26 | - [ ] Tests added/updated 27 | - [ ] All tests pass 28 | 29 | **Labels to Consider** 30 | - `area: algebra` or `area: space` (based on component) 31 | - `priority: critical/high/medium/low` (based on importance) 32 | - `type: enhancement` (for new features) 33 | - `type: refactor` (for refactoring) 34 | - `tech: performance` (if performance related) 35 | - `tech: testing` (if testing related) 36 | - `docs` (if documentation related) 37 | 38 | **Additional Notes** 39 | Add any additional context or notes here. 40 | 41 | ## 📝 Description 42 | 43 | 44 | ## 🔍 Changes include 45 | 46 | - [ ] 🐛 Bugfix 47 | - [ ] ✨ New feature 48 | - [ ] 📚 Documentation 49 | - [ ] ⚡ Performance improvement 50 | - [ ] 🔨 Refactoring 51 | - [ ] ✅ Test updates 52 | 53 | ## 🧪 Testing 54 | 55 | 56 | ## 📋 Checklist 57 | - [ ] I have tested the changes locally 58 | - [ ] I have updated the documentation accordingly 59 | - [ ] I have added tests that prove my fix/feature works 60 | - [ ] All tests pass locally 61 | 62 | ## 📸 Screenshots 63 | 64 | 65 | ## 🔗 Linked Issues 66 | 67 | 68 | closes # -------------------------------------------------------------------------------- /.github/settings.yaml: -------------------------------------------------------------------------------- 1 | repository: 2 | # Enable all features 3 | has_issues: true 4 | has_projects: false 5 | has_wiki: false 6 | has_downloads: false 7 | 8 | # Default branch (recommended to use "main") 9 | default_branch: main 10 | 11 | # Enable vulnerability alerts 12 | enable_vulnerability_alerts: true 13 | 14 | # Allow squash merging only 15 | allow_squash_merge: true 16 | allow_merge_commit: false 17 | allow_rebase_merge: true 18 | 19 | # Use PR title as squash commit message 20 | squash_merge_commit_title: PR_TITLE 21 | squash_merge_commit_message: BLANK 22 | 23 | # Delete head branch after merge 24 | delete_branch_on_merge: true 25 | 26 | # Branch protection rules 27 | branches: 28 | - name: main 29 | protection: 30 | # Require pull request before merging 31 | required_pull_request_reviews: 32 | required_approving_review_count: 1 33 | dismiss_stale_reviews: true 34 | require_code_owner_reviews: false 35 | 36 | # Require status checks to pass 37 | required_status_checks: 38 | strict: true 39 | contexts: [] # Add your required status checks here 40 | 41 | # Prevent direct pushes to main 42 | enforce_admins: true 43 | 44 | # Restrict who can push to matching branches 45 | restrictions: null # Set to null to allow any user with push access 46 | -------------------------------------------------------------------------------- /.github/workflows/book.yaml: -------------------------------------------------------------------------------- 1 | name: MDBook Build (and Deploy on Push) 2 | 3 | on: 4 | pull_request: 5 | branches: ["main"] 6 | push: 7 | branches: ["main"] 8 | 9 | permissions: 10 | contents: read 11 | pages: write 12 | id-token: write 13 | 14 | jobs: 15 | build: 16 | name: Build Documentation 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - name: Install Rust 22 | uses: dtolnay/rust-toolchain@master 23 | with: 24 | toolchain: nightly-2025-05-25 25 | 26 | - name: Install mdbook 27 | uses: taiki-e/install-action@cargo-binstall 28 | with: 29 | tool: mdbook 30 | 31 | - name: Install mdbook-katex 32 | uses: taiki-e/install-action@cargo-binstall 33 | with: 34 | tool: mdbook-katex 35 | 36 | - name: Install mdbook-linkcheck 37 | uses: taiki-e/install-action@cargo-binstall 38 | with: 39 | tool: mdbook-linkcheck 40 | 41 | - name: Build mdBook 42 | run: mdbook build 43 | 44 | - name: Upload artifact 45 | uses: actions/upload-pages-artifact@v3 46 | with: 47 | path: ./docs/html 48 | 49 | deploy: 50 | environment: 51 | name: github-pages 52 | url: ${{ steps.deployment.outputs.page_url }} 53 | runs-on: ubuntu-latest 54 | needs: build 55 | if: github.event_name == 'push' && github.ref == 'refs/heads/main' 56 | steps: 57 | - name: Deploy to GitHub Pages 58 | id: deployment 59 | uses: actions/deploy-pages@v4 -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | permissions: 4 | pull-requests: write 5 | contents: write 6 | 7 | on: 8 | push: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | release: 14 | name: release 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout repository 18 | uses: actions/checkout@v4 19 | with: 20 | fetch-depth: 0 21 | 22 | - name: Install Rust toolchain 23 | uses: dtolnay/rust-toolchain@master 24 | with: 25 | toolchain: nightly-2025-05-25 26 | 27 | - name: Rust Cache 28 | uses: Swatinem/rust-cache@v2 29 | 30 | - name: Install cargo-semver-checks 31 | uses: taiki-e/install-action@cargo-binstall 32 | with: 33 | tool: cargo-semver-checks 34 | 35 | - name: Check semver 36 | run: cargo semver-checks check-release 37 | continue-on-error: true 38 | 39 | - name: Update Cargo.lock 40 | uses: stefanzweifel/git-auto-commit-action@v5 41 | with: 42 | commit_message: "chore: update Cargo.lock" 43 | file_pattern: "Cargo.lock" 44 | 45 | - name: Run release-plz 46 | uses: MarcoIeni/release-plz-action@v0.5.41 47 | env: 48 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 49 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/rust.yaml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | concurrency: 3 | group: ${{ github.workflow }}-${{ github.ref }} 4 | cancel-in-progress: true 5 | 6 | on: 7 | push: 8 | branches: [ main ] 9 | pull_request: 10 | branches: [ main ] 11 | 12 | env: 13 | CARGO_TERM_COLOR: always 14 | 15 | jobs: 16 | rust-fmt: 17 | name: rustfmt 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v4 21 | 22 | - name: Install Rust 23 | uses: dtolnay/rust-toolchain@master 24 | with: 25 | toolchain: nightly-2025-05-25 26 | components: rustfmt 27 | 28 | - name: Rust Cache 29 | uses: Swatinem/rust-cache@v2 30 | with: 31 | key: rust/rustfmt 32 | 33 | - name: Run Rust fmt 34 | run: cargo fmt --all -- --check 35 | 36 | toml-fmt: 37 | name: taplo 38 | runs-on: ubuntu-latest 39 | steps: 40 | - uses: actions/checkout@v4 41 | 42 | - name: Install Rust 43 | uses: dtolnay/rust-toolchain@master 44 | with: 45 | toolchain: nightly-2025-05-25 46 | 47 | - name: Install taplo 48 | uses: taiki-e/install-action@cargo-binstall 49 | with: 50 | tool: taplo-cli 51 | 52 | - name: Rust Cache 53 | uses: Swatinem/rust-cache@v2 54 | with: 55 | key: rust/taplo 56 | 57 | - name: Run TOML fmt 58 | run: taplo fmt --check 59 | 60 | check: 61 | name: check 62 | runs-on: ubuntu-latest 63 | steps: 64 | - uses: actions/checkout@v4 65 | 66 | - name: Install Rust 67 | uses: dtolnay/rust-toolchain@master 68 | with: 69 | toolchain: nightly-2025-05-25 70 | 71 | - name: Rust Cache 72 | uses: Swatinem/rust-cache@v2 73 | with: 74 | key: rust/check 75 | 76 | - name: Run cargo check 77 | run: cargo check --workspace 78 | 79 | check-wasm: 80 | name: check-wasm 81 | runs-on: ubuntu-latest 82 | steps: 83 | - uses: actions/checkout@v4 84 | 85 | - name: Install Rust 86 | uses: dtolnay/rust-toolchain@master 87 | with: 88 | toolchain: nightly-2025-05-25 89 | 90 | - name: Rust Cache 91 | uses: Swatinem/rust-cache@v2 92 | with: 93 | key: rust/check-wasm 94 | 95 | - name: Install WASM target 96 | run: rustup target add wasm32-unknown-unknown 97 | 98 | - name: Run cargo check for WASM 99 | run: cargo check --workspace --target wasm32-unknown-unknown 100 | 101 | clippy: 102 | name: clippy 103 | runs-on: ubuntu-latest 104 | steps: 105 | - uses: actions/checkout@v4 106 | 107 | - name: Install Rust 108 | uses: dtolnay/rust-toolchain@master 109 | with: 110 | toolchain: nightly-2025-05-25 111 | components: clippy 112 | 113 | - name: Rust Cache 114 | uses: Swatinem/rust-cache@v2 115 | with: 116 | key: rust/clippy 117 | 118 | - name: Build 119 | run: cargo build --workspace 120 | 121 | - name: Clippy 122 | run: cargo clippy --all-targets --all-features -- --deny warnings 123 | 124 | clippy-wasm: 125 | name: clippy-wasm 126 | runs-on: ubuntu-latest 127 | steps: 128 | - uses: actions/checkout@v4 129 | 130 | - name: Install Rust 131 | uses: dtolnay/rust-toolchain@master 132 | with: 133 | toolchain: nightly-2025-05-25 134 | components: clippy 135 | 136 | - name: Rust Cache 137 | uses: Swatinem/rust-cache@v2 138 | with: 139 | key: rust/clippy-wasm 140 | 141 | - name: Install WASM target 142 | run: rustup target add wasm32-unknown-unknown 143 | 144 | - name: Clippy for WASM 145 | run: cargo clippy --target wasm32-unknown-unknown --all-features -- --deny warnings 146 | 147 | test: 148 | name: test 149 | runs-on: ubuntu-latest 150 | steps: 151 | - uses: actions/checkout@v4 152 | 153 | - name: Install Rust 154 | uses: dtolnay/rust-toolchain@master 155 | with: 156 | toolchain: nightly-2025-05-25 157 | 158 | - name: Rust Cache 159 | uses: Swatinem/rust-cache@v2 160 | with: 161 | key: rust/test 162 | 163 | - name: Run tests 164 | run: cargo test --verbose --workspace 165 | 166 | semver: 167 | name: semver 168 | runs-on: ubuntu-latest 169 | continue-on-error: true 170 | steps: 171 | - uses: actions/checkout@v4 172 | with: 173 | fetch-depth: 0 174 | 175 | - name: Install Rust 176 | uses: dtolnay/rust-toolchain@master 177 | with: 178 | toolchain: nightly-2025-05-25 179 | 180 | - name: Rust Cache 181 | uses: Swatinem/rust-cache@v2 182 | with: 183 | key: rust/semver 184 | 185 | - name: Install cargo-semver-checks 186 | uses: taiki-e/install-action@cargo-binstall 187 | with: 188 | tool: cargo-semver-checks 189 | 190 | - name: Check semver 191 | run: cargo semver-checks check-release 192 | 193 | udeps: 194 | name: udeps 195 | runs-on: ubuntu-latest 196 | steps: 197 | - uses: actions/checkout@v4 198 | 199 | - name: Install Rust 200 | uses: dtolnay/rust-toolchain@master 201 | with: 202 | toolchain: nightly-2025-05-25 203 | 204 | - name: Rust Cache 205 | uses: Swatinem/rust-cache@v2 206 | with: 207 | key: rust/udeps 208 | 209 | - name: Install cargo-udeps 210 | uses: taiki-e/install-action@cargo-binstall 211 | with: 212 | tool: cargo-udeps 213 | 214 | - name: Run cargo-udeps 215 | run: cargo udeps --workspace 216 | 217 | doc: 218 | name: doc 219 | runs-on: ubuntu-latest 220 | steps: 221 | - uses: actions/checkout@v4 222 | 223 | - name: Install Rust 224 | uses: dtolnay/rust-toolchain@master 225 | with: 226 | toolchain: nightly-2025-05-25 227 | 228 | - name: Rust Cache 229 | uses: Swatinem/rust-cache@v2 230 | with: 231 | key: rust/doc 232 | 233 | - name: Run cargo doc to check for warnings 234 | run: RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features -------------------------------------------------------------------------------- /.github/workflows/sync_labels.yaml: -------------------------------------------------------------------------------- 1 | name: Sync Labels 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - '.github/labels.yaml' 9 | workflow_dispatch: 10 | 11 | permissions: 12 | issues: write 13 | pull-requests: write 14 | 15 | jobs: 16 | sync: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - uses: micnncim/action-label-syncer@v1 22 | env: 23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 24 | with: 25 | manifest: .github/labels.yaml 26 | prune: true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS generated files 2 | .DS_Store 3 | ._* 4 | .Spotlight-V100 5 | .Trashes 6 | ehthumbs.db 7 | Thumbs.db 8 | 9 | # Editor directories and files 10 | .idea/ 11 | .vscode/ 12 | *.swp 13 | *.swo 14 | *~ 15 | 16 | # Log files 17 | *.log 18 | 19 | # Environment files 20 | .env 21 | .env.local 22 | .env.*.local 23 | 24 | # Temporary files 25 | *.tmp 26 | *.temp 27 | .cache/ 28 | 29 | # Build output 30 | dist/ 31 | build/ 32 | out/ 33 | target/ 34 | 35 | # Mdbook 36 | docs/ 37 | -------------------------------------------------------------------------------- /.release-plz.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | allow_dirty = false 3 | dependencies_update = false 4 | semver_check = true 5 | 6 | [[package]] 7 | name = "cova-algebra" 8 | publish = true 9 | 10 | [[package]] 11 | name = "cova-space" 12 | publish = true 13 | 14 | [[package]] 15 | name = "cova" 16 | publish = true 17 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | # Opinionated whitespace and tabs. The most important of these are imports and width settings. 2 | # Others may want to borrow or change these to their own liking. 3 | # https://rust-lang.github.io/rustfmt 4 | 5 | # version-related 6 | edition = "2021" # redundant, fmt will read Cargo.toml for editor edition year 7 | unstable_features = true 8 | use_try_shorthand = true # replace any `try!` (2015 Rust) with `?` 9 | 10 | # misc formatting 11 | condense_wildcard_suffixes = true # replace: (a,b,_,_)=(1, 2, 3, 4); -> (a,b,..)=(1, 2, 3, 4); 12 | format_code_in_doc_comments = true # format code blocks in doc comments 13 | format_macro_matchers = true # $a: ident -> $a:ident 14 | format_strings = true # break and insert newlines for long string literals 15 | match_block_trailing_comma = true # include comma in match blocks after '}' 16 | normalize_comments = true # convert /*..*/ to //.. where possible 17 | reorder_impl_items = true # move `type` and `const` declarations to top of impl block 18 | struct_field_align_threshold = 20 # align struct arguments' types vertically 19 | use_field_init_shorthand = true # struct initialization short {x: x} -> {x} 20 | 21 | # reduce whitespace 22 | blank_lines_upper_bound = 1 # default: 1. Sometimes useful to change to 0 to condense a file. 23 | brace_style = "PreferSameLine" # prefer starting `{` without inserting extra \n 24 | fn_single_line = true # if it's a short 1-liner, let it be a short 1-liner 25 | match_arm_blocks = false # remove unnecessary {} in match arms 26 | newline_style = "Unix" # not auto, we won the culture war. \n over \r\n 27 | overflow_delimited_expr = true # prefer ]); to ]\n); 28 | where_single_line = true # put where on a single line if possible 29 | 30 | # imports preferences 31 | group_imports = "StdExternalCrate" # create import groupings for std, external libs, and internal deps 32 | imports_granularity = "Crate" # aggressively group imports 33 | 34 | # width settings: everything to 100 35 | comment_width = 100 # default: 80 36 | inline_attribute_width = 60 # inlines #[cfg(test)]\nmod test -> #[cfg(test)] mod test 37 | max_width = 100 # default: 100 38 | use_small_heuristics = "Max" # don't ever newline short of `max_width`. 39 | wrap_comments = true # wrap comments at `comment_width` 40 | # format_strings = true # wrap strings at `max_length` 41 | 42 | # tabs and spaces 43 | hard_tabs = false # (def: false) use spaces over tabs 44 | tab_spaces = 2 # 2 > 4, it's just math. 45 | -------------------------------------------------------------------------------- /.taplo.toml: -------------------------------------------------------------------------------- 1 | # .toml file formatting settings for `taplo` 2 | # https://taplo.tamasfe.dev/configuration/formatter-options.html 3 | 4 | [formatting] 5 | # align entries vertically 6 | align_entries = true 7 | # allow up to 1 consecutive empty line (default: 2) 8 | allowed_blank_line = 1 9 | # collapse arrays into one line if they fit 10 | array_auto_collapse = true 11 | # alphabetically sort entries not separated by line breaks 12 | reorder_keys = true 13 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Cova 2 | 3 | Thank you for your interest in contributing to Cova! This document provides guidelines and instructions for contributing to the project. 4 | 5 | ## Table of Contents 6 | - [Code of Conduct](#code-of-conduct) 7 | - [Getting Started](#getting-started) 8 | - [Development Workflow](#development-workflow) 9 | - [Documentation](#documentation) 10 | - [Issue Guidelines](#issue-guidelines) 11 | - [Pull Request Guidelines](#pull-request-guidelines) 12 | - [Code Style](#code-style) 13 | - [Testing](#testing) 14 | 15 | ## Code of Conduct 16 | 17 | By participating in this project, you agree to abide by our Code of Conduct. Please be respectful and considerate of others. 18 | 19 | ## Getting Started 20 | 21 | 1. Fork the repository 22 | 2. Clone your fork: 23 | ```bash 24 | git clone https://github.com/yourusername/cova.git 25 | cd cova 26 | ``` 27 | 3. Set up the development environment: 28 | ```bash 29 | # Install Rust (if not already installed) 30 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 31 | 32 | # Install development tools 33 | rustup component add rustfmt clippy 34 | ``` 35 | 36 | ## Development Workflow 37 | 38 | 1. Create a new branch for your feature/fix: 39 | ```bash 40 | git checkout -b type/area/description 41 | # Example: git checkout -b feat/algebra/vector-spaces 42 | ``` 43 | 44 | 2. Make your changes following the [Code Style](#code-style) guidelines 45 | 46 | 3. Run tests and checks: 47 | ```bash 48 | cargo test 49 | cargo fmt --all -- --check 50 | cargo clippy --all-targets --all-features -- -D warnings 51 | ``` 52 | 53 | 4. Commit your changes following the [Commit Message Format](#commit-message-format) 54 | 55 | 5. Push your branch and create a Pull Request 56 | 57 | ## Documentation 58 | 59 | Harness provides two types of documentation that you should be familiar with: 60 | 61 | ### API Documentation 62 | The Rust API documentation for all crates can be viewed using: 63 | ```bash 64 | just docs 65 | ``` 66 | This will build and open the Rust API documentation in your browser. This documentation is automatically generated from your code comments and should be kept up to date. 67 | 68 | ### Book Documentation 69 | The comprehensive book documentation can be viewed using: 70 | ```bash 71 | just book 72 | ``` 73 | This will serve the book documentation locally and open it in your browser. The book includes detailed explanations of mathematical concepts, examples, and usage guides. 74 | 75 | When contributing, please: 76 | 1. Keep API documentation up to date with your code changes 77 | 2. Update the book documentation if you add new features or change existing behavior 78 | 3. Add examples to both API docs and the book where appropriate 79 | 4. Ensure mathematical definitions and references are accurate 80 | 81 | ## Issue Guidelines 82 | 83 | When creating issues, please use the provided templates and follow these guidelines: 84 | 85 | ### Title Format 86 | ``` 87 | type(area): brief description 88 | ``` 89 | Where: 90 | - `type` is one of: `feat`, `fix`, `refactor`, `docs`, `test`, `chore` 91 | - `area` is one of: `algebra`, `space` 92 | 93 | ### Labels 94 | Please use appropriate labels to categorize your issue: 95 | - Area labels: `area: algebra`, `area: space` 96 | - Priority labels: `priority: critical/high/medium/low` 97 | - Type labels: `type: enhancement`, `type: refactor` 98 | - Technical labels: `tech: performance`, `tech: security`, `tech: testing` 99 | 100 | ## Pull Request Guidelines 101 | 102 | 1. Use the provided PR template 103 | 2. Ensure your PR title follows the format: `type(area): description` 104 | 3. Link related issues using `closes #issue_number` 105 | 4. Keep PRs focused and small when possible 106 | 5. Include tests for new features or bug fixes 107 | 6. Update documentation as needed 108 | 109 | ## Code Style 110 | 111 | - Follow Rust's official style guide 112 | - Use `rustfmt` for formatting 113 | - Run `cargo clippy` to catch common mistakes 114 | - Document public APIs thoroughly 115 | - Use meaningful variable and function names 116 | - Keep functions focused and small 117 | 118 | ## Testing 119 | 120 | - Write unit tests for all new functionality 121 | - Include examples in documentation 122 | - Run all tests before submitting PRs 123 | - Consider edge cases and error conditions 124 | 125 | ## Commit Message Format 126 | 127 | Follow this format for commit messages: 128 | ``` 129 | type(area): description 130 | 131 | [optional body] 132 | 133 | [optional footer] 134 | ``` 135 | 136 | Where: 137 | - `type` is one of: `feat`, `fix`, `refactor`, `docs`, `test`, `chore` 138 | - `area` is one of: `algebra`, `space` 139 | - Description is a brief summary of changes 140 | - Body provides additional context if needed 141 | - Footer references issues or PRs 142 | 143 | ## Questions? 144 | 145 | If you have any questions, feel free to: 146 | 1. Open an issue with the `question` label 147 | 2. Join our community discussions 148 | 3. Contact the maintainers -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "autocfg" 7 | version = "1.4.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 10 | 11 | [[package]] 12 | name = "bitflags" 13 | version = "2.9.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" 16 | 17 | [[package]] 18 | name = "cfg-if" 19 | version = "1.0.0" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 22 | 23 | [[package]] 24 | name = "cova" 25 | version = "0.1.3" 26 | dependencies = [ 27 | "cova-algebra", 28 | "cova-space", 29 | "tempfile", 30 | ] 31 | 32 | [[package]] 33 | name = "cova-algebra" 34 | version = "0.1.2" 35 | dependencies = [ 36 | "num-traits", 37 | ] 38 | 39 | [[package]] 40 | name = "cova-space" 41 | version = "0.2.0" 42 | dependencies = [ 43 | "cova-algebra", 44 | "itertools", 45 | "num-traits", 46 | "rayon", 47 | "tempfile", 48 | ] 49 | 50 | [[package]] 51 | name = "crossbeam-deque" 52 | version = "0.8.6" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" 55 | dependencies = [ 56 | "crossbeam-epoch", 57 | "crossbeam-utils", 58 | ] 59 | 60 | [[package]] 61 | name = "crossbeam-epoch" 62 | version = "0.9.18" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" 65 | dependencies = [ 66 | "crossbeam-utils", 67 | ] 68 | 69 | [[package]] 70 | name = "crossbeam-utils" 71 | version = "0.8.21" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" 74 | 75 | [[package]] 76 | name = "either" 77 | version = "1.15.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 80 | 81 | [[package]] 82 | name = "errno" 83 | version = "0.3.11" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" 86 | dependencies = [ 87 | "libc", 88 | "windows-sys", 89 | ] 90 | 91 | [[package]] 92 | name = "fastrand" 93 | version = "2.3.0" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 96 | 97 | [[package]] 98 | name = "getrandom" 99 | version = "0.3.2" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" 102 | dependencies = [ 103 | "cfg-if", 104 | "libc", 105 | "r-efi", 106 | "wasi", 107 | ] 108 | 109 | [[package]] 110 | name = "itertools" 111 | version = "0.14.0" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" 114 | dependencies = [ 115 | "either", 116 | ] 117 | 118 | [[package]] 119 | name = "libc" 120 | version = "0.2.172" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" 123 | 124 | [[package]] 125 | name = "linux-raw-sys" 126 | version = "0.9.4" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" 129 | 130 | [[package]] 131 | name = "num-traits" 132 | version = "0.2.19" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 135 | dependencies = [ 136 | "autocfg", 137 | ] 138 | 139 | [[package]] 140 | name = "once_cell" 141 | version = "1.21.3" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 144 | 145 | [[package]] 146 | name = "r-efi" 147 | version = "5.2.0" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" 150 | 151 | [[package]] 152 | name = "rayon" 153 | version = "1.10.0" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" 156 | dependencies = [ 157 | "either", 158 | "rayon-core", 159 | ] 160 | 161 | [[package]] 162 | name = "rayon-core" 163 | version = "1.12.1" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" 166 | dependencies = [ 167 | "crossbeam-deque", 168 | "crossbeam-utils", 169 | ] 170 | 171 | [[package]] 172 | name = "rustix" 173 | version = "1.0.7" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" 176 | dependencies = [ 177 | "bitflags", 178 | "errno", 179 | "libc", 180 | "linux-raw-sys", 181 | "windows-sys", 182 | ] 183 | 184 | [[package]] 185 | name = "tempfile" 186 | version = "3.20.0" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" 189 | dependencies = [ 190 | "fastrand", 191 | "getrandom", 192 | "once_cell", 193 | "rustix", 194 | "windows-sys", 195 | ] 196 | 197 | [[package]] 198 | name = "wasi" 199 | version = "0.14.2+wasi-0.2.4" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" 202 | dependencies = [ 203 | "wit-bindgen-rt", 204 | ] 205 | 206 | [[package]] 207 | name = "windows-sys" 208 | version = "0.59.0" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 211 | dependencies = [ 212 | "windows-targets", 213 | ] 214 | 215 | [[package]] 216 | name = "windows-targets" 217 | version = "0.52.6" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 220 | dependencies = [ 221 | "windows_aarch64_gnullvm", 222 | "windows_aarch64_msvc", 223 | "windows_i686_gnu", 224 | "windows_i686_gnullvm", 225 | "windows_i686_msvc", 226 | "windows_x86_64_gnu", 227 | "windows_x86_64_gnullvm", 228 | "windows_x86_64_msvc", 229 | ] 230 | 231 | [[package]] 232 | name = "windows_aarch64_gnullvm" 233 | version = "0.52.6" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 236 | 237 | [[package]] 238 | name = "windows_aarch64_msvc" 239 | version = "0.52.6" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 242 | 243 | [[package]] 244 | name = "windows_i686_gnu" 245 | version = "0.52.6" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 248 | 249 | [[package]] 250 | name = "windows_i686_gnullvm" 251 | version = "0.52.6" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 254 | 255 | [[package]] 256 | name = "windows_i686_msvc" 257 | version = "0.52.6" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 260 | 261 | [[package]] 262 | name = "windows_x86_64_gnu" 263 | version = "0.52.6" 264 | source = "registry+https://github.com/rust-lang/crates.io-index" 265 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 266 | 267 | [[package]] 268 | name = "windows_x86_64_gnullvm" 269 | version = "0.52.6" 270 | source = "registry+https://github.com/rust-lang/crates.io-index" 271 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 272 | 273 | [[package]] 274 | name = "windows_x86_64_msvc" 275 | version = "0.52.6" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 278 | 279 | [[package]] 280 | name = "wit-bindgen-rt" 281 | version = "0.39.0" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" 284 | dependencies = [ 285 | "bitflags", 286 | ] 287 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["cova", "cova-space", "cova-algebra"] 3 | resolver = "2" 4 | 5 | [workspace.dependencies] 6 | # Local dependencies 7 | cova-algebra = { path = "cova-algebra", version = "=0.1.2" } 8 | cova-space = { path = "cova-space", version = "=0.2.0" } 9 | 10 | # External dependencies 11 | itertools = { version = "0.14", default-features = false } 12 | num-traits = { version = "0.2", default-features = false } 13 | rayon = { version = "1.10", default-features = false } 14 | 15 | # Development dependencies 16 | tempfile = { version = "3.20" } 17 | 18 | [profile.release] 19 | codegen-units = 1 20 | lto = true 21 | opt-level = 3 22 | panic = "abort" 23 | strip = true 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Cova Banner 3 |

4 | 5 |

6 | Discord 7 | Twitter 8 | Visitors 9 | License: AGPLv3 10 |

11 | 12 |

13 | Crates.io - cova 14 | docs.rs - cova 15 |

16 | 17 |

18 | Crates.io - cova-space 19 | docs.rs - cova-space 20 |

21 | 22 |

23 | Crates.io - cova-algebra 24 | docs.rs - cova-algebra 25 |

26 | 27 | # Cova 28 | 29 | A Rust ecosystem for mathematical abstractions and computations, focusing on rigorous implementations of algebraic structures, topological spaces, and computational mathematics. 30 | 31 | ## Overview 32 | 33 | Cova provides a collection of crates that implement various mathematical structures and algorithms with a focus on type safety, correctness, and composability. The project aims to provide foundational mathematical tools that can be used in scientific computing, computational topology, abstract algebra, and other domains requiring robust mathematical implementations. 34 | 35 | ## Examples & Demos 36 | 37 | Cova includes interactive demos to help you get started: 38 | 39 | ### 🌐 Interactive Web Demos 40 | 41 | - **[Vietoris-Rips Complex Demo](examples/vietoris_web/README.md)**: An interactive WebAssembly demo showcasing real-time topological data analysis. Click to place points and watch simplicial complexes emerge as you adjust the distance threshold. 42 | 43 | ## Design Philosophy 44 | 45 | - **Type Safety**: Mathematical properties are encoded in the type system where possible 46 | - **Correctness**: Implementations prioritize mathematical correctness over performance 47 | - **Composability**: Structures are designed to work together seamlessly 48 | - **Documentation**: Extensive mathematical documentation and examples 49 | 50 | ## Crates 51 | 52 | ### `cova` 53 | 54 | The `cova` crate is a meta crate that re-exports the `cova-space` and `cova-algebra` crates. 55 | 56 | 57 | ### `cova-space` 58 | 59 | The `cova-space` crate implements topological spaces, simplicial complexes, and graph structures, providing a foundation for computational topology and geometry. It includes: 60 | 61 | - **Topological Spaces**: Sets, metric spaces, normed spaces, and inner product spaces 62 | - **Simplicial Complexes**: Simplex representation, chain complexes, and homology computations 63 | - **Graph Theory**: Flexible directed and undirected graph data structures 64 | - **Sheaf Theory**: Advanced categorical constructions for topology 65 | - **Filtrations**: Tools for persistent homology and topological data analysis 66 | 67 | ### `cova-algebra` 68 | 69 | The `cova-algebra` crate provides implementations of algebraic structures with proper type constraints and mathematical rigor. It includes: 70 | 71 | - **Modular Arithmetic**: Custom modular number types with the `modular!` macro 72 | - **Abstract Algebra**: Groups, rings, fields, modules, and vector spaces 73 | - **Category Theory**: Fundamental categorical constructions and morphisms 74 | - **Tensors**: Tensor algebra and operations 75 | - **Linear Algebra**: Vector spaces and linear transformations 76 | 77 | ## Getting Started 78 | 79 | ### Prerequisites 80 | 81 | Cova requires Rust 1.70 or later. 82 | 83 | ### Installation 84 | 85 | Add the desired crates to your `Cargo.toml`: 86 | 87 | ```toml 88 | [dependencies] 89 | cova = "*" 90 | # or if you only need one of the crates 91 | cova-space = "*" 92 | cova-algebra = "*" 93 | ``` 94 | 95 | ### Development Setup 96 | 97 | 1. Clone the repository: 98 | ```bash 99 | git clone https://github.com/harnesslabs/cova.git 100 | cd cova 101 | ``` 102 | 103 | 2. Install `just` (if not already installed): 104 | ```bash 105 | # macOS 106 | brew install just 107 | 108 | # Linux 109 | curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin 110 | ``` 111 | 112 | 3. Run the development setup: 113 | ```bash 114 | just setup 115 | ``` 116 | 117 | 4. Build and test: 118 | ```bash 119 | just test 120 | ``` 121 | 122 | ### Viewing Documentation 123 | 124 | The project provides two types of documentation: 125 | 126 | 1. **API Documentation**: View the Rust API documentation for all crates: 127 | ```bash 128 | just docs 129 | ``` 130 | This will build and open the Rust API documentation in your browser. 131 | 132 | 2. **Book Documentation**: View the comprehensive book documentation: 133 | ```bash 134 | just book 135 | ``` 136 | This will serve the book documentation locally and open it in your browser. The book includes detailed explanations of mathematical concepts, examples, and usage guides. 137 | 138 | For more development commands, run `just --list`. 139 | 140 | ## Documentation 141 | 142 | - [API Documentation - cova](https://docs.rs/cova) 143 | - [API Documentation - cova-space](https://docs.rs/cova-space) 144 | - [API Documentation - cova-algebra](https://docs.rs/cova-algebra) 145 | - [Book](https://book.harnesslabs.xyz) 146 | 147 | ## Contributing 148 | 149 | We welcome contributions! Please check our [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on how to contribute to the project. 150 | 151 | ## License 152 | 153 | This project is licensed under the [AGPLv3 License](LICENSE). 154 | 155 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | - [Introduction](README.md) 2 | - [Algebra](cova-algebra/README.md) 3 | - [Space](cova-space/README.md) 4 | - [Examples](examples/README.md) 5 | - [Vietoris-Rips Complex Demo](examples/vietoris_web/README.md) 6 | - [Contributing](CONTRIBUTING.md) -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["Harness Lab"] 3 | description = "Cova: A Rust ecosystem for mathematical abstractions and computations, focusing on extensible implementations of mathematical structures and algorithms." 4 | language = "en" 5 | multilingual = false 6 | src = "." 7 | title = "Cova: Abstract Mathematics made Computational" 8 | 9 | [build] 10 | build-dir = "docs" 11 | create-missing = true 12 | use-default-preprocessors = false 13 | 14 | [preprocessor.links] 15 | 16 | [preprocessor.katex] 17 | after = ["links"] 18 | 19 | [output.linkcheck] 20 | follow-web-links = false # TODO (autoparallel): fix this 21 | traverse-parent-directories = true 22 | warning-policy = "ignore" 23 | 24 | # TODO (autoparallel): there's a bunch to fix with this 25 | # [preprocessor.keeper] 26 | # command ="mdbook-keeper" 27 | 28 | [output.html] 29 | default-theme = "dark" 30 | git-repository-url = "https://github.com/harnesslabs/cova" 31 | preferred-dark-theme = "ayu" 32 | site-url = "https://cova.harnesslabs.xyz" 33 | 34 | [output.html.playground] 35 | editable = true 36 | runnable = true 37 | 38 | [rust] 39 | edition = "2021" 40 | -------------------------------------------------------------------------------- /cova-algebra/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | rustdocflags = ["--html-in-header", "./katex-header.html"] 3 | -------------------------------------------------------------------------------- /cova-algebra/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ## [0.1.2](https://github.com/harnesslabs/cova/compare/cova-algebra-v0.1.1...cova-algebra-v0.1.2) - 2025-05-24 10 | 11 | ### Fixed 12 | - book issues ([#72](https://github.com/harnesslabs/cova/pull/72)) 13 | 14 | ### Other 15 | - update README with cova-banner ([#71](https://github.com/harnesslabs/cova/pull/71)) 16 | 17 | ## [0.1.1](https://github.com/harnesslabs/cova/compare/cova-algebra-v0.1.0...cova-algebra-v0.1.1) - 2025-05-23 18 | 19 | ### Other 20 | - re-name, re-release, etc. ([#69](https://github.com/harnesslabs/cova/pull/69)) 21 | -------------------------------------------------------------------------------- /cova-algebra/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cova-algebra" 3 | 4 | authors = ["Harness Labs"] 5 | description = "Cova's algebraic library" 6 | edition = "2021" 7 | keywords = ["mathematics", "algebra"] 8 | license = "AGPL-3.0" 9 | readme = "README.md" 10 | repository = "https://github.com/harnesslabs/cova" 11 | version = "0.1.2" 12 | 13 | [dependencies] 14 | num-traits = { workspace = true } 15 | -------------------------------------------------------------------------------- /cova-algebra/README.md: -------------------------------------------------------------------------------- 1 |

2 | Cova Banner 3 |

4 | 5 | # Cova Algebra 6 | 7 | A comprehensive Rust library for abstract algebra, providing rigorous implementations of algebraic structures from basic arithmetic to advanced category theory and tensor calculus. 8 | 9 | [![Crates.io - cova-algebra](https://img.shields.io/crates/v/cova-algebra?label=cova-algebra)](https://crates.io/crates/cova-algebra) 10 | [![docs.rs - cova-algebra](https://img.shields.io/docsrs/cova-algebra?label=docs.rs%20cova-algebra)](https://docs.rs/cova-algebra) 11 | [![License: AGPLv3](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0) 12 | 13 | ## Overview 14 | 15 | Cova Algebra implements the fundamental structures of abstract algebra with a focus on mathematical correctness, type safety, and composability. The crate provides a hierarchical organization of algebraic concepts, from basic arithmetic operations to advanced constructions in algebra and category theory. 16 | 17 | ## Architecture 18 | 19 | The library is structured around core mathematical concepts, with each module building upon more fundamental structures: 20 | 21 | ### Core Modules 22 | 23 | #### [`arithmetic`](src/arithmetic/mod.rs) 24 | Foundation layer providing basic arithmetic operations and modular arithmetic. Includes the `modular!` macro for creating custom modular number types and fundamental arithmetic traits that serve as building blocks for higher-level structures. 25 | 26 | #### [`groups`](src/groups.rs) 27 | Group theory implementations covering both commutative (Abelian) and non-commutative groups. Provides the fundamental structure for understanding symmetry and transformation in algebra, with proper distinctions between additive and multiplicative group operations. 28 | 29 | #### [`rings`](src/rings.rs) 30 | Ring theory abstractions including rings, fields, and semirings. Establishes the algebraic foundation for structures that support both addition and multiplication, with fields providing division operations for advanced algebraic computations. 31 | 32 | #### [`modules`](src/modules/mod.rs) 33 | Module theory over rings, including vector spaces, semimodules, and specialized constructions like tropical modules. Provides the framework for linear algebra and generalizes vector spaces to work over arbitrary rings. 34 | 35 | ### Advanced Modules 36 | 37 | #### [`algebras`](src/algebras/mod.rs) 38 | Higher-order algebraic structures that combine vector spaces with multiplication operations. Includes Boolean algebra for logical operations and Clifford algebras for geometric applications in physics and computer graphics. 39 | 40 | #### [`tensors`](src/tensors/mod.rs) 41 | Multi-dimensional tensor implementations with both compile-time fixed dimensions and runtime dynamic sizing. Supports tensor operations fundamental to linear algebra, differential geometry, and machine learning applications. 42 | 43 | #### [`category`](src/category.rs) 44 | Category theory primitives providing abstract mathematical frameworks for composition and morphisms. Enables advanced mathematical constructions and provides a unifying language for describing mathematical structures and their relationships. 45 | 46 | ## Design Principles 47 | 48 | - **Mathematical Rigor**: All implementations follow strict mathematical definitions and maintain algebraic properties 49 | - **Type Safety**: Leverages Rust's type system to encode mathematical constraints and prevent invalid operations 50 | - **Composability**: Structures are designed to work together seamlessly, allowing complex mathematical constructions 51 | - **Performance**: Balances mathematical correctness with computational efficiency through careful API design 52 | 53 | ## Usage 54 | 55 | Add to your `Cargo.toml`: 56 | 57 | ```toml 58 | [dependencies] 59 | cova-algebra = "*" 60 | ``` 61 | 62 | The crate provides a comprehensive prelude for convenient importing: 63 | 64 | ```rust 65 | use cova_algebra::prelude::*; 66 | ``` 67 | 68 | ## Module Hierarchy 69 | 70 | The algebraic structures follow a natural mathematical hierarchy: 71 | 72 | ``` 73 | Arithmetic Operations 74 | ├── Groups (symmetry and transformation) 75 | ├── Rings & Fields (number systems) 76 | └── Modules & Vector Spaces (linear structures) 77 | ├── Algebras (vector spaces with multiplication) 78 | ├── Tensors (multi-dimensional arrays) 79 | ``` 80 | 81 | ## Documentation 82 | 83 | Complete API documentation is available on [docs.rs](https://docs.rs/cova-algebra). 84 | 85 | ## Contributing 86 | 87 | Contributions are welcome! Please ensure mathematical correctness and include appropriate documentation for any new algebraic structures. 88 | 89 | ## License 90 | 91 | This project is licensed under the AGPLv3 License - see the [LICENSE](../LICENSE) file for details. 92 | 93 | -------------------------------------------------------------------------------- /cova-algebra/katex-header.html: -------------------------------------------------------------------------------- 1 | 3 | 6 | 9 | -------------------------------------------------------------------------------- /cova-algebra/src/algebras/boolean.rs: -------------------------------------------------------------------------------- 1 | //! # Boolean Algebra Module 2 | //! 3 | //! This module provides an implementation of the Boolean field GF(2) through a wrapper 4 | //! around Rust's `bool` type. 5 | //! 6 | //! ## Mathematical Structure 7 | //! 8 | //! The Boolean field consists of two elements: 9 | //! - `false` (0): The additive identity 10 | //! - `true` (1): The multiplicative identity 11 | //! 12 | //! Operations are defined as: 13 | //! - Addition: Exclusive OR (XOR) operation 14 | //! - Multiplication: Logical AND operation 15 | //! - Negation: Identity operation (x = -x in GF(2)) 16 | //! - Multiplicative inverse: Identity for non-zero elements 17 | //! 18 | //! ## Algebraic Properties 19 | //! 20 | //! The implementation satisfies multiple algebraic structures: 21 | //! - Field: A complete algebraic field with addition and multiplication 22 | //! - Abelian Group: Under addition with identity element `false` 23 | //! - Vector Space: Over itself as the scalar field 24 | //! 25 | //! ## Applications 26 | //! 27 | //! Boolean algebra has numerous applications in: 28 | //! - Digital circuit design 29 | //! - Logic operations 30 | //! - Cryptography (especially in finite field arithmetic) 31 | //! - Error correction codes 32 | //! 33 | //! ## Example 34 | //! 35 | //! ``` 36 | //! use cova_algebra::algebras::boolean::Boolean; 37 | //! 38 | //! // Create Boolean values 39 | //! let a = Boolean(true); // 1 40 | //! let b = Boolean(false); // 0 41 | //! 42 | //! // Addition (XOR) 43 | //! assert_eq!(a + a, Boolean(false)); // 1 + 1 = 0 44 | //! assert_eq!(a + b, Boolean(true)); // 1 + 0 = 1 45 | //! 46 | //! // Multiplication (AND) 47 | //! assert_eq!(a * b, Boolean(false)); // 1 * 0 = 0 48 | //! assert_eq!(a * a, Boolean(true)); // 1 * 1 = 1 49 | //! ``` 50 | 51 | use super::*; 52 | 53 | /// A wrapper around `bool` that implements algebraic operations. 54 | /// 55 | /// This type implements both [`Additive`] and [`Multiplicative`] traits using 56 | /// bitwise operations: 57 | /// - Addition is implemented as XOR (`^`) 58 | /// - Multiplication is implemented as AND (`&`) 59 | /// 60 | /// This makes `Boolean` a field with two elements, where: 61 | /// - `false` is the additive identity (0) 62 | /// - `true` is the multiplicative identity (1) 63 | /// 64 | /// # Examples 65 | /// 66 | /// ``` 67 | /// use cova_algebra::algebras::boolean::Boolean; 68 | /// 69 | /// let a = Boolean(true); 70 | /// let b = Boolean(false); 71 | /// 72 | /// // Addition (XOR) 73 | /// assert_eq!(a + b, Boolean(true)); 74 | /// assert_eq!(a + a, Boolean(false)); // a + a = 0 75 | /// 76 | /// // Multiplication (AND) 77 | /// assert_eq!(a * b, Boolean(false)); 78 | /// assert_eq!(a * a, Boolean(true)); // a * a = a 79 | /// ``` 80 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 81 | pub struct Boolean(pub bool); 82 | 83 | impl From for Boolean { 84 | fn from(b: bool) -> Self { Self(b) } 85 | } 86 | 87 | impl From for bool { 88 | fn from(b: Boolean) -> Self { b.0 } 89 | } 90 | 91 | impl One for Boolean { 92 | fn one() -> Self { Self(true) } 93 | } 94 | 95 | impl Zero for Boolean { 96 | fn zero() -> Self { Self(false) } 97 | 98 | fn is_zero(&self) -> bool { !self.0 } 99 | } 100 | 101 | impl Add for Boolean { 102 | type Output = Self; 103 | 104 | /// Implements addition as XOR operation. 105 | /// 106 | /// This corresponds to the addition operation in the field GF(2). 107 | #[allow(clippy::suspicious_arithmetic_impl)] 108 | fn add(self, rhs: Self) -> Self::Output { Self(self.0 ^ rhs.0) } 109 | } 110 | 111 | impl Sub for Boolean { 112 | type Output = Self; 113 | 114 | #[allow(clippy::suspicious_arithmetic_impl)] 115 | fn sub(self, rhs: Self) -> Self::Output { self + rhs } 116 | } 117 | 118 | impl Neg for Boolean { 119 | type Output = Self; 120 | 121 | fn neg(self) -> Self::Output { self } 122 | } 123 | 124 | impl SubAssign for Boolean { 125 | /// Implements subtraction assignment as XOR operation. 126 | #[allow(clippy::suspicious_op_assign_impl)] 127 | fn sub_assign(&mut self, rhs: Self) { self.0 ^= rhs.0; } 128 | } 129 | 130 | impl AddAssign for Boolean { 131 | /// Implements addition assignment as XOR operation. 132 | #[allow(clippy::suspicious_op_assign_impl)] 133 | fn add_assign(&mut self, rhs: Self) { self.0 ^= rhs.0; } 134 | } 135 | 136 | impl Mul for Boolean { 137 | type Output = Self; 138 | 139 | /// Implements multiplication as AND operation. 140 | /// 141 | /// This corresponds to the multiplication operation in the field GF(2). 142 | fn mul(self, rhs: Self) -> Self::Output { Self(self.0 && rhs.0) } 143 | } 144 | 145 | impl MulAssign for Boolean { 146 | /// Implements multiplication assignment as AND operation. 147 | #[allow(clippy::suspicious_op_assign_impl)] 148 | fn mul_assign(&mut self, rhs: Self) { self.0 &= rhs.0; } 149 | } 150 | 151 | impl Div for Boolean { 152 | type Output = Self; 153 | 154 | #[allow(clippy::suspicious_arithmetic_impl)] 155 | fn div(self, rhs: Self) -> Self::Output { self * rhs } 156 | } 157 | 158 | impl DivAssign for Boolean { 159 | /// Implements division assignment as AND operation. 160 | #[allow(clippy::suspicious_op_assign_impl)] 161 | fn div_assign(&mut self, rhs: Self) { self.0 &= rhs.0; } 162 | } 163 | 164 | impl Additive for Boolean {} 165 | impl Multiplicative for Boolean {} 166 | 167 | impl groups::Group for Boolean { 168 | fn identity() -> Self { Self(false) } 169 | 170 | fn inverse(&self) -> Self { Self(!self.0) } 171 | } 172 | 173 | impl groups::AbelianGroup for Boolean {} 174 | 175 | impl rings::Ring for Boolean {} 176 | 177 | impl rings::Field for Boolean { 178 | fn multiplicative_inverse(&self) -> Self { *self } 179 | } 180 | 181 | impl modules::LeftModule for Boolean { 182 | type Ring = Self; 183 | } 184 | 185 | impl modules::RightModule for Boolean { 186 | type Ring = Self; 187 | } 188 | 189 | impl modules::TwoSidedModule for Boolean { 190 | type Ring = Self; 191 | } 192 | 193 | impl modules::VectorSpace for Boolean {} 194 | -------------------------------------------------------------------------------- /cova-algebra/src/algebras/mod.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of an [`Algebra`] interface and various algebras 2 | //! 3 | //! This module provides implementations of different types of algebras, which are algebraic 4 | //! structures that combine the properties of vector spaces with multiplication operations. An 5 | //! algebra is a vector space equipped with a bilinear product that satisfies certain properties. 6 | //! 7 | //! 8 | //! # Key Concepts 9 | //! 10 | //! - **Algebra**: A vector space equipped with a bilinear product that is compatible with the 11 | //! vector space operations. The product must satisfy the distributive laws with respect to 12 | //! addition and scalar multiplication. 13 | //! 14 | //! - **Clifford Algebra**: A type of algebra that generalizes the real numbers, complex numbers, 15 | //! and quaternions. It is particularly useful in geometry and physics for representing rotations, 16 | //! reflections, and other transformations. 17 | //! 18 | //! # Implementations 19 | //! 20 | //! Currently, this module provides: 21 | //! 22 | //! - [`clifford`]: Implementation of Clifford algebras, which are useful for geometric computations 23 | //! and transformations in n-dimensional spaces. 24 | //! - [`boolean`]: Implementation of Boolean algebra, which is useful for logical operations and 25 | //! boolean logic. 26 | 27 | use super::*; 28 | use crate::{ 29 | arithmetic::Multiplicative, 30 | modules::{TwoSidedModule, VectorSpace}, 31 | rings::Field, 32 | }; 33 | 34 | pub mod boolean; 35 | pub mod clifford; 36 | 37 | /// Trait defining the requirements for an algebra. 38 | /// 39 | /// An algebra is a vector space equipped with a bilinear product that satisfies: 40 | /// - Distributivity: a(b + c) = ab + ac and (a + b)c = ac + bc 41 | /// - Compatibility with scalar multiplication: (ka)b = k(ab) = a(kb) 42 | /// 43 | /// This trait combines the properties of a vector space with those of a multiplicative structure, 44 | /// ensuring that the algebra's operations are compatible with both the vector space and ring 45 | /// operations. 46 | pub trait Algebra: VectorSpace + Multiplicative 47 | where ::Ring: Field { 48 | } 49 | -------------------------------------------------------------------------------- /cova-algebra/src/arithmetic/mod.rs: -------------------------------------------------------------------------------- 1 | //! Basic arithmetic traits and operations. 2 | //! 3 | //! This module provides fundamental arithmetic traits that are used throughout the algebra crate. 4 | //! It re-exports standard arithmetic operations from [`std::ops`] and numeric traits from 5 | //! [`num_traits`]. 6 | //! 7 | //! # Examples 8 | //! 9 | //! ``` 10 | //! use cova_algebra::arithmetic::{Additive, Multiplicative}; 11 | //! 12 | //! // Types implementing Additive can be added and assigned 13 | //! fn add(a: T, b: T) -> T { a + b } 14 | //! 15 | //! // Types implementing Multiplicative can be multiplied and assigned 16 | //! fn multiply(a: T, b: T) -> T { a * b } 17 | //! ``` 18 | 19 | use super::*; 20 | 21 | pub mod modular; 22 | pub mod primitive; 23 | 24 | /// A trait for types that support addition (and comparison) operations. 25 | /// 26 | /// This trait combines the basic requirements for types that can be added together: 27 | /// - Addition operation with [`Add`] trait 28 | /// - Addition assignment with [`AddAssign`] trait 29 | /// - Equality comparison with [`PartialEq`] 30 | /// 31 | /// # Examples 32 | /// - All primitive numeric types implement this trait 33 | /// - [`Boolean`](crate::algebras::boolean::Boolean) type implements this trait using bitwise 34 | /// [`std::ops::BitXor`] 35 | /// - Using the [`modular!`] macro, you can define a modular arithmetic type and it will implement 36 | /// this trait. 37 | /// - Using the [`prime_field!`] macro, you can define a prime field type and it will implement this 38 | /// trait. 39 | pub trait Additive: Add + AddAssign + PartialEq + Sized {} 40 | 41 | /// A trait for types that support multiplication operations. 42 | /// 43 | /// This trait combines the basic requirements for types that can be multiplied (and compared) 44 | /// together: 45 | /// - Multiplication operation with [`Mul`] trait 46 | /// - Multiplication assignment with [`MulAssign`] trait 47 | /// - Equality comparison with [`PartialEq`] 48 | /// 49 | /// # Examples 50 | /// - All primitive numeric types implement this trait 51 | /// - [`Boolean`](crate::algebras::boolean::Boolean) type implements this trait using bitwise 52 | /// [`std::ops::BitAnd`] 53 | /// - Using the [`modular!`] macro, you can define a modular arithmetic type and it will implement 54 | /// this trait. 55 | /// - Using the [`prime_field!`] macro, you can define a prime field type and it will implement this 56 | /// trait. 57 | pub trait Multiplicative: Mul + MulAssign + PartialEq + Sized {} 58 | 59 | /// Trait for types that have a concept of positive infinity. 60 | pub trait Infinity { 61 | /// Returns the positive infinity value for the type. 62 | const INFINITY: Self; 63 | } 64 | -------------------------------------------------------------------------------- /cova-algebra/src/arithmetic/modular.rs: -------------------------------------------------------------------------------- 1 | //! Modular arithmetic abstractions and implementations. 2 | //! 3 | //! This module provides a macro for creating custom modular number types 4 | //! and implementations of various arithmetic operations for them. 5 | //! 6 | //! # Examples 7 | //! 8 | //! ``` 9 | //! use cova_algebra::{modular, prime_field}; 10 | //! 11 | //! // Create a type for numbers modulo 7 (a prime number) 12 | //! modular!(Mod7, u32, 7); 13 | //! prime_field!(Mod7); 14 | //! 15 | //! let a = Mod7::new(3); 16 | //! let b = Mod7::new(5); 17 | //! let sum = a + b; // 8 ≡ 1 (mod 7) 18 | //! 19 | //! let product = a * b; // 15 ≡ 1 (mod 7) 20 | //! 21 | //! let inverse = a.multiplicative_inverse(); // 3 * 5 ≡ 1 (mod 7) 22 | //! ``` 23 | 24 | /// A const function to check if a number is prime at compile time. 25 | /// 26 | /// This is used by the `modular!` macro to determine if a field implementation 27 | /// should be generated. 28 | pub const fn is_prime(n: u32) -> bool { 29 | if n <= 1 { 30 | return false; 31 | } 32 | if n <= 3 { 33 | return true; 34 | } 35 | if n % 2 == 0 || n % 3 == 0 { 36 | return false; 37 | } 38 | let mut i = 5; 39 | while i * i <= n { 40 | if n % i == 0 || n % (i + 2) == 0 { 41 | return false; 42 | } 43 | i += 6; 44 | } 45 | true 46 | } 47 | 48 | /// A macro for creating custom modular number types. 49 | /// 50 | /// This macro creates a new type for numbers modulo a given value, 51 | /// implementing various arithmetic operations and algebraic traits. 52 | /// If the modulus is a prime number, it will also implement the `Field` trait. 53 | /// 54 | /// # Examples 55 | /// 56 | /// ``` 57 | /// use cova_algebra::modular; 58 | /// 59 | /// // Create a type for numbers modulo 7 (a prime number) 60 | /// modular!(Mod7, u32, 7); 61 | /// 62 | /// let a = Mod7::new(3); 63 | /// let b = Mod7::new(5); 64 | /// 65 | /// // Addition: 3 + 5 = 8 ≡ 1 (mod 7) 66 | /// let sum = a + b; 67 | /// assert_eq!(sum.value(), 1); 68 | /// 69 | /// // Multiplication: 3 * 5 = 15 ≡ 1 (mod 7) 70 | /// let product = a * b; 71 | /// assert_eq!(product.value(), 1); 72 | /// ``` 73 | #[macro_export] 74 | macro_rules! modular { 75 | ($name:ident, $inner:ty, $modulus:expr) => { 76 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 77 | pub struct $name($inner); 78 | 79 | impl $name { 80 | /// The modulus for this modular number type. 81 | pub const MODULUS: $inner = $modulus; 82 | 83 | /// Creates a new modular number from a value. 84 | /// 85 | /// The value is automatically reduced modulo `MODULUS`. 86 | pub fn new(value: $inner) -> Self { Self(value % Self::MODULUS) } 87 | 88 | /// Returns the value of this modular number. 89 | #[allow(unused)] 90 | pub const fn value(&self) -> $inner { self.0 } 91 | } 92 | 93 | impl num_traits::Zero for $name { 94 | fn zero() -> Self { Self(0) } 95 | 96 | fn is_zero(&self) -> bool { self.0 == 0 } 97 | } 98 | 99 | impl std::ops::Add for $name { 100 | type Output = Self; 101 | 102 | fn add(self, rhs: Self) -> Self { Self::new(self.0.wrapping_add(rhs.0)) } 103 | } 104 | 105 | impl std::ops::AddAssign for $name { 106 | fn add_assign(&mut self, rhs: Self) { *self = *self + rhs; } 107 | } 108 | 109 | impl std::ops::Neg for $name { 110 | type Output = Self; 111 | 112 | fn neg(self) -> Self { 113 | if self.0 == 0 { 114 | self 115 | } else { 116 | Self::new(Self::MODULUS - self.0) 117 | } 118 | } 119 | } 120 | 121 | impl std::ops::Sub for $name { 122 | type Output = Self; 123 | 124 | fn sub(self, rhs: Self) -> Self { self + (-rhs) } 125 | } 126 | 127 | impl std::ops::SubAssign for $name { 128 | fn sub_assign(&mut self, rhs: Self) { *self = *self - rhs; } 129 | } 130 | 131 | impl num_traits::Bounded for $name { 132 | fn min_value() -> Self { Self(0) } 133 | 134 | fn max_value() -> Self { Self(Self::MODULUS - 1) } 135 | } 136 | 137 | impl num_traits::One for $name { 138 | fn one() -> Self { Self(1) } 139 | } 140 | 141 | impl std::ops::Mul for $name { 142 | type Output = Self; 143 | 144 | fn mul(self, rhs: Self) -> Self { Self::new(self.0.wrapping_mul(rhs.0)) } 145 | } 146 | 147 | impl std::ops::MulAssign for $name { 148 | fn mul_assign(&mut self, rhs: Self) { *self = *self * rhs; } 149 | } 150 | 151 | impl $crate::arithmetic::Additive for $name {} 152 | impl $crate::arithmetic::Multiplicative for $name {} 153 | 154 | impl $crate::groups::Group for $name { 155 | fn identity() -> Self { Self(0) } 156 | 157 | fn inverse(&self) -> Self { Self(Self::MODULUS - self.0) } 158 | } 159 | 160 | impl $crate::groups::AbelianGroup for $name {} 161 | impl $crate::rings::Ring for $name {} 162 | 163 | impl From<$inner> for $name { 164 | fn from(value: $inner) -> Self { Self::new(value) } 165 | } 166 | }; 167 | } 168 | 169 | /// A macro for creating prime field types. 170 | /// 171 | /// This macro extends the given type with a method for computing the modular 172 | /// multiplicative inverse using Fermat's Little Theorem. 173 | /// 174 | /// # Examples 175 | /// 176 | /// ``` 177 | /// use cova_algebra::{modular, prime_field}; 178 | /// 179 | /// modular!(Mod7, u32, 7); 180 | /// prime_field!(Mod7); 181 | /// 182 | /// let a = Mod7::new(3); 183 | /// let inverse = a.multiplicative_inverse(); 184 | /// assert_eq!(inverse.value(), 5); // 3 * 5 ≡ 1 (mod 7) 185 | /// ``` 186 | #[macro_export] 187 | macro_rules! prime_field { 188 | ($inner:ty) => { 189 | impl $inner { 190 | /// Computes the modular multiplicative inverse using Fermat's Little Theorem. 191 | /// 192 | /// # Panics 193 | /// 194 | /// This function will panic if called on zero. 195 | fn multiplicative_inverse(&self) -> Self { 196 | if self.0 == 0 { 197 | panic!("Cannot compute inverse of zero"); 198 | } 199 | // Fermat's Little Theorem: a^(p-1) ≡ 1 (mod p) 200 | // Therefore, a^(p-2) ≡ a^(-1) (mod p) 201 | let mut result = Self(1); 202 | let mut base = *self; 203 | let mut exponent = Self::MODULUS - 2; 204 | while exponent > 0 { 205 | if exponent % 2 == 1 { 206 | result *= base; 207 | } 208 | base = base * base; 209 | exponent /= 2; 210 | } 211 | result 212 | } 213 | } 214 | 215 | impl std::ops::Div for $inner 216 | where [(); $crate::arithmetic::modular::is_prime(<$inner>::MODULUS) as usize - 1]: 217 | { 218 | type Output = Self; 219 | 220 | #[allow(clippy::suspicious_arithmetic_impl)] 221 | fn div(self, rhs: Self) -> Self { self * rhs.multiplicative_inverse() } 222 | } 223 | 224 | impl std::ops::DivAssign for $inner 225 | where [(); $crate::arithmetic::modular::is_prime(<$inner>::MODULUS) as usize - 1]: 226 | { 227 | fn div_assign(&mut self, rhs: Self) { *self = *self / rhs; } 228 | } 229 | 230 | impl $crate::rings::Field for $inner 231 | where [(); $crate::arithmetic::modular::is_prime(<$inner>::MODULUS) as usize - 1]: 232 | { 233 | fn multiplicative_inverse(&self) -> Self { self.multiplicative_inverse() } 234 | } 235 | }; 236 | } 237 | 238 | #[cfg(test)] 239 | mod tests { 240 | use crate::{ 241 | arithmetic::{One, Zero}, 242 | groups::Group, 243 | }; 244 | 245 | modular!(Mod7, u32, 7); 246 | prime_field!(Mod7); 247 | 248 | #[test] 249 | fn test_modular_group() { 250 | // Test modulo 7 arithmetic 251 | let a = Mod7::new(3); // 3 mod 7 252 | let b = Mod7::new(5); // 5 mod 7 253 | 254 | // Test addition: 3 + 5 = 8 ≡ 1 (mod 7) 255 | let sum = a + b; 256 | assert_eq!(sum.value(), 1); 257 | 258 | // Test subtraction: 3 - 5 = -2 ≡ 5 (mod 7) 259 | let diff = a - b; 260 | assert_eq!(diff.value(), 5); 261 | 262 | // Test negation: -3 ≡ 4 (mod 7) and inverse 263 | let neg = -a; 264 | assert_eq!(neg.value(), 4); 265 | assert_eq!(neg.inverse().value(), 3); 266 | 267 | // Test zero and identity 268 | assert_eq!(Mod7::zero().value(), 0); 269 | assert_eq!(Mod7::identity().value(), 0); 270 | } 271 | 272 | #[test] 273 | fn test_modular_ring() { 274 | let a = Mod7::new(3); 275 | let b = Mod7::new(5); 276 | 277 | let sum = a * b; 278 | assert_eq!(sum.value(), 1); 279 | 280 | let product = a * a; 281 | assert_eq!(product.value(), 2); 282 | 283 | // Test additive inverse 284 | let inverse = a.inverse(); 285 | assert_eq!(inverse.value(), 4); 286 | 287 | // Test one 288 | assert_eq!(Mod7::one().value(), 1); 289 | 290 | // Test zero 291 | assert_eq!(Mod7::zero().value(), 0); 292 | } 293 | 294 | #[test] 295 | fn test_modular_field() { 296 | let a = Mod7::new(3); 297 | let inverse = a.multiplicative_inverse(); 298 | assert_eq!(inverse.value(), 5); // 3 * 5 ≡ 1 (mod 7) 299 | } 300 | } 301 | -------------------------------------------------------------------------------- /cova-algebra/src/arithmetic/primitive.rs: -------------------------------------------------------------------------------- 1 | //! # Primitive Types Implementation 2 | //! 3 | //! This module implements the algebraic traits from the crate for Rust's primitive numeric types. 4 | //! 5 | //! ## Implementations 6 | //! 7 | //! - `Additive`: Implemented for all primitive numeric types, indicating they form an additive 8 | //! structure 9 | //! - `Multiplicative`: Implemented for all primitive numeric types, indicating they form a 10 | //! multiplicative structure 11 | //! - `Infinity`: Implemented for floating point types (f32, f64), providing access to their 12 | //! infinity values 13 | //! 14 | //! These trait implementations allow primitive types to be used directly with the algebraic 15 | //! abstractions defined in this crate, enabling seamless integration between Rust's built-in 16 | //! types and the algebraic structures defined in this library. 17 | //! 18 | //! No additional methods are needed as Rust's primitive types already implement the required 19 | //! operations (`Add`, `Mul`, etc.) with the correct semantics. 20 | 21 | use super::*; 22 | 23 | // Implement Additive for all primitive numeric types 24 | impl Additive for u8 {} 25 | impl Additive for u16 {} 26 | impl Additive for u32 {} 27 | impl Additive for u64 {} 28 | impl Additive for u128 {} 29 | impl Additive for usize {} 30 | 31 | impl Additive for i8 {} 32 | impl Additive for i16 {} 33 | impl Additive for i32 {} 34 | impl Additive for i64 {} 35 | impl Additive for i128 {} 36 | impl Additive for isize {} 37 | 38 | impl Additive for f32 {} 39 | impl Additive for f64 {} 40 | 41 | // Implement Multiplicative for all primitive numeric types 42 | impl Multiplicative for u8 {} 43 | impl Multiplicative for u16 {} 44 | impl Multiplicative for u32 {} 45 | impl Multiplicative for u64 {} 46 | impl Multiplicative for u128 {} 47 | impl Multiplicative for usize {} 48 | 49 | impl Multiplicative for i8 {} 50 | impl Multiplicative for i16 {} 51 | impl Multiplicative for i32 {} 52 | impl Multiplicative for i64 {} 53 | impl Multiplicative for i128 {} 54 | impl Multiplicative for isize {} 55 | 56 | impl Multiplicative for f32 {} 57 | impl Multiplicative for f64 {} 58 | 59 | // Implement Infinity for float primitive numeric types 60 | impl Infinity for f32 { 61 | const INFINITY: Self = Self::INFINITY; 62 | } 63 | 64 | impl Infinity for f64 { 65 | const INFINITY: Self = Self::INFINITY; 66 | } 67 | -------------------------------------------------------------------------------- /cova-algebra/src/category.rs: -------------------------------------------------------------------------------- 1 | //! # Category Theory Primitives 2 | //! 3 | //! This module provides a basic trait, [`Category`], for representing abstract 4 | //! categories in mathematics. A category consists of objects and morphisms 5 | //! (or arrows) between these objects. 6 | //! 7 | //! ## Mathematical Definition 8 | //! 9 | //! A category $\mathcal{C}$ consists of: 10 | //! - A collection of **objects**, denoted $\text{ob}(\mathcal{C})$. 11 | //! - For every pair of objects $A, B \in \text{ob}(\mathcal{C})$, a collection of **morphisms** (or 12 | //! arrows) from $A$ to $B$, denoted $\text{Hom}_{\mathcal{C}}(A, B)$. If $f \in 13 | //! \text{Hom}_{\mathcal{C}}(A, B)$, we write $f: A \to B$. 14 | //! - For every object $A \in \text{ob}(\mathcal{C})$, an **identity morphism** $\text{id}_A: A \to 15 | //! A$. 16 | //! - For every triple of objects $A, B, C \in \text{ob}(\mathcal{C})$, a binary operation called 17 | //! **composition of morphisms**, $ \circ : \text{Hom}_{\mathcal{C}}(B, C) \times 18 | //! \text{Hom}_{\mathcal{C}}(A, B) \to \text{Hom}_{\mathcal{C}}(A, C)$. Given $g: B \to C$ and $f: 19 | //! A \to B$, their composition is written $g \circ f: A \to C$. 20 | //! 21 | //! These components must satisfy two axioms: 22 | //! 1. **Associativity**: For any morphisms $f: A \to B$, $g: B \to C$, and $h: C \to D$, the 23 | //! equation $h \circ (g \circ f) = (h \circ g) \circ f$ must hold. 24 | //! 2. **Identity**: For any morphism $f: A \to B$, the equations $\text{id}_B \circ f = f$ and $f 25 | //! \circ \text{id}_A = f$ must hold. 26 | //! 27 | //! In this module, the objects of the category are represented by types that implement 28 | //! the [`Category`] trait itself. The morphisms are represented by an associated type 29 | //! [`Category::Morphism`]. 30 | 31 | // TODO (autoparallel): It may be smarter to have these use references instead of 32 | // ownership. This way we can avoid unnecessary cloning. 33 | /// Represents an object in a category, along with its morphisms and operations. 34 | /// 35 | /// In category theory, a category consists of objects and morphisms between them. 36 | /// This trait models an object within such a category. The type implementing `Category` 37 | /// acts as an object, and it defines an associated type `Morphism` for the arrows. 38 | /// 39 | /// The trait provides methods for morphism composition, obtaining identity morphisms, 40 | /// and applying a morphism to an object (which can be thought of as evaluating a function 41 | /// if objects are sets and morphisms are functions, or as a more abstract action). 42 | pub trait Category: Sized { 43 | /// The type of morphisms (arrows) between objects in this category. 44 | /// For example, if objects are sets, morphisms could be functions. 45 | /// If objects are vector spaces, morphisms could be linear maps. 46 | type Morphism; 47 | 48 | /// Composes two morphisms `f` and `g`. 49 | /// 50 | /// If $g: B \to C$ and $f: A \to B$, then `compose(g, f)` results in a morphism $g \circ f: A \to 51 | /// C$. Note the order: `g` is applied after `f`. 52 | /// 53 | /// # Arguments 54 | /// 55 | /// * `f`: The first morphism to apply (e.g., $f: A \to B$). 56 | /// * `g`: The second morphism to apply (e.g., $g: B \to C$). 57 | /// 58 | /// # Returns 59 | /// 60 | /// The composed morphism $g \circ f$. 61 | fn compose(f: Self::Morphism, g: Self::Morphism) -> Self::Morphism; 62 | 63 | /// Returns the identity morphism for a given object `a`. 64 | /// 65 | /// The identity morphism $\text{id}_a: a \to a$ is such that for any morphism 66 | /// $f: X \to a$, $\text{id}_a \circ f = f$, and for any morphism $g: a \to Y$, 67 | /// $g \circ \text{id}_a = g$. 68 | /// 69 | /// # Arguments 70 | /// 71 | /// * `a`: The object for which to get the identity morphism. In this trait, `Self` is the object. 72 | /// 73 | /// # Returns 74 | /// 75 | /// The identity morphism for object `a`. 76 | fn identity(a: Self) -> Self::Morphism; 77 | 78 | /// Applies a morphism `f` to an object `x`. 79 | /// 80 | /// This can be interpreted in various ways depending on the specific category. 81 | /// If objects are sets and `x` is an element of an object `A` (represented by `Self`), 82 | /// and $f: A \to B$ is a morphism, then `apply(f, x)` could represent $f(x)$, an element of `B`. 83 | /// More generally, if `Self` represents an object `A` and `f` is a morphism $A \to B$, 84 | /// this function should return an object of type `Self` representing `B` after the action of `f` 85 | /// on `A` (or an element of `B` if `Self` represents elements). 86 | /// 87 | /// The exact semantics (whether `Self` represents an object or an element of an object, 88 | /// and what `apply` means) might need clarification based on usage. 89 | /// Given the return type is `Self`, it suggests `f` might be an endomorphism ($f: A \to A$) 90 | /// and `x` is an instance of `A`, or that `Self` represents elements and `f` maps elements of 91 | /// one object (type) to elements of another (potentially same type `Self`). 92 | /// 93 | /// # Arguments 94 | /// 95 | /// * `f`: The morphism to apply. 96 | /// * `x`: The object (or element of an object) to which the morphism is applied. 97 | /// 98 | /// # Returns 99 | /// 100 | /// The result of applying morphism `f` to `x`. 101 | fn apply(f: Self::Morphism, x: Self) -> Self; 102 | } 103 | -------------------------------------------------------------------------------- /cova-algebra/src/groups.rs: -------------------------------------------------------------------------------- 1 | //! Group theory abstractions and implementations. 2 | //! 3 | //! This module provides traits and implementations for group theory concepts, 4 | //! including both Abelian (commutative) and non-Abelian groups. 5 | 6 | use super::*; 7 | 8 | /// A trait representing a mathematical group. 9 | /// 10 | /// A group is a set equipped with an operation that combines any two of its elements 11 | /// to form a third element, satisfying four conditions called the group axioms: 12 | /// closure, associativity, identity, and invertibility. 13 | pub trait Group { 14 | /// Returns the identity element of the group. 15 | fn identity() -> Self; 16 | 17 | /// Returns the inverse of an element. 18 | fn inverse(&self) -> Self; 19 | } 20 | 21 | /// A trait representing an Abelian (commutative) group. 22 | /// 23 | /// An Abelian group is a group where the group operation is commutative. 24 | /// This trait combines the requirements for a group with additional operations 25 | /// that are natural for commutative groups. We mark this as an [`Additive`] structure since this is 26 | /// typical notation for Abelian groups. 27 | pub trait AbelianGroup: 28 | Group + Zero + Additive + Neg + Sub + SubAssign { 29 | } 30 | 31 | /// A trait representing a non-Abelian group. 32 | /// 33 | /// A non-Abelian group is a group where the group operation is not necessarily commutative. 34 | /// This trait combines the requirements for a group with additional operations 35 | /// that are natural for non-commutative groups. We mark this as a [`Multiplicative`] structure 36 | /// since this is typical notation for non-Abelian groups. However, it should be noted that a 37 | /// [`NonAbelianGroup`] group cannot be an [`AbelianGroup`] 38 | pub trait NonAbelianGroup: Group + One + Multiplicative + Div + DivAssign {} 39 | -------------------------------------------------------------------------------- /cova-algebra/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A Rust library for abstract algebra. 2 | //! 3 | //! This crate provides implementations of various algebraic structures and operations, 4 | //! with a focus on modular arithmetic and abstract algebra concepts. 5 | //! 6 | //! # Features 7 | //! 8 | //! - **Modular Arithmetic**: Create custom modular number types with the `modular!` macro 9 | //! - **Abstract Algebra**: Implementations of fundamental algebraic structures: 10 | //! - Groups (both Abelian and Non-Abelian) 11 | //! - Rings 12 | //! - Fields 13 | //! - Modules 14 | //! - Vector Spaces 15 | //! 16 | //! # Examples 17 | //! 18 | //! ## Modular Arithmetic 19 | //! 20 | //! ``` 21 | //! use cova_algebra::{algebras::boolean::Boolean, modular, rings::Field}; 22 | //! 23 | //! // Create a type for numbers modulo 7 24 | //! modular!(Mod7, u32, 7); 25 | //! 26 | //! let a = Mod7::new(3); 27 | //! let b = Mod7::new(5); 28 | //! let sum = a + b; // 8 ≡ 1 (mod 7) 29 | //! ``` 30 | //! 31 | //! ## Vector Spaces 32 | //! 33 | //! ``` 34 | //! use cova_algebra::{algebras::boolean::Boolean, rings::Field, tensors::fixed::FixedVector}; 35 | //! 36 | //! let v1 = FixedVector::<3, f64>([1.0, 2.0, 3.0]); 37 | //! let v2 = FixedVector::<3, f64>([4.0, 5.0, 6.0]); 38 | //! let sum = v1 + v2; 39 | //! ``` 40 | 41 | #![warn(missing_docs)] 42 | #![allow(incomplete_features)] 43 | #![feature(generic_const_exprs)] 44 | 45 | pub mod algebras; 46 | pub mod arithmetic; 47 | pub mod category; 48 | pub mod groups; 49 | pub mod modules; 50 | pub mod rings; 51 | pub mod tensors; 52 | 53 | pub use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; 54 | 55 | pub use num_traits::{One, Zero}; 56 | 57 | pub use crate::arithmetic::{Additive, Multiplicative}; 58 | 59 | pub mod prelude { 60 | //! # Prelude Module 61 | //! 62 | //! This module re-exports the most commonly used types, traits, and operations from the 63 | //! algebra crate for convenient importing. 64 | //! 65 | //! ## Purpose 66 | //! 67 | //! The prelude pattern allows users to import multiple commonly used items with a single 68 | //! import statement, reducing boilerplate and improving code readability. 69 | //! 70 | //! ## Contents 71 | //! 72 | //! The prelude includes: 73 | //! 74 | //! - Core algebraic structures: [`Algebra`], [`Group`], [`Ring`], [`Field`], [`VectorSpace`] 75 | //! - Behavioral traits: [`Additive`], [`Multiplicative`] 76 | //! - Group variants: [`AbelianGroup`], [`NonAbelianGroup`] 77 | //! - Module types: [`LeftModule`], [`RightModule`], [`TwoSidedModule`] 78 | //! - Semimodule types: [`LeftSemimodule`], [`RightSemimodule`], [`TwoSidedSemimodule`] 79 | //! - Fundamental operators: [`Add`], [`Mul`], [`Sub`], [`Div`] and their assignment variants 80 | //! - Identity concepts: [`Zero`], [`One`], [`Neg`] 81 | //! 82 | //! ## Usage 83 | //! 84 | //! ``` 85 | //! // Import everything from the prelude 86 | //! use cova_algebra::prelude::*; 87 | //! ``` 88 | 89 | pub use crate::{ 90 | algebras::Algebra, 91 | arithmetic::{Additive, Multiplicative}, 92 | category::Category, 93 | groups::{AbelianGroup, Group, NonAbelianGroup}, 94 | modules::{ 95 | LeftModule, LeftSemimodule, RightModule, RightSemimodule, TwoSidedModule, TwoSidedSemimodule, 96 | VectorSpace, 97 | }, 98 | rings::{Field, Ring}, 99 | Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, One, Sub, SubAssign, Zero, 100 | }; 101 | } 102 | 103 | #[cfg(test)] 104 | mod fixtures { 105 | use crate::{modular, prime_field}; 106 | 107 | modular!(Mod7, u32, 7); 108 | prime_field!(Mod7); 109 | } 110 | -------------------------------------------------------------------------------- /cova-algebra/src/modules/mod.rs: -------------------------------------------------------------------------------- 1 | // TODO: Redo these docs. 2 | 3 | //! Module theory abstractions and implementations. 4 | //! 5 | //! This module provides traits and implementations for module theory concepts, 6 | //! which generalize vector spaces by allowing the scalars to lie in a ring rather than a field. 7 | //! 8 | //! Semimodule abstractions and implementations. 9 | //! 10 | //! A semimodule is a generalization of vector spaces and modules where the scalars form a semiring 11 | //! rather than a ring or field. Like modules, semimodules support scalar multiplication and 12 | //! addition, but the scalars only need to form a semiring structure. 13 | //! 14 | //! # Key Concepts 15 | //! 16 | //! - **Semimodule**: A set with an additive structure and scalar multiplication by elements of a 17 | //! semiring 18 | //! - **Semiring**: A ring-like structure but without the requirement of additive inverses 19 | //! - **Scalar Multiplication**: Compatible multiplication between semiring elements and semimodule 20 | //! elements 21 | //! 22 | //! # Examples 23 | //! 24 | //! The tropical algebra (implemented in the `tropical` module) is a classic example of a 25 | //! semimodule, where addition is replaced by maximum and multiplication by regular addition. 26 | //! 27 | //! # Module Structure 28 | //! 29 | //! - [`trivial`]: Trivial semimodule 30 | //! - [`tropical`]: Semimodule over the tropical semiring 31 | 32 | use core::marker::PhantomData; 33 | 34 | use super::*; 35 | use crate::{ 36 | groups::{AbelianGroup, Group}, 37 | rings::{Field, Ring, Semiring}, 38 | }; 39 | 40 | pub mod trivial; 41 | pub mod tropical; 42 | 43 | /// A left semimodule over a semiring. 44 | /// 45 | /// A set with commutative addition and left scalar multiplication satisfying: 46 | /// - Distributivity: s * (x + y) = s * x + s * y 47 | /// - Compatibility: (s + t) * x = s * x + t * x 48 | /// - Associativity: (s * t) * x = s * (t * x) 49 | /// - Identity: 1 * x = x 50 | /// - Zero: 0 * x = 0 51 | pub trait LeftSemimodule 52 | where Self: Mul { 53 | /// The Semiring that this semimodule is defined over. 54 | type Semiring: Semiring; 55 | } 56 | 57 | /// A right semimodule over a semiring. 58 | /// 59 | /// A set with commutative addition and right scalar multiplication satisfying: 60 | /// - Distributivity: (x + y) * s = x * s + y * s 61 | /// - Compatibility: x * (s + t) = x * s + x * t 62 | /// - Associativity: x * (s * t) = (x * s) * t 63 | /// - Identity: x * 1 = x 64 | /// - Zero: x * 0 = 0 65 | pub trait RightSemimodule 66 | where Self: Mul { 67 | /// The Semiring that this semimodule is defined over. 68 | type Semiring: Semiring; 69 | } 70 | 71 | /// A two-sided semimodule over a semiring. 72 | /// 73 | /// - **Semimodule**: A vector space generalization where scalars are elements of a semiring 74 | /// - **Left/Right Semimodule**: Defines scalar multiplication from left/right respectively 75 | /// - **Two-Sided Semimodule**: Both left and right semimodule over the same semiring 76 | /// 77 | /// Combines left and right semimodule properties over the same semiring. 78 | /// Note: For commutative semirings, left and right actions typically coincide. 79 | pub trait TwoSidedSemimodule: LeftSemimodule + RightSemimodule { 80 | /// The semiring over which this semimodule is defined. 81 | type Semiring: Semiring; 82 | } 83 | 84 | /// A trait representing a left module over a ring. 85 | /// 86 | /// A left module is a generalization of a vector space, where the scalars lie in a ring 87 | /// rather than a field. This trait combines the requirements for an Abelian group 88 | /// with scalar multiplication by elements of the ring on the left. 89 | pub trait LeftModule: AbelianGroup 90 | where Self::Ring: Mul { 91 | /// The ring over which this module is defined. 92 | type Ring: Ring; 93 | } 94 | 95 | /// A trait representing a right module over a ring. 96 | /// 97 | /// A right module is a generalization of a vector space, where the scalars lie in a ring 98 | /// rather than a field. This trait combines the requirements for an Abelian group 99 | /// with scalar multiplication by elements of the ring on the right. 100 | pub trait RightModule: AbelianGroup 101 | where Self::Ring: Mul { 102 | /// The ring over which this module is defined. 103 | type Ring: Ring; 104 | } 105 | 106 | /// A trait representing a two-sided module over a ring. 107 | /// 108 | /// A two-sided module is a generalization of a vector space, where the scalars lie in a ring 109 | /// rather than a field. This trait combines the requirements for an Abelian group 110 | /// with scalar multiplication by elements of the ring on both the left and right. 111 | pub trait TwoSidedModule: LeftModule + RightModule { 112 | /// The ring over which this module is defined. 113 | type Ring: Ring; 114 | } 115 | 116 | /// A trait representing a vector space over a field. 117 | /// 118 | /// A vector space is a module over a field, meaning it has both addition and 119 | /// scalar multiplication operations, with the scalars coming from a field. 120 | pub trait VectorSpace: TwoSidedModule 121 | where ::Ring: Field { 122 | } 123 | -------------------------------------------------------------------------------- /cova-algebra/src/modules/trivial.rs: -------------------------------------------------------------------------------- 1 | //! # Trivial Module 2 | //! 3 | //! This module provides an implementation of a trivial module over an arbitrary ring. 4 | //! 5 | //! ## Mathematical Background 6 | //! 7 | //! In abstract algebra, a trivial module is a module that contains exactly one element: 8 | //! the zero element. All operations on this element return the zero element itself: 9 | //! 10 | //! - Addition: $0 + 0 = 0$ 11 | //! - Negation: $-0 = 0$ 12 | //! - Scalar multiplication: $r \cdot 0 = 0$ for any ring element $r$ 13 | //! 14 | //! ## Properties 15 | //! 16 | //! The trivial module satisfies all module axioms in the simplest possible way: 17 | //! 18 | //! - It forms an abelian group under addition (with only one element) 19 | //! - Scalar multiplication is distributive over addition 20 | //! - Scalar multiplication is compatible with ring multiplication 21 | //! 22 | //! ## Use Cases 23 | //! 24 | //! The trivial module serves several purposes: 25 | //! 26 | //! - As a base case in recursive constructions and mathematical proofs 27 | //! - To represent the kernel or image of certain module homomorphisms 28 | //! - For testing module-related algorithms with the simplest possible input 29 | //! - As a terminal object in the category of R-modules 30 | //! 31 | //! ## Example 32 | //! 33 | //! ``` 34 | //! use cova_algebra::{modules::trivial::TrivialModule, prelude::*}; 35 | //! 36 | //! // Create a trivial module over the integers 37 | //! let m1: TrivialModule = TrivialModule::zero(); 38 | //! let m2: TrivialModule = TrivialModule::zero(); 39 | //! 40 | //! // All operations return the same element 41 | //! assert_eq!(m1 + m2, m1); 42 | //! assert_eq!(m1 * 42, m1); 43 | //! assert_eq!(-m1, m1); 44 | //! ``` 45 | 46 | use super::*; 47 | 48 | /// A trivial module over a ring. 49 | /// 50 | /// This is a simple implementation of a module that has only one element. 51 | /// It's useful as a base case or for testing purposes. 52 | #[derive(Clone, Copy, Default, Eq, PartialEq, Debug)] 53 | pub struct TrivialModule { 54 | pub(crate) _r: PhantomData, 55 | } 56 | 57 | impl Add for TrivialModule { 58 | type Output = Self; 59 | 60 | fn add(self, _: Self) -> Self::Output { Self { _r: PhantomData } } 61 | } 62 | 63 | impl AddAssign for TrivialModule { 64 | fn add_assign(&mut self, _: Self) {} 65 | } 66 | 67 | impl Sub for TrivialModule { 68 | type Output = Self; 69 | 70 | fn sub(self, _: Self) -> Self::Output { Self { _r: PhantomData } } 71 | } 72 | 73 | impl SubAssign for TrivialModule { 74 | fn sub_assign(&mut self, _: Self) {} 75 | } 76 | 77 | impl Neg for TrivialModule { 78 | type Output = Self; 79 | 80 | fn neg(self) -> Self::Output { Self { _r: PhantomData } } 81 | } 82 | 83 | impl Mul for TrivialModule { 84 | type Output = Self; 85 | 86 | fn mul(self, _: R) -> Self::Output { Self { _r: PhantomData } } 87 | } 88 | 89 | impl Zero for TrivialModule { 90 | fn zero() -> Self { Self { _r: PhantomData } } 91 | 92 | fn is_zero(&self) -> bool { true } 93 | } 94 | 95 | impl Additive for TrivialModule {} 96 | 97 | impl Group for TrivialModule { 98 | fn identity() -> Self { Self { _r: PhantomData } } 99 | 100 | fn inverse(&self) -> Self { Self { _r: PhantomData } } 101 | } 102 | 103 | impl AbelianGroup for TrivialModule {} 104 | impl> LeftModule for TrivialModule { 105 | type Ring = R; 106 | } 107 | 108 | impl> RightModule for TrivialModule { 109 | type Ring = R; 110 | } 111 | 112 | impl> TwoSidedModule for TrivialModule { 113 | type Ring = R; 114 | } 115 | -------------------------------------------------------------------------------- /cova-algebra/src/rings.rs: -------------------------------------------------------------------------------- 1 | //! Ring theory abstractions and implementations. 2 | //! 3 | //! This module provides traits and implementations for ring theory concepts, 4 | //! including both general rings and fields (which are special types of rings). 5 | 6 | use super::*; 7 | use crate::groups::AbelianGroup; 8 | 9 | /// A trait representing a mathematical ring. 10 | /// 11 | /// A ring is a set equipped with two binary operations (addition and multiplication) 12 | /// satisfying properties analogous to those of addition and multiplication of integers. 13 | /// This trait combines the requirements for an Abelian group with multiplicative properties. 14 | pub trait Ring: AbelianGroup + Multiplicative + One {} 15 | 16 | /// A trait representing a mathematical field. 17 | /// 18 | /// A field is a set on which addition, subtraction, multiplication, and division 19 | /// are defined and behave as the corresponding operations on rational and real numbers. 20 | /// Every non-zero element has a multiplicative inverse. 21 | pub trait Field: Ring + Div + DivAssign { 22 | /// Returns the multiplicative inverse of a non-zero element. 23 | /// 24 | /// # Panics 25 | /// 26 | /// This function may panic if called on the zero element. 27 | fn multiplicative_inverse(&self) -> Self; 28 | } 29 | 30 | macro_rules! impl_ring { 31 | ($inner:ty) => { 32 | impl $crate::groups::Group for $inner { 33 | fn identity() -> Self { Self::zero() } 34 | 35 | fn inverse(&self) -> Self { -self } 36 | } 37 | 38 | impl $crate::groups::AbelianGroup for $inner {} 39 | impl $crate::rings::Ring for $inner {} 40 | }; 41 | } 42 | 43 | macro_rules! impl_field { 44 | ($inner:ty) => { 45 | impl $crate::rings::Field for $inner { 46 | fn multiplicative_inverse(&self) -> Self { self.recip() } 47 | } 48 | }; 49 | } 50 | 51 | impl_ring!(i8); 52 | impl_ring!(i16); 53 | impl_ring!(i32); 54 | impl_ring!(i64); 55 | impl_ring!(i128); 56 | impl_ring!(isize); 57 | 58 | impl_ring!(f32); 59 | impl_ring!(f64); 60 | impl_field!(f32); 61 | impl_field!(f64); 62 | 63 | /// A trait representing a mathematical semiring. 64 | /// 65 | /// A semiring is a set equipped with two binary operations (addition and multiplication) 66 | /// satisfying properties of distributivity and associativity analogous to those of addition and 67 | /// multiplication of integers. This trait combines the requirements for an Abelian monoid with 68 | /// multiplicative properties. 69 | /// 70 | /// # Requirements 71 | /// 72 | /// A semiring (R, +, ·) must satisfy: 73 | /// 1. (R, +) is a commutative monoid with identity element 0 74 | /// 2. (R, ·) is a monoid with identity element 1 75 | /// 3. Multiplication distributes over addition: 76 | /// - Left distributivity: a·(b + c) = a·b + a·c 77 | /// - Right distributivity: (a + b)·c = a·c + b·c 78 | /// 4. Multiplication by 0 annihilates R: 0·a = a·0 = 0 79 | /// 80 | /// # Implementation Notes 81 | /// 82 | /// The distributive properties are enforced by the combination of the `Additive` and 83 | /// `Multiplicative` traits. Implementors must ensure that their implementations satisfy these 84 | /// properties. Semirings are not groups because they do not have additive inverses. 85 | /// 86 | /// If you want a structure with an additive inverse, use the Ring trait instead, since it 87 | /// has the abelian group trait bound. If you only need addition to be associative and commutative 88 | /// (but without an additive identity), use the semiring trait. 89 | /// 90 | /// # Examples 91 | /// 92 | /// Common examples of semirings include: 93 | /// - Natural numbers (ℕ, +, ×) 94 | /// - Tropical semiring (ℝ ∪ {∞}, min, +) 95 | /// - Probability semiring (ℝ₊, +, ×) 96 | pub trait Semiring: Additive + Multiplicative + Zero + One {} 97 | -------------------------------------------------------------------------------- /cova-algebra/src/tensors/dynamic/mod.rs: -------------------------------------------------------------------------------- 1 | //! # Dynamic Tensors Module 2 | //! 3 | //! This module provides implementations of tensors with dynamically determined dimensions, 4 | //! focusing on vectors and matrices. 5 | //! 6 | //! ## Overview 7 | //! 8 | //! The dynamic tensors module includes: 9 | //! 10 | //! - `Vector`: A flexible vector implementation with arbitrary dimension 11 | //! - `Matrix`: A clean, ergonomic matrix implementation with block construction support 12 | //! 13 | //! ## Mathematical Foundation 14 | //! 15 | //! Tensors are mathematical objects that generalize vectors and matrices to higher dimensions. 16 | //! The implementations in this module adhere to the algebraic properties of vector spaces 17 | //! and linear transformations over arbitrary fields. 18 | //! 19 | //! ## Examples 20 | //! 21 | //! ``` 22 | //! use cova_algebra::{ 23 | //! prelude::*, 24 | //! tensors::dynamic::{matrix::Matrix, vector::Vector}, 25 | //! }; 26 | //! 27 | //! // Create vectors 28 | //! let v1 = Vector::from([1.0, 2.0, 3.0]); 29 | //! let v2 = Vector::from([4.0, 5.0, 6.0]); 30 | //! 31 | //! // Create a matrix from rows 32 | //! let matrix = Matrix::from_rows([v1, v2]); 33 | //! 34 | //! // Or using builder pattern 35 | //! let matrix = Matrix::::builder().row([1.0, 2.0, 3.0]).row([4.0, 5.0, 6.0]).build(); 36 | //! 37 | //! // Block matrix construction 38 | //! let block_matrix = Matrix::::from_blocks(vec![ 39 | //! vec![Matrix::identity(2), Matrix::zeros(2, 3)], 40 | //! vec![Matrix::zeros(3, 2), Matrix::identity(3)], 41 | //! ]); 42 | //! 43 | //! // Perform Gaussian elimination to row echelon form 44 | //! let (rref, output) = matrix.into_row_echelon_form(); 45 | //! ``` 46 | 47 | pub use matrix::Matrix; 48 | pub use vector::Vector; 49 | 50 | use super::*; 51 | 52 | pub mod matrix; 53 | pub mod vector; 54 | 55 | /// Computes a basis for the quotient space V/U. 56 | /// 57 | /// Given `subspace_vectors` forming a basis for a subspace U, and 58 | /// `space_vectors` forming a basis for a space V (where U is a subspace of V), 59 | /// this method returns a basis for the quotient space V/U. 60 | /// The input vectors are treated as column vectors. 61 | pub fn compute_quotient_basis( 62 | subspace_vectors: &[Vector], 63 | space_vectors: &[Vector], 64 | ) -> Vec> { 65 | if space_vectors.is_empty() { 66 | return Vec::new(); 67 | } 68 | 69 | // Determine the common dimension of all vectors from the first space vector. 70 | // All vectors (subspace and space) must have this same dimension. 71 | let expected_num_rows = space_vectors[0].dimension(); 72 | 73 | // Verify all subspace vectors match this dimension. 74 | for (idx, vec) in subspace_vectors.iter().enumerate() { 75 | assert!( 76 | (vec.dimension() == expected_num_rows), 77 | "Subspace vector at index {} has dimension {} but expected {}", 78 | idx, 79 | vec.dimension(), 80 | expected_num_rows 81 | ); 82 | } 83 | // Verify all other space vectors match this dimension. 84 | for (idx, vec) in space_vectors.iter().skip(1).enumerate() { 85 | assert!( 86 | (vec.dimension() == expected_num_rows), 87 | "Space vector at index {} (after first) has dimension {} but expected {}", 88 | idx + 1, // adjust index because of skip(1) 89 | vec.dimension(), 90 | expected_num_rows 91 | ); 92 | } 93 | 94 | // Create matrix from columns 95 | let mut all_columns = Vec::new(); 96 | all_columns.extend_from_slice(subspace_vectors); 97 | all_columns.extend_from_slice(space_vectors); 98 | 99 | let matrix = Matrix::from_cols(all_columns); 100 | let (_, echelon_output) = matrix.into_row_echelon_form(); 101 | 102 | let mut quotient_basis: Vec> = Vec::new(); 103 | let num_subspace_cols = subspace_vectors.len(); 104 | 105 | let pivot_cols_set: std::collections::HashSet = 106 | echelon_output.pivots.iter().map(|p| p.col).collect(); 107 | 108 | for (i, original_space_vector) in space_vectors.iter().enumerate() { 109 | let augmented_matrix_col_idx = num_subspace_cols + i; 110 | if pivot_cols_set.contains(&augmented_matrix_col_idx) { 111 | quotient_basis.push(original_space_vector.clone()); 112 | } 113 | } 114 | 115 | quotient_basis 116 | } 117 | 118 | #[cfg(test)] 119 | mod tests { 120 | use super::compute_quotient_basis; 121 | use crate::{fixtures::Mod7, tensors::dynamic::vector::Vector}; 122 | 123 | #[test] 124 | fn test_quotient_simple_span() { 125 | // V = span{[1,0,0], [0,1,0]}, U = span{[1,0,0]} 126 | // V/U should be span{[0,1,0]} 127 | let u1 = Vector::from(vec![Mod7::new(1), Mod7::new(0), Mod7::new(0)]); 128 | let v_in_u = Vector::from(vec![Mod7::new(1), Mod7::new(0), Mod7::new(0)]); 129 | let v_new = Vector::from(vec![Mod7::new(0), Mod7::new(1), Mod7::new(0)]); 130 | 131 | let subspace_vectors = vec![u1]; 132 | // Order of space_vectors: putting v_in_u first 133 | let space_vectors = vec![v_in_u.clone(), v_new.clone()]; 134 | 135 | let quotient_basis = compute_quotient_basis(&subspace_vectors, &space_vectors); 136 | 137 | assert_eq!(quotient_basis.len(), 1, "Quotient basis should have 1 vector"); 138 | assert!(quotient_basis.contains(&v_new), "Quotient basis should contain the new vector"); 139 | assert!( 140 | !quotient_basis.contains(&v_in_u), 141 | "Quotient basis should not contain vector already effectively in subspace" 142 | ); 143 | } 144 | 145 | #[test] 146 | fn test_quotient_subspace_equals_space() { 147 | // V = span{[1,0], [0,1]}, U = span{[1,0], [0,1]} 148 | // V/U should be empty 149 | let u1 = Vector::from(vec![Mod7::new(1), Mod7::new(0)]); 150 | let u2 = Vector::from(vec![Mod7::new(0), Mod7::new(1)]); 151 | // space_vectors are the same as subspace_vectors 152 | let space_vectors = vec![u1.clone(), u2.clone()]; 153 | let subspace_vectors = vec![u1.clone(), u2.clone()]; 154 | 155 | let quotient_basis = compute_quotient_basis(&subspace_vectors, &space_vectors); 156 | assert_eq!( 157 | quotient_basis.len(), 158 | 0, 159 | "Quotient basis should be empty when subspace equals space" 160 | ); 161 | } 162 | 163 | #[test] 164 | fn test_quotient_trivial_subspace() { 165 | // V = span{[1,0], [0,1]}, U = {} (trivial subspace) 166 | // V/U should be span{[1,0], [0,1]} 167 | let v1 = Vector::from(vec![Mod7::new(1), Mod7::new(0)]); 168 | let v2 = Vector::from(vec![Mod7::new(0), Mod7::new(1)]); 169 | 170 | let subspace_vectors: Vec> = vec![]; 171 | let space_vectors = vec![v1.clone(), v2.clone()]; 172 | 173 | let quotient_basis = compute_quotient_basis(&subspace_vectors, &space_vectors); 174 | assert_eq!(quotient_basis.len(), 2, "Quotient basis size mismatch for trivial subspace"); 175 | assert!(quotient_basis.contains(&v1), "Quotient basis should contain v1 for trivial subspace"); 176 | assert!(quotient_basis.contains(&v2), "Quotient basis should contain v2 for trivial subspace"); 177 | } 178 | 179 | #[test] 180 | fn test_quotient_dependent_space_vectors() { 181 | // V = span{[1,0], [2,0], [0,1]}, U = span{[1,0]} 182 | // [2,0] is dependent on [1,0]. 183 | // V/U should be span{[0,1]} 184 | let u1 = Vector::from(vec![Mod7::new(1), Mod7::new(0)]); 185 | let v_in_u = Vector::from(vec![Mod7::new(1), Mod7::new(0)]); // Effectively in U 186 | let v_dependent_on_u = Vector::from(vec![Mod7::new(2), Mod7::new(0)]); // 2*u1 187 | let v_new_independent = Vector::from(vec![Mod7::new(0), Mod7::new(1)]); 188 | 189 | let subspace_vectors = vec![u1.clone()]; 190 | let space_vectors = vec![v_in_u.clone(), v_dependent_on_u.clone(), v_new_independent.clone()]; 191 | 192 | let quotient_basis = compute_quotient_basis(&subspace_vectors, &space_vectors); 193 | 194 | assert_eq!( 195 | quotient_basis.len(), 196 | 1, 197 | "Quotient basis should have 1 vector for dependent space vectors case" 198 | ); 199 | assert!( 200 | quotient_basis.contains(&v_new_independent), 201 | "Quotient basis should contain the truly new vector" 202 | ); 203 | assert!(!quotient_basis.contains(&v_in_u)); 204 | assert!(!quotient_basis.contains(&v_dependent_on_u)); 205 | } 206 | 207 | #[test] 208 | fn test_quotient_space_vectors_dependent_among_themselves_but_new_to_subspace() { 209 | // U = span{[1,0,0]} 210 | // V = span{[1,0,0], [0,1,0], [0,2,0], [0,0,1]} 211 | // Original space_vectors to select from for quotient: [[0,1,0], [0,2,0], [0,0,1]] 212 | // Expected quotient basis: a basis for span{[0,1,0], [0,0,1]}, chosen from original space 213 | // vectors. So, should be [[0,1,0], [0,0,1]] if [0,2,0] is correctly identified as dependent 214 | // on [0,1,0] in context of quotient. 215 | let u1 = Vector::from(vec![Mod7::new(1), Mod7::new(0), Mod7::new(0)]); 216 | 217 | let v1_new = Vector::from(vec![Mod7::new(0), Mod7::new(1), Mod7::new(0)]); 218 | let v2_dependent_on_v1 = Vector::from(vec![Mod7::new(0), Mod7::new(2), Mod7::new(0)]); 219 | let v3_new = Vector::from(vec![Mod7::new(0), Mod7::new(0), Mod7::new(1)]); 220 | 221 | let subspace_vectors = vec![u1]; 222 | // Order: v1_new, then its dependent v2_dependent_on_v1, then independent v3_new 223 | let space_vectors = vec![v1_new.clone(), v2_dependent_on_v1.clone(), v3_new.clone()]; 224 | 225 | let quotient_basis = compute_quotient_basis(&subspace_vectors, &space_vectors); 226 | 227 | assert_eq!( 228 | quotient_basis.len(), 229 | 2, 230 | "Quotient basis size mismatch for internally dependent space vectors" 231 | ); 232 | assert!(quotient_basis.contains(&v1_new), "Quotient basis should contain v1_new"); 233 | assert!(quotient_basis.contains(&v3_new), "Quotient basis should contain v3_new"); 234 | assert!( 235 | !quotient_basis.contains(&v2_dependent_on_v1), 236 | "Quotient basis should not contain v2_dependent_on_v1" 237 | ); 238 | } 239 | 240 | #[test] 241 | fn test_quotient_empty_space_vectors() { 242 | let u1 = Vector::from(vec![Mod7::new(1), Mod7::new(0)]); 243 | let subspace_vectors = vec![u1]; 244 | let space_vectors: Vec> = vec![]; 245 | 246 | let quotient_basis = compute_quotient_basis(&subspace_vectors, &space_vectors); 247 | assert!(quotient_basis.is_empty(), "Quotient basis should be empty if space_vectors is empty"); 248 | } 249 | 250 | #[test] 251 | fn test_quotient_zero_dimensional_vectors() { 252 | let u1_zero_dim = Vector::::new(vec![]); 253 | let v1_zero_dim = Vector::::new(vec![]); 254 | let v2_zero_dim = Vector::::new(vec![]); 255 | 256 | let subspace_vectors = vec![u1_zero_dim]; 257 | let space_vectors = vec![v1_zero_dim, v2_zero_dim]; 258 | 259 | let quotient_basis = compute_quotient_basis(&subspace_vectors, &space_vectors); 260 | assert!( 261 | quotient_basis.is_empty(), 262 | "Quotient basis for zero-dimensional vectors should be empty" 263 | ); 264 | 265 | // Case: subspace empty, space has 0-dim vectors 266 | let subspace_vectors_empty: Vec> = vec![]; 267 | let quotient_basis_empty_sub = compute_quotient_basis(&subspace_vectors_empty, &space_vectors); 268 | assert!( 269 | quotient_basis_empty_sub.is_empty(), 270 | "Quotient basis for zero-dimensional vectors (empty subspace) should be empty" 271 | ); 272 | } 273 | 274 | #[test] 275 | fn test_quotient_all_zero_vectors_of_some_dimension() { 276 | // V = span{[0,0], [0,0]}, U = span{[0,0]} 277 | // V/U should be empty 278 | let u1_zero_vec = Vector::from(vec![Mod7::new(0), Mod7::new(0)]); 279 | let v1_zero_vec = Vector::from(vec![Mod7::new(0), Mod7::new(0)]); 280 | let v2_zero_vec = Vector::from(vec![Mod7::new(0), Mod7::new(0)]); 281 | 282 | let subspace_vectors = vec![u1_zero_vec.clone()]; 283 | let space_vectors = vec![v1_zero_vec.clone(), v2_zero_vec.clone()]; 284 | 285 | let quotient_basis = compute_quotient_basis(&subspace_vectors, &space_vectors); 286 | assert!(quotient_basis.is_empty(), "Quotient basis for all zero vectors should be empty"); 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /cova-algebra/src/tensors/fixed.rs: -------------------------------------------------------------------------------- 1 | //! # Fixed Vector Module 2 | //! 3 | //! This module provides a compile-time fixed-size vector implementation over 4 | //! arbitrary fields. 5 | //! 6 | //! ## Mathematical Background 7 | //! 8 | //! A vector space $V$ over a field $F$ is a set equipped with operations of addition 9 | //! and scalar multiplication that satisfy the vector space axioms. This implementation 10 | //! represents elements of $V$ as fixed-length arrays of components from the field $F$. 11 | //! 12 | //! For any two vectors $\mathbf{u}, \mathbf{v} \in V$ and scalar $\alpha \in F$: 13 | //! 14 | //! - Vector addition: $\mathbf{u} + \mathbf{v} = (u_1 + v_1, u_2 + v_2, \ldots, u_n + v_n)$ 15 | //! - Scalar multiplication: $\alpha\mathbf{v} = (\alpha v_1, \alpha v_2, \ldots, \alpha v_n)$ 16 | //! - Additive inverse (negation): $-\mathbf{v} = (-v_1, -v_2, \ldots, -v_n)$ 17 | //! 18 | //! ## Features 19 | //! 20 | //! - Dimension determined at compile-time using const generics 21 | //! - Efficient memory layout with stack allocation 22 | //! - Support for vector arithmetic operations (+, -, *, scalar multiplication) 23 | //! - Implements algebraic traits like `Zero`, `Group`, and `VectorSpace` 24 | //! - Automatic bounds checking prevention through fixed-size arrays 25 | //! 26 | //! ## Examples 27 | //! 28 | //! ``` 29 | //! use cova_algebra::{prelude::*, tensors::fixed::FixedVector}; 30 | //! 31 | //! // Create a 3D vector with f64 components 32 | //! let v = FixedVector::<3, f64>([1.0, 2.0, 3.0]); 33 | //! 34 | //! // Create another vector 35 | //! let w = FixedVector::<3, f64>([4.0, 5.0, 6.0]); 36 | //! 37 | //! // Vector addition 38 | //! let sum = v + w; 39 | //! 40 | //! // Scalar multiplication 41 | //! let scaled = v * 2.0; 42 | //! 43 | //! // Create a zero vector 44 | //! let zero = FixedVector::<3, f64>::zero(); 45 | //! ``` 46 | 47 | use super::*; 48 | 49 | /// A fixed-size vector over a field. 50 | /// 51 | /// This is a concrete implementation of a vector space, where vectors have 52 | /// a fixed number of components and the scalars come from a field. 53 | /// 54 | /// ``` 55 | /// use cova_algebra::{rings::Field, tensors::fixed::FixedVector}; 56 | /// 57 | /// let v = FixedVector::<3, f64>([1.0, 2.0, 3.0]); 58 | /// let w = FixedVector::<3, f64>([4.0, 5.0, 6.0]); 59 | /// let sum = v + w; 60 | /// ``` 61 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 62 | pub struct FixedVector(pub [F; M]); 63 | 64 | impl Default for FixedVector { 65 | fn default() -> Self { Self([F::zero(); M]) } 66 | } 67 | 68 | impl Add for FixedVector { 69 | type Output = Self; 70 | 71 | fn add(self, other: Self) -> Self::Output { 72 | let mut sum = Self::zero(); 73 | for i in 0..M { 74 | sum.0[i] = self.0[i] + other.0[i]; 75 | } 76 | sum 77 | } 78 | } 79 | 80 | impl AddAssign for FixedVector { 81 | fn add_assign(&mut self, rhs: Self) { *self = *self + rhs } 82 | } 83 | 84 | impl Neg for FixedVector { 85 | type Output = Self; 86 | 87 | fn neg(self) -> Self::Output { 88 | let mut neg = Self::zero(); 89 | for i in 0..M { 90 | neg.0[i] = -self.0[i]; 91 | } 92 | neg 93 | } 94 | } 95 | 96 | impl Mul for FixedVector { 97 | type Output = Self; 98 | 99 | fn mul(self, scalar: F) -> Self::Output { 100 | let mut scalar_multiple = Self::zero(); 101 | for i in 0..M { 102 | scalar_multiple.0[i] = scalar * self.0[i]; 103 | } 104 | scalar_multiple 105 | } 106 | } 107 | 108 | impl Sub for FixedVector { 109 | type Output = Self; 110 | 111 | fn sub(self, other: Self) -> Self::Output { self + -other } 112 | } 113 | 114 | impl SubAssign for FixedVector { 115 | fn sub_assign(&mut self, rhs: Self) { *self = *self - rhs } 116 | } 117 | 118 | impl Additive for FixedVector {} 119 | 120 | impl Group for FixedVector { 121 | fn identity() -> Self { Self::zero() } 122 | 123 | fn inverse(&self) -> Self { -*self } 124 | } 125 | 126 | impl Zero for FixedVector { 127 | fn zero() -> Self { Self([F::zero(); M]) } 128 | 129 | fn is_zero(&self) -> bool { self.0.iter().all(|x| *x == F::zero()) } 130 | } 131 | 132 | impl AbelianGroup for FixedVector {} 133 | 134 | impl> LeftModule for FixedVector { 135 | type Ring = F; 136 | } 137 | 138 | impl> RightModule for FixedVector { 139 | type Ring = F; 140 | } 141 | 142 | impl> TwoSidedModule for FixedVector { 143 | type Ring = F; 144 | } 145 | 146 | impl> VectorSpace for FixedVector {} 147 | 148 | impl From<[F; M]> for FixedVector { 149 | fn from(components: [F; M]) -> Self { Self(components) } 150 | } 151 | 152 | impl From<&[F; M]> for FixedVector { 153 | fn from(components: &[F; M]) -> Self { Self(*components) } 154 | } 155 | 156 | #[cfg(test)] 157 | mod tests { 158 | use super::*; 159 | use crate::fixtures::Mod7; 160 | 161 | #[test] 162 | fn test_zero_vector() { 163 | let zero_vec: FixedVector<3, Mod7> = FixedVector::zero(); 164 | assert!(zero_vec.is_zero()); 165 | assert_eq!(zero_vec.0, [Mod7::zero(), Mod7::zero(), Mod7::zero()]); 166 | 167 | let zero_vec_default: FixedVector<3, Mod7> = FixedVector::default(); 168 | assert!(zero_vec_default.is_zero()); 169 | assert_eq!(zero_vec_default.0, [Mod7::zero(), Mod7::zero(), Mod7::zero()]); 170 | 171 | let non_zero_vec = FixedVector::from([Mod7::from(1), Mod7::zero(), Mod7::from(2)]); 172 | assert!(!non_zero_vec.is_zero()); 173 | } 174 | 175 | #[test] 176 | fn test_is_zero_all_components_zero() { 177 | let vec: FixedVector<2, Mod7> = FixedVector::from([Mod7::zero(), Mod7::zero()]); 178 | assert!(vec.is_zero()); 179 | } 180 | 181 | #[test] 182 | fn test_from_array() { 183 | let arr = [Mod7::from(1), Mod7::from(2), Mod7::from(3)]; 184 | let vec: FixedVector<3, Mod7> = FixedVector::from(arr); 185 | assert_eq!(vec.0, arr); 186 | } 187 | 188 | #[test] 189 | fn test_addition() { 190 | let vec1 = FixedVector::from([Mod7::from(1), Mod7::from(2)]); 191 | let vec2 = FixedVector::from([Mod7::from(3), Mod7::from(4)]); 192 | let sum = vec1 + vec2; 193 | assert_eq!(sum.0, [Mod7::from(4), Mod7::from(6)]); 194 | } 195 | 196 | #[test] 197 | fn test_add_assign() { 198 | let mut vec1 = FixedVector::from([Mod7::from(1), Mod7::from(2)]); 199 | let vec2 = FixedVector::from([Mod7::from(3), Mod7::from(4)]); 200 | vec1 += vec2; 201 | assert_eq!(vec1.0, [Mod7::from(4), Mod7::from(6)]); 202 | } 203 | 204 | #[test] 205 | fn test_negation() { 206 | let vec = FixedVector::from([Mod7::from(1), Mod7::from(0), Mod7::from(6)]); 207 | let neg_vec = -vec; 208 | assert_eq!(neg_vec.0, [Mod7::from(6), Mod7::from(0), Mod7::from(1)]); 209 | } 210 | 211 | #[test] 212 | fn test_scalar_multiplication() { 213 | let vec = FixedVector::from([Mod7::from(1), Mod7::from(2), Mod7::from(3)]); 214 | let scalar = Mod7::from(2); 215 | let product = vec * scalar; 216 | assert_eq!(product.0, [Mod7::from(2), Mod7::from(4), Mod7::from(6)]); 217 | 218 | let scalar_zero = Mod7::zero(); 219 | let product_zero = vec * scalar_zero; 220 | assert_eq!(product_zero.0, [Mod7::zero(), Mod7::zero(), Mod7::zero()]); 221 | } 222 | 223 | #[test] 224 | fn test_subtraction() { 225 | let vec1 = FixedVector::from([Mod7::from(5), Mod7::from(3)]); 226 | let vec2 = FixedVector::from([Mod7::from(1), Mod7::from(4)]); 227 | let diff = vec1 - vec2; 228 | // vec1 + (-vec2) = [5,3] + [-1,-4] = [5,3] + [6,3] = [11,6] = [4,6] 229 | assert_eq!(diff.0, [Mod7::from(4), Mod7::from(6)]); 230 | } 231 | 232 | #[test] 233 | fn test_sub_assign() { 234 | let mut vec1 = FixedVector::from([Mod7::from(5), Mod7::from(3)]); 235 | let vec2 = FixedVector::from([Mod7::from(1), Mod7::from(4)]); 236 | vec1 -= vec2; 237 | assert_eq!(vec1.0, [Mod7::from(4), Mod7::from(6)]); 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /cova-algebra/src/tensors/mod.rs: -------------------------------------------------------------------------------- 1 | //! # Tensors Module 2 | //! 3 | //! This module provides implementations of tensors - mathematical objects that 4 | //! generalize vectors and matrices to higher-order dimensions. 5 | //! 6 | //! ## Mathematical Background 7 | //! 8 | //! Tensors are multi-dimensional arrays that transform according to specific rules 9 | //! under changes of coordinates. In this library, they are implemented as concrete 10 | //! representations of vector spaces over arbitrary fields. 11 | //! 12 | //! ## Module Organization 13 | //! 14 | //! The tensors module is organized into two primary submodules: 15 | //! 16 | //! - [`fixed`]: Implementations of tensors with dimensions known at compile-time using const 17 | //! generics for improved performance and type safety. 18 | //! 19 | //! - [`dynamic`]: Implementations of tensors with dimensions determined at runtime, offering 20 | //! greater flexibility for applications where tensor sizes vary. 21 | //! 22 | //! ## Algebraic Structure 23 | //! 24 | //! All tensor implementations satisfy the algebraic properties of vector spaces: 25 | //! 26 | //! - They form abelian groups under addition 27 | //! - They support scalar multiplication with elements from a field 28 | //! - They implement the vector space axioms (distributivity, associativity, etc.) 29 | //! 30 | //! ## Example Usage 31 | //! 32 | //! ``` 33 | //! use cova_algebra::tensors::{dynamic::Vector, fixed::FixedVector}; 34 | //! 35 | //! // Fixed-size vector (dimension known at compile time) 36 | //! let fixed = FixedVector::<3, f64>([1.0, 2.0, 3.0]); 37 | //! 38 | //! // Dynamic vector (dimension determined at runtime) 39 | //! let dynamic = Vector::::from([4.0, 5.0, 6.0]); 40 | //! ``` 41 | 42 | use super::*; 43 | use crate::{ 44 | groups::{AbelianGroup, Group}, 45 | modules::{LeftModule, RightModule, TwoSidedModule, VectorSpace}, 46 | rings::Field, 47 | }; 48 | 49 | pub mod dynamic; 50 | pub mod fixed; 51 | -------------------------------------------------------------------------------- /cova-space/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | rustdocflags = ["--html-in-header", "./katex-header.html"] 3 | -------------------------------------------------------------------------------- /cova-space/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ## [0.1.2](https://github.com/harnesslabs/cova/compare/cova-space-v0.1.1...cova-space-v0.1.2) - 2025-05-24 10 | 11 | ### Fixed 12 | - book issues ([#72](https://github.com/harnesslabs/cova/pull/72)) 13 | 14 | ### Other 15 | - update README with cova-banner ([#71](https://github.com/harnesslabs/cova/pull/71)) 16 | 17 | ## [0.1.1](https://github.com/harnesslabs/cova/compare/cova-space-v0.1.0...cova-space-v0.1.1) - 2025-05-23 18 | 19 | ### Other 20 | - re-name, re-release, etc. ([#69](https://github.com/harnesslabs/cova/pull/69)) 21 | -------------------------------------------------------------------------------- /cova-space/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cova-space" 3 | 4 | authors = ["Harness Labs"] 5 | description = "Cova's geometric and topological library" 6 | edition = "2021" 7 | keywords = ["mathematics", "topology", "geometry"] 8 | license = "AGPL-3.0" 9 | readme = "README.md" 10 | repository = "https://github.com/harnesslabs/cova" 11 | version = "0.2.0" 12 | 13 | [dependencies] 14 | # Local 15 | cova-algebra = { workspace = true } 16 | 17 | # External 18 | itertools = { workspace = true, features = ["use_std"] } 19 | num-traits = { workspace = true } 20 | 21 | # Optional 22 | rayon = { workspace = true, optional = true } 23 | 24 | [dev-dependencies] 25 | tempfile = { workspace = true } 26 | 27 | 28 | [features] 29 | parallel = ["dep:rayon"] 30 | -------------------------------------------------------------------------------- /cova-space/README.md: -------------------------------------------------------------------------------- 1 |

2 | Cova Banner 3 |

4 | 5 | # Cova Space 6 | 7 | A comprehensive Rust library for computational topology and geometric analysis, providing rigorous implementations of topological spaces, simplicial complexes, homology computation, and topological data analysis. 8 | 9 | [![Crates.io - cova-space](https://img.shields.io/crates/v/cova-space?label=cova-space)](https://crates.io/crates/cova-space) 10 | [![docs.rs - cova-space](https://img.shields.io/docsrs/cova-space?label=docs.rs%20cova-space)](https://docs.rs/cova-space) 11 | [![License: AGPLv3](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0) 12 | 13 | ## Overview 14 | 15 | Cova Space implements fundamental structures and algorithms from computational topology with a focus on mathematical rigor, type safety, and performance. The crate provides a comprehensive toolkit for topological computation, from basic set operations to advanced persistent homology and sheaf-theoretic constructions. 16 | 17 | ## Architecture 18 | 19 | The library is organized around core topological concepts, building from foundational structures to sophisticated computational tools: 20 | 21 | ### Core Foundations 22 | 23 | #### [`set`](src/set.rs) 24 | Foundation layer providing collection abstractions and partially ordered sets (posets). Implements basic set operations, ordering relationships, and the mathematical framework for more complex topological structures. 25 | 26 | #### [`definitions`](src/definitions.rs) 27 | Fundamental trait hierarchy for mathematical spaces including topological spaces, metric spaces, normed spaces, and inner product spaces. Establishes the interface for geometric and topological operations with proper mathematical abstractions. 28 | 29 | ### Topological Complexes 30 | 31 | #### [`complexes`](src/complexes/mod.rs) 32 | Comprehensive implementation of cell complexes including simplicial and cubical complexes. Provides generic complex containers, automatic face relation management, and efficient storage with ID-based lattice structures for computational topology applications. 33 | 34 | **Submodules:** 35 | - **`simplicial`**: Simplex definitions and simplicial complex operations 36 | - **`cubical`**: Cube definitions and cubical complex operations 37 | 38 | #### [`graph`](src/graph.rs) 39 | Flexible graph data structures supporting both directed and undirected graphs with comprehensive operations for vertices, edges, and topological relationships. Designed for integration with complex and homological computations. 40 | 41 | ### Computational Topology 42 | 43 | #### [`homology`](src/homology.rs) 44 | Complete homology computation framework including chain complexes, boundary operators, and Betti number calculations. Implements formal chains with ring coefficients and supports homology computation over arbitrary fields for topological analysis. 45 | 46 | #### [`sheaf`](src/sheaf.rs) 47 | Advanced sheaf theory implementations providing categorical constructions over topological spaces. Includes restriction morphisms, global section verification, and coboundary operators for sophisticated topological data analysis. 48 | 49 | ### Topological Data Analysis 50 | 51 | #### [`filtration`](src/filtration/mod.rs) 52 | Filtration frameworks for persistent homology including Vietoris-Rips constructions. Supports both serial and parallel computation of filtered complexes for analyzing multi-scale topological features in data. 53 | 54 | #### [`cloud`](src/cloud.rs) 55 | Point cloud analysis tools designed for topological data analysis applications. Provides the foundation for building filtered complexes from geometric data sets. 56 | 57 | #### [`lattice`](src/lattice.rs) 58 | Sophisticated lattice structures for efficient representation of partial orders and face relationships in complexes. Implements join/meet operations and provides the computational backbone for complex operations. 59 | 60 | ## Design Principles 61 | 62 | - **Mathematical Rigor**: All implementations follow strict topological definitions and maintain structural invariants 63 | - **Type Safety**: Leverages Rust's type system to encode topological properties and prevent invalid operations 64 | - **Computational Efficiency**: Optimized data structures and algorithms for large-scale topological computations 65 | - **Composability**: Modular design allows complex topological constructions from fundamental building blocks 66 | 67 | ## Usage 68 | 69 | Add to your `Cargo.toml`: 70 | 71 | ```toml 72 | [dependencies] 73 | cova-space = "*" 74 | ``` 75 | 76 | The crate provides a comprehensive prelude for convenient importing: 77 | 78 | ```rust 79 | use cova_space::prelude::*; 80 | ``` 81 | 82 | ## Feature Highlights 83 | 84 | - **Generic Complex Framework**: Unified interface for simplicial, cubical, and general cell complexes 85 | - **Homology Computation**: Full chain complex machinery with boundary operators and Betti number calculation 86 | - **Persistent Homology**: Filtration frameworks for multi-scale topological analysis 87 | - **Sheaf Theory**: Advanced categorical constructions for topological data analysis 88 | - **High Performance**: Efficient lattice-based storage and optional parallel computation support 89 | 90 | ## Optional Features 91 | 92 | - **`parallel`**: Enables parallel computation for filtrations and large-scale operations using Rayon 93 | 94 | ## Mathematical Scope 95 | 96 | The library covers essential areas of computational topology: 97 | 98 | ```text 99 | Set Theory & Posets 100 | ├── Topological Spaces (metric, normed, inner product) 101 | ├── Cell Complexes (simplicial, cubical, general) 102 | ├── Homological Algebra (chains, boundaries, homology) 103 | ├── Sheaf Theory (categorical constructions) 104 | └── Topological Data Analysis (filtrations, persistence) 105 | ``` 106 | 107 | ## Documentation 108 | 109 | Complete API documentation is available on [docs.rs](https://docs.rs/cova-space). 110 | 111 | ## Contributing 112 | 113 | Contributions are welcome! Please ensure mathematical correctness and include appropriate documentation for topological algorithms and data structures. 114 | 115 | ## License 116 | 117 | This project is licensed under the AGPLv3 License - see the [LICENSE](../LICENSE) file for details. 118 | 119 | 120 | -------------------------------------------------------------------------------- /cova-space/katex-header.html: -------------------------------------------------------------------------------- 1 | 3 | 6 | 9 | -------------------------------------------------------------------------------- /cova-space/src/cloud.rs: -------------------------------------------------------------------------------- 1 | //! # Cloud - Vector Set in N-dimensional Space 2 | //! 3 | //! This module defines the [`Cloud`] struct and its implementations, representing a collection 4 | //! of points (vectors) in an `N`-dimensional space. 5 | //! 6 | //! ## Overview 7 | //! 8 | //! A [`Cloud`] is essentially a set of N-dimensional vectors with elements [`f64`]. 9 | //! The module provides: 10 | //! 11 | //! - Basic collection operations ([`Collection::contains`], [`Collection::is_empty`]) 12 | //! - Metric space capabilities ([`MetricSpace::distance`]) 13 | //! - Normed space functionality ([`NormedSpace::norm`]) 14 | //! 15 | //! ## Example 16 | //! 17 | //! ``` 18 | //! use cova_algebra::tensors::fixed::FixedVector; 19 | //! use cova_space::{cloud::Cloud, prelude::*}; 20 | //! 21 | //! // Create two 2D vectors 22 | //! let v1 = FixedVector([1.0, 2.0]); 23 | //! let v2 = FixedVector([3.0, 4.0]); 24 | //! 25 | //! // Create a cloud containing these vectors 26 | //! let cloud = Cloud::new(vec![v1, v2]); 27 | //! 28 | //! // Check if the cloud contains a vector 29 | //! assert!(cloud.contains(&v1)); 30 | //! 31 | //! // Calculate distance between vectors 32 | //! let distance = Cloud::<2>::distance(v1, v2); 33 | //! ``` 34 | //! 35 | //! ## Implementation Details 36 | //! 37 | //! The [`Cloud`] implements several traits: 38 | //! - [`Collection`] - Basic set operations 39 | //! - [`MetricSpace`] - Distance calculations 40 | //! - [`NormedSpace`] - Norm calculations (Euclidean norm) 41 | 42 | use cova_algebra::tensors::fixed::FixedVector; 43 | 44 | use crate::{ 45 | definitions::{MetricSpace, NormedSpace}, 46 | set::Collection, 47 | }; 48 | 49 | /// Defines the [`Cloud`] struct, representing a collection of points (vectors) 50 | /// in an N-dimensional space. 51 | /// 52 | /// This module provides the `Cloud` type, which can be used to store and 53 | /// manage a set of points. It implements traits for basic collection operations, 54 | /// as well as for metric and normed space concepts, allowing for calculations 55 | /// like distance and norm. 56 | /// 57 | /// A `Cloud` is essentially a set of vectors, providing basic [`Collection`] operations 58 | /// as well as metric and normed space functionalities. 59 | #[derive(Debug, Clone)] 60 | pub struct Cloud { 61 | points: Vec>, 62 | } 63 | 64 | impl Cloud { 65 | /// Creates a new `Cloud` from a given set of points. 66 | /// 67 | /// # Arguments 68 | /// 69 | /// * `points`: A `HashSet` of `Vector` representing the points in the cloud. 70 | pub const fn new(points: Vec>) -> Self { Self { points } } 71 | 72 | /// Returns a reference to the points in the cloud. 73 | pub const fn points_ref(&self) -> &Vec> { &self.points } 74 | } 75 | 76 | impl Collection for Cloud { 77 | type Item = FixedVector; 78 | 79 | fn contains(&self, point: &Self::Item) -> bool { self.points.contains(point) } 80 | 81 | fn is_empty(&self) -> bool { self.points.is_empty() } 82 | } 83 | 84 | impl MetricSpace for Cloud { 85 | type Distance = f64; 86 | 87 | /// Calculates the distance between two points in the cloud. 88 | /// 89 | /// The distance is defined as the norm of the difference between the two points. 90 | fn distance(point_a: Self::Item, point_b: Self::Item) -> Self::Distance { 91 | ::norm(point_a - point_b) 92 | } 93 | } 94 | 95 | impl NormedSpace for Cloud { 96 | type Norm = f64; 97 | 98 | /// Calculates the norm of a point. 99 | /// 100 | /// The norm is defined as the sum of the squares of its components (Euclidean norm). 101 | fn norm(point: Self::Item) -> Self::Norm { point.0.iter().map(|p| *p * *p).sum::().sqrt() } 102 | } 103 | 104 | #[cfg(test)] 105 | mod tests { 106 | #![allow(clippy::float_cmp)] 107 | 108 | use super::*; 109 | 110 | fn create_test_vector1() -> FixedVector<2, f64> { FixedVector([1.0, 2.0]) } 111 | 112 | fn create_test_vector2() -> FixedVector<2, f64> { FixedVector([3.0, 4.0]) } 113 | 114 | #[test] 115 | fn test_new_cloud() { 116 | let points = vec![create_test_vector1()]; 117 | let cloud = Cloud::new(points.clone()); 118 | assert_eq!(cloud.points, points); 119 | } 120 | 121 | #[test] 122 | fn test_contains_point() { 123 | let points = vec![create_test_vector1()]; 124 | let cloud = Cloud::new(points); 125 | assert!(cloud.contains(&create_test_vector1())); 126 | assert!(!cloud.contains(&create_test_vector2())); 127 | } 128 | 129 | #[test] 130 | fn test_is_empty() { 131 | let points: Vec> = Vec::new(); 132 | let cloud = Cloud::new(points); 133 | assert!(cloud.is_empty()); 134 | 135 | let points_non_empty = vec![create_test_vector1()]; 136 | let cloud_non_empty = Cloud::new(points_non_empty); 137 | assert!(!cloud_non_empty.is_empty()); 138 | } 139 | 140 | #[test] 141 | fn test_norm() { 142 | let v1 = create_test_vector1(); // [1.0, 2.0] 143 | // 1.0*1.0 + 2.0*2.0 = 1.0 + 4.0 = 5.0 144 | assert_eq!(Cloud::<2>::norm(v1), 5.0_f64.sqrt()); 145 | 146 | let v2 = create_test_vector2(); // [3.0, 4.0] 147 | // 3.0*3.0 + 4.0*4.0 = 9.0 + 16.0 = 25.0 148 | assert_eq!(Cloud::<2>::norm(v2), 25.0_f64.sqrt()); 149 | } 150 | 151 | #[test] 152 | fn test_distance() { 153 | let v1 = create_test_vector1(); // [1.0, 2.0] 154 | let v2 = create_test_vector2(); // [3.0, 4.0] 155 | // v1 - v2 = [-2.0, -2.0] 156 | // norm([-2.0, -2.0]) = (-2.0)*(-2.0) + (-2.0)*(-2.0) = 4.0 + 4.0 = 8.0 157 | assert_eq!(Cloud::<2>::distance(v1, v2), 8.0_f64.sqrt()); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /cova-space/src/definitions.rs: -------------------------------------------------------------------------------- 1 | //! # Core Definitions for Mathematical Spaces 2 | //! 3 | //! This module lays the groundwork for representing various mathematical spaces 4 | //! by defining a set of core traits. These traits abstract fundamental properties 5 | //! and operations associated with topological spaces, metric spaces, normed spaces, 6 | //! and inner product spaces. The hierarchy of these traits reflects the way these 7 | //! mathematical structures build upon one another. 8 | //! 9 | //! ## Trait Hierarchy and Concepts 10 | //! 11 | //! 1. **[`Collection`]**: (Defined in `crate::set`) At the base, any space is a collection of items 12 | //! (points). This trait provides basic operations like checking for containment and emptiness. 13 | //! 14 | //! 2. **[`Topology`]**: Extends [`Collection`]. A topological space is a set of points endowed with 15 | //! a structure, called a topology, which allows defining concepts such as continuity, 16 | //! connectedness, and convergence. This trait focuses on operations like finding neighborhoods 17 | //! and computing boundaries of items within the space, crucial for algebraic topology operations 18 | //! like homology (which uses [`Chain`]). 19 | //! 20 | //! 3. **[`MetricSpace`]**: Extends [`Collection`]. A metric space formalizes the concept of 21 | //! distance between points. It introduces a `distance` function. Every metric space can induce a 22 | //! topology (the metric topology), where open sets are defined using open balls. 23 | //! 24 | //! 4. **[`NormedSpace`]**: Extends [`MetricSpace`]. A normed space is a vector space where each 25 | //! vector is assigned a length or "norm." The norm induces a metric, making every normed space a 26 | //! metric space ($d(x,y) = ||x-y||$). 27 | //! 28 | //! 5. **[`InnerProductSpace`]**: Extends [`NormedSpace`]. An inner product space is a vector space 29 | //! equipped with an inner product (or scalar product), which allows defining geometric notions 30 | //! like angles and orthogonality. The inner product induces a norm ($||x|| = \sqrt{\langle x, x 31 | //! \rangle}$), making every inner product space a normed space. 32 | //! 33 | //! ## Usage 34 | //! 35 | //! These traits are intended to be implemented by specific data structures that model these 36 | //! mathematical spaces. For example, a struct representing a simplicial complex might implement 37 | //! `Topology`, while a struct for Euclidean vectors might implement `InnerProductSpace`. 38 | //! By programming against these traits, algorithms in geometry, topology, and related fields 39 | //! can be written more generically. 40 | //! 41 | //! ## Future Considerations 42 | //! 43 | //! - The relationship between `MetricSpace` and `Topology` (a metric induces a topology) could be 44 | //! further formalized, perhaps through blanket implementations or associated functions if a 45 | //! `MetricSpace` is also to be treated as a `Topology` directly through its induced structure. 46 | //! - Default implementations for relationships, e.g., a `MetricSpace` deriving its `Topology` from 47 | //! its metric, or a `NormedSpace` deriving its `distance` function from its `norm`. 48 | 49 | use cova_algebra::rings::Ring; 50 | 51 | use crate::{homology::Chain, set::Collection}; 52 | 53 | /// Defines the properties and operations of a topological space. 54 | /// 55 | /// A topological space consists of a set of points (items) along with a topology, 56 | /// which is a set of open sets satisfying certain axioms. This trait abstracts 57 | /// operations on such spaces, particularly those relevant for constructing 58 | /// chain complexes and computing homology. 59 | /// 60 | /// It extends [`Collection`], indicating that a topological space is fundamentally 61 | /// a collection of items. 62 | /// 63 | /// # Type Parameters 64 | /// 65 | /// The type implementing `Topology` is `Self`, representing the specific topological space. 66 | /// `Self::Item` is the type of points or fundamental components (e.g., cells, simplices) 67 | /// within the space. 68 | pub trait Topology: Sized + Collection { 69 | /// Returns the neighborhood of a given item in the topological space. 70 | /// 71 | /// The definition of a "neighborhood" can vary depending on the specific type of 72 | /// topological space (e.g., for a point, it might be a set of open sets containing it; 73 | /// for a cell in a complex, it might be adjacent cells or cofaces). 74 | /// The exact semantics should be defined by the implementing type. 75 | /// 76 | /// # Arguments 77 | /// 78 | /// * `item`: A reference to an item in the space for which the neighborhood is to be computed. 79 | /// 80 | /// # Returns 81 | /// 82 | /// A `Vec` containing the items that form the neighborhood of the input `item`. 83 | fn neighborhood(&self, item: &Self::Item) -> Vec; 84 | 85 | /// Computes the boundary of a given item in the topological space, represented as a formal chain. 86 | /// 87 | /// The boundary operation, denoted $\partial$, is a fundamental concept in algebraic topology. 88 | /// For a $k$-item (e.g., a $k$-simplex or $k$-cell), its boundary is a formal sum of 89 | /// $(k-1)$-items with coefficients in a ring `R`. This method provides this boundary as a 90 | /// [`Chain`]. 91 | /// 92 | /// For example, the boundary of an edge (1-simplex) $[v_0, v_1]$ is $v_1 - v_0$. 93 | /// The boundary of a triangle (2-simplex) $[v_0, v_1, v_2]$ is $[v_1, v_2] - [v_0, v_2] + [v_0, 94 | /// v_1]$. 95 | /// 96 | /// # Type Parameters 97 | /// 98 | /// * `R`: The type of coefficients for the resulting boundary chain. It must implement [`Ring`] 99 | /// and be `Copy`. 100 | /// 101 | /// # Arguments 102 | /// 103 | /// * `item`: A reference to an item in the space whose boundary is to be computed. 104 | /// 105 | /// # Returns 106 | /// 107 | /// A [`Chain<'_, Self, R>`] representing the formal sum of items that constitute the boundary 108 | /// of the input `item`, with coefficients from the ring `R`. 109 | fn boundary(&self, item: &Self::Item) -> Chain<'_, Self, R>; 110 | } 111 | 112 | // TODO: If a metric space is also a normed space, then it should implement both traits and have a 113 | // default way to compute the distance between two points using the norm. 114 | // TODO: Previously I had a trait for metric spaces that extended `TopologicalSpace`, but this 115 | // was problematic because you really get a topology from the metric. 116 | /// A trait for metric spaces. 117 | /// 118 | /// A metric space is a set together with a notion of distance between points. 119 | /// This trait extends `TopologicalSpace` by adding a distance function. 120 | /// 121 | /// # Type Parameters 122 | /// * `Distance` - The type used to represent distances between points 123 | pub trait MetricSpace: Collection { 124 | /// The type used to represent distances between points 125 | type Distance; 126 | 127 | /// Computes the distance between two points. 128 | /// 129 | /// # Arguments 130 | /// * `point_a` - The first point 131 | /// * `point_b` - The second point 132 | fn distance( 133 | point_a: ::Item, 134 | point_b: ::Item, 135 | ) -> Self::Distance; 136 | } 137 | 138 | /// A trait for normed spaces. 139 | /// 140 | /// A normed space is a vector space equipped with a norm function that assigns 141 | /// a size to each vector. This trait extends `MetricSpace` by adding a norm function. 142 | /// 143 | /// # Type Parameters 144 | /// * `Norm` - The type used to represent the norm of a vector 145 | pub trait NormedSpace: MetricSpace { 146 | /// The type used to represent the norm of a vector 147 | type Norm; 148 | 149 | /// Computes the norm (length/magnitude) of a point/vector. 150 | /// 151 | /// # Arguments 152 | /// * `point` - The point whose norm to compute 153 | fn norm(point: Self::Item) -> Self::Norm; 154 | } 155 | 156 | /// A trait for inner product spaces. 157 | /// 158 | /// An inner product space is a vector space equipped with an inner product operation 159 | /// that allows for notions of angle and orthogonality. This trait extends `NormedSpace` 160 | /// by adding an inner product function. 161 | /// 162 | /// # Type Parameters 163 | /// * `InnerProduct` - The type used to represent inner products 164 | pub trait InnerProductSpace: NormedSpace { 165 | /// The type used to represent inner products 166 | type InnerProduct; 167 | 168 | /// Computes the inner product of two points/vectors. 169 | /// 170 | /// # Arguments 171 | /// * `point_a` - The first point 172 | /// * `point_b` - The second point 173 | fn inner_product(&self, point_a: Self::Item, point_b: Self::Item) -> Self::InnerProduct; 174 | } 175 | -------------------------------------------------------------------------------- /cova-space/src/filtration/mod.rs: -------------------------------------------------------------------------------- 1 | //! Defines traits for building filtered topological spaces. 2 | 3 | pub mod vietoris_rips; 4 | 5 | /// A trait for processes that construct an output space from an input space 6 | /// based on a given parameter. This is a core concept in filtrations, 7 | /// where the parameter (e.g., a distance threshold) determines the structure 8 | /// of the output space. 9 | pub trait Filtration { 10 | /// The type of the input space (e.g., a point cloud). 11 | type InputSpace; 12 | /// The type of the parameter used for filtering (e.g., a distance epsilon). 13 | type InputParameter; 14 | /// The type of the output space (e.g., a simplicial complex). 15 | type OutputSpace; 16 | /// The type of the output parameter (e.g., the dimension of the homology group). 17 | type OutputParameter; 18 | 19 | /// Constructs an output space from the input space using the given parameter. 20 | /// 21 | /// # Arguments 22 | /// * `input`: A reference to the input space. 23 | /// * `param`: The parameter value that drives the construction. 24 | /// 25 | /// # Returns 26 | /// The constructed output space. 27 | fn build( 28 | &self, 29 | input: &Self::InputSpace, 30 | input_param: Self::InputParameter, 31 | output_param: &Self::OutputParameter, 32 | ) -> Self::OutputSpace; 33 | 34 | /// Builds the output space in serial for multiple parameters. 35 | /// 36 | /// # Arguments 37 | /// * `input`: A reference to the input space. 38 | /// * `param`: A vector of parameters to build the output space for. 39 | /// 40 | /// # Returns 41 | fn build_serial( 42 | &self, 43 | input: &Self::InputSpace, 44 | input_param: Vec, 45 | output_param: &Self::OutputParameter, 46 | ) -> Vec { 47 | input_param.into_iter().map(|p| self.build(input, p, output_param)).collect() 48 | } 49 | } 50 | 51 | #[cfg(feature = "parallel")] use rayon::prelude::*; 52 | 53 | #[cfg(feature = "parallel")] 54 | /// A trait for filtrations that can be built in parallel. 55 | pub trait ParallelFiltration: Filtration 56 | where 57 | Self: Sync, 58 | Self::InputSpace: Sync, 59 | Self::InputParameter: Send, 60 | Self::OutputSpace: Send, 61 | Self::OutputParameter: Send + Sync, { 62 | /// Builds the output space in parallel for multiple parameters. 63 | /// 64 | /// # Arguments 65 | /// * `input`: A reference to the input space. 66 | /// * `param`: A vector of parameters to build the output space for. 67 | /// 68 | /// # Returns 69 | fn build_parallel( 70 | &self, 71 | input: &Self::InputSpace, 72 | input_param: Vec, 73 | output_param: &Self::OutputParameter, 74 | ) -> Vec { 75 | input_param.into_par_iter().map(|p| self.build(input, p, output_param)).collect() 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /cova-space/src/graph.rs: -------------------------------------------------------------------------------- 1 | //! Graph implementation with support for both directed and undirected graphs. 2 | //! 3 | //! This module provides a flexible graph data structure that can represent both directed 4 | //! and undirected graphs through a type parameter. The implementation supports basic 5 | //! set operations and is designed to work with the topology traits defined in the 6 | //! definitions module. 7 | 8 | use std::{collections::HashSet, hash::Hash, marker::PhantomData}; 9 | 10 | use crate::set::Collection; 11 | 12 | /// Private module to implement the sealed trait pattern. 13 | /// This prevents other crates from implementing DirectedType. 14 | mod sealed { 15 | pub trait Sealed {} 16 | } 17 | 18 | /// A trait to distinguish between directed and undirected graphs. 19 | /// 20 | /// This trait is sealed and can only be implemented by the `Directed` and 21 | /// `Undirected` types provided in this module. 22 | pub trait DirectedType: sealed::Sealed {} 23 | 24 | /// Type marker for undirected graphs. 25 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 26 | pub struct Undirected; 27 | impl sealed::Sealed for Undirected {} 28 | impl DirectedType for Undirected {} 29 | 30 | /// Type marker for directed graphs. 31 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 32 | pub struct Directed; 33 | impl sealed::Sealed for Directed {} 34 | impl DirectedType for Directed {} 35 | 36 | /// Represents a point in a graph, which can be either a vertex or a point on an edge. 37 | /// 38 | /// # Type Parameters 39 | /// * `V` - The type of vertex identifiers 40 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] 41 | pub enum VertexOrEdge { 42 | /// A vertex in the graph 43 | Vertex(V), 44 | /// An edge between two vertices 45 | Edge(V, V), 46 | } 47 | 48 | /// A graph data structure supporting both directed and undirected graphs. 49 | /// 50 | /// # Type Parameters 51 | /// * `V` - The type of vertex identifiers 52 | /// * `D` - The directedness type (`Directed` or `Undirected`) 53 | /// 54 | /// # Examples 55 | /// ``` 56 | /// use std::collections::HashSet; 57 | /// # use cova_space::graph::{Graph, Undirected}; 58 | /// 59 | /// let mut vertices = HashSet::new(); 60 | /// vertices.insert(1); 61 | /// vertices.insert(2); 62 | /// 63 | /// let mut edges = HashSet::new(); 64 | /// edges.insert((1, 2)); 65 | /// 66 | /// let graph = Graph::::new(vertices, edges); 67 | /// ``` 68 | #[derive(Debug, Clone)] 69 | pub struct Graph { 70 | /// The set of vertices in the graph 71 | vertices: HashSet, 72 | /// The set of edges in the graph 73 | edges: HashSet<(V, V)>, 74 | /// Phantom data to carry the directedness type 75 | d: PhantomData, 76 | } 77 | 78 | impl Graph { 79 | /// Creates a new graph with the given vertices and edges. 80 | /// 81 | /// For undirected graphs, edges are normalized so that the smaller vertex 82 | /// (by `PartialOrd`) is always first in the pair. 83 | /// 84 | /// # Arguments 85 | /// * `vertices` - The set of vertices in the graph 86 | /// * `edges` - The set of edges in the graph 87 | /// 88 | /// # Panics 89 | /// * If any edge references a vertex not in the vertex set 90 | pub fn new(vertices: HashSet, edges: HashSet<(V, V)>) -> Self { 91 | let edges = 92 | edges.into_iter().map(|(a, b)| if a <= b { (a, b) } else { (b, a) }).collect::>(); 93 | 94 | assert!( 95 | edges.iter().all(|(a, b)| vertices.contains(a) && vertices.contains(b)), 96 | "All edges must be between vertices", 97 | ); 98 | Self { vertices, edges, d: PhantomData } 99 | } 100 | } 101 | 102 | impl Graph { 103 | /// Creates a new graph with the given vertices and edges. 104 | /// 105 | /// For undirected graphs, edges are normalized so that the smaller vertex 106 | /// (by `PartialOrd`) is always first in the pair. 107 | /// 108 | /// # Arguments 109 | /// * `vertices` - The set of vertices in the graph 110 | /// * `edges` - The set of edges in the graph 111 | /// 112 | /// # Panics 113 | /// * If any edge references a vertex not in the vertex set 114 | pub fn new(vertices: HashSet, edges: HashSet<(V, V)>) -> Self { 115 | assert!( 116 | edges.iter().all(|(a, b)| vertices.contains(a) && vertices.contains(b)), 117 | "All edges must be between vertices", 118 | ); 119 | Self { vertices, edges, d: PhantomData } 120 | } 121 | } 122 | 123 | impl Collection for Graph { 124 | type Item = VertexOrEdge; 125 | 126 | fn is_empty(&self) -> bool { self.vertices.is_empty() } 127 | 128 | fn contains(&self, point: &Self::Item) -> bool { 129 | match point { 130 | VertexOrEdge::Vertex(v) => self.vertices.contains(v), 131 | VertexOrEdge::Edge(u, v) => self.edges.contains(&(u.clone(), v.clone())), 132 | } 133 | } 134 | } 135 | 136 | impl Collection for Graph { 137 | type Item = VertexOrEdge; 138 | 139 | fn is_empty(&self) -> bool { self.vertices.is_empty() } 140 | 141 | fn contains(&self, point: &Self::Item) -> bool { 142 | match point { 143 | VertexOrEdge::Vertex(v) => self.vertices.contains(v), 144 | VertexOrEdge::Edge(u, v) => 145 | self.edges.contains(&(u.clone(), v.clone())) | self.edges.contains(&(v.clone(), u.clone())), 146 | } 147 | } 148 | } 149 | 150 | #[cfg(test)] 151 | mod tests { 152 | use super::*; 153 | 154 | /// Helper function to create a test graph. 155 | fn create_graph_undirected() -> Graph { 156 | let mut vertices = HashSet::new(); 157 | vertices.insert(1); 158 | vertices.insert(2); 159 | vertices.insert(3); 160 | vertices.insert(4); 161 | vertices.insert(5); 162 | 163 | let mut edges = HashSet::new(); 164 | edges.insert((1, 2)); 165 | edges.insert((2, 3)); 166 | edges.insert((3, 4)); 167 | 168 | Graph::::new(vertices, edges) 169 | } 170 | 171 | /// Helper function to create a test graph. 172 | fn create_graph_directed() -> Graph { 173 | let mut vertices = HashSet::new(); 174 | vertices.insert(1); 175 | vertices.insert(2); 176 | vertices.insert(3); 177 | vertices.insert(4); 178 | vertices.insert(5); 179 | 180 | let mut edges = HashSet::new(); 181 | edges.insert((1, 2)); 182 | edges.insert((2, 3)); 183 | edges.insert((3, 4)); 184 | edges.insert((4, 5)); 185 | 186 | Graph::::new(vertices, edges) 187 | } 188 | 189 | #[test] 190 | fn graph_builds_undirected() { 191 | let graph = create_graph_undirected(); 192 | assert_eq!(graph.vertices.len(), 5); 193 | assert_eq!(graph.edges.len(), 3); 194 | } 195 | 196 | #[test] 197 | fn graph_builds_directed() { 198 | let graph = create_graph_directed(); 199 | assert_eq!(graph.vertices.len(), 5); 200 | assert_eq!(graph.edges.len(), 4); 201 | } 202 | 203 | #[test] 204 | fn graph_contains_vertex() { 205 | let graph = create_graph_undirected(); 206 | assert!(graph.contains(&VertexOrEdge::Vertex(1))); 207 | assert!(!graph.contains(&VertexOrEdge::Vertex(6))); 208 | } 209 | 210 | #[test] 211 | fn graph_contains_edge() { 212 | let graph = create_graph_undirected(); 213 | assert!(graph.contains(&VertexOrEdge::Edge(1, 2))); 214 | } 215 | 216 | #[test] 217 | fn graph_contains_edge_undirected() { 218 | let graph = create_graph_undirected(); 219 | assert!(graph.contains(&VertexOrEdge::Edge(1, 2))); 220 | assert!(graph.contains(&VertexOrEdge::Edge(2, 1))); 221 | } 222 | 223 | #[test] 224 | fn graph_contains_edge_directed() { 225 | let graph = create_graph_directed(); 226 | assert!(graph.contains(&VertexOrEdge::Edge(1, 2))); 227 | assert!(!graph.contains(&VertexOrEdge::Edge(2, 1))); 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /cova-space/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc = include_str!("../README.md")] 2 | #![warn(missing_docs)] 3 | 4 | pub mod cloud; 5 | pub mod complexes; 6 | pub mod definitions; 7 | pub mod filtration; 8 | pub mod graph; 9 | pub mod homology; 10 | pub mod lattice; 11 | pub mod set; 12 | pub mod sheaf; 13 | 14 | use cova_algebra::prelude::*; 15 | 16 | pub mod prelude { 17 | //! The prelude for the `space` crate. 18 | //! 19 | //! This module re-exports the most commonly used types and traits from the `space` crate. 20 | //! It provides a convenient way to import these types and traits into your code without 21 | //! having to specify the crate name each time. 22 | pub use crate::{ 23 | complexes::ComplexElement, 24 | definitions::{MetricSpace, NormedSpace, Topology}, 25 | set::{Collection, Poset}, 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /cova-space/src/set.rs: -------------------------------------------------------------------------------- 1 | //! # Set Module 2 | //! 3 | //! This module provides traits for abstracting over collection types and partially 4 | //! ordered sets (posets). 5 | //! 6 | //! The core traits defined are: 7 | //! - [`Collection`]: For types that represent a collection of items, supporting basic operations 8 | //! like checking for containment and emptiness. 9 | //! - [`Poset`]: Extends [`Collection`] for sets that also define a partial order relation among 10 | //! their items, along with related poset operations like finding upsets, downsets, 11 | //! minimal/maximal elements, etc. 12 | //! 13 | //! Implementations of [`Collection`] are provided for standard library types such as 14 | //! [`HashSet`], [`BTreeSet`], and [`Vec`]. 15 | 16 | use std::{ 17 | collections::{BTreeSet, HashSet}, 18 | hash::{BuildHasher, Hash}, 19 | }; 20 | 21 | /// A trait for collections that support basic set operations. 22 | /// 23 | /// This trait defines fundamental operations applicable to various collection types, 24 | /// focusing on item containment and checking for emptiness. 25 | /// 26 | /// # Type Parameters 27 | /// 28 | /// * `Item`: The type of elements contained within the collection. 29 | /// 30 | /// # Implementations 31 | /// 32 | /// Implementations are provided for: 33 | /// * [`HashSet`]: Where `T: Hash + Eq + Clone` and `S: BuildHasher + Default`. 34 | /// * [`BTreeSet`]: Where `T: Ord + Clone`. 35 | /// * [`Vec`]: Where `T: PartialEq`. 36 | pub trait Collection { 37 | /// The type of elements stored in the collection. 38 | type Item; 39 | 40 | /// Checks if an item is present in the collection. 41 | /// 42 | /// # Arguments 43 | /// 44 | /// * `point`: A reference to the item to check for containment. 45 | /// 46 | /// # Returns 47 | /// 48 | /// `true` if the item is found in the collection, `false` otherwise. 49 | fn contains(&self, point: &Self::Item) -> bool; 50 | 51 | /// Determines if the collection is empty. 52 | /// 53 | /// # Returns 54 | /// 55 | /// * `true` if the collection contains no items. 56 | /// * `false` if the collection contains one or more items. 57 | fn is_empty(&self) -> bool; 58 | } 59 | 60 | /// A trait for sets that support partial order relations, building upon [`Collection`]. 61 | /// 62 | /// This trait extends the basic [`Collection`] operations with methods specific to 63 | /// partially ordered sets (posets). This includes checking the partial order 64 | /// relation (`leq`), and computing various poset-specific subsets and elements. 65 | /// 66 | /// # Type Parameters 67 | /// 68 | /// * `Item`: The type of elements contained in the set, which are subject to the partial order. 69 | pub trait Poset: Collection { 70 | /// Tests if one item is less than or equal to another according to the partial order. 71 | /// 72 | /// The `leq` relation (often denoted as $\le$) must satisfy reflexivity, antisymmetry, 73 | /// and transitivity. 74 | /// 75 | /// # Arguments 76 | /// 77 | /// * `a`: A reference to the first item. 78 | /// * `b`: A reference to the second item. 79 | /// 80 | /// # Returns 81 | /// 82 | /// * `Some(true)` if `a` is less than or equal to `b` ($a \le b$). 83 | /// * `Some(false)` if `a` is not less than or equal to `b` (and both are comparable in the set). 84 | /// * `None` if the relation cannot be determined (e.g., if one or both items are not considered 85 | /// part of the poset for comparison, or if the specific poset implementation cannot compare 86 | /// them). 87 | fn leq(&self, a: &Self::Item, b: &Self::Item) -> Option; 88 | 89 | /// Computes the upset of an item `a`. 90 | /// 91 | /// The upset of `a`, denoted $\uparrow a$, is the set of all items `x` in the poset 92 | /// such that $a \le x$. 93 | /// 94 | /// # Arguments 95 | /// 96 | /// * `a`: The item whose upset is to be computed. 97 | /// 98 | /// # Returns 99 | /// 100 | /// A `HashSet` containing all items `x` such that `a` is less than or equal to `x`. 101 | fn upset(&self, a: Self::Item) -> HashSet; 102 | 103 | /// Computes the downset of an item `a`. 104 | /// 105 | /// The downset of `a`, denoted $\downarrow a$, is the set of all items `x` in the poset 106 | /// such that $x \le a$. 107 | /// 108 | /// # Arguments 109 | /// 110 | /// * `a`: The item whose downset is to be computed. 111 | /// 112 | /// # Returns 113 | /// 114 | /// A `HashSet` containing all items `x` such that `x` is less than or equal to `a`. 115 | fn downset(&self, a: Self::Item) -> HashSet; 116 | 117 | /// Finds all minimal elements of the poset. 118 | /// 119 | /// An item `m` is minimal if there is no other item `x` in the poset such that $x < m$ 120 | /// (i.e., $x \le m$ and $x \neq m$). 121 | /// 122 | /// # Returns 123 | /// 124 | /// A `HashSet` containing all minimal elements of the poset. 125 | fn minimal_elements(&self) -> HashSet; 126 | 127 | /// Finds all maximal elements of the poset. 128 | /// 129 | /// An item `m` is maximal if there is no other item `x` in the poset such that $m < x$ 130 | /// (i.e., $m \le x$ and $m \neq x$). 131 | /// 132 | /// # Returns 133 | /// 134 | /// A `HashSet` containing all maximal elements of the poset. 135 | fn maximal_elements(&self) -> HashSet; 136 | 137 | /// Computes the join (least upper bound) of two items `a` and `b`, if it exists. 138 | /// 139 | /// The join $a \lor b$ is an item `j` such that $a \le j$ and $b \le j$, and for any 140 | /// other item `k` with $a \le k$ and $b \le k$, it holds that $j \le k$. 141 | /// 142 | /// # Arguments 143 | /// 144 | /// * `a`: The first item. 145 | /// * `b`: The second item. 146 | /// 147 | /// # Returns 148 | /// 149 | /// * `Some(join_element)` if the join of `a` and `b` exists. 150 | /// * `None` if the join does not exist or is not unique. 151 | fn join(&self, a: Self::Item, b: Self::Item) -> Option; 152 | 153 | /// Computes the meet (greatest lower bound) of two items `a` and `b`, if it exists. 154 | /// 155 | /// The meet $a \land b$ is an item `m` such that $m \le a$ and $m \le b$, and for any 156 | /// other item `k` with $k \le a$ and $k \le b$, it holds that $k \le m$. 157 | /// 158 | /// # Arguments 159 | /// 160 | /// * `a`: The first item. 161 | /// * `b`: The second item. 162 | /// 163 | /// # Returns 164 | /// 165 | /// * `Some(meet_element)` if the meet of `a` and `b` exists. 166 | /// * `None` if the meet does not exist or is not unique. 167 | fn meet(&self, a: Self::Item, b: Self::Item) -> Option; 168 | 169 | /// Finds all direct successors (covers) of an item `a`. 170 | /// 171 | /// An item `s` is a direct successor of `a` if $a < s$ (i.e., $a \le s$ and $a \neq s$) 172 | /// and there is no item `x` such that $a < x < s$. 173 | /// 174 | /// # Arguments 175 | /// 176 | /// * `a`: The item whose successors are to be found. 177 | /// 178 | /// # Returns 179 | /// 180 | /// A `HashSet` containing all direct successors of `a`. 181 | fn successors(&self, a: Self::Item) -> HashSet; 182 | 183 | /// Finds all direct predecessors of an item `a`. 184 | /// 185 | /// An item `p` is a direct predecessor of `a` if $p < a$ (i.e., $p \le a$ and $p \neq a$) 186 | /// and there is no item `x` such that $p < x < a$. 187 | /// 188 | /// # Arguments 189 | /// 190 | /// * `a`: The item whose predecessors are to be found. 191 | /// 192 | /// # Returns 193 | /// 194 | /// A `HashSet` containing all direct predecessors of `a`. 195 | fn predecessors(&self, a: Self::Item) -> HashSet; 196 | } 197 | 198 | impl Collection for HashSet { 199 | type Item = T; 200 | 201 | /// Checks if the `HashSet` contains the specified item. 202 | /// This is a direct wrapper around [`HashSet::contains`]. 203 | fn contains(&self, point: &Self::Item) -> bool { Self::contains(self, point) } 204 | 205 | /// Checks if the `HashSet` is empty. 206 | /// This is a direct wrapper around [`HashSet::is_empty`]. 207 | fn is_empty(&self) -> bool { Self::is_empty(self) } 208 | } 209 | 210 | impl Collection for BTreeSet { 211 | type Item = T; 212 | 213 | /// Checks if the `BTreeSet` contains the specified item. 214 | /// This is a direct wrapper around [`BTreeSet::contains`]. 215 | fn contains(&self, point: &Self::Item) -> bool { Self::contains(self, point) } 216 | 217 | /// Checks if the `BTreeSet` is empty. 218 | /// This is a direct wrapper around [`BTreeSet::is_empty`]. 219 | fn is_empty(&self) -> bool { Self::is_empty(self) } 220 | } 221 | 222 | impl Collection for Vec { 223 | type Item = T; 224 | 225 | /// Checks if the `Vec` contains the specified item by iterating through its elements. 226 | fn contains(&self, point: &Self::Item) -> bool { self.iter().any(|p| p == point) } 227 | 228 | /// Checks if the `Vec` is empty. 229 | /// This is a direct wrapper around [`Vec::is_empty`]. 230 | fn is_empty(&self) -> bool { self.is_empty() } 231 | } 232 | -------------------------------------------------------------------------------- /cova/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | rustdocflags = ["--html-in-header", "./katex-header.html"] 3 | -------------------------------------------------------------------------------- /cova/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ## [0.1.3](https://github.com/harnesslabs/cova/compare/cova-v0.1.2...cova-v0.1.3) - 2025-05-25 10 | 11 | ### Other 12 | - update Cargo.lock dependencies 13 | 14 | ## [0.1.2](https://github.com/harnesslabs/cova/compare/cova-v0.1.1...cova-v0.1.2) - 2025-05-24 15 | 16 | ### Other 17 | - update README with cova-banner ([#71](https://github.com/harnesslabs/cova/pull/71)) 18 | 19 | ## [0.1.1](https://github.com/harnesslabs/cova/compare/cova-v0.1.0...cova-v0.1.1) - 2025-05-23 20 | 21 | ### Other 22 | - re-name, re-release, etc. ([#69](https://github.com/harnesslabs/cova/pull/69)) 23 | -------------------------------------------------------------------------------- /cova/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cova" 3 | 4 | authors = ["Harness Labs"] 5 | description = "First principles, minimally dependent, geometric and topologically focused math library" 6 | edition = "2021" 7 | keywords = ["mathematics", "topology", "geometry"] 8 | license = "AGPL-3.0" 9 | readme = "README.md" 10 | repository = "https://github.com/harnesslabs/cova" 11 | version = "0.1.3" 12 | 13 | [dependencies] 14 | cova-algebra = { workspace = true } 15 | cova-space = { workspace = true } 16 | 17 | [dev-dependencies] 18 | tempfile = { workspace = true } 19 | 20 | 21 | [features] 22 | parallel = ["cova-space/parallel"] 23 | -------------------------------------------------------------------------------- /cova/README.md: -------------------------------------------------------------------------------- 1 |

2 | Cova Banner 3 |

4 | 5 | # Cova 6 | 7 | A unified Rust ecosystem for rigorous mathematical computation, bridging abstract algebra and computational topology to provide a comprehensive foundation for mathematical software development. 8 | 9 | [![Crates.io - cova](https://img.shields.io/crates/v/cova?label=cova)](https://crates.io/crates/cova) 10 | [![docs.rs - cova](https://img.shields.io/docsrs/cova?label=docs.rs%20cova)](https://docs.rs/cova) 11 | [![License: AGPLv3](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0) 12 | 13 | ## Mathematical Vision 14 | 15 | Cova represents a principled approach to mathematical software, where abstract algebraic structures provide the computational foundation for sophisticated topological and geometric algorithms. By unifying algebra and topology in a single ecosystem, Cova enables mathematical computations that span traditional disciplinary boundaries. 16 | 17 | ## Unified Architecture 18 | 19 | The Cova ecosystem consists of two complementary mathematical domains: 20 | 21 | ### Abstract Algebra (`cova-algebra`) 22 | Provides the algebraic foundation with rigorous implementations of: 23 | - **Arithmetic Systems**: Modular arithmetic, ring theory, and field extensions 24 | - **Structural Algebra**: Groups, rings, fields, modules, and vector spaces 25 | - **Advanced Constructions**: Category theory, tensor algebra, and Clifford algebras 26 | - **Computational Framework**: Type-safe operations preserving mathematical properties 27 | 28 | ### Computational Topology (`cova-space`) 29 | Builds sophisticated topological structures and algorithms: 30 | - **Foundational Topology**: Topological spaces, metric structures, and geometric abstractions 31 | - **Complex Machinery**: Simplicial and cubical complexes with efficient storage and operations 32 | - **Homological Algebra**: Chain complexes, boundary operators, and homology computation 33 | - **Advanced Methods**: Sheaf theory, persistent homology, and topological data analysis 34 | 35 | ## Algebraic-Topological Synergy 36 | 37 | The power of Cova emerges from the interaction between its algebraic and topological components: 38 | 39 | ### Coefficient Systems 40 | Topological computations (homology, cohomology) use algebraic structures as coefficient systems, allowing homology over arbitrary rings and fields defined in `cova-algebra`. 41 | 42 | ### Geometric Algebra 43 | Clifford algebras from `cova-algebra` provide natural frameworks for geometric computations in the topological spaces of `cova-space`. 44 | 45 | ### Categorical Foundations 46 | Category theory concepts span both domains, providing unified abstractions for mathematical constructions and morphisms. 47 | 48 | ### Computational Efficiency 49 | Algebraic optimizations (efficient field arithmetic, tensor operations) directly enhance topological algorithms that depend on large-scale linear algebra. 50 | 51 | ## Usage 52 | 53 | ### Unified Access 54 | Import the entire ecosystem: 55 | ```rust 56 | use cova::prelude::*; 57 | ``` 58 | 59 | ### Domain-Specific Access 60 | Access individual mathematical domains: 61 | ```rust 62 | use cova::algebra::prelude::*; // Abstract algebra 63 | use cova::space::prelude::*; // Computational topology 64 | ``` 65 | 66 | ### Cross-Domain Computations 67 | Leverage both domains together: 68 | ```rust 69 | use cova::prelude::*; 70 | 71 | // Compute homology over a custom finite field 72 | let field_element = Mod7::new(3); 73 | let homology = complex.homology::(dimension); 74 | 75 | // Use Clifford algebra for geometric transformations 76 | let rotor = CliffordElement::from_bivector(bivector); 77 | let transformed_space = apply_rotor(space, rotor); 78 | ``` 79 | 80 | ## Mathematical Scope 81 | 82 | Cova covers essential mathematical areas with seamless integration: 83 | 84 | ``` 85 | Cova Ecosystem 86 | ├── Abstract Algebra 87 | │ ├── Arithmetic (modular, primitive types) 88 | │ ├── Group Theory (abelian, non-abelian) 89 | │ ├── Ring Theory (rings, fields, semirings) 90 | │ ├── Module Theory (vector spaces, linear algebra) 91 | │ ├── Advanced Algebra (Clifford, Boolean) 92 | │ ├── Tensor Calculus (fixed, dynamic tensors) 93 | │ └── Category Theory (morphisms, composition) 94 | └── Computational Topology 95 | ├── Set Theory (collections, posets) 96 | ├── Topological Spaces (metric, normed) 97 | ├── Cell Complexes (simplicial, cubical) 98 | ├── Homological Algebra (chains, homology) 99 | ├── Sheaf Theory (categorical constructions) 100 | └── Topological Data Analysis (filtrations) 101 | ``` 102 | 103 | ## Design Principles 104 | 105 | ### Mathematical Rigor 106 | All implementations follow strict mathematical definitions with proper algebraic and topological properties preserved through the type system. 107 | 108 | ### Compositional Architecture 109 | Structures are designed for seamless composition, allowing complex mathematical constructions from fundamental building blocks across both algebraic and topological domains. 110 | 111 | ### Performance Through Abstraction 112 | High-level mathematical abstractions are implemented with careful attention to computational efficiency, enabling both correctness and performance. 113 | 114 | ### Type-Driven Safety 115 | Rust's type system encodes mathematical constraints, preventing invalid operations while maintaining zero-cost abstractions. 116 | 117 | ## Feature Integration 118 | 119 | ### Optional Features 120 | - **`parallel`**: Enables parallel computation acros topological algorithms (filtration construction) 121 | 122 | ### Cross-Crate Compatibility 123 | All types and traits are designed for interoperability, allowing algebraic structures to serve as coefficient systems for topological computations and vice versa. 124 | 125 | ## Applications 126 | 127 | Cova provides a foundation for: 128 | - **Scientific Computing**: Rigorous mathematical foundations for numerical algorithms 129 | - **Computer Graphics**: Geometric algebra and topological methods for rendering and modeling 130 | - **Machine Learning**: Topological data analysis and algebraic machine learning methods 131 | - **Mathematical Research**: Experimental mathematics with computational verification 132 | - **Educational Software**: Teaching tools with mathematically accurate implementations 133 | 134 | ## Documentation 135 | 136 | Complete documentation covering both mathematical foundations and practical usage: 137 | - [Unified API Documentation](https://docs.rs/cova) 138 | - [Algebra Documentation](https://docs.rs/cova-algebra) 139 | - [Topology Documentation](https://docs.rs/cova-space) 140 | 141 | ## License 142 | 143 | This project is licensed under the AGPLv3 License, ensuring mathematical software remains open and accessible to the research community. -------------------------------------------------------------------------------- /cova/katex-header.html: -------------------------------------------------------------------------------- 1 | 3 | 6 | 9 | -------------------------------------------------------------------------------- /cova/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub use cova_algebra as algebra; 2 | pub use cova_space as space; 3 | 4 | pub mod prelude { 5 | pub use crate::{algebra::prelude::*, space::prelude::*}; 6 | } 7 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Cova Examples 2 | 3 | This directory contains interactive examples and demonstrations of the Cova computational topology library. 4 | 5 | ## Available Examples 6 | 7 | ### 🌐 Vietoris-Rips Interactive Demo 8 | 9 | **Location**: `examples/vietoris_web/` 10 | 11 | An interactive web-based demonstration of Vietoris-Rips complexes that lets you: 12 | - Click to add points to a 2D plane 13 | - Right-click to remove points 14 | - Adjust the distance threshold (epsilon) with a slider 15 | - Watch simplicial complexes form in real-time 16 | 17 | **Features:** 18 | - Real-time visualization of vertices, edges, and triangles 19 | - Live statistics showing complex properties 20 | - Educational tool for understanding topological data analysis 21 | 22 | **How to run:** 23 | ```bash 24 | cd examples/vietoris_web 25 | cargo run 26 | ``` 27 | Then open your browser to `http://localhost:3030` 28 | 29 | **Technologies used:** 30 | - Rust backend with `cova-space` for topology computation 31 | - WebAssembly for browser integration 32 | - HTML5 Canvas for visualization 33 | - Built-in web server using `warp` 34 | 35 | ## Adding New Examples 36 | 37 | To add a new example: 38 | 39 | 1. Create a new directory under `examples/` 40 | 2. Add a standalone `Cargo.toml` with path dependencies to the workspace crates: 41 | ```toml 42 | [dependencies] 43 | cova = { path = "../../cova" } 44 | ``` 45 | 3. Implement your example in `src/main.rs` 46 | 4. Update this README with documentation 47 | 48 | ## Requirements 49 | 50 | - Rust 2021 edition or later 51 | - For web examples: Modern browser with WebAssembly support 52 | 53 | ## Educational Value 54 | 55 | These examples are designed to: 56 | - Demonstrate practical applications of computational topology 57 | - Provide interactive learning experiences 58 | - Show integration patterns for the Cova library 59 | - Serve as starting points for your own projects 60 | 61 | Happy exploring! 🎭✨ 62 | -------------------------------------------------------------------------------- /examples/vietoris_web/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Harness Labs"] 3 | description = "Interactive Vietoris-Rips Complex Demo using cova" 4 | edition = "2021" 5 | name = "vietoris-web-demo" 6 | version = "0.1.0" 7 | 8 | [package.metadata.wasm-pack.profile.release] 9 | wasm-opt = false 10 | 11 | [workspace] 12 | 13 | # Server binary 14 | [[bin]] 15 | name = "server" 16 | path = "src/main.rs" 17 | 18 | [dependencies] 19 | 20 | [target.'cfg(target_arch = "wasm32")'.dependencies] 21 | console_error_panic_hook = { version = "0.1" } 22 | cova = { path = "../../cova" } 23 | getrandom = { version = "0.2", features = ["js"] } 24 | js-sys = { version = "0.3" } 25 | wasm-bindgen = { version = "0.2" } 26 | web-sys = { version = "0.3", features = [ 27 | "console", 28 | "CanvasRenderingContext2d", 29 | "HtmlCanvasElement", 30 | "HtmlInputElement", 31 | "MouseEvent", 32 | "Element", 33 | "Document", 34 | "Window", 35 | "Event", 36 | "EventTarget", 37 | ] } 38 | 39 | [target.'cfg(not(target_arch = "wasm32"))'.dependencies] 40 | tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } 41 | warp = { version = "0.3" } 42 | 43 | [lib] 44 | crate-type = ["cdylib", "rlib"] 45 | 46 | [profile.release] 47 | codegen-units = 1 48 | lto = true 49 | opt-level = 3 50 | panic = "abort" 51 | strip = true 52 | -------------------------------------------------------------------------------- /examples/vietoris_web/README.md: -------------------------------------------------------------------------------- 1 | # Vietoris-Rips Complex Web Demo 2 | 3 | An interactive web demonstration of Vietoris-Rips complexes using the `cova` library. 4 | 5 | ## Features 6 | 7 | - **Interactive Point Placement**: Click to add points, right-click to remove 8 | - **Real-time Complex Computation**: Uses `cova` to compute Vietoris-Rips complexes 9 | - **Visual Simplicial Complex**: See vertices, epsilon bubbles, edges, and triangles 10 | - **Adjustable Epsilon**: Slider to control the distance threshold 11 | 12 | ## Project Structure 13 | 14 | ``` 15 | vietoris_web/ 16 | ├── src/ 17 | │ ├── lib.rs # WASM library using cova 18 | │ └── main.rs # Simple web server binary 19 | ├── index.html # Web interface 20 | └── Cargo.toml # Dependencies and configuration 21 | ``` 22 | 23 | ## Quick Start 24 | 25 | 1. **Build WASM module**: 26 | ```bash 27 | wasm-pack build --target web 28 | ``` 29 | 30 | 2. **Start the server**: 31 | ```bash 32 | cargo run --bin server 33 | ``` 34 | 35 | 3. **Open browser**: Navigate to http://localhost:3030 36 | 37 | ### Dependencies 38 | 39 | The project uses target-specific dependencies: 40 | 41 | - **Core**: `cova` - The unified mathematical library 42 | - **Server** (native only): `tokio`, `warp` - Async web server 43 | - **WASM** (wasm32 only): `wasm-bindgen`, `web-sys` - WebAssembly bindings 44 | 45 | ## Usage 46 | 47 | 1. Click anywhere on the canvas to add points 48 | 2. Right-click near a point to remove it 49 | 3. Adjust the epsilon slider to see how the complex changes 50 | 4. Watch as triangles form when three points are within epsilon distance 51 | 52 | The demo showcases how `cova` computes Vietoris-Rips complexes in real-time! -------------------------------------------------------------------------------- /examples/vietoris_web/build-optimized.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | echo "🚀 Building maximum performance WASM for Vietoris-Rips demo..." 6 | 7 | # Clean previous builds 8 | echo "🧹 Cleaning previous builds..." 9 | rm -rf pkg/ 10 | 11 | # Set RUSTFLAGS to enable bulk memory operations from the start 12 | export RUSTFLAGS="-C target-feature=+bulk-memory,+mutable-globals,+sign-ext,+nontrapping-fptoint,+simd128" 13 | 14 | # Build with wasm-pack using release profile focused on speed 15 | echo "📦 Building with wasm-pack (speed optimized)..." 16 | wasm-pack build \ 17 | --target web \ 18 | --release \ 19 | --out-dir pkg 20 | 21 | # First, run wasm-opt to validate and optimize with bulk memory support 22 | echo "⚡ Running initial optimization with bulk memory support..." 23 | wasm-opt pkg/vietoris_web_demo_bg.wasm \ 24 | --enable-bulk-memory \ 25 | --enable-sign-ext \ 26 | --enable-mutable-globals \ 27 | --enable-nontrapping-float-to-int \ 28 | --enable-simd \ 29 | -O2 \ 30 | -o pkg/vietoris_web_demo_bg.wasm 31 | 32 | # Now run the aggressive performance optimizations 33 | echo "🏎️ Applying maximum performance optimizations..." 34 | wasm-opt pkg/vietoris_web_demo_bg.wasm \ 35 | -O4 \ 36 | --enable-bulk-memory \ 37 | --enable-sign-ext \ 38 | --enable-mutable-globals \ 39 | --enable-nontrapping-float-to-int \ 40 | --enable-simd \ 41 | --enable-threads \ 42 | --fast-math \ 43 | --inline-functions-with-loops \ 44 | --optimize-level=4 \ 45 | --shrink-level=0 \ 46 | --converge \ 47 | --always-inline-max-function-size=500 \ 48 | --flexible-inline-max-function-size=1000 \ 49 | --partial-inlining-ifs=4 \ 50 | -o pkg/vietoris_web_demo_bg.wasm 51 | 52 | # Show file sizes (just for reference, not optimizing for this) 53 | echo "📊 Build results:" 54 | echo "Final binary size: $(du -h pkg/vietoris_web_demo_bg.wasm | cut -f1)" 55 | 56 | echo "✅ Maximum performance build complete!" 57 | echo "🏎️ Optimized for speed, not size - expect larger but faster WASM!" -------------------------------------------------------------------------------- /examples/vietoris_web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Vietoris-Rips Complex Demo | Harness Labs 7 | 263 | 264 | 265 | 266 |
267 |
268 |
Harness Labs
269 |

Vietoris-Rips Complex

270 |

An interactive demonstration of topological data analysis. Click to place points and observe how 271 | simplicial complexes emerge from geometric proximity.

272 |
273 | 274 |
275 |
276 | 277 |
278 | 279 |
280 |
281 |

Distance Threshold

282 |
283 | 284 | 285 |
50
286 |
287 |
288 | Gray circles show the ε-neighborhood around each point 289 |
290 |
291 | 292 |
293 |

Complex Statistics

294 |
295 |
296 | Vertices (0-simplices) 297 | 0 298 |
299 |
300 | Edges (1-simplices) 301 | 0 302 |
303 |
304 | Triangles (2-simplices) 305 | 0 306 |
307 |
308 |
309 | 310 |
311 |

Instructions

312 |
313 |

Interaction

314 |
    315 |
  • Click to add points
  • 316 |
  • Right-click to remove points
  • 317 |
  • Adjust ε to change connectivity
  • 318 |
  • Observe emerging topology
  • 319 |
320 |
321 |
322 | 323 |
324 | 325 |
326 |
327 |
328 |
329 | 330 | 424 | 425 | 426 | -------------------------------------------------------------------------------- /examples/vietoris_web/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # Interactive Vietoris-Rips Complex Demo 2 | //! 3 | //! A WebAssembly library that provides an interactive demonstration of Vietoris-Rips complexes 4 | //! using the `cova` library. 5 | //! 6 | //! ## Features 7 | //! - Interactive point placement and removal 8 | //! - Real-time Vietoris-Rips complex computation 9 | //! - Canvas-based visualization of simplicial complexes 10 | //! - Adjustable epsilon parameter 11 | 12 | #![cfg(target_arch = "wasm32")] 13 | 14 | use cova::{ 15 | algebra::tensors::fixed::FixedVector, 16 | prelude::*, 17 | space::{ 18 | cloud::Cloud, 19 | complexes::SimplicialComplex, 20 | filtration::{Filtration, vietoris_rips::VietorisRips}, 21 | }, 22 | }; 23 | use wasm_bindgen::prelude::*; 24 | use web_sys::{CanvasRenderingContext2d, console}; 25 | 26 | // Enable better error messages in debug mode 27 | extern crate console_error_panic_hook; 28 | 29 | /// Statistics about the current simplicial complex 30 | #[wasm_bindgen] 31 | pub struct ComplexStats { 32 | vertices: usize, 33 | edges: usize, 34 | triangles: usize, 35 | } 36 | 37 | #[wasm_bindgen] 38 | impl ComplexStats { 39 | #[wasm_bindgen(constructor)] 40 | pub fn new(vertices: usize, edges: usize, triangles: usize) -> ComplexStats { 41 | ComplexStats { vertices, edges, triangles } 42 | } 43 | 44 | #[wasm_bindgen(getter)] 45 | pub fn vertices(&self) -> usize { self.vertices } 46 | 47 | #[wasm_bindgen(getter)] 48 | pub fn edges(&self) -> usize { self.edges } 49 | 50 | #[wasm_bindgen(getter)] 51 | pub fn triangles(&self) -> usize { self.triangles } 52 | } 53 | 54 | /// Main demo structure that manages the interactive Vietoris-Rips visualization 55 | #[wasm_bindgen] 56 | pub struct VietorisRipsDemo { 57 | cloud: Cloud<2>, 58 | epsilon: f64, 59 | canvas_width: f64, 60 | canvas_height: f64, 61 | vr_builder: VietorisRips<2, SimplicialComplex>, 62 | } 63 | 64 | #[wasm_bindgen] 65 | impl VietorisRipsDemo { 66 | /// Create a new demo instance 67 | #[wasm_bindgen(constructor)] 68 | pub fn new(canvas_width: f64, canvas_height: f64) -> Self { 69 | console_error_panic_hook::set_once(); 70 | 71 | Self { 72 | cloud: Cloud::new(Vec::new()), 73 | epsilon: 50.0, 74 | canvas_width, 75 | canvas_height, 76 | vr_builder: VietorisRips::new(), 77 | } 78 | } 79 | 80 | /// Add a point at the given coordinates 81 | #[wasm_bindgen] 82 | pub fn add_point(&mut self, x: f64, y: f64) { 83 | let point = FixedVector::<2, f64>::from([x, y]); 84 | let mut points = self.cloud.points_ref().to_vec(); 85 | points.push(point); 86 | self.cloud = Cloud::new(points); 87 | 88 | console::log_1( 89 | &format!("Added point at ({}, {}). Total: {}", x, y, self.cloud.points_ref().len()).into(), 90 | ); 91 | } 92 | 93 | /// Remove the point closest to the given coordinates (within threshold) 94 | #[wasm_bindgen] 95 | pub fn remove_point(&mut self, x: f64, y: f64) -> bool { 96 | const REMOVE_THRESHOLD: f64 = 20.0; 97 | 98 | let points = self.cloud.points_ref(); 99 | if let Some((index, _)) = points 100 | .iter() 101 | .enumerate() 102 | .map(|(i, p)| (i, (p.0[0] - x).hypot(p.0[1] - y))) 103 | .filter(|(_, dist)| *dist < REMOVE_THRESHOLD) 104 | .min_by(|(_, d1), (_, d2)| d1.partial_cmp(d2).unwrap()) 105 | { 106 | let mut new_points = points.to_vec(); 107 | new_points.remove(index); 108 | self.cloud = Cloud::new(new_points); 109 | 110 | console::log_1(&format!("Removed point. Total: {}", self.cloud.points_ref().len()).into()); 111 | true 112 | } else { 113 | false 114 | } 115 | } 116 | 117 | /// Set the epsilon value for the Vietoris-Rips complex 118 | #[wasm_bindgen] 119 | pub fn set_epsilon(&mut self, epsilon: f64) { 120 | self.epsilon = epsilon; 121 | console::log_1(&format!("Set epsilon to: {}", epsilon).into()); 122 | } 123 | 124 | /// Get the current epsilon value 125 | #[wasm_bindgen] 126 | pub fn get_epsilon(&self) -> f64 { self.epsilon } 127 | 128 | /// Get the number of points 129 | #[wasm_bindgen] 130 | pub fn point_count(&self) -> usize { self.cloud.points_ref().len() } 131 | 132 | /// Clear all points 133 | #[wasm_bindgen] 134 | pub fn clear_points(&mut self) { 135 | self.cloud = Cloud::new(Vec::new()); 136 | console::log_1(&"Cleared all points".into()); 137 | } 138 | 139 | /// Build the Vietoris-Rips complex and return statistics 140 | #[wasm_bindgen] 141 | pub fn get_complex_stats(&self) -> ComplexStats { 142 | if self.cloud.is_empty() { 143 | return ComplexStats::new(0, 0, 0); 144 | } 145 | 146 | let complex = self.vr_builder.build(&self.cloud, self.epsilon, &()); 147 | 148 | let vertices = complex.elements_of_dimension(0).len(); 149 | let edges = complex.elements_of_dimension(1).len(); 150 | let triangles = complex.elements_of_dimension(2).len(); 151 | 152 | ComplexStats::new(vertices, edges, triangles) 153 | } 154 | 155 | /// Render the current state to the canvas 156 | #[wasm_bindgen] 157 | pub fn render(&self, context: &CanvasRenderingContext2d) { 158 | // Clear canvas with white background 159 | context.set_fill_style(&JsValue::from_str("#ffffff")); 160 | context.fill_rect(0.0, 0.0, self.canvas_width, self.canvas_height); 161 | 162 | if self.cloud.is_empty() { 163 | return; 164 | } 165 | 166 | // Build the complex using cova 167 | let complex = self.vr_builder.build(&self.cloud, self.epsilon, &()); 168 | 169 | // Render in order: epsilon bubbles, triangles, edges, vertices (back to front) 170 | self.render_epsilon_bubbles(&context); 171 | self.render_triangles(&context, &complex); 172 | self.render_edges(&context, &complex); 173 | self.render_vertices(&context); 174 | } 175 | 176 | /// Render epsilon distance bubbles around each point 177 | fn render_epsilon_bubbles(&self, context: &CanvasRenderingContext2d) { 178 | context.set_stroke_style(&JsValue::from_str("#e5e7eb")); // Light gray 179 | context.set_line_width(1.0); 180 | context.set_fill_style(&JsValue::from_str("rgba(0, 0, 0, 0.02)")); // Very subtle fill 181 | 182 | for point in self.cloud.points_ref() { 183 | context.begin_path(); 184 | context.arc(point.0[0], point.0[1], self.epsilon, 0.0, 2.0 * std::f64::consts::PI).unwrap(); 185 | context.fill(); 186 | context.stroke(); 187 | } 188 | } 189 | 190 | /// Render vertices as sharp black circles 191 | fn render_vertices(&self, context: &CanvasRenderingContext2d) { 192 | context.set_fill_style(&JsValue::from_str("#000000")); // Pure black 193 | context.set_stroke_style(&JsValue::from_str("#ffffff")); // White border 194 | context.set_line_width(2.0); 195 | 196 | for point in self.cloud.points_ref() { 197 | context.begin_path(); 198 | context.arc(point.0[0], point.0[1], 6.0, 0.0, 2.0 * std::f64::consts::PI).unwrap(); 199 | context.fill(); 200 | context.stroke(); 201 | } 202 | } 203 | 204 | /// Render edges as clean geometric lines 205 | fn render_edges(&self, context: &CanvasRenderingContext2d, complex: &SimplicialComplex) { 206 | context.set_stroke_style(&JsValue::from_str("#3b82f6")); // Clean blue 207 | context.set_line_width(2.0); 208 | 209 | let points = self.cloud.points_ref(); 210 | let edges = complex.elements_of_dimension(1); 211 | for edge in edges { 212 | let vertices = edge.vertices(); 213 | if vertices.len() == 2 { 214 | let p1 = &points[vertices[0]]; 215 | let p2 = &points[vertices[1]]; 216 | 217 | context.begin_path(); 218 | context.move_to(p1.0[0], p1.0[1]); 219 | context.line_to(p2.0[0], p2.0[1]); 220 | context.stroke(); 221 | } 222 | } 223 | } 224 | 225 | /// Render triangles as subtle geometric shapes 226 | fn render_triangles(&self, context: &CanvasRenderingContext2d, complex: &SimplicialComplex) { 227 | context.set_fill_style(&JsValue::from_str("rgba(59, 130, 246, 0.1)")); // Very subtle blue 228 | context.set_stroke_style(&JsValue::from_str("rgba(59, 130, 246, 0.3)")); // Light blue border 229 | context.set_line_width(1.0); 230 | 231 | let points = self.cloud.points_ref(); 232 | let triangles = complex.elements_of_dimension(2); 233 | for triangle in triangles { 234 | let vertices = triangle.vertices(); 235 | if vertices.len() == 3 { 236 | let p1 = &points[vertices[0]]; 237 | let p2 = &points[vertices[1]]; 238 | let p3 = &points[vertices[2]]; 239 | 240 | context.begin_path(); 241 | context.move_to(p1.0[0], p1.0[1]); 242 | context.line_to(p2.0[0], p2.0[1]); 243 | context.line_to(p3.0[0], p3.0[1]); 244 | context.close_path(); 245 | context.fill(); 246 | context.stroke(); 247 | } 248 | } 249 | } 250 | } 251 | 252 | /// Initialize the WASM module 253 | #[wasm_bindgen(start)] 254 | pub fn main() { 255 | console_error_panic_hook::set_once(); 256 | console::log_1(&"🦀 Vietoris-Rips Demo WASM module initialized!".into()); 257 | } 258 | -------------------------------------------------------------------------------- /examples/vietoris_web/src/main.rs: -------------------------------------------------------------------------------- 1 | //! # Vietoris-Rips Demo Server 2 | //! 3 | //! A simple web server that serves the interactive Vietoris-Rips complex demo. 4 | //! 5 | //! ## Usage 6 | //! ```bash 7 | //! cargo run --bin server 8 | //! ``` 9 | //! Then open http://localhost:3030 10 | 11 | use warp::Filter; 12 | 13 | const HTML_CONTENT: &str = include_str!("../index.html"); 14 | 15 | #[tokio::main] 16 | async fn main() { 17 | println!("🦀 Starting Vietoris-Rips Demo Server..."); 18 | 19 | // Serve the main HTML page 20 | let index = warp::path::end().map(|| warp::reply::html(HTML_CONTENT)); 21 | 22 | // Serve WASM files from pkg directory 23 | let wasm_files = warp::path("pkg").and(warp::fs::dir("pkg")); 24 | 25 | // Combine routes with CORS 26 | let routes = index.or(wasm_files).with(warp::cors().allow_any_origin()); 27 | 28 | println!("🌐 Demo available at: http://localhost:3030"); 29 | println!("📖 Click to add points, right-click to remove, adjust epsilon slider!"); 30 | println!("🛑 Press Ctrl+C to stop the server"); 31 | 32 | warp::serve(routes).run(([127, 0, 0, 1], 3030)).await; 33 | } 34 | -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | default: 2 | @just --list 3 | 4 | [private] 5 | warn := "\\033[33m" 6 | error := "\\033[31m" 7 | info := "\\033[34m" 8 | success := "\\033[32m" 9 | reset := "\\033[0m" 10 | bold := "\\033[1m" 11 | 12 | # Print formatted headers without shell scripts 13 | [private] 14 | header msg: 15 | @printf "{{info}}{{bold}}==> {{msg}}{{reset}}\n" 16 | 17 | # Install cargo tools 18 | install-cargo-tools: 19 | @just header "Installing Cargo tools" 20 | # cargo-udeps 21 | if ! command -v cargo-udeps > /dev/null; then \ 22 | printf "{{info}}Installing cargo-udeps...{{reset}}\n" && \ 23 | cargo install cargo-udeps --locked; \ 24 | else \ 25 | printf "{{success}}✓ cargo-udeps already installed{{reset}}\n"; \ 26 | fi 27 | # cargo-semver-checks 28 | if ! command -v cargo-semver-checks > /dev/null; then \ 29 | printf "{{info}}Installing cargo-semver-checks...{{reset}}\n" && \ 30 | cargo install cargo-semver-checks; \ 31 | else \ 32 | printf "{{success}}✓ cargo-semver-checks already installed{{reset}}\n"; \ 33 | fi 34 | # taplo 35 | if ! command -v taplo > /dev/null; then \ 36 | printf "{{info}}Installing taplo...{{reset}}\n" && \ 37 | cargo install taplo-cli; \ 38 | else \ 39 | printf "{{success}}✓ taplo already installed{{reset}}\n"; \ 40 | fi 41 | 42 | # Install mdbook and plugins 43 | install-mdbook-tools: 44 | @just header "Installing mdbook and plugins" 45 | if ! command -v mdbook > /dev/null; then \ 46 | printf "{{info}}Installing mdbook...{{reset}}\n" && \ 47 | cargo install mdbook; \ 48 | else \ 49 | printf "{{success}}✓ mdbook already installed{{reset}}\n"; \ 50 | fi 51 | if ! command -v mdbook-linkcheck > /dev/null; then \ 52 | printf "{{info}}Installing mdbook-linkcheck...{{reset}}\n" && \ 53 | cargo install mdbook-linkcheck; \ 54 | else \ 55 | printf "{{success}}✓ mdbook-linkcheck already installed{{reset}}\n"; \ 56 | fi 57 | if ! command -v mdbook-katex > /dev/null; then \ 58 | printf "{{info}}Installing mdbook-katex...{{reset}}\n" && \ 59 | cargo install mdbook-katex; \ 60 | else \ 61 | printf "{{success}}✓ mdbook-katex already installed{{reset}}\n"; \ 62 | fi 63 | 64 | # Install nightly rust 65 | install-rust-nightly: 66 | @just header "Installing Rust nightly" 67 | rustup install nightly 68 | 69 | # Setup complete development environment 70 | setup: install-cargo-tools install-rust-nightly install-mdbook-tools 71 | @printf "{{success}}{{bold}}Development environment setup complete!{{reset}}\n" 72 | 73 | # Check the with local OS target 74 | check: 75 | @just header "Building workspace" 76 | cargo build --workspace --all-targets 77 | 78 | # Build with local OS target 79 | check-wasm: 80 | @just header "Building workspace" 81 | cargo build --workspace --all-targets --target wasm32-unknown-unknown 82 | 83 | # Build with local OS target 84 | build: 85 | @just header "Building workspace" 86 | cargo build --workspace --all-targets 87 | 88 | # Build with local OS target 89 | build-wasm: 90 | @just header "Building workspace" 91 | cargo build --workspace --all-targets --target wasm32-unknown-unknown 92 | 93 | # Run the tests on your local OS 94 | test: 95 | @just header "Running main test suite" 96 | cargo test --workspace --all-targets --all-features 97 | @just header "Running doc tests" 98 | cargo test --workspace --doc 99 | 100 | # Run clippy for the workspace on your local OS 101 | lint: 102 | @just header "Running clippy" 103 | cargo clippy --workspace --all-targets --all-features 104 | 105 | # Run clippy for the workspace on WASM 106 | lint-wasm: 107 | @just header "Running clippy" 108 | cargo clippy --workspace --all-targets --all-features --target wasm32-unknown-unknown 109 | 110 | # Check for semantic versioning for workspace crates 111 | semver: 112 | @just header "Checking semver compatibility" 113 | cargo semver-checks check-release --workspace 114 | 115 | # Run format for the workspace 116 | fmt: 117 | @just header "Formatting code" 118 | cargo fmt --all 119 | taplo fmt 120 | 121 | # Check for unused dependencies in the workspace 122 | udeps: 123 | @just header "Checking unused dependencies" 124 | cargo +nightly udeps --workspace 125 | 126 | # Run cargo clean to remove build artifacts 127 | clean: 128 | @just header "Cleaning build artifacts" 129 | cargo clean 130 | 131 | # Serve the mdbook documentation (with live reload) 132 | book: 133 | @just header "Serving mdbook documentation" 134 | mdbook serve 135 | 136 | book-check: 137 | @just header "Checking mdbook documentation" 138 | mdbook build 139 | 140 | # Open cargo docs in browser 141 | docs: 142 | @just header "Building and opening cargo docs" 143 | cargo doc --workspace --no-deps --open 144 | 145 | doc-check: 146 | @just header "Checking cargo docs" 147 | RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features 148 | 149 | # Show your relevant environment information 150 | info: 151 | @just header "Environment Information" 152 | @printf "{{info}}OS:{{reset}} %s\n" "$(uname -s)" 153 | @printf "{{info}}Rust:{{reset}} %s\n" "$(rustc --version)" 154 | @printf "{{info}}Cargo:{{reset}} %s\n" "$(cargo --version)" 155 | @printf "{{info}}Installed targets:{{reset}}\n" 156 | @rustup target list --installed | sed 's/^/ /' 157 | 158 | # Run all possible CI checks (cannot test a non-local OS target!) 159 | ci: 160 | @printf "{{bold}}Starting CI checks{{reset}}\n\n" 161 | @ERROR=0; \ 162 | just run-single-check "Rust formatting" "cargo fmt --all -- --check" || ERROR=1; \ 163 | just run-single-check "TOML formatting" "taplo fmt --check" || ERROR=1; \ 164 | just run-single-check "Check" "cargo check --workspace" || ERROR=1; \ 165 | just run-single-check "Check WASM" "cargo check --workspace --target wasm32-unknown-unknown" || ERROR=1; \ 166 | just run-single-check "Clippy" "cargo clippy --workspace --all-targets --all-features -- --deny warnings" || ERROR=1; \ 167 | just run-single-check "Clippy WASM" "cargo clippy --workspace --target wasm32-unknown-unknown --all-features -- --deny warnings" || ERROR=1; \ 168 | just run-single-check "Test suite" "cargo test --verbose --workspace" || ERROR=1; \ 169 | just run-single-check "Doc check" "RUSTDOCFLAGS=\"-D warnings\" cargo doc --no-deps --all-features" || ERROR=1; \ 170 | just run-single-check "Unused dependencies" "cargo +nightly udeps --workspace" || ERROR=1; \ 171 | just run-single-check "Semver compatibility" "cargo semver-checks check-release --workspace" || ERROR=1; \ 172 | printf "\n{{bold}}CI Summary:{{reset}}\n"; \ 173 | if [ $ERROR -eq 0 ]; then \ 174 | printf "{{success}}{{bold}}All checks passed successfully!{{reset}}\n"; \ 175 | else \ 176 | printf "{{error}}{{bold}}Some checks failed. See output above for details.{{reset}}\n"; \ 177 | exit 1; \ 178 | fi 179 | 180 | # Run a single check and return status (0 = pass, 1 = fail) 181 | [private] 182 | run-single-check name command: 183 | #!/usr/bin/env sh 184 | printf "{{info}}{{bold}}Running{{reset}} {{info}}%s{{reset}}...\n" "{{name}}" 185 | if {{command}} > /tmp/check-output 2>&1; then 186 | printf " {{success}}{{bold}}PASSED{{reset}}\n" 187 | exit 0 188 | else 189 | printf " {{error}}{{bold}}FAILED{{reset}}\n" 190 | printf "{{error}}----------------------------------------\n" 191 | while IFS= read -r line; do 192 | printf "{{error}}%s{{reset}}\n" "$line" 193 | done < /tmp/check-output 194 | printf "{{error}}----------------------------------------{{reset}}\n" 195 | exit 1 196 | fi 197 | 198 | # Success summary (called if all checks pass) 199 | [private] 200 | _ci-summary-success: 201 | @printf "\n{{bold}}CI Summary:{{reset}}\n" 202 | @printf "{{success}}{{bold}}All checks passed successfully!{{reset}}\n" 203 | 204 | # Failure summary (called if any check fails) 205 | [private] 206 | _ci-summary-failure: 207 | @printf "\n{{bold}}CI Summary:{{reset}}\n" 208 | @printf "{{error}}{{bold}}Some checks failed. See output above for details.{{reset}}\n" 209 | @exit 1 210 | 211 | 212 | -------------------------------------------------------------------------------- /katex-header.html: -------------------------------------------------------------------------------- 1 | 3 | 6 | 9 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2025-05-25" 3 | --------------------------------------------------------------------------------