<feed xmlns='http://www.w3.org/2005/Atom'>
<title>apt/apt-pkg/solver3.h, branch 2.9.31</title>
<subtitle>Debians commandline package manager</subtitle>
<id>https://git.kalnischkies.de/apt/atom?h=2.9.31</id>
<link rel='self' href='https://git.kalnischkies.de/apt/atom?h=2.9.31'/>
<link rel='alternate' type='text/html' href='https://git.kalnischkies.de/apt/'/>
<updated>2025-02-15T15:54:38Z</updated>
<entry>
<title>Add missing #include &lt;memory&gt;</title>
<updated>2025-02-15T15:54:38Z</updated>
<author>
<name>Julian Andres Klode</name>
<email>julian.klode@canonical.com</email>
</author>
<published>2025-02-15T15:50:57Z</published>
<link rel='alternate' type='text/html' href='https://git.kalnischkies.de/apt/commit/?id=2614ff646e812e2d9515e6f0e7be076e97c9ec1a'/>
<id>urn:sha1:2614ff646e812e2d9515e6f0e7be076e97c9ec1a</id>
<content type='text'>
</content>
</entry>
<entry>
<title>solver3: Store clauses as the reasons for decisions</title>
<updated>2025-02-14T18:08:45Z</updated>
<author>
<name>Julian Andres Klode</name>
<email>julian.klode@canonical.com</email>
</author>
<published>2025-02-10T22:01:36Z</published>
<link rel='alternate' type='text/html' href='https://git.kalnischkies.de/apt/commit/?id=9b36a29ffebde3088cec2048505b8d644f46c2c3'/>
<id>urn:sha1:9b36a29ffebde3088cec2048505b8d644f46c2c3</id>
<content type='text'>
So far we only stored the last reason why something was decided,
for example, if "A depends B | C" and we assigned B=false, C=false,
we'd store "(not) C" as the reason for "(not) A".

This gives us only a partial implication graph; after all "C" was
not the *sole* reason for not installing A. This has two implications:

1. We cannot do conflict-driven clause learning
2. We cannot print excellent information about why packages cannot be
   installed (or removed)

This commit is incomplete in addressing both; in particular, we always
store a clause as a reason for something that is not a root object;
whereas MiniSAT would only store a clause on propagation. That is,
if A depends B | C, and we install A, then we have to make a choice
between B|C. Let's say we pick B, we store 'A depends B|C' as the
reason whereas MiniSAT would not store a reason (because it picked
the "next best" unassigned literal).

Hopefully this is not going to be an issue. The reason is used to
calculate the assignments that caused the decision in MiniSAT, but
the idea is that we can just treat reason clauses with unassigned
values as "no reason".

The conflict explanation (WhyStr) has been changed to print the
strongest reason; which produces the same result as the previous
solution for the test suite. What does this mean?

If we look at A depends B|C, let's analyse:

    Why not A?
        We return the first assigned value for B|C, likely B.
        We might have returned C here before as it was the
        last assignment, but we might also return C here,
        if B is not assigned.

    Why B? We return A.

If we look at A conflicts B:

    Why not A? Well B
    Why not B? Well A

Thanks to the structure of the implication graph this is quite
simple, but also generalizing this to the CNF format should not
be hard.

A future version will extend clauses with backlinks to
pkgCache::Dependency*, allowing us to print useful information
to uses such as "A Depends B | C | D (&gt;= 2)" in the real form, rather
than the expanded form which may be "A -&gt; B | C | D=3 | D=2".
</content>
</entry>
<entry>
<title>solver3: Remove work rescoring in favor of unit propagation</title>
<updated>2025-02-14T18:08:45Z</updated>
<author>
<name>Julian Andres Klode</name>
<email>julian.klode@canonical.com</email>
</author>
<published>2025-02-12T19:39:33Z</published>
<link rel='alternate' type='text/html' href='https://git.kalnischkies.de/apt/commit/?id=2050ecb34a9e18cf1d8edbff8c52d456a7229162'/>
<id>urn:sha1:2050ecb34a9e18cf1d8edbff8c52d456a7229162</id>
<content type='text'>
Instead of expensive rescoring of all outstanding items, use
unit propagation to find new units after conflicts.

We still count the items when adding them; but unless they are
0 or 1, which they should not be, they don't have any effect:
The size field is now effectively static.

