dep_selector 0.0.8 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/ext/dep_gecode/dep_selector_swig.i +2 -1
- data/ext/dep_gecode/dep_selector_swig_wrap.cxx +530 -180
- data/ext/dep_gecode/dep_selector_to_gecode.cpp +404 -360
- data/ext/dep_gecode/dep_selector_to_gecode.h +13 -5
- data/ext/dep_gecode/dep_selector_to_gecode_interface.cpp +3 -2
- data/ext/dep_gecode/dep_selector_to_gecode_interface.h +2 -1
- data/ext/dep_gecode/extconf.rb +24 -6
- data/lib/dep_selector/dep_selector_version.rb +1 -1
- data/lib/dep_selector/dependency_graph.rb +4 -1
- data/lib/dep_selector/error_reporter/simple_tree_traverser.rb +4 -0
- data/lib/dep_selector/exceptions.rb +5 -0
- data/lib/dep_selector/gecode_wrapper.rb +7 -4
- data/lib/dep_selector/selector.rb +46 -40
- metadata +71 -43
@@ -53,6 +53,7 @@ struct VersionProblemPool
|
|
53
53
|
void DeleteAll();
|
54
54
|
};
|
55
55
|
|
56
|
+
#define DEBUG_PREFIX_LENGTH 40
|
56
57
|
|
57
58
|
class VersionProblem : public Space
|
58
59
|
{
|
@@ -62,7 +63,11 @@ public:
|
|
62
63
|
static const int MAX_TRUST_LEVEL;
|
63
64
|
static const int MAX_PREFERRED_WEIGHT;
|
64
65
|
|
65
|
-
|
66
|
+
static int instance_counter;
|
67
|
+
|
68
|
+
VersionProblem(int packageCount, bool dumpStats = true,
|
69
|
+
bool debug = false,
|
70
|
+
const char * logId = 0);
|
66
71
|
// Clone constructor; check gecode rules for this...
|
67
72
|
VersionProblem(bool share, VersionProblem & s);
|
68
73
|
virtual ~VersionProblem();
|
@@ -103,17 +108,20 @@ public:
|
|
103
108
|
// Debug and utility functions
|
104
109
|
void Print(std::ostream &out);
|
105
110
|
void PrintPackageVar(std::ostream & out, int packageId) ;
|
111
|
+
const char * DebugPrefix() const { return debugPrefix; }
|
106
112
|
|
107
|
-
|
113
|
+
static VersionProblem *InnerSolve(VersionProblem * problem, int & itercount);
|
108
114
|
static VersionProblem *Solve(VersionProblem *problem);
|
109
|
-
|
110
115
|
|
111
116
|
protected:
|
117
|
+
int instance_id;
|
112
118
|
int size;
|
113
119
|
int version_constraint_count;
|
114
120
|
int cur_package;
|
115
121
|
bool dump_stats;
|
116
|
-
bool
|
122
|
+
bool debugLogging;
|
123
|
+
char debugPrefix[DEBUG_PREFIX_LENGTH];
|
124
|
+
char outputBuffer[1024];
|
117
125
|
bool finalized;
|
118
126
|
|
119
127
|
BoolVarArgs version_flags;
|
@@ -139,7 +147,7 @@ public:
|
|
139
147
|
void AddPackagesPreferredToBeAtLatestObjectiveFunction(const VersionProblem & best_known_solution);
|
140
148
|
void ConstrainVectorLessThanBest(IntVarArgs & current, IntVarArgs & best);
|
141
149
|
void BuildCostVector(IntVarArgs & costVector) const;
|
142
|
-
|
150
|
+
|
143
151
|
friend class VersionProblemPool;
|
144
152
|
};
|
145
153
|
|
@@ -29,9 +29,10 @@
|
|
29
29
|
// insure proper memory behaviour
|
30
30
|
|
31
31
|
// FFI friendly
|
32
|
-
VersionProblem * VersionProblemCreate(int packageCount, bool dump_stats,
|
32
|
+
VersionProblem * VersionProblemCreate(int packageCount, bool dump_stats,
|
33
|
+
bool debug, const char * logId)
|
33
34
|
{
|
34
|
-
return new VersionProblem(packageCount, dump_stats, debug);
|
35
|
+
return new VersionProblem(packageCount, dump_stats, debug, logId);
|
35
36
|
}
|
36
37
|
|
37
38
|
void VersionProblemDestroy(VersionProblem * p)
|
@@ -31,7 +31,8 @@ extern "C" {
|
|
31
31
|
typedef struct VersionProblem VersionProblem;
|
32
32
|
#endif // __cplusplus
|
33
33
|
|
34
|
-
VersionProblem * VersionProblemCreate(int packageCount, bool dumpStats,
|
34
|
+
VersionProblem * VersionProblemCreate(int packageCount, bool dumpStats,
|
35
|
+
bool debug, const char * logId);
|
35
36
|
void VersionProblemDestroy(VersionProblem * vp);
|
36
37
|
|
37
38
|
|
data/ext/dep_gecode/extconf.rb
CHANGED
@@ -23,16 +23,34 @@
|
|
23
23
|
# to work properly here.
|
24
24
|
require 'mkmf'
|
25
25
|
|
26
|
-
$LIBS << " -lstdc++"
|
27
|
-
|
28
26
|
# $CFLAGS << "-g"
|
29
27
|
|
30
28
|
gecode_installed =
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
# Gecode documentation notes:
|
30
|
+
# "Some linkers require the list of libraries to be sorted such that
|
31
|
+
# libraries appear before all libraries they depend on."
|
32
|
+
# http://www.gecode.org/doc-latest/MPG.pdf
|
33
|
+
#
|
34
|
+
# This appears to be true of the version of mingw that ships with Ruby 1.9.3.
|
35
|
+
# The correct order of `-l` flags according to the docs is:
|
36
|
+
#
|
37
|
+
# 1. -lgecodeflatzinc
|
38
|
+
# 2. -lgecodedriver
|
39
|
+
# 3. -lgecodegist
|
40
|
+
# 4. -lgecodesearch,
|
41
|
+
# 5. -lgecodeminimodel
|
42
|
+
# 6. -lgecodeset
|
43
|
+
# 7. -lgecodefloat
|
44
|
+
# 8. -lgecodeint
|
45
|
+
# 9. -lgecodekernel
|
46
|
+
# 10. -lgecodesupport
|
47
|
+
#
|
48
|
+
# Ruby `mkmf` will add `-l` flags in the _REVERSE_ order that they appear here.
|
34
49
|
have_library('gecodesupport') &&
|
35
|
-
have_library('
|
50
|
+
have_library('gecodekernel') &&
|
51
|
+
have_library('gecodeint') &&
|
52
|
+
have_library('gecodeminimodel') &&
|
53
|
+
have_library('gecodesearch')
|
36
54
|
|
37
55
|
unless gecode_installed
|
38
56
|
STDERR.puts <<EOS
|
@@ -26,6 +26,8 @@ require 'dep_selector/gecode_wrapper'
|
|
26
26
|
module DepSelector
|
27
27
|
class DependencyGraph
|
28
28
|
|
29
|
+
DebugOptionFile = "/tmp/DepSelectorDebugOn"
|
30
|
+
|
29
31
|
attr_reader :packages
|
30
32
|
|
31
33
|
def initialize
|
@@ -58,10 +60,11 @@ module DepSelector
|
|
58
60
|
packages.map{ |name, pkg| pkg }
|
59
61
|
end
|
60
62
|
|
63
|
+
debugFlag = DebugOptionFile && File::exists?(DebugOptionFile)
|
61
64
|
# In addition to all the packages that the user specified,
|
62
65
|
# there is a "ghost" package that contains the solution
|
63
66
|
# constraints. See Selector#solve for more information.
|
64
|
-
@gecode_wrapper = GecodeWrapper.new(packages_in_solve.size + 1)
|
67
|
+
@gecode_wrapper = GecodeWrapper.new(packages_in_solve.size + 1, debugFlag)
|
65
68
|
packages_in_solve.each{ |pkg| pkg.generate_gecode_wrapper_constraints }
|
66
69
|
end
|
67
70
|
end
|
@@ -78,11 +78,15 @@ module DepSelector
|
|
78
78
|
|
79
79
|
# determine all versions of curr_pkg that match
|
80
80
|
# version_constraint and recurse into them
|
81
|
+
seen_dep_trees = {}
|
81
82
|
curr_pkg[version_constraint].each do |curr_pkg_ver|
|
83
|
+
next if seen_dep_trees.has_key?(curr_pkg_ver.dependencies.to_s)
|
82
84
|
curr_path.push(curr_pkg_ver)
|
83
85
|
curr_pkg_ver.dependencies.each do |dep|
|
86
|
+
next if curr_pkg.name == dep.package.name
|
84
87
|
paths_to_pkg(dep_graph, dep.package, dep.constraint, target_pkg, curr_path, all_paths)
|
85
88
|
end
|
89
|
+
seen_dep_trees[curr_pkg_ver.dependencies.to_s] = true
|
86
90
|
curr_path.pop
|
87
91
|
end
|
88
92
|
end
|
@@ -38,6 +38,11 @@ module DepSelector
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
+
class TimeBoundExceeded < StandardError
|
42
|
+
end
|
43
|
+
class TimeBoundExceededNoSolution < StandardError
|
44
|
+
end
|
45
|
+
|
41
46
|
# This exception is thrown by gecode_wrapper and only used
|
42
47
|
# internally
|
43
48
|
class NoSolutionFound < StandardError
|
@@ -17,22 +17,25 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
+
require "uuidtools"
|
20
21
|
require "dep_gecode"
|
21
22
|
require 'dep_selector/exceptions'
|
22
23
|
|
23
24
|
module DepSelector
|
24
25
|
class GecodeWrapper
|
25
26
|
attr_reader :gecode_problem
|
27
|
+
attr_reader :debug_logs_on
|
26
28
|
DontCareConstraint = -1
|
27
29
|
NoMatchConstraint = -2
|
28
30
|
DumpStatistics = true
|
29
|
-
DebugLogsOn = false
|
30
31
|
|
31
32
|
# This insures that we properly deallocate the c++ class at the heart of dep_gecode.
|
32
33
|
# modeled after http://www.mikeperham.com/2010/02/24/the-trouble-with-ruby-finalizers/
|
33
|
-
def initialize(problem_or_package_count)
|
34
|
+
def initialize(problem_or_package_count, debug=false)
|
34
35
|
if (problem_or_package_count.is_a?(Numeric))
|
35
|
-
|
36
|
+
logId = UUIDTools::UUID.random_create().to_str()
|
37
|
+
@debug_logs_on = debug
|
38
|
+
@gecode_problem = Dep_gecode.VersionProblemCreate(problem_or_package_count, DumpStatistics, debug, logId)
|
36
39
|
else
|
37
40
|
@gecode_problem = problem_or_package_count
|
38
41
|
end
|
@@ -142,7 +145,7 @@ module DepSelector
|
|
142
145
|
|
143
146
|
def solve()
|
144
147
|
raise "Gecode internal failure (solve)" if gecode_problem.nil?
|
145
|
-
solution = GecodeWrapper.new(Dep_gecode.Solve(gecode_problem))
|
148
|
+
solution = GecodeWrapper.new(Dep_gecode.Solve(gecode_problem), debug_logs_on)
|
146
149
|
raise "Gecode internal failure (no solution found)" if (solution.nil?)
|
147
150
|
|
148
151
|
raise Exceptions::NoSolutionFound.new(solution) if solution.package_disabled_count > 0
|
@@ -17,6 +17,7 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
+
require 'timeout'
|
20
21
|
require 'dep_selector/dependency_graph'
|
21
22
|
require 'dep_selector/exceptions'
|
22
23
|
require 'dep_selector/error_reporter'
|
@@ -29,12 +30,13 @@ require 'dep_selector/error_reporter/simple_tree_traverser'
|
|
29
30
|
# constraint that makes a solution impossible.
|
30
31
|
module DepSelector
|
31
32
|
class Selector
|
32
|
-
attr_accessor :dep_graph, :error_reporter
|
33
|
+
attr_accessor :dep_graph, :error_reporter, :time_bound
|
33
34
|
|
34
35
|
DEFAULT_ERROR_REPORTER = ErrorReporter::SimpleTreeTraverser.new
|
35
36
|
|
36
|
-
def initialize(dep_graph, error_reporter = DEFAULT_ERROR_REPORTER)
|
37
|
+
def initialize(dep_graph, time_bound = 5, error_reporter = DEFAULT_ERROR_REPORTER)
|
37
38
|
@dep_graph = dep_graph
|
39
|
+
@time_bound = time_bound
|
38
40
|
@error_reporter = error_reporter
|
39
41
|
end
|
40
42
|
|
@@ -65,8 +67,10 @@ module DepSelector
|
|
65
67
|
packages_to_include_in_solve = trim_unreachable_packages(dep_graph, solution_constraints)
|
66
68
|
|
67
69
|
begin
|
68
|
-
|
69
|
-
|
70
|
+
Timeout::timeout(@time_bound, Exceptions::TimeBoundExceeded) do
|
71
|
+
# first, try to solve the whole set of constraints
|
72
|
+
solve(dep_graph.clone, solution_constraints, valid_packages, packages_to_include_in_solve)
|
73
|
+
end
|
70
74
|
rescue Exceptions::NoSolutionFound
|
71
75
|
# since we're here, solving the whole system failed, so add
|
72
76
|
# the solution_constraints one-by-one and try to solve in
|
@@ -79,48 +83,50 @@ module DepSelector
|
|
79
83
|
# iteratively add and solve in order to re-use
|
80
84
|
# propagations. This will require separating setting up the
|
81
85
|
# constraints from searching for the solution.
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
86
|
+
Timeout::timeout(@time_bound, Exceptions::TimeBoundExceededNoSolution) do
|
87
|
+
solution_constraints.each_index do |idx|
|
88
|
+
workspace = dep_graph.clone
|
89
|
+
begin
|
90
|
+
solve(workspace, solution_constraints[0..idx], valid_packages, packages_to_include_in_solve)
|
91
|
+
rescue Exceptions::NoSolutionFound => nsf
|
92
|
+
disabled_packages =
|
93
|
+
packages_to_include_in_solve.inject([]) do |acc, elt|
|
89
94
|
pkg = workspace.package(elt.name)
|
90
95
|
acc << pkg if nsf.unsatisfiable_problem.is_package_disabled?(pkg.gecode_package_id)
|
91
96
|
acc
|
92
97
|
end
|
93
|
-
|
98
|
+
# disambiguate between packages disabled becuase they
|
94
99
|
# don't exist and those that have otherwise problematic
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
100
|
+
# constraints
|
101
|
+
disabled_non_existent_packages = []
|
102
|
+
disabled_most_constrained_packages = []
|
103
|
+
disabled_packages.each do |disabled_pkg|
|
104
|
+
disabled_collection =
|
105
|
+
if disabled_pkg.valid? || (valid_packages && valid_packages.include?(disabled_pkg))
|
106
|
+
disabled_most_constrained_packages
|
107
|
+
else
|
108
|
+
disabled_non_existent_packages
|
109
|
+
end
|
110
|
+
disabled_collection << disabled_pkg
|
111
|
+
end
|
112
|
+
|
113
|
+
# Pick the first non-existent or most-constrained package
|
114
|
+
# that was required or the package whose constraints had
|
115
|
+
# to be disabled in order to find a solution and generate
|
116
|
+
# feedback for it. We only report feedback for one
|
117
|
+
# package, because it is in fact actionable and dispalying
|
118
|
+
# feedback for every disabled package would probably be
|
119
|
+
# too long. The full set of disabled packages is
|
120
|
+
# accessible in the NoSolutionExists exception.
|
121
|
+
disabled_package_to_report_on = disabled_non_existent_packages.first ||
|
122
|
+
disabled_most_constrained_packages.first
|
123
|
+
feedback = error_reporter.give_feedback(dep_graph, solution_constraints, idx,
|
124
|
+
disabled_package_to_report_on)
|
125
|
+
|
126
|
+
raise Exceptions::NoSolutionExists.new(feedback, solution_constraints[idx],
|
127
|
+
disabled_non_existent_packages,
|
128
|
+
disabled_most_constrained_packages)
|
106
129
|
end
|
107
|
-
|
108
|
-
# Pick the first non-existent or most-constrained package
|
109
|
-
# that was required or the package whose constraints had
|
110
|
-
# to be disabled in order to find a solution and generate
|
111
|
-
# feedback for it. We only report feedback for one
|
112
|
-
# package, because it is in fact actionable and dispalying
|
113
|
-
# feedback for every disabled package would probably be
|
114
|
-
# too long. The full set of disabled packages is
|
115
|
-
# accessible in the NoSolutionExists exception.
|
116
|
-
disabled_package_to_report_on = disabled_non_existent_packages.first ||
|
117
|
-
disabled_most_constrained_packages.first
|
118
|
-
feedback = error_reporter.give_feedback(dep_graph, solution_constraints, idx,
|
119
|
-
disabled_package_to_report_on)
|
120
|
-
|
121
|
-
raise Exceptions::NoSolutionExists.new(feedback, solution_constraints[idx],
|
122
|
-
disabled_non_existent_packages,
|
123
|
-
disabled_most_constrained_packages)
|
124
130
|
end
|
125
131
|
end
|
126
132
|
end
|
metadata
CHANGED
@@ -1,35 +1,68 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: dep_selector
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
segments:
|
6
|
-
- 0
|
7
|
-
- 0
|
8
|
-
- 8
|
9
|
-
version: 0.0.8
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
10
5
|
platform: ruby
|
11
|
-
authors:
|
6
|
+
authors:
|
12
7
|
- Christopher Walters
|
13
8
|
- Mark Anderson
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
12
|
+
date: 2014-03-18 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: uuidtools
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ~>
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '2.1'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '2.1'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rspec
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ~>
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '2.14'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ~>
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '2.14'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rake-compiler
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ~>
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: 0.9.2
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ~>
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 0.9.2
|
56
|
+
description: Given packages, versions, and a dependency graph, find a valid assignment
|
57
|
+
of package versions
|
58
|
+
email:
|
24
59
|
- cw@opscode.com
|
25
60
|
- mark@opscode.com
|
26
61
|
executables: []
|
27
|
-
|
28
|
-
extensions:
|
62
|
+
extensions:
|
29
63
|
- ext/dep_gecode/extconf.rb
|
30
64
|
extra_rdoc_files: []
|
31
|
-
|
32
|
-
files:
|
65
|
+
files:
|
33
66
|
- lib/dep_selector/densely_packed_set.rb
|
34
67
|
- lib/dep_selector/dep_selector_version.rb
|
35
68
|
- lib/dep_selector/dependency.rb
|
@@ -53,36 +86,31 @@ files:
|
|
53
86
|
- ext/dep_gecode/dep_selector_to_gecode_interface.cpp
|
54
87
|
- ext/dep_gecode/extconf.rb
|
55
88
|
- ext/dep_gecode/lib/dep_selector_to_gecode.rb
|
56
|
-
has_rdoc: false
|
57
89
|
homepage: http://github.com/algorist/dep_selector
|
58
|
-
licenses:
|
90
|
+
licenses:
|
59
91
|
- Apache v2
|
92
|
+
metadata: {}
|
60
93
|
post_install_message:
|
61
94
|
rdoc_options: []
|
62
|
-
|
63
|
-
require_paths:
|
95
|
+
require_paths:
|
64
96
|
- lib
|
65
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
-
requirements:
|
67
|
-
- -
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
segments:
|
77
|
-
- 0
|
78
|
-
version: "0"
|
79
|
-
requirements:
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - '>='
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
requirements:
|
80
108
|
- gecode, version 3.5 or greater
|
81
109
|
- g++
|
82
110
|
rubyforge_project:
|
83
|
-
rubygems_version:
|
111
|
+
rubygems_version: 2.0.3
|
84
112
|
signing_key:
|
85
|
-
specification_version:
|
86
|
-
summary: Given packages, versions, and a dependency graph, find a valid assignment
|
113
|
+
specification_version: 4
|
114
|
+
summary: Given packages, versions, and a dependency graph, find a valid assignment
|
115
|
+
of package versions
|
87
116
|
test_files: []
|
88
|
-
|