Skip to content

Commit

Permalink
Make maxsum solver behavior uniform across platforms
Browse files Browse the repository at this point in the history
Use Int64 instead of Int, remove the noise term
in FieldValues, import the graph dict in a sorted
way so as to avoid the variability induced by
hashing on 64 vs 32 bit machines.
  • Loading branch information
carlobaldassi committed Dec 9, 2017
1 parent d65a063 commit 99d0229
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 42 deletions.
37 changes: 15 additions & 22 deletions src/resolve/FieldValues.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ using ...VersionWeights

export FieldValue, Field, validmax, secondmax

# FieldValue is a hierarchical numeric type with 6 levels.
# FieldValue is a hierarchical numeric type with 5 levels.
# When summing two FieldValues, the levels are summed independently.
# When comparing them, lower levels take precedence.
# The levels are used as such:
Expand All @@ -16,22 +16,19 @@ export FieldValue, Field, validmax, secondmax
# l2 : for favoring higher versions of all other packages
# l3 : for favoring uninstallation of non-needed packages
# l4 : for favoring dependants over dependencies
# l5 : for symmetry-breaking random noise
#
struct FieldValue
l0::Int
l0::Int64
l1::VersionWeight
l2::VersionWeight
l3::Int
l4::Int
l5::Int128
l3::Int64
l4::Int64
FieldValue(l0::Integer = 0,
l1::VersionWeight = zero(VersionWeight),
l2::VersionWeight = zero(VersionWeight),
l3::Integer = 0,
l4::Integer = 0) = new(l0, l1, l2, l3, l4)
end
FieldValue(l0::Integer, l1::VersionWeight, l2::VersionWeight, l3::Integer, l4::Integer) = FieldValue(l0, l1, l2, l3, l4, Int128(0))
FieldValue(l0::Integer, l1::VersionWeight, l2::VersionWeight, l3::Integer) = FieldValue(l0, l1, l2, l3, 0)
FieldValue(l0::Integer, l1::VersionWeight, l2::VersionWeight) = FieldValue(l0, l1, l2, 0)
FieldValue(l0::Integer, l1::VersionWeight) = FieldValue(l0, l1, zero(VersionWeight))
FieldValue(l0::Integer) = FieldValue(l0, zero(VersionWeight))
FieldValue() = FieldValue(0)

# This isn't nice, but it's for debugging only anyway
function Base.show(io::IO, a::FieldValue)
Expand All @@ -44,19 +41,17 @@ function Base.show(io::IO, a::FieldValue)
print(io, ".", a.l3)
a == FieldValue(a.l0, a.l1, a.l2, a.l3) && return
print(io, ".", a.l4)
a == FieldValue(a.l0, a.l1, a.l2, a.l3, a.l4) && return
print(io, ".", a.l5)
return
end

const Field = Vector{FieldValue}

Base.zero(::Type{FieldValue}) = FieldValue()

Base.typemin(::Type{FieldValue}) = (x=typemin(Int); y=typemin(VersionWeight); FieldValue(x, y, y, x, x, typemin(Int128)))
Base.typemin(::Type{FieldValue}) = (x=typemin(Int64); y=typemin(VersionWeight); FieldValue(x, y, y, x, x))

Base.:-(a::FieldValue, b::FieldValue) = FieldValue(a.l0-b.l0, a.l1-b.l1, a.l2-b.l2, a.l3-b.l3, a.l4-b.l4, a.l5-b.l5)
Base.:+(a::FieldValue, b::FieldValue) = FieldValue(a.l0+b.l0, a.l1+b.l1, a.l2+b.l2, a.l3+b.l3, a.l4+b.l4, a.l5+b.l5)
Base.:-(a::FieldValue, b::FieldValue) = FieldValue(a.l0-b.l0, a.l1-b.l1, a.l2-b.l2, a.l3-b.l3, a.l4-b.l4)
Base.:+(a::FieldValue, b::FieldValue) = FieldValue(a.l0+b.l0, a.l1+b.l1, a.l2+b.l2, a.l3+b.l3, a.l4+b.l4)

function Base.isless(a::FieldValue, b::FieldValue)
a.l0 < b.l0 && return true
Expand All @@ -70,17 +65,15 @@ function Base.isless(a::FieldValue, b::FieldValue)
a.l3 < b.l3 && return true
a.l3 > b.l3 && return false
a.l4 < b.l4 && return true
a.l4 > b.l4 && return false
a.l5 < b.l5 && return true
return false
end

