[Aptitude-svn-commit] r3836 - in branches/aptitude-0.3/aptitude: . src/generic src/generic/problemresolver

Daniel Burrows dburrows at costa.debian.org
Sat Aug 13 00:57:16 UTC 2005


Author: dburrows
Date: Sat Aug 13 00:57:11 2005
New Revision: 3836

Modified:
   branches/aptitude-0.3/aptitude/ChangeLog
   branches/aptitude-0.3/aptitude/src/generic/aptcache.cc
   branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver.cc
   branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver.h
   branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver_universe.h
   branches/aptitude-0.3/aptitude/src/generic/problemresolver/dump_universe.h
   branches/aptitude-0.3/aptitude/src/generic/problemresolver/problemresolver.h
   branches/aptitude-0.3/aptitude/src/generic/problemresolver/solution.h
   branches/aptitude-0.3/aptitude/src/generic/problemresolver/test.cc
Log:
Initial work on handling soft dependencies (untested).

Modified: branches/aptitude-0.3/aptitude/ChangeLog
==============================================================================
--- branches/aptitude-0.3/aptitude/ChangeLog	(original)
+++ branches/aptitude-0.3/aptitude/ChangeLog	Sat Aug 13 00:57:11 2005
@@ -1,5 +1,10 @@
 2005-08-12  Daniel Burrows  <dburrows at debian.org>
 
+	* src/generic/aptcache.cc, src/generic/aptitude_resolver_universe.h, src/generic/aptitude_resolver.cc, src/generic/aptitude_resolver.h, src/generic/problemresolver/dump_universe.h, src/generic/problemresolver/problemresolver.h, src/generic/problemresolver/solution.h, src/generic/problemresolver/test.cc:
+
+	  Add basic support for "soft dependencies" (i.e., recommends) to
+	  the resolver.
+
 	* src/generic/aptcache.cc:
 
 	  Don't try so hard to avoid keeping or upgrading packages, try a

Modified: branches/aptitude-0.3/aptitude/src/generic/aptcache.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/aptcache.cc	(original)
+++ branches/aptitude-0.3/aptitude/src/generic/aptcache.cc	Sat Aug 13 00:57:11 2005
@@ -1352,6 +1352,7 @@
 
   resolver=new aptitude_resolver(aptcfg->FindI(PACKAGE "::ProblemResolver::StepScore", -10),
 				 aptcfg->FindI(PACKAGE "::ProblemResolver::BrokenScore", -100),
+				 aptcfg->FindI(PACKAGE "::ProblemResolver::UnfixedSoftScore", -10000),
 				 aptcfg->FindI(PACKAGE "::ProblemResolver::Infinity", 1000000),
 				 aptcfg->FindI(PACKAGE "::ProblemResolver::Max-Successors", 0),
 				 aptcfg->FindI(PACKAGE "::ProblemResolver::ResolutionScore", 50),

Modified: branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver.cc	(original)
+++ branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver.cc	Sat Aug 13 00:57:11 2005
@@ -21,13 +21,14 @@
 
 #include "config_signal.h"
 
-aptitude_resolver::aptitude_resolver(int step_penalty,
-				     int broken_penalty,
+aptitude_resolver::aptitude_resolver(int step_score,
+				     int broken_score,
+				     int unfixed_soft_score,
 				     int infinity,
 				     int max_successors,
 				     int resolution_score,
 				     aptitudeDepCache *cache)
-  :generic_problem_resolver<aptitude_universe>(step_penalty, broken_penalty, infinity, max_successors, resolution_score, aptitude_universe(cache))
+  :generic_problem_resolver<aptitude_universe>(step_score, broken_score, unfixed_soft_score, infinity, max_successors, resolution_score, aptitude_universe(cache))
 {
   set_remove_stupid(aptcfg->FindB(PACKAGE "::ProblemResolver::Remove-Stupid-Pairs", true));
 }

Modified: branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver.h	(original)
+++ branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver.h	Sat Aug 13 00:57:11 2005
@@ -45,6 +45,7 @@
 {
 public:
   aptitude_resolver(int step_score, int broken_score,
+		    int unfixed_soft_score,
 		    int infinity, int max_successors,
 		    int resolution_score,
 		    aptitudeDepCache *cache);

Modified: branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver_universe.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver_universe.h	(original)
+++ branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver_universe.h	Sat Aug 13 00:57:11 2005
@@ -31,6 +31,13 @@
 
 class aptitude_resolver_version;
 
+// This should be a static member of the universe object, but it's
+// rather awkward to put it there right now.
+inline bool aptitude_universe_is_interesting_dep(const pkgCache::DepIterator &d)
+{
+  return (*apt_cache_file)->IsImportantDep(d);
+}
+
 /** Wraps a PkgIterator for the resolver. */
 class aptitude_resolver_package
 {
@@ -260,6 +267,11 @@
       start=dep;
   }
 
+  bool is_soft() const
+  {
+    return start->Type == pkgCache::Dep::Recommends;
+  }
+
   bool operator==(const aptitude_resolver_dep &other) const
   {
     return start == other.start && prv == other.prv;
@@ -393,7 +405,7 @@
   void normalize()
   {
     while(!dep_lst.end() &&
-	  (!dep_lst.IsCritical() || !applicable()))
+	  (!aptitude_universe_is_interesting_dep(dep_lst) || !applicable()))
       ++dep_lst;
 
     if(dep_lst.end() && !provides_open)
@@ -404,7 +416,7 @@
 	  {
 	    dep_lst=prv_lst.ParentPkg().RevDependsList();
 	    while(!dep_lst.end() &&
-		  (!dep_lst.IsCritical() || !applicable()))
+		  (!aptitude_universe_is_interesting_dep(dep_lst) || !applicable()))
 	      ++dep_lst;
 	  }
 	provides_open=true;
@@ -422,7 +434,7 @@
 	    dep_lst=prv_lst.ParentPkg().RevDependsList();
 
 	    while(!dep_lst.end() &&
-		  (!dep_lst.IsCritical() || !applicable()))
+		  (!aptitude_universe_is_interesting_dep(dep_lst) || !applicable()))
 	      ++dep_lst;
 	  }
       }
