-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Heterogeneous graph and new associated RL pipeline. #229
Conversation
…l into heterogeneous
…l into heterogeneous
ef=fgs.ef, | ||
gf=fgs.gf | ||
) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Zigote.ignore() should not contain the code block :
return BatchedFeaturedGraph{Float32}(
fgs.graph;
nf=g.σ.(g.weight1 ⊠ X .+ g.weight2 ⊠ X ⊠ A .+ g.bias),
ef=fgs.ef,
gf=fgs.gf
)
As long as there no operation computed, this is maybe not a problem, but I'd rather remove this block from the ignore()
if it doesn't lead to an error
return BatchedHeterogeneousFeaturedGraph{Float32}( | ||
contovar, | ||
valtovar, | ||
g.σ.(g.weightsvar ⊠ vcat(X1, H1, H2 ⊠ contovarN, H3 ⊠ valtovarN) .+ g.biasvar), | ||
g.σ.(g.weightscon ⊠ vcat(X2, H2, H1 ⊠ vartoconN) .+ g.biascon), | ||
g.σ.(g.weightsval ⊠ vcat(X3, H3, H1 ⊠ vartovalN) .+ g.biasval), | ||
fgs.gf | ||
) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment here. What do you think of this @gostreap ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should not forget to correct this before merging with master. As the function is not recursive, it is ok to return under Zygote.ignore()
statement but the operations that are computed inside the return here should be copied outside thr Zygote.ignore()
domain. We have solved the same issue on heterogeneousgraphtransformer.jl
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What causes the Zygote errors is the construction of the BatchedHeterogeneousFeaturedGraph
. It would even be safer to do separate construction of the object under Zygote.ignore() and return outside it.
@@ -81,7 +81,7 @@ struct CPLayerGraph <: LightGraphs.AbstractGraph{Int} | |||
""" | |||
function CPLayerGraph(cpmodel::CPModel) | |||
variables = Set{AbstractVar}(values(cpmodel.variables)) | |||
valuesOfVariables = branchable_values(cpmodel) | |||
valuesOfVariables = sort(branchable_values(cpmodel)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you explain briefly what the issue was with the previous pipeline ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In short, the ordering of the actions taken by the agent was not consistent with the ordering of value node features in the graph. As a result, the values embeddings in FullFeaturedCPNN
didn't match the actions taken by the agent afterwards. But this fix doesn't impact other CPNNs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We just have to check that Zygote.ignore()
statements in all convolutional layers are well positioned and we can merge this branch on master
.
@@ -257,6 +257,8 @@ Empty the CPModel. | |||
""" | |||
function Base.empty!(model::CPModel) | |||
empty!(model.variables) | |||
empty!(model.branchable_variables) | |||
empty!(model.branchable) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These lines fix a major bug caused by the fact that the model was not properly emptied after the resolution of each instance in the training process.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice spot !
if !isempty(x.children) | ||
for child in x.children | ||
cardinality += length(child.domain) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We now take all variables, including VarViews
into consideration in global_domain_cardinality
for (x1, x2) in variableConnections | ||
v1, v2 = VariableVertex(x1), VariableVertex(x2) | ||
add_edge!(fixedEdgesGraph, nodeToId[v1], nodeToId[v2]) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes absolutely. They are now represented as simple constraints (of type ViewConstraint
) between 2 variables.
else | ||
error("WARNING: Unknwon VarViewType: please implement DefaultFeaturization for this type!") | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the problem we are trying to solve has ViewConstraints
, in constraint_type
, we encode them thanks to 4 new components, respectively: one-hot encoding of the fact the considered constraint is a ViewConstraint
, multiplication coefficient if the ViewConstraint
is of type IntVarViewMul
or IntVarViewOpposite
, offset coefficient if the if the ViewConstraint
is of type IntVarViewOffset
, and one-hot encoding of the fact the ViewConstraint
is of type BoolVarViewNot
.
@assert all(var .<= size(fg.varnf,2)) "The variable index is out of bound" | ||
@assert all(reduce(vcat,val) .<= size(fg.valnf,2)) "One of the values index is out of bound" | ||
@assert all(reduce(vcat,[[tuple[2] for tuple in countmap([c for c in vals])] for vals in val]) .== 1) "values array contains one element at least twice" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we remove them now as they haven't caused any error so far?
@@ -94,8 +95,8 @@ function fill_with_generator!(cpmodel::CPModel, gen::HomogenousGraphColoringGene | |||
|
|||
# edge constraints | |||
for i in 1:n | |||
for j in 1:n | |||
if i != j && rand(rng) <= p | |||
for j in (i+1):n |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This helps to remove symmetries when generating graphcoloring instances.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we remove them now as they haven't caused any error so far?
As long as computing performance is not a true bottleneck, I'd prefer to keep them in place as long as SeaPearl won't be (at least currently) put into production even if they are computationally inefficient.
Or we can remove only the last one which is the most greedy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok no problem!
ef=fgs.ef, | ||
gf=fgs.gf | ||
) | ||
sum = replace(reshape(mapslices(x -> sum(eachrow(x)), A, dims=[1, 2]), 1, :, size(A, 3)), 0=>1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the reason for adding a replace( M, 0=>1)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
edit : This is to avoid any division by 0, in case a node has no neighbors, which can happen for value that belongs to no domain after pruning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the case where a node has no neighbor, the sum is zero, which will then cause problems in the division.
Putting a 1 in the division should not be a problem, because it will divide a vector composed only of 0. Any constant other than 1 would have done the job as well.
Co-authored-by: Tom Marty <59280588+3rdCore@users.noreply.github.com>
…l into heterogeneous
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we are now ready to merge with master.
* Add MaximumIndependentSet Generator * Change NotEqual to SumLessThan * Fix test by introducing LigthGraphs. everywhere * Introduce test for maximum independent set * Fix testset for maximumindependentset * Update src/CP/constraints/algorithms/matching.jl Co-authored-by: Tom Marty <59280588+3rdCore@users.noreply.github.com> * Update src/CP/constraints/alldifferent.jl Co-authored-by: Tom Marty <59280588+3rdCore@users.noreply.github.com> * Add missing LightGraphs. prefix Co-authored-by: Tom Marty <59280588+3rdCore@users.noreply.github.com> Co-authored-by: louis-gautier <louisgautier99@gmail.com>
@@ -112,7 +111,11 @@ Update the StateRepesentation according to its Type and Featurization. | |||
""" | |||
function update_representation!(sr::DefaultStateRepresentation, model::CPModel, x::AbstractIntVar) | |||
update_features!(sr, model) | |||
ncon = sr.cplayergraph.numberOfConstraints | |||
nvar = sr.cplayergraph.numberOfVariables | |||
sr.possibleValuesIdx = map(v -> indexFromCpVertex(sr.cplayergraph, ValueVertex(v)), collect(x.domain)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did we specifically test this change ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we tested it. Maybe we should create an issue for each behavior we want to test, without postponing the merge?
function adjacency_matrices(cplayergraph::CPLayerGraph) | ||
g = LightGraphs.Graph(cplayergraph) # Update the graph with the new information | ||
nvar = cplayergraph.numberOfVariables | ||
ncon = cplayergraph.numberOfConstraints | ||
nval = cplayergraph.numberOfValues | ||
contovar = zeros(ncon, nvar) | ||
valtovar = zeros(nval, nvar) | ||
for (i, node) in enumerate(cplayergraph.idToNode) | ||
if isa(node, ConstraintVertex) | ||
neighbors = LightGraphs.outneighbors(g, i) | ||
for neighbor in neighbors | ||
contovar[i, neighbor - ncon] = 1 | ||
end | ||
elseif isa(node, ValueVertex) | ||
neighbors = LightGraphs.outneighbors(g, i) | ||
for neighbor in neighbors | ||
valtovar[i - ncon - nvar, neighbor - ncon] = 1 | ||
end | ||
end | ||
end | ||
return contovar, valtovar |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did we tested this ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we have unit tests for this in test/heterogeneousstaterepresentation.jl.
Co-authored-by: Tom Marty <59280588+3rdCore@users.noreply.github.com>
The purpose of this pull request is to allow the implementation of the new graph convolution discussed in issue #225.
The major novelties are :
VarViews
:VarView
relations were formerly represented as an edge between 2 distinct variables (the parent and its child). With this PR,VarView
relations are now represented as constraints of typeViewConstraint
linked to these 2 variables. Whenconstraint_type
is set totrue
inchosen_features
, and a problem containtsVarView
relations, it now encodes the type of the constraint with 4 new dimensions reflecting the exact nature of theVarView
relation. Please refer tofeaturize
function inheterogeneousstaterepresentation.jl
for more information.HeterogeneousGraphConvInit
GraphConv
:HeterogeneousGraphConv
.HeterogeneousCPNN
,HeterogeneousFullFeaturedCPNN
andHeterogeneousVariableOutputCPNN
.mean
aggregation in the convolutional layers.Minor updates also concern: