Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create Solver solution #2584

Merged
merged 16 commits into from
Jul 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why a template here? From the std::visit in the implementation, it looks like you are operating on the type Action defined here

Copy link
Member Author

@AntoinePrv AntoinePrv Jul 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this is not the idiomatic way of doing this, but this was to deduce the constness of Action, used to deduce the constness of the returned pointer.

{
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same remark here.

{
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same remark as previous regarding the template

{
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
Klaim marked this conversation as resolved.
Show resolved Hide resolved
#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
AntoinePrv marked this conversation as resolved.
Show resolved Hide resolved
{
/** 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