@@ -433,7 +445,7 @@
    */
   bool applicable() const
   {
-    if(!const_cast<pkgCache::DepIterator &>(dep_lst).IsCritical())
+    if(!aptitude_universe_is_interesting_dep(dep_lst))
       return false;
 
     // Unversioned deps always apply.
@@ -547,7 +559,7 @@
     // dependency.
     while(!dep.end() &&
 	  (dep.ParentPkg() == dep.TargetPkg() ||
-	   !dep.IsCritical()))
+	   !aptitude_universe_is_interesting_dep(dep)))
       ++dep;
 
     // If we ran out of deps, we're done!
@@ -1158,7 +1170,7 @@
     void normalize()
     {
       while(!the_dep.end() &&
-	    !(the_dep.IsCritical() &&
+	    !(aptitude_universe_is_interesting_dep(the_dep) &&
 	      dep_is_inst_broken(the_dep)))
 	++the_dep;
 
@@ -1180,7 +1192,7 @@
 		the_dep=ver.DependsList();
 
 	      while(!the_dep.end() &&
-		    !(the_dep.IsCritical() &&
+		    !(aptitude_universe_is_interesting_dep(the_dep) &&
 		      dep_is_inst_broken(the_dep)))
 		++the_dep;
 
@@ -1189,7 +1201,7 @@
 	    }
 	}
 
-      assert(the_dep.end() || the_dep.IsCritical());
+      assert(the_dep.end() || aptitude_universe_is_interesting_dep(the_dep));
 
       // Now dep is a broken critical dep or an end dep.  If it is a
       // conflicts, we might need to push down into Provides...

Modified: branches/aptitude-0.3/aptitude/src/generic/problemresolver/dump_universe.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/problemresolver/dump_universe.h	(original)
+++ branches/aptitude-0.3/aptitude/src/generic/problemresolver/dump_universe.h	Sat Aug 13 00:57:11 2005
@@ -42,7 +42,12 @@
       const typename PackageUniverse::version &sv=(*d).get_source();
       const typename PackageUniverse::package &sp=sv.get_package();
 
-      out << "  DEP " << sp.get_name() << " " << sv.get_name() << " -> < ";
+      if((*d).is_soft())
+	out << "SOFTDEP ";
+      else
+	out << "  DEP ";
+
+      out << sp.get_name() << " " << sv.get_name() << " -> < ";
 
       for(typename PackageUniverse::dep::solver_iterator t=(*d).solvers_begin();
 	  !t.end(); ++t)

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 13 00:57:11 2005
@@ -206,7 +206,7 @@
   /** How much to reward long and/or broken solutions.  Typically
    *  negative to penalize such things, or 0 to ignore them.
    */
-  int step_score, broken_score;
+  int step_score, broken_score, unfixed_soft_score;
 
   /** Solutions whose score is smaller than this value will be
    *  discarded rather than being enqueued.
@@ -410,12 +410,17 @@
 		      const version &v,
 		      dep &d)
   {
+    // Don't flag an error if a dep that's SUPPOSED to be unresolved
+    // gets broken.
+    const std::set<dep> &ignore_deps = s.get_unresolved_soft_deps();
+
     drop_package dropped(s, v.get_package());
 
     version curr = v.get_package().current_version();
     for(typename version::revdep_iterator i = curr.revdeps_begin();
 	!i.end(); ++i)
-      if((*i).broken_under(dropped))
+      if(ignore_deps.find(*i) == ignore_deps.end() &&
+	 (*i).broken_under(dropped))
 	{
 	  d = *i;
 	  return true;
@@ -423,7 +428,8 @@
 
     for(typename version::revdep_iterator i = curr.revdeps_begin();
 	!i.end(); ++i)
-      if((*i).broken_under(dropped))
+      if(ignore_deps.find(*i) == ignore_deps.end() &&
+	 (*i).broken_under(dropped))
 	{
 	  d = *i;
 	  return true;
@@ -431,7 +437,8 @@
 
     for(typename version::dep_iterator i = curr.deps_begin();
 	!i.end(); ++i)
-      if((*i).broken_under(dropped))
+      if(ignore_deps.find(*i) == ignore_deps.end() &&
+	 (*i).broken_under(dropped))
 	{
 	  d = *i;
 	  return true;
@@ -663,11 +670,20 @@
   /** Calculate a new set of broken dependencies given an a starting
    *  solution object, old set of broken dependencies and a range of
    *  versions to install.
+   *
+   *  \param s the starting package -> version map
+   *  \param vbegin the start of the range of versions to install
+   *  \param vend the end of the range of versions to install
+   *  \param unresolved_soft_deps a set of soft dependencies to ignore
+   *  \param old_broken the old set of broken dependencies
+   *  \param new_broken a set into which the newly broken dependencies
+   *                    should be inserted.
    */
   template<typename VerIter, typename SolutionType>
   void update_broken(const SolutionType &s,
 		     const VerIter &vbegin,
 		     const VerIter &vend,
+		     const std::set<dep> &unresolved_soft_deps,
 		     const std::set<dep> &old_broken,
 		     std::set<dep> &new_broken)
   {
@@ -706,25 +722,29 @@
 	// Check reverse deps of the old version
 	for(typename version::revdep_iterator rd=old_version.revdeps_begin();
 	    !rd.end(); ++rd)
-	  if((*rd).broken_under(tmpsol))
+	  if(unresolved_soft_deps.find(*rd) == unresolved_soft_deps.end() &&
+	     (*rd).broken_under(tmpsol))
 	    new_broken.insert(*rd);
 
 	// Check reverse deps of the new version
 	for(typename version::revdep_iterator rd=v.revdeps_begin();
 	    !rd.end(); ++rd)
-	  if((*rd).broken_under(tmpsol))
+	  if(unresolved_soft_deps.find(*rd) == unresolved_soft_deps.end() &&
+	     (*rd).broken_under(tmpsol))
 	    new_broken.insert(*rd);
 
 	// Check forward deps of the new version
 	for(typename version::dep_iterator di=v.deps_begin();
 	    !di.end(); ++di)
-	  if((*di).broken_under(tmpsol))
+	  if(unresolved_soft_deps.find(*di) == unresolved_soft_deps.end() &&
+	     (*di).broken_under(tmpsol))
 	    new_broken.insert(*di);
       }
 
     for(typename std::set<dep>::const_iterator bd=old_broken.begin();
 	bd!=old_broken.end(); ++bd)
-      if((*bd).broken_under(tmpsol))
+      if(unresolved_soft_deps.find(*bd) == unresolved_soft_deps.end() &&
+	 (*bd).broken_under(tmpsol))
 	new_broken.insert(*bd);
   }
 
