Skip to content

Commit

Permalink
feat: better solutions when no complete one exists
Browse files Browse the repository at this point in the history
  • Loading branch information
mosteo committed Jan 5, 2025
1 parent 92e75be commit 942d145
Show file tree
Hide file tree
Showing 13 changed files with 722 additions and 431 deletions.
1 change: 0 additions & 1 deletion TODO

This file was deleted.

6 changes: 6 additions & 0 deletions src/alire/alire-dependencies-states.ads
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ package Alire.Dependencies.States is

function Is_Missing (This : State) return Boolean;

function Is_Skipped (This : State) return Boolean;
-- If both missing and marked as skipped

function Is_Pinned (This : State) return Boolean;

function Is_Provided (This : State) return Boolean;
Expand Down Expand Up @@ -368,6 +371,9 @@ private
function Is_Provided (This : State) return Boolean
is (This.Has_Release and then This.Release.Name /= This.Crate);

function Is_Skipped (This : State) return Boolean
is (This.Is_Missing and then This.Reason = Skipped);

function Is_Solved (This : State) return Boolean
is (This.Fulfilled.Fulfillment = Solved);

Expand Down
152 changes: 15 additions & 137 deletions src/alire/alire-solutions.adb
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
with Ada.Containers;

with Alire.Settings.Builtins;
with Alire.Crates;
with Alire.Dependencies.Diffs;
Expand All @@ -18,7 +16,6 @@ package body Alire.Solutions is

package Semver renames Semantic_Versioning;

use type Ada.Containers.Count_Type;
use type Alire.Releases.Release;
use type Semantic_Versioning.Version;
use all type States.Missed_Reasons;
Expand Down Expand Up @@ -78,6 +75,14 @@ package body Alire.Solutions is
Crate : Crate_Name) return Boolean
is (This.Depends_On (Crate) and then This.State (Crate).Has_Release);

----------------------
-- Contains_Skipped --
----------------------

function Contains_Skipped (This : Solution) return Boolean
is (for some Dep of This.Dependencies =>
Dep.Is_Missing and then Dep.Reason = Skipped);

