dep_selector 0.0.8 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
-
|