@@ -735,11 +755,21 @@
    *  extreme in its approach.  As usual, no effort is made to avoid
    *  stupid pairs.
    *
+   *  \param actions the set of actions to apply
+   *
+   *  \param unresolved_soft_deps a set of broken dependencies which
+   *                             are permitted (indeed, required?)
+   *                             to be broken at the end of the process.
+   *
+   *  \param forbidden_iter an iterator over the list of versions that
+   *  should be forbidden in the new solution.
+   *
    *  \return a solution containing only the actions which appear to
    *  be necessary.
    */
   template<typename forbid_iter>
   solution filter_unnecessary_actions(const std::vector<action> &actions,
+				      const std::set<dep> &unresolved_soft_deps,
 				      const forbid_iter &forbidden_iter)
   {
     // Versions from which to choose.
@@ -763,6 +793,10 @@
 	dep d = *broken_deps.begin();
 	broken_deps.erase(broken_deps.begin());
 
+	// If it's to be ignored, just drop it on the floor.
+	if(unresolved_soft_deps.find(d) != unresolved_soft_deps.end())
+	  continue;
+
 	// Now, pick an "arbitrary" resolver of this dep.
 	//
 	// (maybe pick the best-scored one that's available instead?)
@@ -801,6 +835,7 @@
 	update_broken(partial_solution<map_solution>(output_actions),
 		      project_ver(&act),
 		      project_ver((&act)+1),
+		      unresolved_soft_deps,
 		      broken_deps,
 		      new_broken);
 
@@ -819,6 +854,7 @@
 
     return solution(project_iter_2nd(output_actions.begin()),
 		    project_iter_2nd(output_actions.end()),
+		    unresolved_soft_deps,
 		    broken_deps,
 		    forbidden_iter,
 		    score,
@@ -833,7 +869,7 @@
    */
   solution eliminate_stupid(const solution &s)
   {
-    assert(s.get_broken().begin() == s.get_broken().end());
+    assert(s.get_broken().empty());
 
     stupid_table stupid_pairs;
 
@@ -915,6 +951,7 @@
 			      repl_action);
 
 	    rval = solution(swbegin, swend,
+			    rval.get_unresolved_soft_deps(),
 			    rval.get_broken(),
 			    apt_iter_wrapper(rval.get_forbidden_versions().begin(),
 					     rval.get_forbidden_versions().end()),
@@ -945,6 +982,7 @@
 	      }
 
 	    rval = filter_unnecessary_actions(actions,
+					      rval.get_unresolved_soft_deps(),
 					      apt_iter_wrapper(rval.get_forbidden_versions().begin(),
 							       rval.get_forbidden_versions().end()));
 	  }
@@ -966,7 +1004,7 @@
 	  }
       }
 
