Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/workflows/validate-repo-maintenance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Validate Repo Maintenance

# Branch protection should require the Actions check context `validate`.
# GitHub exposes the job check run by this job name, not by the workflow title.

on:
pull_request:
push:
branches:
- main

jobs:
validate:
name: validate
runs-on: macos-26
steps:
# This is a validated floor, not a ceiling; update to newer stable official versions when validated.
- uses: actions/checkout@v6.0.2
- name: Report selected Xcode
run: xcode-select --print-path
- name: Report Swift toolchain
run: xcrun swift --version
- name: Install Swift repo-maintenance tools
run: brew install swiftformat swiftlint
- name: Run repo-maintenance validation
run: bash scripts/repo-maintenance/validate-all.sh
4 changes: 4 additions & 0 deletions .spi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
version: 1
builder:
configs:
- documentation_targets: [MaxVol]
92 changes: 92 additions & 0 deletions .swiftformat
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Exported from Gale's SwiftFormat for Xcode settings and curated for repo use.
# This file is the repository source of truth for formatting. If the host app
# configuration changes later, re-export from the shared SwiftFormat settings
# and review the diff before importing it back into the app.

--rules andOperator,anyObjectProtocol,applicationMain,assertionFailures,blankLineAfterImports,blankLinesAfterGuardStatements,blankLinesAroundMark,blankLinesAtEndOfScope,blankLinesAtStartOfScope,blankLinesBetweenChainedFunctions,blankLinesBetweenImports,blankLinesBetweenScopes,braces,conditionalAssignment,consecutiveBlankLines,consecutiveSpaces,consistentSwitchCaseSpacing,docComments,docCommentsBeforeModifiers,duplicateImports,elseOnSameLine,emptyBraces,emptyExtensions,enumNamespaces,environmentEntry,extensionAccessControl,fileMacro,genericExtensions,headerFileName,hoistAwait,hoistPatternLet,hoistTry,indent,initCoderUnavailable,isEmpty,leadingDelimiters,linebreakAtEndOfFile,linebreaks,modifierOrder,noForceTryInTests,noForceUnwrapInTests,noGuardInTests,numberFormatting,opaqueGenericParameters,organizeDeclarations,preferFinalClasses,privateStateVariables,redundantAsync,redundantBackticks,redundantBreak,redundantClosure,redundantEquatable,redundantExtensionACL,redundantFileprivate,redundantGet,redundantInit,redundantInternal,redundantLet,redundantLetError,redundantMemberwiseInit,redundantNilInit,redundantObjc,redundantOptionalBinding,redundantParens,redundantPattern,redundantPublic,redundantRawValues,redundantReturn,redundantSelf,redundantSendable,redundantStaticSelf,redundantSwiftTestingSuite,redundantThrows,redundantType,redundantTypedThrows,redundantVariable,redundantViewBuilder,semicolons,simplifyGenericConstraints,sortDeclarations,sortImports,sortTypealiases,spaceAroundBraces,spaceAroundBrackets,spaceAroundComments,spaceAroundGenerics,spaceAroundOperators,spaceAroundParens,spaceInsideBrackets,spaceInsideComments,spaceInsideGenerics,spaceInsideParens,strongOutlets,strongifiedSelf,swiftTestingTestCaseNames,todos,trailingClosures,trailingCommas,trailingSpace,typeSugar,validateTestCases,void,wrap,wrapArguments,wrapAttributes,wrapLoopBodies,wrapMultilineFunctionChains,wrapSingleLineComments,yodaConditions

