|
| 1 | +# Tests for carpanzano_tearing.jl - determinism and Heuristic 2 correctness |
| 2 | + |
| 3 | +using BipartiteGraphs |
| 4 | +import Graphs: add_edge! |
| 5 | + |
| 6 | +struct TestSystemStructure <: StateSelection.SystemStructure |
| 7 | + graph::BipartiteGraph{Int,Nothing} |
| 8 | + solvable_graph::BipartiteGraph{Int,Nothing} |
| 9 | + var_to_diff::DiffGraph |
| 10 | + eq_to_diff::DiffGraph |
| 11 | +end |
| 12 | + |
| 13 | +@testset "carpanzano_tearing" begin |
| 14 | + @testset "Heuristic 2 picks variable with maximum incidence" begin |
| 15 | + # Graph: 3 equations (source vertices), 3 variables (destination vertices). |
| 16 | + # Every edge is also present in the solvable_graph (all variables solvable in |
| 17 | + # all equations they appear in), so Heuristic 1 never finds a non-solvable |
| 18 | + # variable and falls through to Heuristic 2. |
| 19 | + # |
| 20 | + # Incidence of each variable (number of equations it appears in): |
| 21 | + # v1 (idx 1): eq1, eq2 => 2 |
| 22 | + # v2 (idx 2): eq1, eq2, eq3 => 3 # maximum -> must be torn (algebraic) |
| 23 | + # v3 (idx 3): eq1, eq3 => 2 |
| 24 | + # |
| 25 | + # Before the fix, max_incidence_cnt was never updated inside the Heuristic 2 |
| 26 | + # loop, so every variable satisfied cnt > typemin(Int) and the last variable |
| 27 | + # in hash-iteration order was chosen -- non-deterministic and wrong. |
| 28 | + graph = BipartiteGraph(3, 3) |
| 29 | + for (eq, var) in [(1,1),(1,2),(1,3),(2,1),(2,2),(3,2),(3,3)] |
| 30 | + add_edge!(graph, eq, var) |
| 31 | + end |
| 32 | + solvable_graph = BipartiteGraph(3, 3) |
| 33 | + for (eq, var) in [(1,1),(1,2),(1,3),(2,1),(2,2),(3,2),(3,3)] |
| 34 | + add_edge!(solvable_graph, eq, var) |
| 35 | + end |
| 36 | + |
| 37 | + structure = TestSystemStructure( |
| 38 | + graph, solvable_graph, |
| 39 | + DiffGraph(3), DiffGraph(3) |
| 40 | + ) |
| 41 | + alg = StateSelection.CarpanzanoTearing() |
| 42 | + # complete() makes invview(var_eq_matching) available, which the algorithm uses |
| 43 | + # internally to find the variable matched to a solved equation. |
| 44 | + var_eq_matching = complete( |
| 45 | + Matching{Union{Unassigned, SelectedState}}(3), 3 |
| 46 | + ) |
| 47 | + active_vars = Set{Int}([1, 2, 3]) |
| 48 | + active_eqs = Set{Int}([1, 2, 3]) |
| 49 | + |
| 50 | + StateSelection.carpanzano_tear_scc!( |
| 51 | + alg, structure, var_eq_matching, active_vars, active_eqs |
| 52 | + ) |
| 53 | + |
| 54 | + # v2 has the highest incidence (3 equations) -- Heuristic 2 must choose it as |
| 55 | + # the algebraic (torn) variable, leaving it unmatched. |
| 56 | + @test var_eq_matching[2] === unassigned |
| 57 | + # v1 and v3 must each be matched to some equation. |
| 58 | + @test var_eq_matching[1] isa Int |
| 59 | + @test var_eq_matching[3] isa Int |
| 60 | + end |
| 61 | +end |
0 commit comments