-    assert(rval.get_broken().begin() == rval.get_broken().end());
+    assert(rval.get_broken().empty());
 
     return rval;
   }
@@ -1060,11 +1098,12 @@
   }
 
   /** Generates a successor to s by performing the actions
-   *  [abegin,aend).
+   *  [abegin,aend) and ignoring the (soft) deps [ubegin,uend).
    */
-  template<class forbid_iter, class a_iter>
+  template<class forbid_iter, class a_iter, class u_iter>
   solution do_install(const solution &s,
 		      const a_iter &abegin, const a_iter &aend,
+		      const u_iter &ubegin, const u_iter &uend,
 		      const forbid_iter &forbidden_iter)
   {
     int new_action_score=s.get_action_score();
@@ -1087,62 +1126,58 @@
 
 
     std::set<dep> new_broken;
+    std::set<dep> new_unresolved_soft(s.get_unresolved_soft_deps());
+    new_unresolved_soft.insert(ubegin, uend);
     update_broken(s, project_ver(abegin),
 		  project_ver(aend),
+		  new_unresolved_soft,
 		  s.get_broken(),
 		  new_broken);
 
+    for(u_iter u = ubegin; u != uend; ++u)
+      new_broken.erase(*u);
 
-    int new_score=new_action_score+broken_score*new_broken.size();
+    int new_score=new_action_score + broken_score * new_broken.size()
+      + unfixed_soft_score * new_unresolved_soft.size();
 
     if(new_broken.size() == 0)
       new_score+=full_solution_score;
 
     return solution(abegin, aend, s,
+		    ubegin, uend,
 		    new_broken,
 		    forbidden_iter,
 		    new_score,
 		    new_action_score);
   }
 
-  /** Enqueues a single successor node to the given solution by
-   *  installing the given package versions.
-   *
-   *  \param s the predecessor of the new solution
-   *  \param v the version to install
-   *  \param forbidden_iter an APT-style iterator over a set
-   *  of versions that should be forbidden.
+  /** Tries to enqueue the given package.
    *
-   *  \return \b true if the new solution was not in the closed set.
+   *  \return \b true if the solution was not irrelevant.
    */
-  template<class forbid_iter, class action_iter>
-  bool try_install(const solution &s,
-		   const action_iter &abegin, const action_iter &aend,
-		   const forbid_iter &forbidden_iter)
+  bool try_enqueue(const solution &s)
   {
-    solution s2=do_install(s, abegin, aend, forbidden_iter);
-
-    if(irrelevant(s2))
+    if(irrelevant(s))
       {
 	if(debug)
 	  {
 	    std::cout << "Dropping irrelevant solution ";
-	    s2.dump(std::cout);
+	    s.dump(std::cout);
 	    std::cout << std::endl;
 	  }
 
 	return false;
       }
-    else if(is_rejected(s2))
+    else if(is_rejected(s))
       {
 	if(debug)
 	  {
 	    std::cout << "Deferring rejected solution ";
-	    s2.dump(std::cout);
+	    s.dump(std::cout);
 	    std::cout << std::endl;
 	  }
 
-	deferred.insert(s2);
+	deferred.insert(s);
 	return false;
       }
     else
@@ -1150,16 +1185,37 @@
 	if(debug)
 	  {
 	    std::cout << "Enqueuing ";
-	    s2.dump(std::cout);
+	    s.dump(std::cout);
 	    std::cout << std::endl;
 	  }
 
-	open.push(s2);
+	open.push(s);
 
 	return true;
       }
   }
 