--acronyms ID,URL,UUID
--allow-partial-wrapping true
--anonymous-for-each convert
--asset-literals visual-width
--binary-grouping 4,8
--line-between-guards false
--category-mark "MARK: %c"
--class-threshold 0
--closing-paren balanced
--closure-void remove
--complex-attributes preserve
--computed-var-attributes preserve
--conditional-assignment after-property
--date-format system
--decimal-grouping 3,6
--doc-comments before-declarations
--else-position same-line
--empty-braces no-space
--enum-namespaces always
--equatable-macro none
--exponent-case lowercase
--extension-acl on-extension
--file-macro "#file"
--func-attributes preserve
--group-blank-lines true
--guard-else auto
--header ignore
--hex-grouping 4,8
--hex-literal-case uppercase
--ifdef outdent
--import-grouping alpha,access-control
--indent 4
--indent-case true
--indent-strings false
--inferred-types always
--init-coder-nil false
--line-after-marks true
--linebreaks lf
--mark-categories false
--mark-class-threshold 40
--mark-enum-threshold 40
--mark-extension-threshold 40
--mark-struct-threshold 40
--max-width none
--operator-func spaced
--organization-mode type
--organize-types actor,class,enum,struct
--pattern-let hoist
--prefer-synthesized-init-for-internal-structs never
--property-types infer-locals-only
--ranges no-space
--redundant-async tests-only
--redundant-throws tests-only
--self remove
--semicolons inline-only
--short-optionals preserve-struct-inits
--smart-tabs enabled
--some-any true
--sort-swiftui-properties alphabetize
--stored-var-attributes preserve
--struct-threshold 40
--strip-unused-args always
--suite-name-format standard-identifiers
--test-case-name-format raw-identifiers
--timezone system
--trailing-commas always
--trim-whitespace always
--type-attributes preserve
--type-blank-lines remove
--type-body-marks preserve
--type-delimiter space-after
--class-threshold 40
--enum-threshold 40
--extension-threshold 40
--void-type Void
--wrap-arguments preserve
--wrap-collections preserve
--wrap-conditions preserve
--wrap-effects preserve
--wrap-return-type preserve
--wrap-string-interpolation default
--wrap-ternary default
--wrap-type-aliases preserve
--xcode-indentation disabled
--yoda-swap always
20 changes: 20 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Keep SwiftLint focused on non-formatting checks.
# SwiftFormat owns visual shape in this repository.

excluded:
- .build
- .local

only_rules:
- duplicate_imports
- empty_count
- fatal_error_message
- force_try
- force_unwrapping
- unused_import

force_try:
severity: warning

force_unwrapping:
severity: warning
39 changes: 39 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,42 @@
- Validate both Debug and Release paths when optimization or packaging differences matter, and treat tagged releases as a cue to verify the Release artifact path before publishing.
- Keep `xcodebuild` invocations explicit and reproducible (always pass scheme, destination or SDK, and configuration when relevant).
- Prefer deterministic non-interactive CLI usage in automation/CI for both `swift package` and `xcodebuild`.

## Swift Package Workflow

