[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