[Aptitude-svn-commit] r3934 - in branches/aptitude-0.3/aptitude: .
src/generic/problemresolver
Daniel Burrows
dburrows at costa.debian.org
Sat Aug 20 17:10:41 UTC 2005
Author: dburrows
Date: Sat Aug 20 17:10:37 2005
New Revision: 3934
Modified:
branches/aptitude-0.3/aptitude/ChangeLog
branches/aptitude-0.3/aptitude/src/generic/problemresolver/problemresolver.h
Log:
Get everything compiling and sort of working.
Modified: branches/aptitude-0.3/aptitude/ChangeLog
==============================================================================
--- branches/aptitude-0.3/aptitude/ChangeLog (original)
+++ branches/aptitude-0.3/aptitude/ChangeLog Sat Aug 20 17:10:37 2005
@@ -1,3 +1,10 @@
+2005-08-20 Daniel Burrows <dburrows at debian.org>
+
+ * src/generic/problemresolver/problemresolver.h:
+
+ Get everything compiling and sort of working. Probably all
+ sorts of stuff needs to be fixed up, though :-/.
+
2005-08-19 Daniel Burrows <dburrows at debian.org>
* src/generic/problemresolver/problemresolver.h:
Modified: branches/aptitude-0.3/aptitude/src/generic/problemresolver/problemresolver.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/problemresolver/problemresolver.h (original)
+++ branches/aptitude-0.3/aptitude/src/generic/problemresolver/problemresolver.h Sat Aug 20 17:10:37 2005
@@ -160,7 +160,6 @@
* issued.
*/
-
template<class PackageUniverse>
class generic_problem_resolver
{
@@ -302,17 +301,38 @@
bool from_dep_source;
- act_conflict(version &_ver)
+ act_conflict()
+ :from_dep_source(false)
+ {
+ }
+
+ act_conflict(const version &_ver)
:ver(_ver), from_dep_source(false)
{
}
- act_conflict(version &_ver, dep &_d)
+ act_conflict(const version &_ver, const dep &_d)
:ver(_ver), d(_d), from_dep_source(true)
{
}
- bool operator==(const act_conflict &other)
+ /** \return \b true if this action will match the action given by
+ * other: true if the versions are equal and either they
+ * both follow from the same dep, or 'other' doesn't
+ * follow from any dep.
+ */
+ bool subsumes(const act_conflict &other) const
+ {
+ if(ver != other.ver)
+ return false;
+
+ if(!other.from_dep_source)
+ return true;
+ else
+ return from_dep_source && d == other.d;
+ }
+
+ bool operator==(const act_conflict &other) const
{
if(from_dep_source != other.from_dep_source)
return false;
@@ -323,7 +343,7 @@
return ver == other.ver;
}
- bool operator!=(const act_conflict &other)
+ bool operator!=(const act_conflict &other) const
{
if(from_dep_source != other.from_dep_source)
return true;
@@ -334,7 +354,7 @@
return ver != other.ver;
}
- bool operator<(const act_conflict &other)
+ bool operator<(const act_conflict &other) const
{
if(!from_dep_source && other.from_dep_source)
return true;
@@ -344,13 +364,17 @@
return ver < other.ver;
else if(ver < other.ver) // if(from_dep_source)
return true;
- else if(ver > other.ver)
+ else if(other.ver < ver)
return false;
else
return d < other.d;
}
};
+ // Needs to be a friend since it has to be global.
+ template<class PackageUniverse2>
+ friend std::ostream &operator<<(std::ostream &out, const typename std::map<typename PackageUniverse2::package, typename generic_problem_resolver<PackageUniverse2>::act_conflict> &ac);
+
/** Stores conflicts: sets of installations that have been
* determined to be mutually incompatible.
*/
@@ -382,18 +406,26 @@
typedef std::set<std::pair<version, version> > stupid_table;
- /** \return \b true if the given solution contains a conflict when
- * the given package and version are additionally installed.
- */
- bool will_conflict(const solution &s,
- const package &p,
- const act_conflict &a)
+ // FIXME: temporary hack so I don't have to lift code all over.
+ std::ostream &dump(std::ostream &out, const std::map<package, act_conflict> &act) const;
+ std::ostream &dump(std::ostream &out, const act_conflict &act) const;
+
+ /** Test whether the given solution contains a conflict when the
+ * given action is taken.
+ *
+ * \return such a conflict if it exists; otherwise conflicts.end().
+ */
+ typename std::set<std::map<package, act_conflict> >::const_iterator
+ will_conflict(const solution &s,
+ const act_conflict &a) const
{
// For now I'm being lazy and actually generating a full mapping.
// However, this could be done much more efficiently if optimizing
// this code is important.
std::map<package, act_conflict> m;
+ package p = a.ver.get_package();
+
for(typename std::map<package, action>::const_iterator si
= s.get_actions().begin(); si != s.get_actions().end(); ++si)
m[si->first] = act_conflict(si->second.ver);
@@ -405,22 +437,32 @@
m[p] = a;
+ if(debug)
+ {
+ std::cout << "Checking for conflicts in temporary solution:" << std::endl;
+ dump(std::cout, m);
+ std::cout << std::endl;
+ }
+
for(typename std::set<std::map<package, act_conflict> >::const_iterator ci = conflicts.begin();
ci != conflicts.end(); ++ci)
{
typename std::map<package, act_conflict>::const_iterator cj = ci->begin();
- typename std::map<package, act_conflict>::const_iterator mi = ci->begin();
+ typename std::map<package, act_conflict>::const_iterator mi = m.begin();
bool is_subset = true;
while(cj != ci->end() &&
- mi != ci->end())
+ mi != m.end())
{
- if(cj->first < mi->first)
- ++cj;
- else if(mi->first < cj->first)
+ if(mi->first < cj->first)
++mi;
- else if(mi->second != cj->second)
+ else if(cj->first < mi->first)
+ {
+ is_subset = false;
+ break;
+ }
+ else if(!(mi->second.subsumes(cj->second)))
{
is_subset = false;
break;
@@ -432,31 +474,31 @@
}
}
+ // If we didn't consume the entire conflict, it clearly isn't
+ // a subset of this proposed solution.
+ if(cj != ci->end())
+ is_subset = false;
+
if(is_subset)
{
if(debug)
{
- std::cout << "Discovered conflict (";
- for(std::map<package, act_conflict> cj = ci->begin();
- cj != cj->end(); ++cj)
- {
- if(cj != ci->begin())
- std::cout << ", ";
- std::cout << cj->first.name() << " " <<
- cj->second.ver.name();
+ std::cout << "Adding " << p.get_name() << " "
+ << a.ver.get_name();
- if(cj->second.from_dep_source)
- std::cout << " [" << cj->second.d << "]";
- }
+ if(a.from_dep_source)
+ std::cout << " due to " << a.d;
- std::cout << ")" << std::endl;
+ std::cout << " will trigger conflict ";
+ dump(std::cout, *ci);
+ std::cout << std::endl;
}
- return true;
+ return ci;
}
}
- return false;
+ return conflicts.end();
}
/** Generate a table listing the "stupid" pairs of actions in a
@@ -1654,11 +1696,17 @@
std::map<version, dep> &toforbid,
std::set<dep> &toignore)
{
+ // As we progress, reasons for forbidding each solver are tossed
+ // into this map. If the solution is eventaully discarded, this
+ // object will contain a conflict that explains the discard.
+ std::map<package, act_conflict> partial_conflict;
+
version v;
version source_version=d.get_source();
package source_package=source_version.get_package();
bool found=false, from_source=false;
+
if(debug)
{
std::cout << "Testing whether " << d << " is a forced dependency." << std::endl;
@@ -1670,37 +1718,141 @@
{
for(typename package::version_iterator vi=source_package.versions_begin();
!vi.end(); ++vi)
- // Note that testing against toforbid is strictly a
- // performance hack (it would be caught in the next cycle if
- // we didn't do it here, but why not use the information
- // ASAP?)
- if(*vi != source_version &&
- s.get_forbidden_versions().find(*vi) == s.get_forbidden_versions().end() &&
- toforbid.find(*vi)==toforbid.end())
- {
- if(found)
- return false;
- found=true;
- from_source=true;
- v=*vi;
- }
+ {
+ // Ignore the source version, of course.
+ if(*vi == source_version)
+ continue;
+
+ typename std::map<version, dep>::const_iterator fi = s.get_forbidden_versions().find(*vi);
+ if(fi != s.get_forbidden_versions().end())
+ {
+ // Whoops, it was forbidden in the past.
+ partial_conflict[fi->first.get_package()]
+ = act_conflict(fi->first, fi->second);
+
+ continue;
+ }
+
+ fi = toforbid.find(*vi);
+ if(fi != toforbid.end())
+ {
+ partial_conflict[fi->first.get_package()]
+ = act_conflict(fi->first, fi->second);
+
+ continue;
+ }
+
+ // If there's not essential conflict, check for a
+ // higher-order conflict.
+ typename std::set<std::map<package, act_conflict> >::const_iterator
+ found_conflict = will_conflict(s, act_conflict(*vi, d));
+ if(found_conflict != conflicts.end())
+ {
+ // Insert the elements of the new conflict other than
+ // the one that was speculatively inserted.
+ for(typename std::map<package, act_conflict>::const_iterator
+ fci = found_conflict->begin();
+ fci != found_conflict->end(); ++fci)
+ {
+ if(fci->first != (*vi).get_package())
+ partial_conflict.insert(*fci);
+ }
+ continue;
+ }
+
+ // If we already found a legal solver, then we now know
+ // that we can't force this dep and it's certainly not an
+ // essential conflict.
+ if(found)
+ return false;
+
+ found = true;
+ from_source = true;
+ v = *vi;
+ }
}
+ else
+ // If the source of the dependency was already installed, the
+ // conflict explanation for not being able to remove it is
+ // itself!
+ partial_conflict[source_package] = act_conflict(source_version);
- for(typename dep::solver_iterator si=d.solvers_begin();
+ for(typename dep::solver_iterator si = d.solvers_begin();
!si.end(); ++si)
{
- version sol_ver=*si;
+ version sol_ver = *si;
- if(sol_ver != sol_ver.get_package().current_version() &&
- s.get_actions().find(sol_ver.get_package())==s.get_actions().end() &&
- s.get_forbidden_versions().find(sol_ver) == s.get_forbidden_versions().end() &&
- toforbid.find(sol_ver)==toforbid.end())
+ // If the package has already been modified, don't modify it
+ // again.
+ typename std::map<package, action>::const_iterator ai
+ = s.get_actions().find(sol_ver.get_package());
+ if(ai != s.get_actions().end())
+ {
+ typename std::map<package, act_conflict>::iterator pci
+ = partial_conflict.find(ai->first);
+
+ if(pci != partial_conflict.end())
+ {
+ // The partial conflict must contain only stuff
+ // that's already in this solution.
+ assert(pci->second.ver == ai->second.ver);
+
+ // Make sure that this is an expansive conflictor.
+ pci->second.from_dep_source = false;
+ }
+ else
+ partial_conflict[ai->first] = ai->second.ver;
+
+ continue;
+ }
+
+ // Since we assume the dep is broken, this shouldn't happen!
+ assert(sol_ver != sol_ver.get_package().current_version());
+
+ typename std::map<version, dep>::const_iterator fi = s.get_forbidden_versions().find(*si);
+ if(fi != s.get_forbidden_versions().end())
{
- if(found)
- return false;
- found=true;
- v=sol_ver;
+ // Whoops, it was forbidden in the past.
+ partial_conflict[fi->first.get_package()]
+ = act_conflict(fi->first, fi->second);
+
+ continue;
+ }
+
+ fi = toforbid.find(*si);
+ if(fi != toforbid.end())
+ {
+ partial_conflict[fi->first.get_package()]
+ = act_conflict(fi->first, fi->second);
+
+ continue;
+ }
+
+ // If there's not essential conflict, check for a
+ // higher-order conflict.
+ typename std::set<std::map<package, act_conflict> >::const_iterator
+ found_conflict = will_conflict(s, act_conflict(*si));
+ if(found_conflict != conflicts.end())
+ {
+ // Insert the elements of the new conflict other than
+ // the one that was speculatively inserted.
+ for(typename std::map<package, act_conflict>::const_iterator
+ fci = found_conflict->begin();
+ fci != found_conflict->end(); ++fci)
+ {
+ if(fci->first != (*si).get_package())
+ partial_conflict.insert(*fci);
+ }
+
+ partial_conflict.insert(found_conflict->begin(),
+ found_conflict->end());
+ continue;
}
+
+ if(found)
+ return false;
+ found=true;
+ v=sol_ver;
}
if(found)
@@ -1741,7 +1893,15 @@
else
{
if(debug)
- std::cout << "Discarding solution: unsolvable dependency " << d << std::endl;
+ {
+ std::cout << "Discarding solution: unsolvable dependency " << d
+ << " with new conflict ";
+ dump(std::cout, partial_conflict);
+
+ std::cout << std::endl;
+
+ conflicts.insert(partial_conflict);
+ }
return true;
}
@@ -2200,5 +2360,58 @@
}
};
+template<class PackageUniverse>
+inline
+std::ostream &operator<<(std::ostream &out, const typename std::map<typename PackageUniverse::package, typename generic_problem_resolver<PackageUniverse>::act_conflict> &ac)
+{
+ out << "(";
+
+ for(typename std::map<typename PackageUniverse::package, typename generic_problem_resolver<PackageUniverse>::act_conflict>::const_iterator ci
+ = ac.begin(); ci != ac.end(); ++ci)
+ {
+ if(ci != ci->begin())
+ out << ", ";
+ out << ci->first.name() << " "
+ << ci->second.ver.name();
+
+ if(ci->second.from_dep_source)
+ out << " [" << ci->second.d << "]";
+ }
+
+ out << ")";
+
+ return out;
+}
+
+template<class PackageUniverse>
+std::ostream &generic_problem_resolver<PackageUniverse>::dump(std::ostream &out, const typename generic_problem_resolver<PackageUniverse>::act_conflict &act) const
+{
+ out << act.ver.get_package().get_name() << " "
+ << act.ver.get_name();
+
+ if(act.from_dep_source)
+ out << " [" << act.d << "]";
+
+ return out;
+}
+
+template<class PackageUniverse>
+std::ostream &generic_problem_resolver<PackageUniverse>::dump(std::ostream &out, const typename std::map<typename PackageUniverse::package, typename generic_problem_resolver<PackageUniverse>::act_conflict> &act) const
+{
+ out << "(";
+
+ for(typename std::map<typename PackageUniverse::package, typename generic_problem_resolver<PackageUniverse>::act_conflict>::const_iterator ci
+ = act.begin(); ci != act.end(); ++ci)
+ {
+ if(ci != act.begin())
+ out << ", ";
+
+ dump(out, ci->second);
+ }
+
+ out << ")";
+
+ return out;
+}
#endif
More information about the Aptitude-svn-commit
mailing list