diff --git a/dune-project b/dune-project index be2fc95e69ce876d72bbd15895e7b58745600308..2efbe51f707406ca26e9c15bb9a503ce1fc7afac 100644 --- a/dune-project +++ b/dune-project @@ -1,4 +1,4 @@ -(lang dune 3.0) +(lang dune 3.7) (name robinson) diff --git a/lib/pqtrees/pqChainInsertion.ml b/lib/pqtrees/pqChainInsertion.ml index 998773dec1a3f26e534455df86bea503763e04e3..781a8088285b03dae54530a291be7638634c2869 100644 --- a/lib/pqtrees/pqChainInsertion.ml +++ b/lib/pqtrees/pqChainInsertion.ml @@ -47,7 +47,8 @@ module Make = type external_subtree = | ConstantSubtree of int * pqtree - | IncreasingSubtree of int * pqtree DeQueue.t * int (* an increasing subtree is necessarily a Q-node *) + | IncreasingSubtree of int * pqtree DeQueue.t * int + (* an increasing subtree is necessarily a Q-node *) let bounds = function | ConstantSubtree (delta,_) -> (delta, delta) diff --git a/lib/pqtrees/pqChainInsertion.mli b/lib/pqtrees/pqChainInsertion.mli index 7be1df77f13c0835fb4098935c8e78cc7661e092..d220897ced07f2911f6ced5e5a05c6c9dc33c311 100644 --- a/lib/pqtrees/pqChainInsertion.mli +++ b/lib/pqtrees/pqChainInsertion.mli @@ -1,7 +1,84 @@ +open DataStruct + module Make : functor (Chain : sig type t val s : t val d : t -> int end) -> - sig - val insert_chain : Chain.t PqTree.t -> Chain.t PqTree.t option - end + sig + type elt = Chain.t + type pqtree = elt PqTree.t + + val q_node : pqtree DeQueue.t -> pqtree + + + type external_subtree = + | ConstantSubtree of int * pqtree + | IncreasingSubtree of int * pqtree DeQueue.t * int + + val bounds : external_subtree -> int * int + val d_min : external_subtree -> int + val d_max : external_subtree -> int + val tree_of_external_tree : external_subtree -> pqtree + val is_increasing_sequence : external_subtree DeQueue.t -> bool + val force_increasing_sequence : external_subtree DeQueue.t -> external_subtree DeQueue.t option + val expand_increasing_sequence : external_subtree DeQueue.t -> pqtree DeQueue.t + val sort_into_increasing_sequence : external_subtree DeQueue.t -> external_subtree list DeQueue.t + + type sorting_group = + | Group of int * pqtree list + | Single of external_subtree + + val group_d_min : sorting_group -> int + val group_d_max : sorting_group -> int + val sort_children_of_p_node : external_subtree DeQueue.t -> sorting_group DeQueue.t + + val is_increasing_group_sequence : sorting_group DeQueue.t -> bool + + + type centered_subtree = + | Balanced of int * pqtree + | Skew of int * pqtree DeQueue.t * int + + val tree_of_centered_tree : centered_subtree -> pqtree + val bounds_centered : centered_subtree -> int * int + val contract_centered : centered_subtree -> pqtree list + + type result = + | NotRepresentable + | CenteredSubtree of centered_subtree + | ExternalSubtree of external_subtree + + type classification = + | Unclassifiable + | Internal of external_subtree DeQueue.t * centered_subtree * external_subtree DeQueue.t + | External of external_subtree DeQueue.t + + val classify : result list -> classification + + + type queue = + { left_bound : int; + trees : pqtree DeQueue.t; + right_bound : int + } + + val init_queue : centered_subtree -> queue + val is_balanced : queue -> bool + val collapse : queue -> int * pqtree + val enqueue_right : sorting_group -> queue -> queue + val enqueue_left : sorting_group -> queue -> queue + val finalize : queue -> centered_subtree + val enqueue : sorting_group DeQueue.t -> queue -> result + + val build_p_internal : centered_subtree -> external_subtree DeQueue.t -> result + + val centered_subtree : int -> pqtree DeQueue.t -> int -> result -val refine_by_distances : 'elt -> ('elt -> int) -> 'elt PqTree.t -> 'elt PqTree.t option + val build_q_internal : external_subtree DeQueue.t -> centered_subtree -> external_subtree DeQueue.t -> result + val contract_group : sorting_group -> pqtree DeQueue.t + val build_p_external : external_subtree DeQueue.t -> result + val build_q_external : external_subtree DeQueue.t -> result + val dispatch : pqtree -> result list -> result + val children : pqtree -> pqtree list + val solve : pqtree -> result + val insert_chain : pqtree -> pqtree option + end +val refine_by_distances : 'elt -> ('elt -> int) -> 'elt PqTree.t -> 'elt PqTree.t option diff --git a/lib/pqtrees/pqTree.mli b/lib/pqtrees/pqTree.mli index 3fe47b2050e62caaec8e0360071e386a128a9d5c..875b7ed8c72b74d7f198b867616b90c7ac42e72e 100644 --- a/lib/pqtrees/pqTree.mli +++ b/lib/pqtrees/pqTree.mli @@ -165,7 +165,7 @@ end (** A functor to build a function to enumerate over PQ-trees. *) module MakeEnumerate : - functor (RND : FeatCore.RandomSig.S) -> EnumerateSig with type elt = int + functor (_ : FeatCore.RandomSig.S) -> EnumerateSig with type elt = int (** A pre-application of the [MakeEnumerate] functor, to enumerate of diff --git a/robinson.opam b/robinson.opam index a19265d7839c3987e2f085ab7ab71b3d5aef0bb6..cef5503597f781ec775e454fffd94185b0505b3c 100644 --- a/robinson.opam +++ b/robinson.opam @@ -11,7 +11,7 @@ doc: "https://url/to/documentation" bug-reports: "https://github.com/username/reponame/issues" depends: [ "ocaml" - "dune" {>= "3.0"} + "dune" {>= "3.7"} "fix" "feat" "RobinsonLib" diff --git a/test/propertytest/chainInsertion.ml b/test/propertytest/chainInsertion.ml new file mode 100644 index 0000000000000000000000000000000000000000..ea4dd55cfe8e3e08d812dde42d3e5e4e2fd74f06 --- /dev/null +++ b/test/propertytest/chainInsertion.ml @@ -0,0 +1,43 @@ +open PqTreeLib +open RobinsonTest +open IntPqTree +open DataStruct + +open QCheck2 + + +module IntSet = Set.Make(Int) + +let insert_interval interval pqtree = + let f i = if IntSet.mem i interval then 0 else 1 in + let s = IntSet.choose interval in + PqChainInsertion.refine_by_distances s f pqtree + + +let rec is_an_interval ints = function + | [] -> IntSet.cardinal ints = 0 + | (hd :: _) as permutation when IntSet.mem hd ints -> + let length = IntSet.cardinal ints in + (permutation |> MoreList.take length |> List.for_all (fun i -> IntSet.mem i ints)) + && (permutation |> MoreList.drop length |> List.for_all (fun i -> not (IntSet.mem i ints))) + | _ :: permutation -> is_an_interval ints permutation + + +let interval_insertion_does_not_fail (pqtree,interval) = + insert_interval (IntSet.of_list interval) pqtree + |> Option.is_some + + +let test_interval_insertion_does_not_fail = + Test.make + ~name:"Chain insertion generalizes interval insertion in PQ-tree" + ~print:Print.(pair to_string (list int)) + Gen.(int_range 1 100 >>= sized_pqtree_interval_gen) + interval_insertion_does_not_fail + + + +let tests = + [ + test_interval_insertion_does_not_fail + ] diff --git a/test/propertytest/main_prop_test.ml b/test/propertytest/main_prop_test.ml index c96b6938feebe3090db08bdd888b02016d373e98..99e03c758536c0d6c37e7494e853b4f8d1f583ca 100644 --- a/test/propertytest/main_prop_test.ml +++ b/test/propertytest/main_prop_test.ml @@ -3,7 +3,8 @@ let all_tests = [ Pqtree.tests; FunctionalBLtest.tests; ImperativeBLTest.tests; - Pivotpair.tests + Pivotpair.tests; + ChainInsertion.tests ] let%test _ = diff --git a/test/unit/chainInsertionTest.ml b/test/unit/chainInsertionTest.ml index 6bf88586e3f4a39a88f2b2ef30df2dd6647d2cb2..95fa15190f333a6bf71717d9627a0968f782b461 100644 --- a/test/unit/chainInsertionTest.ml +++ b/test/unit/chainInsertionTest.ml @@ -96,30 +96,63 @@ let%expect_test _ = let d3 = [|66;5;56;0;15;77;3;82;56;60|] let d4 = [|52;12;41;15;0;63;18;67;42;46|] -let d5 = [|12;74;22;77;63;0;80;7;23;18|] -let d6 = [|69;8;59;3;18;80;0;84;59;63|] -let d7 = [|16;78;27;82;67;7;84;0;27;23|] -let d8 = [|11;52;8;56;42;23;59;27;0;10|] -let d9 = [|9;57;5;60;46;18;63;23;10;0|] let%expect_test _ = refine_by_distances 3 (fun n -> d3.(n)) tree_2 |> output; [%expect{|Q[Leaf 6;Leaf 3;Leaf 1;Leaf 4;Leaf 8;Leaf 2;Leaf 9;Leaf 0;Leaf 5;Leaf 7]|}] let%expect_test _ = refine_by_distances 4 (fun n -> d4.(n)) tree_2 - |> output; [%expect{|Q[Leaf 6;Leaf 3;Leaf 1;Leaf 4;Leaf 8;Leaf 2;Leaf 9;Leaf 0;Leaf 5;Leaf 7]|}] + |> output; [%expect{|not an interval|}] + + + +let interval_distance elements i = + if List.mem i elements then 0 + else 1 + +let ptree1 = + P[Leaf 0;Leaf 1; + P[Leaf 2;Leaf 3;Leaf 4; + P[P[P[Leaf 5;Leaf 6];Leaf 7];Leaf 8;P[Leaf 9;Leaf 10];Leaf 11]; + P[Leaf 12;Leaf 13]];Leaf 14;Leaf 15;Leaf 16;Leaf 17; + P[P[Leaf 18;Leaf 19];Leaf 20;Leaf 21];Leaf 22 + ] + let%expect_test _ = - refine_by_distances 5 (fun n -> d5.(n)) tree_2 - |> output; [%expect{|Q[Leaf 6;Leaf 3;Leaf 1;Leaf 4;Leaf 8;Leaf 2;Leaf 9;Leaf 0;Leaf 5;Leaf 7]|}] + refine_by_distances 10 (interval_distance [10;12]) ptree1 + |> output; [%expect{| |}] + + +let ptree2 = + P[Leaf 2;Leaf 3;Leaf 4; + P[P[P[Leaf 5;Leaf 6];Leaf 7];Leaf 8;P[Leaf 9;Leaf 10];Leaf 11]; + P[Leaf 12;Leaf 13]] + let%expect_test _ = - refine_by_distances 6 (fun n -> d6.(n)) tree_2 - |> output; [%expect{|Q[Leaf 6;Leaf 3;Leaf 1;Leaf 4;Leaf 8;Leaf 2;Leaf 9;Leaf 0;Leaf 5;Leaf 7]|}] + refine_by_distances 10 (interval_distance [10;12]) ptree2 + |> output; [%expect{| |}] + + +let ptree3 = + P[Leaf 2; + P[Leaf 7;P[Leaf 9;Leaf 10]]; + P[Leaf 12;Leaf 13] + ] + let%expect_test _ = - refine_by_distances 7 (fun n -> d7.(n)) tree_2 - |> output; [%expect{|Q[Leaf 6;Leaf 3;Leaf 1;Leaf 4;Leaf 8;Leaf 2;Leaf 9;Leaf 0;Leaf 5;Leaf 7]|}] + refine_by_distances 10 (interval_distance [10;12]) ptree3 + |> output; [%expect{| |}] + +let ptree4 = + P[Leaf 7;P[Leaf 8; Leaf 9;Leaf 10];Leaf 11] + let%expect_test _ = - refine_by_distances 8 (fun n -> d8.(n)) tree_2 - |> output; [%expect{|Q[Leaf 6;Leaf 3;Leaf 1;Leaf 4;Leaf 8;Leaf 2;Leaf 9;Leaf 0;Leaf 5;Leaf 7]|}] + refine_by_distances 10 (interval_distance [10;12]) ptree4 + |> output; [%expect{| |}] + +let ptree5 = + P[Leaf 8; Leaf 9;Leaf 10] + let%expect_test _ = - refine_by_distances 9 (fun n -> d9.(n)) tree_2 - |> output; [%expect{|Q[Leaf 6;Leaf 3;Leaf 1;Leaf 4;Leaf 8;Leaf 2;Leaf 9;Leaf 0;Leaf 5;Leaf 7]|}] + refine_by_distances 10 (interval_distance [10;12]) ptree5 + |> output; [%expect{| |}] diff --git a/test/unit/dune b/test/unit/dune index 71b6de2f84fd39542a93958a3782dfece325bec8..ace45e2394cf230180429c86344318146084b418 100644 --- a/test/unit/dune +++ b/test/unit/dune @@ -1,6 +1,6 @@ (library (name RobinsonUnit) - (libraries RobinsonLib RobinsonTest) + (libraries RobinsonLib ChainLib RobinsonTest) (inline_tests) (preprocess (pps ppx_inline_test ppx_expect)) ) diff --git a/test/unit/robinsonByChainTest.ml b/test/unit/robinsonByChainTest.ml new file mode 100644 index 0000000000000000000000000000000000000000..a3ac4428b1fa5c3749d3c009ed916f6463709e35 --- /dev/null +++ b/test/unit/robinsonByChainTest.ml @@ -0,0 +1,39 @@ +open RobinsonTest.IntPqTree + +open ChainLib + + +let output result = + result + |> Option.map Canonical.canonical + |> Option.map to_string + |> Option.value ~default:"not an interval" + |> print_endline + + +let print_order order = + let open Format in + fprintf std_formatter + "%a\n" + (pp_print_list ~pp_sep:(fun fmt () -> pp_print_string fmt ", ") pp_print_int) + order + + +let diss1 = RandomDissimilarity.Toeplitz.toeplitz012 ~k:1 ~n:10 + +let%expect_test _ = + begin match RobinsonByChain.find_compatible_order diss1 with + | Some order -> print_order order + | None -> Format.(fprintf std_formatter "not Robinson") + end; + [%expect{| 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 |}] + + +let diss2 = RandomDissimilarity.Toeplitz.toeplitz012 ~k:3 ~n:20 + +let%expect_test _ = + begin match RobinsonByChain.find_compatible_order diss2 with + | Some order -> print_order order + | None -> Format.(fprintf std_formatter "not Robinson") + end; + [%expect{| 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 |}]