From 4d434f0cc7df3dc986ae58c41748a0163836f6ee Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 12:17:32 +0000 Subject: [PATCH 1/2] fix: make Frequency.isSubset truly generic (remove hardcoded float key type) The inner helper function issubset was typed as list and Map, which forced F# type inference to constrain the outer isSubset to Map despite its signature appearing generic. This meant isSubset could not be used with string, int, or any other key type produced by Frequency.createGeneric. Fix: replace explicit float type annotations in the helper with the generic type variable 'a, making isSubset work for all comparable key types. Add 6 tests covering float, string, int, and empty histogram cases. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/FSharp.Stats/Distributions/Frequency.fs | 4 +- .../DistributionsEmpirical.fs | 41 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/FSharp.Stats/Distributions/Frequency.fs b/src/FSharp.Stats/Distributions/Frequency.fs index 086e81e6..0dd5f287 100644 --- a/src/FSharp.Stats/Distributions/Frequency.fs +++ b/src/FSharp.Stats/Distributions/Frequency.fs @@ -124,8 +124,8 @@ module Frequency = /// /// /// - let isSubset (histA:Map<_,int>) (histB:Map<_,int>) = - let rec issubset (histA:list) (histB:Map) = + let isSubset (histA:Map<'a,int>) (histB:Map<'a,int>) = + let rec issubset (histA:list<'a*int>) (histB:Map<'a,int>) = match histA with | head::rest -> let k,v = head diff --git a/tests/FSharp.Stats.Tests/DistributionsEmpirical.fs b/tests/FSharp.Stats.Tests/DistributionsEmpirical.fs index a1fd55c8..1348dc70 100644 --- a/tests/FSharp.Stats.Tests/DistributionsEmpirical.fs +++ b/tests/FSharp.Stats.Tests/DistributionsEmpirical.fs @@ -190,3 +190,44 @@ let empiricalTests = "Empirical.merge leads to a wrong distribution merge" ] +[] +let frequencyTests = + testList "Distributions.Frequency" [ + + testCase "isSubset float keys - A is subset of B" <| fun () -> + let histA = Frequency.create 0.1 [0.1; 0.2; 0.3] + let histB = Frequency.create 0.1 [0.1; 0.2; 0.3; 0.4; 0.5] + Expect.isTrue (Frequency.isSubset histA histB) + "histA should be a subset of histB" + + testCase "isSubset float keys - A is not subset of B" <| fun () -> + let histA = Frequency.create 0.1 [0.1; 0.1; 0.2] + let histB = Frequency.create 0.1 [0.1; 0.2] + Expect.isFalse (Frequency.isSubset histA histB) + "histA with count 2 for 0.1 should not be a subset of histB with count 1 for 0.1" + + testCase "isSubset string keys - A is subset of B" <| fun () -> + let histA = Frequency.createGeneric ["a"; "b"; "a"] + let histB = Frequency.createGeneric ["a"; "a"; "a"; "b"; "b"; "c"] + Expect.isTrue (Frequency.isSubset histA histB) + "histA (a:2, b:1) should be a subset of histB (a:3, b:2, c:1)" + + testCase "isSubset string keys - A is not subset of B" <| fun () -> + let histA = Frequency.createGeneric ["a"; "a"; "a"] + let histB = Frequency.createGeneric ["a"; "a"; "b"] + Expect.isFalse (Frequency.isSubset histA histB) + "histA (a:3) should not be a subset of histB (a:2, b:1)" + + testCase "isSubset int keys - A is subset of B" <| fun () -> + let histA = Frequency.createGeneric [1; 2; 1] + let histB = Frequency.createGeneric [1; 1; 1; 2; 2; 3] + Expect.isTrue (Frequency.isSubset histA histB) + "histA (1:2, 2:1) should be a subset of histB (1:3, 2:2, 3:1)" + + testCase "isSubset empty histA is always subset" <| fun () -> + let histA : Map = Map.empty + let histB = Frequency.createGeneric ["a"; "b"] + Expect.isTrue (Frequency.isSubset histA histB) + "empty histA should be a subset of any histB" + ] + From e3f79d156f160919d071ba7e2f6c2efffa3ce229 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 19 Apr 2026 12:17:34 +0000 Subject: [PATCH 2/2] ci: trigger checks