If the size of an optional clause changed to 1, it is inserted
a second time, and then moves up to the top of the optional
items per the Work::operator&lt; rules.
</content>
</entry>
<entry>
<title>solver3: Pass EDSP flags directly rather than via config</title>
<updated>2025-02-14T18:08:45Z</updated>
<author>
<name>Julian Andres Klode</name>
<email>julian.klode@canonical.com</email>
</author>
<published>2025-02-11T21:03:03Z</published>
<link rel='alternate' type='text/html' href='https://git.kalnischkies.de/apt/commit/?id=3ae41a76c19e5ad05600188de43b46c3e2800676'/>
<id>urn:sha1:3ae41a76c19e5ad05600188de43b46c3e2800676</id>
<content type='text'>
This was a rather silly way to communicate state, and it was
in the wrong place. Notably also, multiple calls to the solver
had the options sticky, that is, if you run upgrade and then
it calls ResolveByKeep(), for example.
</content>
</entry>
<entry>
<title>solver3: Defer 3.0 'deep' autoremoval to 3.1, fix autoremove</title>
<updated>2025-02-14T18:08:45Z</updated>
<author>
<name>Julian Andres Klode</name>
<email>julian.klode@canonical.com</email>
</author>
<published>2025-02-11T11:11:20Z</published>
<link rel='alternate' type='text/html' href='https://git.kalnischkies.de/apt/commit/?id=4c48b5618ba15d4e33625cec81843891910e81a2'/>
<id>urn:sha1:4c48b5618ba15d4e33625cec81843891910e81a2</id>
<content type='text'>
Restore the depcache's MarkRequired logic for 3.0 solver; and
change the MarkInstall() call to pass a more correct value for
FromUser, to not override an existing automatic status.
</content>
</entry>
<entry>
<title>solver3: Reject reverse dependencies natively</title>
<updated>2025-02-14T18:04:56Z</updated>
<author>
<name>Julian Andres Klode</name>
<email>julian.klode@canonical.com</email>
</author>
<published>2025-02-05T20:31:53Z</published>
<link rel='alternate' type='text/html' href='https://git.kalnischkies.de/apt/commit/?id=b8918cb89ada945d92c720446177f1ef5185b5a5'/>
<id>urn:sha1:b8918cb89ada945d92c720446177f1ef5185b5a5</id>
<content type='text'>
Instead of utilizing the reverse depends functionality of the cache
and marking all possible reverse dependencies for removal, mark them
ourselves by keeping track of reverse-implication-clauses.

Notably, this improves the reverse dependency rejection substantially:
The previous RejectReverseDependencies() function did not handle
Provides.

For this to work correctly right now, we need to discover optional
clauses too when queuing them. This is somewhat suboptimal as we
technically we don't care if they become unsat, we just waste time
tracking them.

The tests get a bit awkward, but oh well, we use what we can
use.
</content>
</entry>
<entry>
<title>solver3: Implement a timeout, default 10s</title>
<updated>2025-02-14T18:04:56Z</updated>
<author>
<name>Julian Andres Klode</name>
<email>julian.klode@canonical.com</email>
</author>
<published>2025-02-10T18:56:16Z</published>
<link rel='alternate' type='text/html' href='https://git.kalnischkies.de/apt/commit/?id=a9587b39ea6776b1d1324288786176102f65cee5'/>
<id>urn:sha1:a9587b39ea6776b1d1324288786176102f65cee5</id>
<content type='text'>
A SAT solver can run more or less forever, but that's not a good
user experience.
</content>
</entry>
<entry>
<title>solver3: Discover recursive dependencies</title>
<updated>2025-02-14T18:04:56Z</updated>
<author>
<name>Julian Andres Klode</name>
<email>julian.klode@canonical.com</email>
</author>
<published>2025-02-10T16:17:35Z</published>
<link rel='alternate' type='text/html' href='https://git.kalnischkies.de/apt/commit/?id=222271ee0d44c8e7bc00935fbbc2615529a4cdfc'/>
<id>urn:sha1:222271ee0d44c8e7bc00935fbbc2615529a4cdfc</id>
<content type='text'>
When we have discovered all clauses for a version, discover
each possible solution for the clauses. This means that when
Discover(foo) is called _anything_ that could lead to foo becoming
uninstallable is translated; so we can extend this next by keeping
a list of reverse dependencies for each package and rejecting
those.

We limit the discovery to those variables that we did not already
enqueue as a negative fact at the root level, as those can never
become true.

We are utilizing a queue here which is not the most performant
solution possible, but where it excels is in producing usable
stack traces when debugging. Traversing the entire dependency
tree using recursion can easily produce thousand levels of
recursion.

The queue means that we discover packages in a breadth-first
manner compatible with the order in which we propagate dependencies,
which is helpful for consistency.

The queue did not appear as a bottleneck in benchmarking. If it did,
we could switch to a grow-only ring buffer (std::queue's underlying
deque also shrinks automatically which is suboptimal).
</content>
</entry>
<entry>
<title>solver3: Defer version selection where possible</title>
<updated>2025-02-14T18:04:56Z</updated>
<author>
<name>Julian Andres Klode</name>
<email>julian.klode@canonical.com</email>
</author>
<published>2025-02-05T19:11:35Z</published>
<link rel='alternate' type='text/html' href='https://git.kalnischkies.de/apt/commit/?id=f870bd44522d195199987b0e073d495eed060495'/>
<id>urn:sha1:f870bd44522d195199987b0e073d495eed060495</id>
<content type='text'>
If a dependency can be satisfied by all versions of a package,
add the package to the clause instead of the version object.

This works only if there are no providers for the package: Providers
are quite hard to enumerate over and make sure that all versions of
a package satisfy the provider dependency.

Implement arbitrary selection between packages and versions for
the CompareProviders class: We pick the best version for each package
and then pit them against each other.
</content>
</entry>
<entry>
<title>solver3: Avoid std::vector for statically sized arrays</title>
<updated>2025-02-07T19:59:43Z</updated>
<author>
<name>Julian Andres Klode</name>
<email>julian.klode@canonical.com</email>
</author>
<published>2025-02-06T11:40:01Z</published>
<link rel='alternate' type='text/html' href='https://git.kalnischkies.de/apt/commit/?id=cce96b85691fac0bbbbb84a501c6f39a0c9125c0'/>
<id>urn:sha1:cce96b85691fac0bbbbb84a501c6f39a0c9125c0</id>
<content type='text'>
The bounds checking on the vector accesses is killing performance,
so switch from vector to a basic array, given that we don't actually
need _any_ functionality from vector...

Of course while we are at it, let us define a safe wrapper around
it so we cannot accidentally index arrays for package IDs with
version IDs and whatnot.
</content>
</entry>
</feed>