- Use `swift build` and `swift test` as the default first-pass validation commands for this package.
- Use `bootstrap-swift-package` when a new Swift package repo still needs to be created from scratch.
- Use `sync-swift-package-guidance` when the repo guidance for this package drifts and needs to be refreshed or merged forward.
- Re-run `sync-swift-package-guidance` after substantial package-workflow or plugin updates so local guidance stays aligned.
- Use `swift-package-build-run-workflow` for manifest, dependency, plugin, resource, Metal-distribution, build, and run work when `Package.swift` is the source of truth.
- Use `swift-package-testing-workflow` for Swift Testing, XCTest holdouts, `.xctestplan`, fixtures, and package test diagnosis.
- Use `scripts/repo-maintenance/validate-all.sh` for local maintainer validation and `scripts/repo-maintenance/sync-shared.sh` for repo-local sync steps.
- Use `scripts/repo-maintenance/release.sh --mode standard --version vX.Y.Z` from a feature branch or worktree only when the task is actually a protected-main release, publish, merge, tag, or release-PR preparation.
- Do not run the standard release workflow from `main`; when a protected-main release is explicitly requested, let it validate, bump versions, tag, push the branch and tag, open the release PR, watch CI, address valid PR comments or record out-of-scope concerns in `ROADMAP.md`, merge to protected `main`, fast-forward local `main`, and clean up stale branches.
- Treat `scripts/repo-maintenance/config/profile.env` as the installed `maintain-project-repo` profile marker, and keep it on the `swift-package` profile for plain package repos.
- Read relevant SwiftPM, Swift, and Apple documentation before proposing package-structure, dependency, manifest, concurrency, or architecture changes.
- Prefer Xcode MCP DocumentationSearch or local Swift docs first for Apple-owned Swift and SDK behavior; use Dash MCP or Dash HTTP next for installed Swift package, SwiftPM, and non-Apple docs; then use official Swift or Apple docs when local docs are insufficient.
- When SwiftPM behavior, manifest syntax, package plugins, resources, products, targets, or dependency rules matter, prefer the Dash.app docset workflow with the `swiftlang/swift-package-manager` docset first; fall back to the canonical `swiftlang/swift-package-manager` GitHub repository only when the local docset is unavailable or insufficient.
- Prefer the simplest correct Swift that is easiest to read and reason about.
- Prefer synthesized and framework-provided behavior over extra wrappers and boilerplate.
- For public Swift APIs, treat streamlined, compact, ergonomic call sites as the only acceptable default; prefer optional parameters with explicit default values over additional methods or overloads when the difference is optional behavior on the same operation.
- When a public function, initializer, or method reaches four or more arguments or parameters, strongly prefer a named typed `struct` request, options, or configuration value so call sites stay readable and future additions do not multiply overloads.
- Prefer enums, enum cases with associated values, and narrow typed values over strings, booleans, sentinel values, or parallel parameters whenever the domain has a closed or meaningful set of choices.
- Keep data flow straight and dependency direction unidirectional.
- Treat `Package.swift` as the source of truth for package structure, targets, products, and dependencies.
- Prefer `swift package` subcommands for structural package edits before manually editing `Package.swift`.
- Edit `Package.swift` intentionally and keep it readable; agents may modify it when package structure, targets, products, or dependencies need to change, and should try to keep package graph updates consolidated in one change when possible.
- Keep `Package.swift` explicit about its package-wide Swift language mode. On current Swift 6-era manifests, prefer `swiftLanguageModes: [.v6]` as the default declaration, treat `swiftLanguageVersions` as a legacy alias used only when an older manifest surface requires it, and keep the supported Swift toolchain window focused on the latest stable minor and previous stable minor. Treat Swift `6.2` as the current minimum floor for trait-enabled manifests, not as a ceiling; use newer stable Swift toolchains when available and validated, and refresh this guidance when the maintained floor or window changes. Do not lower `// swift-tools-version:` below `6.2` without an explicit repo policy and a matching guidance update.
- Keep `swift-configuration` as the default configuration dependency for Swift packages unless the package has a concrete reason to remove it. The preferred manifest shape depends on `https://github.com/apple/swift-configuration` from `1.2.0`, enables the `.defaults`, `Reloading`, `YAML`, and `CommandLineArguments` package traits, and adds the `Configuration` product to the primary target. Add the `PropertyList` trait when the package should parse property-list configuration, and add the `Logging` trait when configuration access should integrate with `SwiftLog.Logger`.
- Keep dependency provenance concise but explicit enough for another contributor to fetch the same package: use package-manager, package-registry, GitHub URL, or other real remote repository requirements, and do not commit machine-local dependency paths such as `/Users/...`, `~/...`, `../...`, local worktrees, or private checkout paths. Avoid branch- or revision-based requirements unless the user explicitly asks for that level of control.
- Treat `Package.resolved` and similar package-manager outputs as generated files; do not hand-edit them.
- Prefer Swift Testing by default unless an external constraint requires XCTest.
- Use `apple-ui-accessibility-workflow` when the package work crosses into SwiftUI accessibility semantics, Apple UI accessibility review, or UIKit/AppKit accessibility bridge behavior.
- Keep package resources under the owning target tree, declare them intentionally with `Resource.process(...)`, `Resource.copy(...)`, `Resource.embedInCode(...)`, and load them through `Bundle.module`.
- Keep test fixtures as test-target resources instead of relying on the working directory.
- Bundle precompiled Metal artifacts such as `.metallib` files as explicit resources when they ship with the package, and prefer `xcode-build-run-workflow` when shader compilation or Apple-managed Metal toolchain behavior matters.
- Prefer normal SwiftPM parallel test execution for ordinary Swift Testing and XCTest runs. Do not serialize regular package tests just because they use Swift, XCTest, async tests, fixtures, or test plans.
- Treat tests that load large local AI or ML models, especially models over 500 million parameters, as heavy system-resource tests. Run those tests sequentially, one at a time, and call `unload_models` on Gale's live TTS service before the heavy run and `reload_models` after it ends, even when the run fails or is interrupted.
- Validate both Debug and Release paths when optimization or packaging differences matter, and treat tagged releases as a cue to verify the Release artifact path before publishing.
- Prefer `xcode-build-run-workflow` or `xcode-testing-workflow` only when package work needs Xcode-managed SDK, toolchain, or test behavior.
- Keep runtime UI accessibility verification and XCUITest follow-through in `xcode-testing-workflow` rather than treating package-side testing as a substitute for live UI verification.
6 changes: 5 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ let package = Package(
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "MaxVol"
name: "MaxVol",
cSettings: [
.define("ACCELERATE_NEW_LAPACK"),
.define("ACCELERATE_LAPACK_ILP64"),
]
),
.testTarget(
name: "MaxVolTests",
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ following the same shape once the API is settled.
- Initialize pivots with `dgetrf`.
- Solve for expansion coefficients with triangular solves.
- Iterate row swaps using the standard rank-one update with `dger`.
- Return selected row indices, coefficient matrix, and iteration count.
- Return selected row indices, coefficient matrix, iteration count, and
whether the coefficient tolerance was reached.

3. Add RectMaxVol on top of square MaxVol.
- Start from square MaxVol pivots.
Expand All @@ -34,7 +35,8 @@ following the same shape once the API is settled.
- Verify reconstruction `A ~= C * A[pivots, :]`.
- Check pivot count, uniqueness, and bounds.
- Cover identity, tall random, rank-deficient, tolerance, and max-iteration cases.
- Compare small deterministic fixtures against a reference Python or Julia result.
- Compare small deterministic fixtures against reference Python, Julia, or R
results.

5. Add performance-focused refinements only after the behavior is stable.
- Avoid repeated temporary allocations in the swap loop.
Expand Down
95 changes: 95 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# MaxVol Roadmap

## Current Focus

- Ship `v0.5.0` with square MaxVol for real-valued `Double` matrices backed by
modern Accelerate BLAS/LAPACK.
- Keep Swift Testing as the package test surface and require reference fixtures
before broadening the algorithm surface.
- Treat public API compatibility as pre-1.0 until RectMaxVol, Float support, and
reference parity are complete.

## Algorithm Milestones

1. Implement square MaxVol for `Double`.
- Accept a tall or square `DenseColumnMajorMatrix<Double>` where
`rows >= columns`.
- Initialize pivots with Accelerate LAPACK LU factorization.
- Solve expansion coefficients with Accelerate triangular solve routines.
- Iterate row swaps with BLAS rank-one updates.
- Return selected row indices, coefficient matrix, iteration count, and
convergence status.

2. Add RectMaxVol for `Double`.
- Start from square MaxVol selected rows.
- Append rows while coefficient row norms exceed tolerance.
- Support explicit `minRows` and `maxRows` bounds.
- Reuse coefficient-update primitives from square MaxVol where practical.

3. Add `Float` support after the `Double` API is stable.
- Mirror the `Double` API shape.
- Map to the matching single-precision Accelerate entry points.
- Keep shared validation and result semantics identical.

4. Add reference-parity fixtures for each supported algorithm.
- Keep small deterministic fixtures generated from `maxvolpy`, `Maxvol.jl`,
or an R implementation.
- Record selected rows, coefficients, iteration counts, and convergence
status for fixture matrices that require zero, one, and multiple swaps.
- Include independent reconstruction checks for every fixture.

## Test Coverage

- Cover matrix storage, checked access, shape validation, and result invariants.
- Verify selected row count, uniqueness, and bounds.
- Verify reconstruction: `A ~= C * A[selectedRows, :]`.
- Cover identity, square, tall deterministic, rank-deficient, tolerance, and
maximum-iteration cases.
- Keep reference fixtures generated from upstream Python, Julia, or R
implementations when algorithm behavior changes.
- Add randomized orthonormal-matrix tests similar to `Maxvol.jl` before `1.0.0`.
- Add Release-mode validation once behavior depends on optimization-sensitive
Accelerate calls.
- Keep validation clean under the modern Accelerate `ACCELERATE_NEW_LAPACK` and
`ACCELERATE_LAPACK_ILP64` import surface.

## Documentation

- Maintain the DocC catalog for the package.
- Document column-major storage and the relationship to Accelerate/LAPACK leading
dimensions.
- Document square MaxVol and RectMaxVol usage with small examples.
- Keep algorithm limitations and non-goals visible before `1.0.0`.
- Keep public API docs aligned with tested behavior.
- Add a DocC article that explains tolerance, convergence status, and
iteration-limited partial results before `1.0.0`.

## Swift Package Index

- Keep SPI readiness checks in the release path.
- Keep `.spi.yml` aligned with DocC targets when package documentation changes.
- Verify `swift package dump-package`, `swift build`, `swift test`, and DocC
generation before submitting to Swift Package Index.
- Submit only after the GitHub repository is public and a SemVer tag exists.

## GitHub Publication

- Keep the public `gaelic-ghost/MaxVol` repository aligned with SemVer tags.
- Merge focused pull requests into `main` only after serial `swift build`,
`swift test`, repo-maintenance validation, and DocC conversion pass.
- Submit to Swift Package Index after the first public SemVer tag is pushed.

## Before `1.0.0`

- Implement and test RectMaxVol for `Double`.
- Add `Float` support with the same API shape and reference fixtures.
- Decide whether complex-valued matrices are in scope for `1.0.0` or explicitly
post-1.0.
- Add broader randomized numerical tests, including orthonormal tall matrices
and near-rank-deficient cases.
- Add Release-mode validation for optimization-sensitive Accelerate behavior.
- Add performance benchmarks for allocation count and row-swap throughput.
- Expand DocC with algorithm notes, limitations, and reference-fixture
provenance.
- Submit the tagged public package to Swift Package Index and verify rendered
documentation.
Loading
Loading