Skip to content

Commit 3c48c33

Browse files
authored
Bench updates (#36)
* Save for benchs * Tests for circuit count cumulative element extension instantiation * Tests for intention maximum mdd minimum * Tests for nvalues nooverlap ordered regular sum * Update no_overlap to match pairvars parameter generation * Fixes channel and element signatures * Versions bump in toml and ci * Versions bump in ci * Remove push activation for CI
1 parent 5369229 commit 3c48c33

23 files changed

+509
-75
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
name: CI
22
on:
3-
- push
43
- pull_request
54
jobs:
65
test:
@@ -10,7 +9,7 @@ jobs:
109
fail-fast: false
1110
matrix:
1211
version:
13-
- "1.8"
12+
- "1.9"
1413
- 'nightly'
1514
os:
1615
- ubuntu-latest

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "Constraints"
22
uuid = "30f324ab-b02d-43f0-b619-e131c61659f7"
33
authors = ["Jean-François Baffier"]
4-
version = "0.5.2"
4+
version = "0.5.3"
55

66
[deps]
77
CompositionalNetworks = "4b67e4b5-442d-4ef5-b760-3f5df3a57537"

src/constraint.jl

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,16 @@ mutable struct Constraint{FConcept<:Function,FError<:Function}
1515
concept::FConcept
1616
description::String
1717
error::FError
18-
params::Vector{Dict{Symbol, Bool}}
18+
params::Vector{Dict{Symbol,Bool}}
1919
symmetries::Set{Symbol}
2020

2121
function Constraint(;
2222
args=0,
2323
concept=x -> true,
2424
description="No given description!",
2525
error=(x; param=0, dom_size=0) -> Float64(!concept(x)),
26-
params=Vector{Dict{Symbol, Bool}}(),
27-
syms=Set{Symbol}(),
26+
params=Vector{Dict{Symbol,Bool}}(),
27+
syms=Set{Symbol}()
2828
)
2929
return new{typeof(concept),typeof(error)}(
3030
args, concept, description, error, params, syms
@@ -85,7 +85,9 @@ Simply delete the `concept_` part of symbol or string starting with it. TODO: ad
8585
"""
8686
shrink_concept(s) = Symbol(string(s)[9:end])
8787

88-
## SECTION - Test Items
88+
function concept_vs_error(c, e, args...; kargs...)
89+
return c(args...; kargs...) (e(args...; kargs...) > 0.0)
90+
end
8991
@testitem "Empty constraint" tags = [:constraint, :empty] begin
9092
c = Constraint()
9193
@test concept(c, []) == true

src/constraints/all_different.jl

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,28 @@
33
xcsp_all_different(list, ::Nothing) = allunique(list)
44

55
function xcsp_all_different(list, except)
6-
return xcsp_all_different(list=Iterators.filter(x -> x except, list))
6+
return xcsp_all_different(list=Iterators.filter(x -> x except[:, 1], list))
77
end
88

99
xcsp_all_different(; list, except=nothing) = xcsp_all_different(list, except)
1010

1111
const description_all_different = """Global constraint ensuring that all the values of a given configuration are unique"""
1212

1313
@usual concept_all_different(x; vals=nothing) = xcsp_all_different(list=x, except=vals)
14+
15+
## SECTION - Test Items
16+
@testitem "All Different" tags = [:usual, :constraints, :all_different] begin
17+
c = USUAL_CONSTRAINTS[:all_different] |> concept
18+
e = USUAL_CONSTRAINTS[:all_different] |> error_f
19+
vs = Constraints.concept_vs_error
20+
21+
@test c([1, 2, 3, 4])
22+
@test !c([1, 2, 3, 1])
23+
@test c([1, 0, 0, 4]; vals=[0])
24+
@test !c([1, 0, 0, 1]; vals=[0])
25+
26+
@test vs(c, e, [1, 2, 3, 4])
27+
@test vs(c, e, [1, 2, 3, 1])
28+
@test vs(c, e, [1, 0, 0, 4]; vals=[0])
29+
@test vs(c, e, [1, 0, 0, 1]; vals=[0])
30+
end

src/constraints/all_equal.jl

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,33 @@ concept_all_equal(x, val) = all(y -> y == val, x)
66

77
xcsp_all_equal(; list) = concept_all_equal(list; val=first(list))
88

9-
@usual function concept_all_equal(x; val=nothing, pair_vars=zero(x))
10-
return concept_all_equal(x+pair_vars, val)
9+
@usual function concept_all_equal(x; val=nothing, pair_vars=zero(x), op=+)
10+
if iszero(pair_vars)
11+
return concept_all_equal(x, val)
12+
else
13+
aux = map(t -> op(t...), Iterators.zip(x, pair_vars))
14+
return concept_all_equal(aux, val)
15+
end
1116
end
1217
concept_all_equal(x, ::Nothing) = xcsp_all_equal(list=x)
18+
19+
## SECTION - Test Items
20+
@testitem "All Equal" tags = [:usual, :constraints, :all_equal] begin
21+
c = USUAL_CONSTRAINTS[:all_equal] |> concept
22+
e = USUAL_CONSTRAINTS[:all_equal] |> error_f
23+
vs = Constraints.concept_vs_error
24+
25+
@test c([0, 0, 0, 0])
26+
@test !c([1, 2, 3, 4])
27+
@test c([3, 2, 1, 0]; pair_vars=[0, 1, 2, 3])
28+
@test !c([0, 1, 2, 3]; pair_vars=[0, 1, 2, 3])
29+
@test c([1, 2, 3, 4]; op=/, val=1, pair_vars=[1, 2, 3, 4])
30+
@test !c([1, 2, 3, 4]; op=*, val=1, pair_vars=[1, 2, 3, 4])
31+
32+
@test vs(c, e, [0, 0, 0, 0])
33+
@test vs(c, e, [1, 2, 3, 4])
34+
@test vs(c, e, [3, 2, 1, 0]; pair_vars=[0, 1, 2, 3])
35+
@test vs(c, e, [0, 1, 2, 3]; pair_vars=[0, 1, 2, 3])
36+
@test vs(c, e, [1, 2, 3, 4]; op=/, val=1, pair_vars=[1, 2, 3, 4])
37+
@test vs(c, e, [1, 2, 3, 4]; op=*, val=1, pair_vars=[1, 2, 3, 4])
38+
end

src/constraints/cardinality.jl

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,53 @@ function xcsp_cardinality(; list, values, occurs, closed=false)
2121
end
2222

2323
@usual function concept_cardinality(x; bool=false, vals)
24-
values = vals[1]
25-
occurs = if length(vals) 3
26-
map(i -> vals[2][i]:(vals[2][i] vals[3][i] ? 1 : -1):(vals[3][i]), 1:length(vals[1]))
24+
values = vals[:, 1]
25+
occurs = if size(vals, 2) == 1
26+
ones(Int, size(vals, 1))
27+
elseif size(vals, 2) 3
28+
map(i -> vals[i, 2]:(vals[i, 2] vals[i, 3] ? 1 : -1):(vals[i, 3]), 1:size(vals, 1))
2729
else
28-
vals[2]
30+
vals[:, 2]
2931
end
3032
return xcsp_cardinality(; list=x, values, occurs, closed=bool)
3133
end
3234

3335
@usual concept_cardinality_closed(x; vals) = concept_cardinality(x; bool=true, vals)
3436
@usual concept_cardinality_open(x; vals) = concept_cardinality(x; bool=false, vals)
37+
38+
## SECTION - Test Items
39+
@testitem "Cardinality" tags = [:usual, :constraints, :cardinality] begin
40+
c = USUAL_CONSTRAINTS[:cardinality] |> concept
41+
e = USUAL_CONSTRAINTS[:cardinality] |> error_f
42+
vs = Constraints.concept_vs_error
43+
44+
@test c([2, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3])
45+
@test c([8, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3], bool=false)
46+
@test !c([8, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3], bool=true)
47+
@test c([2, 5, 10, 10]; vals=[2 1; 5 1; 10 2])
48+
@test c([2, 5, 10, 10]; vals=[2 0 1 42; 5 1 3 7; 10 2 3 -4])
49+
@test !c([2, 5, 5, 10]; vals=[2 0 1; 5 1 3; 10 2 3])
50+
@test !c([2, 5, 10, 8]; vals=[2 1; 5 1; 10 2])
51+
@test !c([5, 5, 5, 10]; vals=[2 0 1 42; 5 1 3 7; 10 2 3 -4])
52+
53+
54+
@test vs(c, e, [2, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3])
55+
@test vs(c, e, [8, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3], bool=false)
56+
@test vs(c, e, [8, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3], bool=true)
57+
@test vs(c, e, [2, 5, 10, 10]; vals=[2 1; 5 1; 10 2])
58+
@test vs(c, e, [2, 5, 10, 10]; vals=[2 0 1 42; 5 1 3 7; 10 2 3 -4])
59+
@test vs(c, e, [2, 5, 5, 10]; vals=[2 0 1; 5 1 3; 10 2 3])
60+
@test vs(c, e, [2, 5, 10, 8]; vals=[2 1; 5 1; 10 2])
61+
@test vs(c, e, [5, 5, 5, 10]; vals=[2 0 1 42; 5 1 3 7; 10 2 3 -4])
62+
63+
cc = USUAL_CONSTRAINTS[:cardinality_closed] |> concept
64+
ec = USUAL_CONSTRAINTS[:cardinality_closed] |> error_f
65+
@test cc([8, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3]) == c([8, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3], bool=true)
66+
@test vs(cc, ec, [8, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3])
67+
68+
co = USUAL_CONSTRAINTS[:cardinality_open] |> concept
69+
eo = USUAL_CONSTRAINTS[:cardinality_open] |> error_f
70+
@test co([8, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3]) == c([8, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3], bool=false)
71+
@test vs(co, eo, [8, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3])
72+
73+
end

src/constraints/channel.jl

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function xcsp_channel(list)
1+
function xcsp_channel(list::AbstractVector)
22
for (i, j) in enumerate(list)
33
if i j
44
list[j] == i || return false
@@ -7,17 +7,24 @@ function xcsp_channel(list)
77
return true
88
end
99

10-
function xcsp_channel(l1, l2)
11-
for (i, j) in enumerate(l2)
10+
function xcsp_channel(list::Tuple)
11+
l1, l2 = list
12+
l = length(l1)
13+
for j in l2
14+
# @info "debug in" l1 l2 k j list
15+
0 < j l || (return false)
16+
i = l2[j]
17+
0 < i l || (return false)
1218
if l1[i] j || l2[j] i
1319
return false
1420
end
1521
end
1622
return true
1723
end
1824

19-
xcsp_channel(; list...) = xcsp_channel(values(list)...)
20-
25+
function xcsp_channel(; list)
26+
xcsp_channel(values(list))
27+
end
2128
function concept_channel(x, ::Val{2})
2229
mid = length(x) ÷ 2
2330
return xcsp_channel(list=(@view(x[1:mid]), @view(x[mid+1:end])))
@@ -27,6 +34,29 @@ concept_channel(x, ::Val) = xcsp_channel(list=x)
2734

2835
const description_channel = """Global constraint ensuring that all ...`"""
2936

30-
@usual concept_channel(x; dim=1) = concept_channel(x, Val(dim))
37+
concept_channel(x, id) = count(!iszero, x) == 1 == x[id]
38+
39+
@usual function concept_channel(x; dim=1, id = nothing)
40+
return isnothing(id) ? concept_channel(x, Val(dim)) : concept_channel(x, id)
41+
end
42+
@testitem "Channel" tags = [:usual, :constraints, :channel] begin
43+
c = USUAL_CONSTRAINTS[:channel] |> concept
44+
e = USUAL_CONSTRAINTS[:channel] |> error_f
45+
vs = Constraints.concept_vs_error
46+
47+
@test c([2, 1, 4, 3])
48+
@test c([1, 2, 3, 4])
49+
@test !c([2, 3, 1, 4])
50+
@test c([2, 1, 5, 3, 4, 2, 1, 4, 5, 3]; dim=2)
51+
@test !c([2, 1, 4, 3, 5, 2, 1, 4, 5, 3]; dim=2)
52+
@test c([false, false, true, false]; id=3)
53+
@test !c([false, false, true, false]; id=1)
3154

32-
@usual concept_channel(x::AbstractVector{Bool}; id) = count(x) == 1 == x[id]
55+
@test vs(c, e, [2, 1, 4, 3])
56+
@test vs(c, e, [1, 2, 3, 4])
57+
@test vs(c, e, [2, 3, 1, 4])
58+
@test vs(c, e, [2, 1, 5, 3, 4, 2, 1, 4, 5, 3]; dim=2)
59+
@test vs(c, e, [2, 1, 4, 3, 5, 2, 1, 4, 5, 3]; dim=2)
60+
@test vs(c, e, [false, false, true, false]; id=3)
61+
@test vs(c, e, [false, false, true, false]; id=1)
62+
end

src/constraints/circuit.jl

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,41 @@ end
99
const description_circuit = "Global constraint ensuring that the values of `x` form a circuit. If the indices of the variables are not `1:length(x)`, the indices can be indicated as the `param` collection"
1010

1111
# circuit (full circuit)
12-
@usual function concept_circuit(x; op = , val = 1)
13-
s = Set(1:length(x))
14-
d = Dict{Int, Int}()
15-
while !isempty(s)
16-
u = pop!(s)
17-
push!(d, u => 0)
18-
l = 0
19-
while !isempty(s)
20-
v = pop!(s, x[u], 0)
21-
if iszero(v)
22-
break
23-
end
24-
l += 1
25-
δ = get!(d, v, l) - l
26-
!iszero(δ) && op(δ, val) && (return true)
27-
u = v
12+
@usual function concept_circuit(x; op = , val = length(x))
13+
V = Set(1:length(x))
14+
S = Vector{eltype(x)}()
15+
D = Set{Int}()
16+
17+
while !isempty(V)
18+
v = isempty(S) ? pop!(V) : pop!(V, x[last(S)])
19+
push!(S, v)
20+
notvalid = false
21+
(cycle = x[v] S) || (notvalid = (v == x[v] || x[v] V || x[v] D))
22+
if cycle
23+
λ = length(S) - findfirst(u -> u == x[v], S) + 1
24+
op(λ, val) && return true
25+
end
26+
if cycle || notvalid
27+
union!(D, S)
28+
empty!(S)
2829
end
29-
setdiff!(s, keys(d))
3030
end
3131
return false
3232
end
33+
34+
## SECTION - Test Items
35+
@testitem "Circuit" tags = [:usual, :constraints, :circuit] begin
36+
c = USUAL_CONSTRAINTS[:circuit] |> concept
37+
e = USUAL_CONSTRAINTS[:circuit] |> error_f
38+
vs = Constraints.concept_vs_error
39+
40+
@test !c([1, 2, 3, 4])
41+
@test c([2, 3, 4, 1])
42+
@test c([2, 3, 1, 4]; op = ==, val = 3)
43+
@test c([4, 3, 1, 3]; op = >, val = 0)
44+
45+
@test vs(c, e, [1, 2, 3, 4])
46+
@test vs(c, e, [2, 3, 4, 1])
47+
@test vs(c, e, [2, 3, 1, 4]; op = ==, val = 3)
48+
@test vs(c, e, [4, 3, 1, 3]; op = >, val = 0)
49+
end

src/constraints/count.jl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,30 @@ const description_at_most = """Constraint ensuring that ...`"""
1717
const description_exactly = """Constraint ensuring that ...`"""
1818

1919
@usual concept_exactly(x; vals, val) = concept_count(x; vals, op = ==, val)
20+
21+
## SECTION - Test Items
22+
@testitem "Count" tags = [:usual, :constraints, :count] begin
23+
c = USUAL_CONSTRAINTS[:count] |> concept
24+
e = USUAL_CONSTRAINTS[:count] |> error_f
25+
vs = Constraints.concept_vs_error
26+
27+
c_at_least = USUAL_CONSTRAINTS[:at_least] |> concept
28+
e_at_least = USUAL_CONSTRAINTS[:at_least] |> error_f
29+
30+
c_at_most = USUAL_CONSTRAINTS[:at_most] |> concept
31+
e_at_most = USUAL_CONSTRAINTS[:at_most] |> error_f
32+
33+
c_exactly = USUAL_CONSTRAINTS[:exactly] |> concept
34+
e_exactly = USUAL_CONSTRAINTS[:exactly] |> error_f
35+
36+
@test c([2, 1, 4, 3]; vals = [1, 2, 3, 4], op = , val = 2) && c_at_least([2, 1, 4, 3]; vals = [1, 2, 3, 4], val = 2)
37+
@test c([1, 2, 3, 4]; vals = [1, 2], op = ==, val = 2) && c_exactly([1, 2, 3, 4]; vals = [1, 2], val = 2)
38+
@test !c([2, 1, 4, 3]; vals = [1, 2], op = , val = 1) && !c_at_most([2, 1, 4, 3]; vals = [1, 2], val = 1)
39+
40+
@test vs(c, e, [2, 1, 4, 3]; vals = [1, 2, 3, 4], op = , val = 2)
41+
@test vs(c_at_least, e_at_least, [2, 1, 4, 3]; vals = [1, 2, 3, 4], val = 2)
42+
@test vs(c, e, [1, 2, 3, 4]; vals = [1, 2], op = ==, val = 2)
43+
@test vs(c_exactly, e_exactly, [1, 2, 3, 4]; vals = [1, 2], val = 2)
44+
@test vs(c, e, [2, 1, 4, 3]; vals = [1, 2], op = , val = 2)
45+
@test vs(c_at_most, e_at_most, [2, 1, 4, 3]; vals = [1, 2], val = 1)
46+
end

src/constraints/cumulative.jl

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
function xcsp_cumulative(; origins, lengths, heights, condition)
2-
acc = Dict{eltype(origins),Int}()
3-
for t in sort(collect(zip(origins, lengths, heights)))
4-
foreach(t -> t t[1] && delete!(acc, t), keys(acc))
5-
incsert!(acc, t[1] + t[2], t[3])
6-
condition[1](sum(values(acc)), condition[2]) || return false
2+
tasks = Vector{Tuple{eltype(origins),eltype(origins)}}()
3+
for t in Iterators.zip(origins, lengths, heights)
4+
push!(tasks, (t[1], t[3]))
5+
push!(tasks,(t[1]+t[2], -t[3]))
6+
end
7+
η = zero(eltype(origins))
8+
for t in sort!(tasks)
9+
η += t[2]
10+
condition[1](η, condition[2]) || return false
711
end
812
return true
913
end
1014

1115
function concept_cumulative(x, pair_vars, op, val)
1216
return xcsp_cumulative(
13-
origins=x, lengths=pair_vars[1], heights=pair_vars[2], condition=(op, val)
17+
origins=x, lengths=pair_vars[1,:], heights=pair_vars[2, :], condition=(op, val)
1418
)
1519
end
1620

@@ -20,6 +24,22 @@ end
2024

2125
const description_cumulative = """Global constraint ensuring that all ...`"""
2226

23-
@usual function concept_cumulative(x; pair_vars=ones(eltype(x), length(x)), op=, val)
27+
@usual function concept_cumulative(x; pair_vars=ones(eltype(x), (2, length(x))), op=, val)
2428
return concept_cumulative(x, pair_vars, op, val)
2529
end
30+
31+
@testitem "Cumulative" tags = [:usual, :constraints, :cumulative] begin
32+
c = USUAL_CONSTRAINTS[:cumulative] |> concept
33+
e = USUAL_CONSTRAINTS[:cumulative] |> error_f
34+
vs = Constraints.concept_vs_error
35+
36+
@test c([1, 2, 3, 4, 5]; val=1)
37+
@test !c([1, 2, 2, 4, 5]; val=1)
38+
@test c([1, 2, 3, 4, 5]; pair_vars=[3 2 5 4 2; 1 2 1 1 3], op= , val=5)
39+
@test !c([1, 2, 3, 4, 5]; pair_vars=[3 2 5 4 2; 1 2 1 1 3], op= <, val=5)
40+
41+
@test vs(c, e, [1, 2, 3, 4, 5]; val=1)
42+
@test vs(c, e, [1, 2, 2, 4, 5]; val=1)
43+
@test vs(c, e, [1, 2, 3, 4, 5]; pair_vars=[3 2 5 4 2; 1 2 1 1 3], op= , val=5)
44+
@test vs(c, e, [1, 2, 3, 4, 5]; pair_vars=[3 2 5 4 2; 1 2 1 1 3], op= <, val=5)
45+
end

0 commit comments

Comments
 (0)