+  /** Enqueues a single successor node to the given solution by
+   *  installing the given package versions.
+   *
+   *  \param s the predecessor of the new solution
+   *  \param v the version to install
+   *  \param forbidden_iter an APT-style iterator over a set
+   *  of versions that should be forbidden.
+   *
+   *  \return \b true if the new solution was not in the closed set.
+   */
+  template<class forbid_iter, class action_iter, class unresolved_iter>
+  bool try_install(const solution &s,
+		   const action_iter &abegin, const action_iter &aend,
+		   const unresolved_iter &ubegin, const unresolved_iter &uend,
+		   const forbid_iter &forbidden_iter)
+  {
+    solution s2=do_install(s, abegin, aend, ubegin, uend,
+			   forbidden_iter);
+    return try_enqueue(s2);
+  }
+
   /** Generates (and enqueues) successor nodes for the given broken
    *  dependency of the given solution.
    *
@@ -1221,7 +1277,8 @@
 		std::cout << "  Trying to resolve " << d << " by installing " << (*vi).get_package().get_name() << " version " << (*vi).get_name() << std::endl;
 
 	      action act(*vi, d, s.get_actions().size());
-	      if(try_install(s, &act, (&act)+1, d.solvers_begin()))
+	      if(try_install(s, &act, (&act)+1,
+			     (dep*)0, (dep*)0, d.solvers_begin()))
 		++count;
 	    }
       }
@@ -1253,10 +1310,27 @@
 	      std::cout << "  Trying to resolve " << d << " by installing " << (*si).get_package().get_name() << " version " << (*si).get_name() << std::endl;
 
 	    action act(*si, d, s.get_actions().size());
-	    if(try_install(s, &act, (&act)+1, dummy_end_iterator<version>()))
+	    if(try_install(s, &act, (&act)+1,
+			   (dep*)0, (dep*)0,
+			   dummy_end_iterator<version>()))
 	      ++count;
 	  }
       }
+
+    // For soft dependencies, we can optionally leave the dependency
+    // unresolved!
+    if(d.is_soft())
+      {
+	std::cout << "  Trying to ignore soft dependency " << d
+		  << std::endl;
+
+	// Only score change is that something goes from being broken
+	// to being permanently unfixed and "soft".
+	if(try_enqueue(solution(s, d,
+				s.get_score() - broken_score,
+				s.get_action_score() + unfixed_soft_score)))
+	  ++count;
+      }
   }
 
   /** Generate "forced" successors -- those successors which are
@@ -1277,7 +1351,8 @@
   bool generate_forced_successor(const solution &s,
 				 const dep &d,
 				 std::set<action> &actions,
-				 std::set<version> &toforbid)
+				 std::set<version> &toforbid,
+				 std::set<dep> &toignore)
   {
     version v;
     version source_version=d.get_source();
@@ -1330,6 +1405,11 @@
 
     if(found)
       {
+	// Soft dependencies shouldn't be forced, as you have the
+	// option of discarding them.
+	if(d.is_soft())
+	  return true;
+
 	if(debug)
 	    std::cout << "Forced resolution of " << d
 		      << " by installing " << v.get_package().get_name()
@@ -1346,10 +1426,25 @@
       }
     else
       {
-	if(debug)
-	  std::cout << "Discarding solution: unsolvable dependency " << d << std::endl;
+	// If there really is no choice, then soft deps can be left
+	// unresolved.
+	if(d.is_soft())
+	  {
+	    if(debug)
+	      std::cout << "Forced soft dependency " << d
+			<< " to be left unresolved." << std::endl;
 
-	return true;
+	    toignore.insert(d);
+
+	    return false;
+	  }
+	else
+	  {
+	    if(debug)
+	      std::cout << "Discarding solution: unsolvable dependency " << d << std::endl;
+
+	    return true;
+	  }
       }
   }
 
@@ -1363,19 +1458,22 @@
 
     std::set<action> forced_actions;
     std::set<version> forced_forbidden_versions;
+    std::set<dep> forced_unresolved_soft_deps;
 
 
     for(typename std::set<dep>::const_iterator bi=s.get_broken().begin();
 	bi!=s.get_broken().end(); ++bi)
       if(generate_forced_successor(s, *bi,
 				   forced_actions,
-				   forced_forbidden_versions))
+				   forced_forbidden_versions,
+				   forced_unresolved_soft_deps))
 	return;
 
-    if(!forced_actions.empty())
+    if(!forced_actions.empty() || !forced_unresolved_soft_deps.empty())
       {
 	try_install(s,
 		    forced_actions.begin(), forced_actions.end(),
+		    forced_unresolved_soft_deps.begin(), forced_unresolved_soft_deps.end(),
 		    apt_iter_wrapper(forced_forbidden_versions.begin(), forced_forbidden_versions.end()));
 	return;
       }
@@ -1390,6 +1488,7 @@
    *
    *  \param _score_score the score per "step" of a (partial) solution.  Typically negative.
    *  \param _broken_score the score to add per broken dependency of a (partial) solution.  Typically negative.
+   *  \param _unfixed_soft_score the score to add per soft dependency LEFT UNFIXED.  Typically negative.
    *  \param infinity a score value that will be considered to be "infinite".  Solutions
    *  with less than -infinity points will be immediately discarded.
    *  \param _full_solution_score a bonus for goal nodes (things
@@ -1397,10 +1496,12 @@
    *  \param _universe the universe in which we are working.
    */
   generic_problem_resolver(int _step_score, int _broken_score,
+			   int _unfixed_soft_score,
 			   int infinity, unsigned int _max_successors,
 			   int _full_solution_score,
 			   const PackageUniverse &_universe)
     :step_score(_step_score), broken_score(_broken_score),
