Skip to content

Commit

Permalink
Merge branch 'master' into 224-gaussian-mixture-relax-constraints-all…
Browse files Browse the repository at this point in the history
…-around
  • Loading branch information
bvdmitri committed Nov 4, 2022
2 parents ef9ec75 + ae952de commit e200708
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 5 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "ReactiveMP"
uuid = "a194aa59-28ba-4574-a09c-4a745416d6e3"
authors = ["Dmitry Bagaev <[email protected]>", "Albert Podusenko <[email protected]>", "Bart van Erp <[email protected]>", "Ismail Senoz <[email protected]>"]
version = "3.0.1"
version = "3.0.2"

[deps]
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Expand Down
21 changes: 17 additions & 4 deletions src/constraints/specifications/meta.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,31 @@ See also: [`ConstraintsSpecification`](@ref)
function resolve_meta(metaspec, fform, variables)
symfform = as_node_symbol(fform)

var_names = map(name, variables)
var_refs = map(resolve_variable_proxy, variables)
var_names = map(name, TupleTools.flatten(variables))
var_refs = map(resolve_variable_proxy, TupleTools.flatten(variables))
var_refs_names = map(r -> r[1], var_refs)

found = nothing

unrolled_foreach(getentries(metaspec)) do fentry
# We iterate over all entries in the meta specification
if functionalform(fentry) === symfform && (all(s -> s var_names, getnames(fentry)) || all(s -> s var_refs_names, getnames(fentry)))
if found !== nothing
if isnothing(found)
# if we find an appropriate meta spec we simply set it
found = fentry
elseif !isnothing(found) && issubset(getnames(fentry), getnames(found)) && issubset(getnames(found), getnames(fentry))
# The error case is the meta specification collision, two sets of names are exactly the same
error("Ambigous meta object resolution for the node $(fform). Check $(found) and $(fentry).")
elseif !isnothing(found) && issubset(getnames(fentry), getnames(found))
# If we find another matching meta spec, but it has fewer names in it we simply keep the previous one
nothing
elseif !isnothing(found) && issubset(getnames(found), getnames(fentry))
# If we find another matching meta spec, and it has more names we override the previous one
found = fentry
elseif !isnothing(found) && !issubset(getnames(fentry), getnames(found)) && !issubset(getnames(found), getnames(fentry))
# The error case is the meta specification collision, two sets of names are different and do not include each other
error("Ambigous meta object resolution for the node $(fform). Check $(found) and $(fentry).")
end
found = fentry
end
end

Expand Down
85 changes: 85 additions & 0 deletions test/constraints/test_meta.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
module ReactiveMPFactorisationSpecTest

using Test
using ReactiveMP

import ReactiveMP: MetaSpecification, MetaSpecificationOptions, MetaSpecificationEntry
import ReactiveMP: resolve_meta

@testset "Meta specification" begin
@testset "resolve_meta #1" begin
spec = MetaSpecification(
(
MetaSpecificationEntry(:NormalMeanPrecision, (:x, :z), 1),
MetaSpecificationEntry(:NormalMeanPrecision, (:y, :z), 2),
MetaSpecificationEntry(:NormalMeanVariance, (), 3)
),
MetaSpecificationOptions(false)
)

@test resolve_meta(spec, NormalMeanPrecision, (randomvar(:a), randomvar(:b))) === nothing
@test resolve_meta(spec, NormalMeanPrecision, (randomvar(:b), randomvar(:x))) === nothing
@test resolve_meta(spec, NormalMeanPrecision, (randomvar(:b), randomvar(:z))) === nothing

@test resolve_meta(spec, NormalMeanPrecision, (randomvar(:x), randomvar(:z))) === 1
@test resolve_meta(spec, NormalMeanPrecision, (randomvar(:y), randomvar(:z))) === 2

@test resolve_meta(spec, NormalMeanVariance, (randomvar(:x), randomvar(:z))) === 3
@test resolve_meta(spec, NormalMeanVariance, (randomvar(:y), randomvar(:z))) === 3
end