---------------------------
-- Contains_Incompatible --
---------------------------
Expand Down Expand Up @@ -214,6 +219,13 @@ package body Alire.Solutions is
function Misses (This : Solution) return State_Map
is (This.Dependencies_That (States.Is_Missing'Access));

-------------
-- Skipped --
-------------

function Skipped (This : Solution) return State_Map
is (This.Dependencies_That (States.Is_Skipped'Access));

-------------
-- Missing --
-------------
Expand Down Expand Up @@ -559,140 +571,6 @@ package body Alire.Solutions is
end return;
end Including;

---------------
-- Is_Better --
---------------

function Is_Better (This, Than : Solution) return Boolean is

type Comparison is (Better, Equivalent, Worse);

----------------------
-- Compare_Versions --
----------------------

function Compare_Versions (This, Than : Solution) return Comparison is
begin

-- TODO: instead of using the first discrepancy, we should count all
-- differences and see which one is globally "newer".

-- Check releases in both only

for Rel of This.Releases loop
if Than.Contains_Release (Rel.Name) then
if Than.Releases_Providing (Rel.Name)
.First_Element.Version < Rel.Version
then
return Better;
elsif
Rel.Version < Than.Releases_Providing (Rel.Name)
.First_Element.Version
then
return Worse;
end if;
end if;
end loop;

return Equivalent;
end Compare_Versions;

-----------------------------
-- Lexicographical_Compare --
-----------------------------

function Lexicographical_Compare (This, Than : Solution) return Boolean
is
begin
for Crate of This.Crates.Union (Than.Crates) loop
if This.Depends_On (Crate) and then not Than.Depends_On (Crate)
then
return True;
elsif not This.Depends_On (Crate) and then Than.Depends_On (Crate)
then
return False;
end if;
end loop;

return False; -- Identical
end Lexicographical_Compare;

begin

-- Prefer better compositions

if This.Composition < Than.Composition then
return True;
elsif This.Composition > Than.Composition then
return False;
end if;

-- Within complete solutions, prefer higher versions

if This.Composition = Releases then
case Compare_Versions (This, Than) is
when Better => return True;
when Worse => return False;
when Equivalent =>
case Compare_Versions (This => Than, Than => This) is
when Better => return False;
when Worse => return True;
when Equivalent => null;
end case;
end case;

-- Disambiguate preferring a complete solution with less releases

if This.Releases.Length < Than.Releases.Length then
return True;
elsif This.Releases.Length > Than.Releases.Length then
return False;
end if;

-- At this point they must be identical; just in case keep comparing

end if;

-- Prefer more fulfilled releases when the solution is incomplete.
-- The rationale is that fewer solved releases will mean more unknown
-- missing indirect dependencies.

if This.Releases.Length > Than.Releases.Length then
return True;
elsif This.Releases.Length < Than.Releases.Length then
return False;
end if;

-- Prefer more undetected hints; at least we know these dependencies
-- exist in some platforms and can be made available somehow.

if This.Hints.Length > Than.Hints.Length then
return True;
elsif This.Hints.Length < Than.Hints.Length then
return False;
end if;

-- Prefer fewer missing crates, although at this point who knows what
-- indirect dependencies we are missing through undetected/missing
-- dependencies.

if This.Misses.Length < Than.Misses.Length then
return True;
elsif This.Misses.Length > Than.Misses.Length then
return False;
end if;

-- Final disambiguation by any known versions in [partial] solutions

case Compare_Versions (This, Than) is
when Better => return True;
when Worse => return False;
when Equivalent => return Lexicographical_Compare (This, Than);
-- Final way out is lexicographical ordering of crates, and first
-- one missing a crate in the other solution is worse.
end case;
end Is_Better;

-------------
-- Linking --
-------------
Expand Down
22 changes: 18 additions & 4 deletions src/alire/alire-solutions.ads
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@ package Alire.Solutions is

function Composition (This : Solution) return Compositions;

function Length (This : Solution) return Natural;
-- Amount of dependencies in this solution

function Contains (This : Solution;
Release : Alire.Releases.Release) return Boolean;
-- Say if the solution contains exactly this release
Expand All @@ -206,6 +209,11 @@ package Alire.Solutions is
-- provided by the given release; in which case Release cannot be added
-- to this solution for a different dependency.

function Contains_Skipped (This : Solution) return Boolean;
-- Some dependencies are missing because they have been deliverately
-- skipped. This is used by the solver to ensure completeness of
-- exploration, but these solutions are in all likelyhood suboptimal.

function Crates (This : Solution) return Name_Set;
-- Dependency name closure, independent of the status in the solution, as
-- found by the solver starting from the direct dependencies.
Expand Down Expand Up @@ -295,10 +303,6 @@ package Alire.Solutions is
Post => Is_Attempted'Result = (This.Composition /= Unsolved);
-- Say if a real attempt at solving has been done

function Is_Better (This, Than : Solution) return Boolean;
-- Relative ordering to prioritize found solutions. We prefer decreasing
-- order of Composition (avoid undetected externals/missing dependencies).

function Is_Complete (This : Solution) return Boolean;
-- A solution is complete when it fulfills all dependencies via regular
-- releases, detected externals, or linked directories.
Expand All @@ -312,6 +316,9 @@ package Alire.Solutions is
function Misses (This : Solution) return State_Map;
-- Return crates for which there is neither hint nor proper versions

function Skipped (This : Solution) return State_Map;
-- Return dependencies that have been deliberately skipped

function Pins (This : Solution) return Conditional.Dependencies;
-- Return all version-pinned dependencies as a dependency tree containing
-- exact versions. NOTE that the original dependency is thus lost in this
Expand Down Expand Up @@ -477,6 +484,13 @@ private
-- Has solving been attempted?
end record;

------------
-- Length --
------------

function Length (This : Solution) return Natural
is (Natural (This.Dependencies.Length));

-- Implementations moved to body due to bug about missing symbols in
-- predicates otherwise.

Expand Down
Loading

0 comments on commit 942d145

Please sign in to comment.