+     unfixed_soft_score(_unfixed_soft_score),
      minimum_score(-infinity), max_successors(_max_successors),
      full_solution_score(_full_solution_score),
      universe(_universe), finished(false), rejections_dirty(false), debug(false), remove_stupid(true)
@@ -1427,6 +1528,7 @@
 
   int get_step_score() {return step_score;}
   int get_broken_score() {return broken_score;}
+  int get_unresolved_soft_dep_score() {return unfixed_soft_score;}
   int get_infinity() {return -minimum_score;}
   int get_max_successors() {return max_successors;}
   int get_full_solution_score() {return full_solution_score;}
@@ -1609,7 +1711,7 @@
 	  }
 
 	// If all dependencies are satisfied, we found a solution.
-	if(s.get_broken().empty())
+	if(s.is_full_solution())
 	  {
 	    if(debug)
 	      {

Modified: branches/aptitude-0.3/aptitude/src/generic/problemresolver/solution.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/problemresolver/solution.h	(original)
+++ branches/aptitude-0.3/aptitude/src/generic/problemresolver/solution.h	Sat Aug 13 00:57:11 2005
@@ -29,6 +29,11 @@
 /** Represents a partial or complete solution to a dependency
  *  problem.  Solutions are transparently refcounted to save on
  *  memory and avoid copies.
+ *
+ *  Solution identity is based on both the mapping stored in the
+ *  solution and on the set of unfixed soft dependencies stored in it.
+ *  Dependencies in unfixed_soft_deps are removed from broken_deps so
+ *  it's easy to check whether a solution is complete.
  */
 template<class PackageUniverse>
 class generic_solution
@@ -83,6 +88,9 @@
     /** The full list of currently broken dependencies. */
     std::set<dep> broken_deps;
 
+    /** The set of soft dependencies being left unresolved. */
+    std::set<dep> unresolved_soft_deps;
+
     /** A set of versions that have been "locked out" by this
      *	solution.  Primarily used to optimize the common case of
      *	having to "climb a hill" as removals propagate up the
@@ -107,6 +115,24 @@
     void incref() const {++refcount;}
     void decref() const {assert(refcount>0); if(--refcount==0) delete this;}
 
+    /** Construct a new solution_rep by taking the given solution and
+     *  moving a single dependency into the set of unresolved soft
+     *  deps.
+     */
+    solution_rep(const generic_solution &parent,
+		 const dep &ignore,
+		 int _score, int _action_score)
+      :actions(parent.get_actions()),
+       broken_deps(parent.get_broken()),
+       unresolved_soft_deps(parent.get_unresolved_soft_deps()),
+       score(_score), action_score(_action_score), refcount(1)
+    {
+      assert(broken_deps.find(ignore) != broken_deps.end());
+
+      broken_deps.erase(ignore);
+      unresolved_soft_deps.erase(ignore);
+    }
+
     /** Construct a new solution_rep.  The initial reference count
      *  is \b 1.
      *
@@ -118,14 +144,17 @@
      *         newly forbidden versions
      *  \param _action_score the score not due to broken deps
      */
-    template<class forbid_iter, class action_iter>
+    template<class forbid_iter, class action_iter, class unresolved_iter>
     solution_rep(const action_iter &abegin,
 		 const action_iter &aend,
 		 const generic_solution &parent,
+		 const unresolved_iter &ubegin,
+		 const unresolved_iter &uend,
 		 const std::set<dep> &_broken_deps,
 		 const forbid_iter &forbidden_iter,
 		 int _score, int _action_score)
       :actions(parent.get_actions()), broken_deps(_broken_deps),
+       unresolved_soft_deps(parent.get_unresolved_soft_deps()),
        score(_score), action_score(_action_score),
        refcount(1)
     {
@@ -137,6 +166,12 @@
 	  assert(actions.find(a->ver.get_package()) == actions.end());
 	  actions[a->ver.get_package()] = *a;
 	}
+
+      for(unresolved_iter u = ubegin; u != uend; ++u)
+	{
+	  assert(broken_deps.find(*u) == broken_deps.end());
+	  unresolved_soft_deps.insert(*u);
+	}
     }
 
     /** Construct a new solution_rep.  The initial reference count is
@@ -153,10 +188,12 @@
     template<class forbid_iter, class action_iter>
     solution_rep(const action_iter &abegin,
 		 const action_iter &aend,
+		 const std::set<dep> &_unresolved_soft_deps,
 		 const std::set<dep> &_broken_deps,
 		 const forbid_iter &forbidden_iter,
 		 int _score, int _action_score)
       :broken_deps(_broken_deps),
+       unresolved_soft_deps(_unresolved_soft_deps),
        score(_score), action_score(_action_score),
        refcount(1)
     {
@@ -186,9 +223,9 @@
       return broken_deps;
     }
 
-    std::set<dep> &get_broken_deps()
+    const std::set<dep> &get_unresolved_soft_deps() const
     {
-      return broken_deps;
+      return unresolved_soft_deps;
     }
 
     const std::map<package, action> &get_actions() const
@@ -224,6 +261,14 @@
 public:
   generic_solution():real_soln(0) {}
 
+  /** Create a solution. */
+  generic_solution(const generic_solution &parent,
+		   const dep &ignore,
+		   int score, int action_score)
+    :real_soln(new solution_rep(parent, ignore, score, action_score))
+  {
+  }
+
   /** Create a solution.
    *
    * \param [abegin,aend) the new actions to enqueue
@@ -237,17 +282,18 @@
    *
    * \param action_score the portion of score due to actions
    */
-  template<class forbid_iter, class action_iter>
+  template<class forbid_iter, class action_iter, class unresolved_iter>
   generic_solution(const action_iter &abegin,
 		   const action_iter &aend,
 		   const generic_solution &parent,
+		   const unresolved_iter &ubegin,
+		   const unresolved_iter &uend,
 		   const std::set<dep> &broken_deps,
 		   const forbid_iter &forbidden_iter,
 		   int score, int action_score)
-    :real_soln(new solution_rep(abegin, aend,
-				parent, broken_deps,
-				forbidden_iter,
-				score, action_score))
+    :real_soln(new solution_rep(abegin, aend, parent,
+				ubegin, uend, broken_deps,
+				forbidden_iter, score, action_score))
   {
   }
 
@@ -265,10 +311,12 @@
   template<class forbid_iter, class action_iter>
   generic_solution(const action_iter &abegin,
 		   const action_iter &aend,
+		   const std::set<dep> &unresolved_soft_deps,
 		   const std::set<dep> &broken_deps,
 		   const forbid_iter &forbidden_iter,
 		   int score, int action_score)
     :real_soln(new solution_rep(abegin, aend,
+				unresolved_soft_deps,
 				broken_deps,
 				forbidden_iter,
 				score, action_score))
@@ -362,6 +410,11 @@
     return real_soln->get_broken_deps();
   }
 