@testset "resolve_meta #2" begin
spec = MetaSpecification((MetaSpecificationEntry(:NormalMeanPrecision, (:x, :z), 1), MetaSpecificationEntry(:NormalMeanPrecision, (), 2)), MetaSpecificationOptions(false))

@test resolve_meta(spec, NormalMeanPrecision, (randomvar(:x), randomvar(:z))) === 1
@test resolve_meta(spec, NormalMeanPrecision, (randomvar(:y), randomvar(:z))) === 2

@test resolve_meta(spec, NormalMeanPrecision, (randomvar(:x),)) === 2
@test resolve_meta(spec, NormalMeanPrecision, (randomvar(:z),)) === 2
end

@testset "resolve_meta #3" begin
spec = MetaSpecification(
(MetaSpecificationEntry(:NormalMeanPrecision, (:x,), 1), MetaSpecificationEntry(:NormalMeanPrecision, (:x, :z), 2)), MetaSpecificationOptions(false)
)

@test resolve_meta(spec, NormalMeanPrecision, (randomvar(:z),)) === nothing
@test resolve_meta(spec, NormalMeanPrecision, (randomvar(:x),)) === 1
@test resolve_meta(spec, NormalMeanPrecision, (randomvar(:x), randomvar(:z))) === 2
@test resolve_meta(spec, NormalMeanPrecision, (randomvar(:x), randomvar(:y), randomvar(:z))) === 2
end

@testset "resolve_meta #4" begin
spec = MetaSpecification((MetaSpecificationEntry(:NormalMeanPrecision, (:x, :z), 1), MetaSpecificationEntry(:NormalMeanPrecision, (), 2)), MetaSpecificationOptions(false))

@test resolve_meta(spec, NormalMeanPrecision, ((randomvar(:x), randomvar(:x)), randomvar(:z))) === 1
@test resolve_meta(spec, NormalMeanPrecision, (randomvar(:x), (randomvar(:z), randomvar(:z)))) === 1
@test resolve_meta(spec, NormalMeanPrecision, (randomvar(:y), randomvar(:z))) === 2
@test resolve_meta(spec, NormalMeanPrecision, ((randomvar(:y), randomvar(:y)), randomvar(:z))) === 2
@test resolve_meta(spec, NormalMeanPrecision, (randomvar(:y), (randomvar(:z), randomvar(:z)))) === 2

@test resolve_meta(spec, NormalMeanPrecision, ((randomvar(:x), randomvar(:x)),)) === 2
@test resolve_meta(spec, NormalMeanPrecision, ((randomvar(:z), randomvar(:z)),)) === 2
end

@testset "resolve_meta ambiguity error #1" begin
spec = MetaSpecification(
(MetaSpecificationEntry(:NormalMeanPrecision, (:x, :z), 1), MetaSpecificationEntry(:NormalMeanPrecision, (:x, :y), 2)), MetaSpecificationOptions(false)
)

@test resolve_meta(spec, NormalMeanPrecision, (randomvar(:x), randomvar(:z))) === 1
@test resolve_meta(spec, NormalMeanPrecision, (randomvar(:x), randomvar(:y))) === 2
@test_throws ErrorException resolve_meta(spec, NormalMeanPrecision, (randomvar(:x), randomvar(:y), randomvar(:z)))
end

@testset "resolve_meta ambiguity error #2" begin
spec = MetaSpecification(
(MetaSpecificationEntry(:NormalMeanPrecision, (:x, :z), 1), MetaSpecificationEntry(:NormalMeanPrecision, (:z, :x), 2)), MetaSpecificationOptions(false)
)

@test_throws ErrorException resolve_meta(spec, NormalMeanPrecision, (randomvar(:x), randomvar(:z)))
@test_throws ErrorException resolve_meta(spec, NormalMeanPrecision, (randomvar(:z), randomvar(:x)))
end
end

end

0 comments on commit e200708

Please sign in to comment.