Skip to content

Commit

Permalink
Create Solver solution (#2584)
Browse files Browse the repository at this point in the history
* Replace MTransaction to_remove with PackageInfo

* Add a solution class

* Fix Solution for_each

* Add Solution empty and size

* Make MTransaction::filter const

* Remove unused MTransaction::m_force_reinstall

* Rename MSolver::set_flags

* Refactor MSolver flags

* Call solver.flag() once in MTransaction

* Implement Solution as alias with free functions

* Remove as many MSolver flag setters as possible

* Make Soltion a struct to possibly add more members

* Remove useless function call

* Add Solution::Omit

* Rename template typenames and parameters in Solution

* Fix MSolver const parameter
  • Loading branch information
AntoinePrv authored Jul 4, 2023
1 parent cbd8087 commit 5208728
Show file tree
Hide file tree
Showing 8 changed files with 319 additions and 98 deletions.
1 change: 1 addition & 0 deletions libmamba/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ set(LIBMAMBA_PUBLIC_HEADERS
${LIBMAMBA_INCLUDE_DIR}/mamba/core/repo.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/run.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/shell_init.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/solution.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/solver.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/subdirdata.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/thread_utils.hpp
Expand Down
218 changes: 218 additions & 0 deletions libmamba/include/mamba/core/solution.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
// Copyright (c) 2023, QuantStack and Mamba Contributors
//
// Distributed under the terms of the BSD 3-Clause License.
//
// The full license is in the file LICENSE, distributed with this software.

#ifndef MAMBA_CORE_SOLUTION_HPP
#define MAMBA_CORE_SOLUTION_HPP

#include <variant>
#include <vector>

#include "package_info.hpp"

namespace mamba
{
namespace detail
{
template <typename T, typename... U>
inline constexpr bool is_any_of_v = std::disjunction_v<std::is_same<T, U>...>;
}

struct Solution
{
struct Omit
{
PackageInfo what;
};
struct Upgrade
{
PackageInfo remove;
PackageInfo install;
};
struct Downgrade
{
PackageInfo remove;
PackageInfo install;
};
struct Change
{
PackageInfo remove;
PackageInfo install;
};
struct Reinstall
{
PackageInfo what;
};
struct Remove
{
PackageInfo remove;
};
struct Install
{
PackageInfo install;
};

template <typename T>
inline static constexpr bool has_remove_v = detail::is_any_of_v<T, Upgrade, Downgrade, Change, Remove>;

template <typename T>
inline static constexpr bool has_install_v = detail::is_any_of_v<T, Upgrade, Downgrade, Change, Install>;

using Action = std::variant<Omit, Upgrade, Downgrade, Change, Reinstall, Remove, Install>;
using action_list = std::vector<Action>;

action_list actions = {};
};

template <typename Iter, typename UnaryFunc>
void for_each_to_remove(Iter first, Iter last, UnaryFunc&& func);
template <typename Range, typename UnaryFunc>
void for_each_to_remove(Range&& actions, UnaryFunc&& func);

template <typename Iter, typename UnaryFunc>
void for_each_to_install(Iter first, Iter last, UnaryFunc&& func);
template <typename Range, typename UnaryFunc>
void for_each_to_install(Range&& actions, UnaryFunc&& func);

template <typename Iter, typename UnaryFunc>
void for_each_to_omit(Iter first, Iter last, UnaryFunc&& func);
template <typename Range, typename UnaryFunc>
void for_each_to_omit(Range&& actions, UnaryFunc&& func);
}

#include <type_traits>

namespace mamba
{
/********************************
* Implementation of Solution *
********************************/

namespace detail
{
template <typename Action>
auto to_remove_ptr(Action& action)
{
using PackageInfoPtr = std::conditional_t<std::is_const_v<Action>, const PackageInfo*, PackageInfo*>;
return std::visit(
[](auto& a) -> PackageInfoPtr
{
using A = std::decay_t<decltype(a)>;
if constexpr (Solution::has_remove_v<A>)
{
return &(a.remove);
}
else if constexpr (std::is_same_v<A, Solution::Reinstall>)
{
return &(a.what);
}
return nullptr;
},
action
);
}
}

template <typename Iter, typename UnaryFunc>
void for_each_to_remove(Iter first, Iter last, UnaryFunc&& func)
{
for (; first != last; ++first)
{
if (auto* const ptr = detail::to_remove_ptr(*first))
{
func(*ptr);
}
}
}

template <typename Range, typename UnaryFunc>
void for_each_to_remove(Range&& actions, UnaryFunc&& func)
{
return for_each_to_remove(actions.begin(), actions.end(), std::forward<UnaryFunc>(func));
}

namespace detail
{
template <typename Action>
auto to_install_ptr(Action& action)
{
using PackageInfoPtr = std::conditional_t<std::is_const_v<Action>, const PackageInfo*, PackageInfo*>;
return std::visit(
[](auto& a) -> PackageInfoPtr
{
using A = std::decay_t<decltype(a)>;
if constexpr (Solution::has_install_v<A>)
{
return &(a.install);
}
else if constexpr (std::is_same_v<A, Solution::Reinstall>)
{
return &(a.what);
}
return nullptr;
},
action
);
}
}

template <typename Iter, typename UnaryFunc>
void for_each_to_install(Iter first, Iter last, UnaryFunc&& func)
{
for (; first != last; ++first)
{
if (auto* const ptr = detail::to_install_ptr(*first))
{
func(*ptr);
}
}
}

template <typename Range, typename UnaryFunc>
void for_each_to_install(Range&& actions, UnaryFunc&& func)
{
return for_each_to_install(actions.begin(), actions.end(), std::forward<UnaryFunc>(func));
}

namespace detail
{
template <typename Action>
auto to_omit_ptr(Action& action)
{
using PackageInfoPtr = std::conditional_t<std::is_const_v<Action>, const PackageInfo*, PackageInfo*>;
return std::visit(
[](auto& a) -> PackageInfoPtr
{
using A = std::decay_t<decltype(a)>;
if constexpr (std::is_same_v<A, Solution::Omit>)
{
return &(a.what);
}
return nullptr;
},
action
);
}
}

template <typename Iter, typename UnaryFunc>
void for_each_to_omit(Iter first, Iter last, UnaryFunc&& func)
{
for (; first != last; ++first)
{
if (auto* const ptr = detail::to_omit_ptr(*first))
{
func(*ptr);
}
}
}

template <typename Range, typename UnaryFunc>
void for_each_to_omit(Range&& actions, UnaryFunc&& func)
{
return for_each_to_omit(actions.begin(), actions.end(), std::forward<UnaryFunc>(func));
}
}
#endif
37 changes: 25 additions & 12 deletions libmamba/include/mamba/core/solver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@

#include "match_spec.hpp"

#define MAMBA_NO_DEPS 0b0001
#define MAMBA_ONLY_DEPS 0b0010
#define MAMBA_FORCE_REINSTALL 0b0100
#define PY_MAMBA_NO_DEPS 0b0001
#define PY_MAMBA_ONLY_DEPS 0b0010
#define PY_MAMBA_FORCE_REINSTALL 0b0100

extern "C"
{
Expand Down Expand Up @@ -60,6 +60,16 @@ namespace mamba
{
public:

struct Flags
{
/** Keep the dependencies of the install package in the solution. */
bool keep_dependencies = true;
/** Keep the original required package in the solution. */
bool keep_specs = true;
/** Force reinstallation of jobs. */
bool force_reinstall = false;
};

MSolver(MPool pool, std::vector<std::pair<int, int>> flags = {});
~MSolver();

Expand All @@ -73,12 +83,17 @@ namespace mamba
void add_constraint(const std::string& job);
void add_pin(const std::string& pin);
void add_pins(const std::vector<std::string>& pins);
void set_flags(const std::vector<std::pair<int, int>>& flags);
void set_postsolve_flags(const std::vector<std::pair<int, int>>& flags);

[[deprecated]] void py_set_postsolve_flags(const std::vector<std::pair<int, int>>& flags);

void set_flags(const Flags& flags); // TODO temporary Itf meant to be passed in ctor
[[nodiscard]] auto flags() const -> const Flags&;
[[deprecated]] void py_set_libsolv_flags(const std::vector<std::pair<int, int>>& flags);

[[nodiscard]] bool try_solve();
void must_solve();

[[nodiscard]] bool is_solved() const;

[[nodiscard]] std::string problems_to_str() const;
[[nodiscard]] std::vector<std::string> all_problems() const;
[[nodiscard]] std::vector<MSolverProblem> all_problems_structured() const;
Expand All @@ -101,25 +116,23 @@ namespace mamba
auto solver() -> solv::ObjSolver&;
auto solver() const -> const solv::ObjSolver&;

bool only_deps = false;
bool no_deps = false;
bool force_reinstall = false;

private:

std::vector<std::pair<int, int>> m_flags;
std::vector<std::pair<int, int>> m_libsolv_flags;
std::vector<MatchSpec> m_install_specs;
std::vector<MatchSpec> m_remove_specs;
std::vector<MatchSpec> m_neuter_specs;
std::vector<MatchSpec> m_pinned_specs;
bool m_is_solved;
// Order of m_pool and m_solver is critical since m_pool must outlive m_solver.
MPool m_pool;
// Temporary Pimpl all libsolv to keep it private
std::unique_ptr<solv::ObjSolver> m_solver;
std::unique_ptr<solv::ObjQueue> m_jobs;
Flags m_flags = {};
bool m_is_solved;

void add_reinstall_job(MatchSpec& ms, int job_flag);
void apply_libsolv_flags();
};
} // namespace mamba

Expand Down
9 changes: 4 additions & 5 deletions libmamba/include/mamba/core/transaction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "mamba_fs.hpp"
#include "match_spec.hpp"
#include "package_cache.hpp"
#include "package_info.hpp"
#include "prefix_data.hpp"
#include "solver.hpp"
#include "transaction_context.hpp"
Expand Down Expand Up @@ -86,19 +87,17 @@ namespace mamba
TransactionContext m_transaction_context;
MultiPackageCache m_multi_cache;
const fs::u8path m_cache_path;
std::vector<solv::ObjSolvableViewConst> m_to_install;
std::vector<solv::ObjSolvableViewConst> m_to_remove;
std::vector<PackageInfo> m_to_install;
std::vector<PackageInfo> m_to_remove;

History::UserRequest m_history_entry = History::UserRequest::prefilled();
// Temporarily using Pimpl for encapsulation
std::unique_ptr<solv::ObjTransaction> m_transaction;

std::vector<MatchSpec> m_requested_specs;

bool m_force_reinstall = false;

void init();
bool filter(const solv::ObjSolvableViewConst& s);
bool filter(const solv::ObjSolvableViewConst& s) const;

auto trans() -> solv::ObjTransaction&;
auto trans() const -> const solv::ObjTransaction&;
Expand Down
10 changes: 6 additions & 4 deletions libmamba/src/api/install.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
#include "mamba/core/channel.hpp"
#include "mamba/core/env_lockfile.hpp"
#include "mamba/core/environments_manager.hpp"
#include "mamba/core/fetch.hpp"
#include "mamba/core/mamba_fs.hpp"
#include "mamba/core/output.hpp"
#include "mamba/core/package_cache.hpp"
#include "mamba/core/package_download.hpp"
#include "mamba/core/pinning.hpp"
#include "mamba/core/transaction.hpp"
#include "mamba/core/util_string.hpp"
Expand Down Expand Up @@ -512,9 +512,11 @@ namespace mamba
}
);

solver.set_postsolve_flags({ { MAMBA_NO_DEPS, no_deps },
{ MAMBA_ONLY_DEPS, only_deps },
{ MAMBA_FORCE_REINSTALL, force_reinstall } });
solver.set_flags({
/* .keep_dependencies= */ !no_deps,
/* .keep_specs= */ !only_deps,
/* .force_reinstall= */ force_reinstall,
});

if (freeze_installed && !prefix_pkgs.empty())
{
Expand Down
Loading

0 comments on commit 5208728

Please sign in to comment.