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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ All notable changes to `RiskLabAI.jl` are documented here. The format is based o
[Semantic Versioning](https://semver.org/spec/v2.0.0.html) (pre-1.0: minor
versions may include breaking changes).

## [0.5.1] — 2026-06-19

### Fixed

- `Optimization.hrp` now symmetrises the correlation-distance matrix before
single-linkage clustering, so it accepts correlation matrices with the tiny
floating-point asymmetry that real sample covariances always have (previously
`Clustering.hclust` threw `ArgumentError: Distance matrix should be symmetric`).
Added a regression test covering an asymmetric correlation input.

## [0.5.0] — 2026-06-19

First substantive release. The package was reconstructed from the ground up to
Expand Down Expand Up @@ -67,5 +77,6 @@ machine-learning pieces are validated structurally. The parity ledger lives in

- Initial package skeleton.

[0.5.1]: https://github.com/RiskLabAI/RiskLabAI.jl/releases/tag/v0.5.1
[0.5.0]: https://github.com/RiskLabAI/RiskLabAI.jl/releases/tag/v0.5.0
[0.0.1]: https://github.com/RiskLabAI/RiskLabAI.jl/releases/tag/v0.0.1
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "RiskLabAI"
uuid = "a72881da-fdaa-49c1-8962-99caf4ccfee8"
version = "0.5.0"
version = "0.5.1"
authors = ["RiskLab AI <research@risklab.ai>"]

[deps]
Expand Down
1 change: 1 addition & 0 deletions src/Optimization/HierarchicalRiskParity.jl
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ function hrp(
correlation::AbstractMatrix{<:Real},
)
distance = distance_corr(correlation)
distance = (distance .+ distance') ./ 2 # enforce exact symmetry for hclust
order = hclust(distance; linkage = :single).order
bisection = recursive_bisection(covariance, order)
weights = zeros(Float64, length(order))
Expand Down
12 changes: 12 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,18 @@ end
@test length(w_hrp) == 4
@test sum(w_hrp) ≈ 1.0
@test all(w_hrp .> 0)

# Regression: hrp() must accept a correlation with floating-point asymmetry
# (real sample covariances are not bit-exactly symmetric → hclust would throw
# "Distance matrix should be symmetric" without the symmetrisation guard).
g = randn(MersenneTwister(7), 6, 6)
psd = g * g'
sym_corr = RiskLabAI.Cluster.covariance_to_correlation(psd)
asym_corr = copy(sym_corr)
asym_corr[1, 2] += 1e-12 # break exact symmetry, as FP does
w_sample = O.hrp(psd, asym_corr)
@test length(w_sample) == 6
@test sum(w_sample) ≈ 1.0
end

@testset "Validation — cross-validators (parity with Python)" begin
Expand Down
Loading