+  const std::set<dep> &get_unresolved_soft_deps() const
+  {
+    return real_soln->get_unresolved_soft_deps();
+  }
+
   const std::map<package, action> &get_actions() const
   {
     return real_soln->get_actions();
@@ -372,6 +425,11 @@
     return real_soln->get_forbidden_versions();
   }
 
+  bool is_full_solution() const
+  {
+    return get_broken().empty();
+  }
+
   /** \return the score of the scolution */
   int get_score() const
   {
@@ -406,6 +464,20 @@
       }
     out << ">;[";
 
+
+    if(!get_unresolved_soft_deps().empty())
+      {
+	out << "<!";
+	for(typename std::set<dep>::const_iterator i
+	      = get_unresolved_soft_deps().begin();
+	    i != get_unresolved_soft_deps().end(); ++i)
+	  {
+	    if(i != get_unresolved_soft_deps().begin())
+	      out << ", ";
+	    out << *i;
+	  }
+      }
+
     for(typename std::set<dep>::const_iterator i=get_broken().begin();
 	i!=get_broken().end(); ++i)
       {

Modified: branches/aptitude-0.3/aptitude/src/generic/problemresolver/test.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/problemresolver/test.cc	(original)
+++ branches/aptitude-0.3/aptitude/src/generic/problemresolver/test.cc	Sat Aug 13 00:57:11 2005
@@ -261,14 +261,21 @@
   dummy_dep(const dummy_dep &other);
 
   unsigned int ID;
+
+  bool soft;
 public:
   typedef vector<dummy_version *>::const_iterator solver_iterator;
 
   dummy_dep(dummy_version *_source,
 	    const vector<dummy_version *> &_target_set,
-	    unsigned int _ID)
-    :source(_source), target_set(_target_set), ID(_ID)
+	    unsigned int _ID, bool _soft)
+    :source(_source), target_set(_target_set), ID(_ID), soft(_soft)
+  {
+  }
+
+  bool is_soft() const
   {
+    return soft;
   }
 
   bool operator==(const dummy_dep &other) const
