Refactor july - #62
Merged
Merged
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
bit true now maps to -1, so XOR on stored bits is exactly the +-1 product. Sign-based real-vector constructor (zero elements throw, pointing to TernaryHV), corrected summary labels, regenerated doctests, and polarity-locking tests (x * x is the all-+1 identity, construction/indexing round-trip, summary counts). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
perturbate(::FHRR, ...) threw a MethodError (no eldist); dedicated methods now resample e^(2pi*i*rand()) at the selected positions. Locked by tests asserting unit modulus, untouched positions, and exact resample counts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The vector decodelevel methods now accept (and ignore) testbound so the generic forwarding no longer mis-dispatches into a MethodError. Adjacent bug flagged, not fixed: the instance path builds encoder and decoder over different random ladders (TODO 1.4b). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
RealHV/GradedHV/GradedBipolarHV results carried the default distr, which silently changed normalize! numerics. Locked by metadata assertions and a numerical test that normalize! rescales to the original spread. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Generic shift! and the clamp!-based normalize! methods returned the raw wrapped vector. Locked by op!(hv) === hv tests for all types and all in-place operations. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
δ was an exported non-const global (type-unstable at call sites). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
isequal compared raw storage across types, so a BinaryHV equalled a BipolarHV whenever the bits matched; the one-arg hash override was inconsistent with two-arg hashing. isequal is now a same-type storage fast path, cross-type comparisons fall back to Base element semantics, and hashing is element-based. Locked by same-bits/different-type tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Collaborator
Author
|
Please don't push to this branch today, still work in progress |
The previous fix (2e952a7) let cross-type comparisons fall back to Base elementwise semantics, but Julia treats Bool as numeric (true == 1), so an all-true BinaryHV still equalled an all-+1 BipolarHV — whose stored bits are the exact opposite since the polarity flip. == and isequal between different hypervector types now return false unconditionally; same-family comparisons (e.g. TernaryHV{Int8} vs TernaryHV{Int64}) compare by value, and comparisons against plain vectors keep Base elementwise semantics. Hashing stays on the element-based AbstractArray fallback: isequal(hv, ::Vector) can be true, so a type-salted hash would break the hash/equality contract. Locked by tests covering the numeric-coincidence case, the same-family case, and the hash contract for all seven types (including BipolarHV, where storage and elements disagree) and against plain vectors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds the missing encoder layer (raw data in, hypervector out) and gives every constructor form exactly one meaning: - encode(HV, x; D) is the canonical deterministic token path (hash -> seed); HV(x) is shorthand for it. encode(HV, x, strategy) dispatches on the new AbstractEncoding strategies: KMer(k) (windows as atomic hashed tokens — resolves #53), NGram(n) (symbol-level shift-binding via ngrams), Sequence() (bundlesequence) and BagOfSymbols() (multiset). KMer and NGram are genuinely different operations and are documented as such. Extension point: one struct subtyping AbstractEncoding plus one encode method. - HV(n::Number) throws an ArgumentError naming both alternatives (D = n / encode(HV, n)); the one-time @warn and its testset are gone. - Data constructors are widened to AbstractVector{<:Real} and validate each type's element domain: BinaryHV {0,1}; BipolarHV strictly ±1 (zero points to TernaryHV, no more silent sign-taking); TernaryHV {-1,0,+1} (inner constructors stay permissive for operation results); Graded types range-checked instead of silently clamped; FHRR unit modulus. Invalid arrays throw instead of silently token-encoding — BinaryHV([1, 0]) is now a 2-element hypervector, killing that trapdoor. Tuples of reals read as data. BREAKING: numeric constructor tokens throw; graded out-of-range data throws instead of clamping; bipolar non-±1 data throws instead of sign-coercion; Vector{<:Real} data construction added for BinaryHV. Also fixes a tutorial example that constructed an invalid TernaryHV from 0:9 (now RealHV). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The §1.6 fix (9049cb9) is verified correct for every argument form; the locking test only covered the count form — now also fraction, mask, and index-vector. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
eldist(hv) now returns hv.distr for RealHV, GradedHV and GradedBipolarHV instead of falling back to the type default, so perturbate (and level ladders built from custom-distr hypervectors) draw replacement elements from the vector's own distribution. Locked by a resampled-element statistics testset. Closes TODO §1.5c. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Collaborator
Author
|
Big change @cvigilv, you might take a look and see if we can commit before finishing tutorials. |
Collaborator
I'll review it now and let you know. Thanks for the PR |
Collaborator
|
Looks great! I honestly have no problem with merging this. That said, we will have some work merging the tutorials branch, so we can (again) make use of Claude for that. I'll approve this, merge it to the tutorial branch, solve the conflicts, and ask for a review again. |
cvigilv
approved these changes
Jul 14, 2026
Collaborator
Author
|
If this is approved I can rework the tutorials based on the material I made.
…On Tue, 14 Jul 2026, 19:24 Carlos Vigil-Vásquez, ***@***.***> wrote:
*cvigilv* left a comment (Kermit-UGent/HyperdimensionalComputing.jl#62)
<#62 (comment)>
Looks great! I honestly have no problem with merging this. That said, we
will have some work merging the tutorials branch, so we can (again) make
use of Claude for that. I'll approve this, merge it to the tutorial branch,
solve the conflicts, and ask for a review again.
—
Reply to this email directly, view it on GitHub
<#62?email_source=notifications&email_token=ABN5PI3656ZAHSFDRK4OLE35EZUEZA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIOJXGIYDKMZQHE3KM4TFMFZW63VGMF2XI2DPOKSWK5TFNZ2KYZTPN52GK4S7MNWGSY3L#issuecomment-4972053096>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABN5PIYMME7YNVCEIE46UUT5EZUEZAVCNFSNUABFKJSXA33TNF2G64TZHM2DCNZRHE4TQNJSHNEXG43VMU5TIOBYGIYDOOJWHA3KC5QC>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixing all kinds of issues
.vstorage, each with an explicit verdict. Fixed: summary labels (were inverted), the data constructor (was negating input), stale doctests/README. Verified correct without change: bundle's majority vote (mapping-invariant), the bipolar dot formula, isapprox, hash/isequal, shift/perturbate. New polarity-locking tests are deliberately not polarity-blind (all(x * x .== 1), construction/indexing round-trip, summary counts) — the original bug survived a green suite because XOR-self-inversion and cosine are invariant under the flip. Tie-break outcome change noted under Add another stragery for tie-breaking #15.distr(locked by the numerical consequence: normalize! rescales to the original spread), in-place ops returning raw vectors (shift! and the three clamp!-based normalize! methods; all perturbate! argument forms locked),const δ, and cross-type isequal/hash. Adjacent bug found and flagged, not fixed: instance-path convertlevel builds encoder and decoder over different random ladders — measured decode(encode(x)) error up to 1.0 (TODO §1.4b, retired properly by the encoder follow-up below).true == 1let an all-true BinaryHV equal an all-+1 BipolarHV even though their stored bits are opposite since the flip.==/isequalbetween different hypervector types return false; same-family different-parameter (TernaryHV{Int8} vs {Int64}) compares by value; hashing stays element-based becauseisequal(hv, ::Vector)can legitimately be true and the hash/equality contract must hold against plain vectors too. All locked by tests.hv.distr(found in the §1.5 pattern sweep — right metadata, wrong-distribution elements; measured std ≈ 1 where 5 was configured). Fixed with instanceeldistmethods and locked by resampled-statistics tests.encodeinterface (design change): the package now has an explicit layer taxonomy — primitives (operations.jl) → combinators (encoding.jl, unchanged) → encoders (encode.jl, new: raw data in, hypervector out).encode(HV, x)is the canonical deterministic token path;HV(x)is sugar for it. Constructors have one meaning each:HV(n::Number)throws an ArgumentError naming both alternatives (D = n/encode(HV, n)) — replacing the @warn from item 2 — and data constructors are widened toAbstractVector{<:Real}with per-type element validation (BinaryHV {0,1} —BinaryHV([1, 0])is finally a 2-element hypervector, not a silent 10,000-dim hash; BipolarHV strictly ±1 with zero pointing to TernaryHV; TernaryHV {-1,0,+1} with permissive inner constructors for operation results; graded ranges rejected instead of silently clamped; FHRR unit-modulus). Tuples of reals read as data. Sequence strategies dispatch onAbstractEncoding: KMer(k) resolves New k-mers encoder #53 (windows as atomic hashed tokens) and is deliberately distinct from NGram(n) (symbol-level shift-binding via ngrams); plus Sequence() and BagOfSymbols(). Extension point: one struct + one encode method. The new validation immediately caught two latent wrongs: a test using the old trap idiom and a tutorial example constructing a TernaryHV from 0:9.Test suite: 268 → 669 assertions (plus 37 extension tests in a separate process and CI-enforced doctests). Breaking changes: seeded RNG streams (MersenneTwister → Xoshiro), BipolarHV polarity + strict data validation, graded types reject instead of clamp, cross-type equality, numeric constructor tokens throw.
Follow-ups (tracked in TODO.md)
AbstractEncoder{HV}hierarchy (RandomProjection,LevelEncoder) with encode/decode — retires §1.4b properly;encode's first-arg slot is reserved for it.train/predict) — the JuliaCon demo.similar,normalizeclash), CI matrix, coverage, CompatHelper/TagBot → register in General (Release package #9).