diff --git a/test/Syntax.jl b/test/Syntax.jl index b0b9c18a..6fe21406 100755 --- a/test/Syntax.jl +++ b/test/Syntax.jl @@ -341,209 +341,3 @@ end @test_throws Exception @eval @feet begin A => B; 1 => 2; end end -########################### - -@testset "infer_links works as expected" begin - # No prior mappings means no inferred mappings - @test (infer_links(StockAndFlowF(), StockAndFlowF(), Dict{Symbol, Vector{Int64}}(:S => [], :F => [], :SV => [], :P => [], :V => [])) - == Dict(:LS => [], :LSV => [], :LV => [], :I => [], :O => [], :LPV => [], :LVV => [])) - - # S: 1 -> 1 and SV: 1 -> 1 implies LS: 1 -> 1 - @test (infer_links( - (@stock_and_flow begin; :stocks; A; :sums; NA = [A]; end), - (@stock_and_flow begin; :stocks; B; :sums; NB = [B]; end), - Dict{Symbol, Vector{Int64}}(:S => [1], :F => [], :SV => [1], :P => [], :V => [])) - == Dict(:LS => [1], :LSV => [], :LV => [], :I => [], :O => [], :LPV => [], :LVV => [])) - - # annoying exanmple, required me to add code to disambiguate using position - # that is, vA = A + A, vA -> vB, A -> implies that the As in the vA definition map to the Bs in the vB definition - # But both As link to the same stock and dynamic variable so just looking at those isn't enough to figure out what it maps to. - # There will exist cases where it's impossible to tell - eg, when there exist multiple duplicate links, and some positions don't match up. - - # It does not currently look at the operator. You could therefore map vA = A + A -> vB = B * B - # I can see this being useful, actually, specifically when mapping between + and -, * and /, etc. Probably logs and powers too. - # Just need to be aware that it won't say it's invalid. - @test (infer_links( - (@stock_and_flow begin; :stocks; A; :dynamic_variables; vA = A + A; end), - (@stock_and_flow begin; :stocks; B; :dynamic_variables; vB = B + B; end), - Dict{Symbol, Vector{Int64}}(:S => [1], :F => [], :SV => [], :P => [], :V => [1])) - == Dict(:LS => [], :LSV => [], :LV => [2,2], :I => [], :O => [], :LPV => [], :LVV => [])) # If duplicate values, always map to end. - - @test (infer_links( - (@stock_and_flow begin; :stocks; A; :parameters; pA; :dynamic_variables; vA = A + pA; end), - (@stock_and_flow begin; :stocks; B; :parameters; pB; :dynamic_variables; vB = pB + B; end), - Dict{Symbol, Vector{Int64}}(:S => [1], :F => [], :SV => [], :P => [1], :V => [1])) - == Dict(:LS => [], :LSV => [], :LV => [1], :I => [], :O => [], :LPV => [1], :LVV => [])) - - @test (infer_links( - (@stock_and_flow begin - :stocks - S - I - R - - :parameters - p_inf - p_rec - - - :flows - S => f_StoI(p_inf * S) => I - I => f_ItoR(I * p_rec) => R - - :sums - N = [S,I,R] - NI = [I] - NS = [S,I,R] - end), - (@stock_and_flow begin - :stocks - pop - - :parameters - p_generic - - - :flows - pop => f_generic(p_generic * pop) => pop - - :sums - N = [pop] - NI = [pop] - NS = [pop] - end), - - Dict{Symbol, Vector{Int64}}(:S => [1,1,1], :F => [1,1], :SV => [1,2,3], :P => [1,1], :V => [1,1])) - == Dict(:LS => [1,3,1,2,3,1,3], :LSV => [], :LV => [1,1], :I => [1,1], :O => [1,1], :LPV => [1,1], :LVV => [])) - - -end - - -@testset "Applying flags can correctly find substring matches" begin - @test apply_flags(:f_, Set([:~]), Vector{Symbol}()) == [] - @test apply_flags(:f_, Set([:~]), [:f_death, :f_birth]) == [:f_death, :f_birth] - @test apply_flags(:NOMATCH, Set([:~]), [:f_death, :f_birth]) == [] - @test apply_flags(:f_birth, Set([:~]), [:f_death, :f_birth]) == [:f_birth] - @test apply_flags(:f_birth, Set{Symbol}(), [:f_death, :f_birth]) == [:f_birth] - - # Note, apply_flags is specifically meant to work on vectors without duplicates; the vector which is input are the keys of a dictionary. - # Regardless, the following will hold: - @test apply_flags(:f_birth, Set{Symbol}(), [:f_death, :f_birth, :f_birth, :f_birth]) == [:f_birth] - @test apply_flags(:f_birth, Set{Symbol}([:~]), [:f_death, :f_birth, :f_birth, :f_birth]) == [:f_birth, :f_birth, :f_birth] -end - - -@testset "substitute_symbols will correctly associate values of the two provided dictionaries based on user defined mappings" begin - # substitute_symbols(s::Dict{Symbol, Int}, t::Dict{Symbol, Int}, m::Vector{DSLArgument} ; use_flags::Bool=true)::Dict{Int, Int} - - - # Note, these dictionaries represent a vector where all the entries are unique, and the values are the original indices. - # So, both keys and values should be unique. - # For stratification, first dictionary is strata or aggregate, second is type, and the vector of DSLArgument are the user-defined maps. - # For homomorphism, first argument is src, second is dest, vector are user-defined maps. - @test substitute_symbols(Dict{Symbol, Int}(), Dict{Symbol, Int}(), Vector{DSLArgument}()) == Dict{Int, Int}() - @test substitute_symbols(Dict{Symbol, Int}(), Dict(:B => 2), Vector{DSLArgument}()) == Dict{Int, Int}() - - @test substitute_symbols(Dict(:A => 1), Dict(:B => 1), [DSLArgument(:A, :B, Set{Symbol}())]) == Dict(1 => 1) - @test substitute_symbols(Dict(:A1 => 1, :A2 => 2), Dict(:B => 1), [DSLArgument(:A1, :B, Set{Symbol}()), DSLArgument(:A2, :B, Set{Symbol}())]) == Dict(1 => 1, 2 => 1) - @test substitute_symbols(Dict(:A1 => 1), Dict(:B1 => 1, :B2 => 2), [DSLArgument(:A1, :B2, Set{Symbol}())]) == Dict(1 => 2) - - - @test substitute_symbols(Dict(:A1 => 1, :A2 => 2), Dict(:B1 => 1, :B2 => 2), [DSLArgument(:A, :B2, Set{Symbol}([:~]))]) == Dict(1 => 2, 2 => 2) - - # 1:100 - # 1:50 - # All multiples x of 14 below 100 go to x % 10 + 1 - @test (substitute_symbols(Dict(Symbol(i) => i for i ∈ 1:100), Dict(Symbol(-i) => i for i ∈ 1:50), [DSLArgument(Symbol(i), Symbol(-((i%10) + 1)), Set{Symbol}()) for i ∈ 1:100 if i % 14 == 0]) - == Dict(14 => 5, 28 => 9, 42 => 3, 56 => 7, 70 => 1, 84 => 5, 98 => 9)) - - # Captures everything with a 7 as a digit - @test (substitute_symbols(Dict(Symbol(i) => i for i ∈ 1:100), Dict(Symbol(-i) => i for i ∈ 1:50), [DSLArgument(Symbol(7), Symbol(-1), Set{Symbol}([:~]))]) - == Dict(7 => 1, 17 => 1, 27 => 1, 37 => 1, 47 => 1, 57 => 1, 67 => 1, 70 => 1, 71 => 1, 72 => 1, 73 => 1, 74 => 1, 75 => 1, 76 => 1, 77 => 1, 78 => 1, 79 => 1, 87 => 1, 97 => 1)) - - @test substitute_symbols(Dict(Symbol("~") => 1), Dict(:R => 1), [DSLArgument(Symbol("~"), :R, Set([:~]))], ; use_flags = false) == Dict(1 => 1) # Note, the Set([:~]) is ignored because use_flags is false - -end - - -@testset "non-natural transformations fail infer_links" begin - - # Map both dynamic variables to the same - # Obviously, this will fail, as the new dynamic variable needs a LVV and one LV, but instead has two LV - @test_throws KeyError (infer_links( - (@stock_and_flow begin - :stocks - A - - :dynamic_variables - v1 = A + A - v2 = v1 + A - end), - (@stock_and_flow begin - :stocks - A - - :dynamic_variables - v1 = A + A - end), - Dict{Symbol, Vector{Int64}}(:S => [1], :V => [1,1]))) - - - - # Mapping it all to I - - # This one fails when trying to figure out the inflow. Stock maps to 2, and flow maps to 2, - # But inflows on the target have (1,2) and (2,3) - - # This also wouldn't work if we tried mapping flow to 1 instead. Outflows expect 1,1 or 2,2, - # so it fails on (2,1). - @test_throws KeyError (infer_links( - (@stock_and_flow begin - :stocks - pop - - :parameters - p_generic - - - :flows - pop => f_generic(p_generic * pop) => pop - - :sums - N = [pop] - NI = [pop] - NS = [pop] - end), - (@stock_and_flow begin - :stocks - S - I - R - - :parameters - p_inf - p_rec - - - :flows - S => f_StoI(p_inf * S) => I - I => f_ItoR(I * p_rec) => R - - :sums - N = [S,I,R] - NI = [I] - NS = [S,I,R] - end), - Dict{Symbol, Vector{Int64}}(:S => [2], :F => [2], :SV => [1,2,3], :P => [2], :V => [2]))) - -end - -@testset "Applying flags throws on invalid inputs" begin - @test_throws ErrorException apply_flags(:f_, Set([:+]), [:f_death, :f_birth]) # fails because :+ is not a defined operation - @test_throws ErrorException apply_flags(:f_birth, Set([:~, :+]), [:f_death, :f_birth]) # also fails for same reason - - @test_throws AssertionError apply_flags(:NOMATCH, Set{Symbol}(), Vector{Symbol}()) # fails because it's not looking for substrings, and :NOMATCH isn't in the list of options. - @test_throws AssertionError apply_flags(:NOMATCH, Set{Symbol}(), [:nomatch]) # same reason - -end