Base.:(==)(a::FieldValue, b::FieldValue) =
a.l0 == b.l0 && a.l1 == b.l1 && a.l2 == b.l2 && a.l3 == b.l3 && a.l4 == b.l4 && a.l5 == b.l5
a.l0 == b.l0 && a.l1 == b.l1 && a.l2 == b.l2 && a.l3 == b.l3 && a.l4 == b.l4

Base.abs(a::FieldValue) = FieldValue(abs(a.l0), abs(a.l1), abs(a.l2), abs(a.l3), abs(a.l4), abs(a.l5))
Base.abs(a::FieldValue) = FieldValue(abs(a.l0), abs(a.l1), abs(a.l2), abs(a.l3), abs(a.l4))

Base.copy(a::FieldValue) = FieldValue(a.l0, copy(a.l1), copy(a.l2), a.l3, a.l4, a.l5)
Base.copy(a::FieldValue) = FieldValue(a.l0, copy(a.l1), copy(a.l2), a.l3, a.l4)

# if the maximum field has l0 < 0, it means that
# some hard constraint is being violated
Expand Down
23 changes: 9 additions & 14 deletions src/resolve/MaxSum.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ mutable struct MaxSumParams
end
end

# aux function to make graph generation consistent across platforms
sortedpairs(d::Dict) = (k=>d[k] for k in sort!(collect(keys(d))))

# Graph holds the graph structure onto which max-sum is run, in
# sparse format
mutable struct Graph
Expand All @@ -60,8 +63,7 @@ mutable struct Graph
# Used to break symmetry between dependants and
# dependencies (introduces a FieldValue at level l3).
# The "both" case is for when there are dependency
# relations which go both ways, in which case the
# noise is left to discriminate in case of ties
# relations which go both ways
gdir::Vector{Vector{Int}}

# adjacency dict:
Expand Down Expand Up @@ -93,12 +95,12 @@ mutable struct Graph
gdir = [Int[] for i = 1:np]
adjdict = [Dict{Int,Int}() for i = 1:np]

for (p,depsp) in deps
for (p,depsp) in sortedpairs(deps)
p0 = pdict[p]
vdict0 = vdict[p0]
for (vn,vdep) in depsp
for (vn,vdep) in sortedpairs(depsp)
v0 = vdict0[vn]
for (rp, rvs) in vdep
for (rp, rvs) in sortedpairs(vdep)
p1 = pdict[rp]

j0 = 1
Expand Down Expand Up @@ -187,15 +189,8 @@ mutable struct Messages
pdict = interface.pdict
vweight = interface.vweight

# a "deterministic noise" function based on hashes
function noise(p0::Int, v0::Int)
s = string(pkgs[p0]) * string(v0 == spp[p0] ? "UNINST" : pvers[p0][v0])
Int128(hash(s))
end

# external fields: there are 2 terms, a noise to break potential symmetries
# and one to favor newest versions over older, and no-version over all
fld = [[FieldValue(0, zero(VersionWeight), vweight[p0][v0], (v0==spp[p0]), 0, noise(p0,v0)) for v0 = 1:spp[p0]] for p0 = 1:np]
# external fields: favor newest versions over older, and no-version over all
fld = [[FieldValue(0, zero(VersionWeight), vweight[p0][v0], (v0==spp[p0]), 0) for v0 = 1:spp[p0]] for p0 = 1:np]

# enforce requirements
for (rp, rvs) in reqs
Expand Down
12 changes: 6 additions & 6 deletions src/resolve/VersionWeights.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@ export VersionWeight
# The numeric type used to determine how the different
# versions of a package should be weighed
struct VersionWeight
major::Int
minor::Int
patch::Int
major::Int64
minor::Int64
patch::Int64
end
VersionWeight(major::Int, minor::Int) = VersionWeight(major, minor, 0)
VersionWeight(major::Int) = VersionWeight(major, 0)
VersionWeight(major::Integer, minor::Integer) = VersionWeight(major, minor, 0)
VersionWeight(major::Integer) = VersionWeight(major, 0)
VersionWeight() = VersionWeight(0)

Base.convert(::Type{VersionWeight}, vn::VersionNumber) = VersionWeight(vn.major, vn.minor, vn.patch)

Base.zero(::Type{VersionWeight}) = VersionWeight()

Base.typemin(::Type{VersionWeight}) = (x=typemin(Int); VersionWeight(x, x, x))
Base.typemin(::Type{VersionWeight}) = (x=typemin(Int64); VersionWeight(x, x, x))

Base.:(-)(a::VersionWeight, b::VersionWeight) =
VersionWeight(a.major-b.major, a.minor-b.minor, a.patch-b.patch)
Expand Down

0 comments on commit 99d0229

Please sign in to comment.