@@ -449,6 +456,11 @@
 
     typedef wrap_ptr_iter<dummy_version, version> solver_iterator;
 
+    bool is_soft() const
+    {
+      return real_dep->is_soft();
+    }
+
     bool operator==(const dep &other) const
     {
       return real_dep==other.real_dep;
@@ -630,7 +642,7 @@
    */
   void add_dep(string pkg_name, string pkg_ver,
 	       const vector<pair<string, string> > &target_names,
-	       bool is_conflict)
+	       bool is_conflict, bool is_soft)
   {
     dummy_package *pkg=find_package_internal(pkg_name);
 
@@ -649,7 +661,8 @@
     if(!is_conflict)
       deps.push_back(new dummy_dep(pkg->version_from_name(pkg_ver),
 				   vector<dummy_version *>(targets.begin(), targets.end()),
-				   deps.size()));
+				   deps.size(),
+				   is_soft));
     else
       {
 	set<dummy_version *> targets2;
@@ -663,7 +676,8 @@
 
 	deps.push_back(new dummy_dep(pkg->version_from_name(pkg_ver),
 				     vector<dummy_version *>(targets2.begin(), targets2.end()),
-				     deps.size()));
+				     deps.size(),
+				     is_soft));
       }
 
     dummy_dep *newdep=deps.back();
@@ -779,10 +793,10 @@
 
   void add_dep(string pkg_name, string pkg_ver,
 	       const vector<pair<string, string> > &target_names,
-	       bool is_conflict)
+	       bool is_conflict, bool is_soft)
   {
     rep->universe->add_dep(pkg_name, pkg_ver,
-			   target_names, is_conflict);
+			   target_names, is_conflict, is_soft);
   }
 
   package find_package(string pkg_name) const
@@ -841,6 +855,7 @@
 // UNIVERSE ::= (PACKAGE | DEP) ...
 // PACKAGE ::= "PACKAGE" pkgname "<" vername1 ... ">" currentver
 // DEP ::= "DEP" pkgname1 vername1 "->" "<" pkgname2 vername2 ... ">"
+//       | "SOFTDEP" pkgname1 vername1 "->" "<" pkgname2 vername2 ... ">"
 //       | "DEP" pkgname1 vername1 "!!" "<" pkgname2 vername2 ... ">"
 //
 // TEST ::= "TEST" step_score broken_score "{" SCORE ... "}" "EXPECT" "(" SOLN ... ")"
@@ -939,10 +954,11 @@
 
 	  rval.add_package(pkgname, vernames, curname);
 	}
-      else if(s == "DEP")
+      else if(s == "DEP" || s == "SOFTDEP")
 	{
 	  pair<string, string> source=read_pkgverpair(in);
 	  bool is_conflict=false;
+	  bool is_soft = (s == "SOFTDEP");
 
 	  in >> s >> ws;
 
@@ -988,10 +1004,10 @@
 	    }
 
 	  rval.add_dep(source.first, source.second, targets,
-		       is_conflict);
+		       is_conflict, is_soft);
 	}
       else
-	throw ParseError("Expected PACKAGE or DEP, got "+s);
+	throw ParseError("Expected PACKAGE, DEP, or SOFTDEP, got "+s);
 
       if(in.eof())
 	throw ParseError("Expected ']' following universe declaration, got EOF.");
@@ -1167,17 +1183,18 @@
 
 	  int step_score;
 	  int broken_score;
+	  int unfixed_soft_score;
 	  int infinity;
 	  int max_successors;
 	  int goal_score;
 
-	  f >> step_score >> broken_score >> infinity >> max_successors >> goal_score;
+	  f >> step_score >> broken_score >> unfixed_soft_score >> infinity >> max_successors >> goal_score;
 
 	  if(f.eof())
 	    throw ParseError("Expected '{' following broken_score, got EOF");
 
 	  if(!f)
-	    throw ParseError("Error reading step_score, broken_score, infinity, max_succ, and goal_score after 'TEST'");
+	    throw ParseError("Error reading step_score, broken_score, unfixed_soft_score, infinity, max_succ, and goal_score after 'TEST'");
 
 	  f >> s >> ws;
 
@@ -1185,6 +1202,7 @@
 	    throw ParseError("Expected '{' following TEST, got "+s);
 
 	  dummy_resolver resolver(step_score, broken_score,
+				  unfixed_soft_score,
 				  infinity, max_successors,
 				  goal_score, universe);
 



More information about the Aptitude-svn-commit mailing list