Skip to content

Commit

Permalink
Add ObjSolver (#2504)
Browse files Browse the repository at this point in the history
* Add ObjSolver

* Add ObjSolver problems

* Add ObjSolver rule getters

* Add ObjPool::add_conda_dependency

* Add ObjSolver::solve test

* Add extra header
  • Loading branch information
AntoinePrv authored May 25, 2023
1 parent 17232ca commit 2dec4ae
Show file tree
Hide file tree
Showing 11 changed files with 389 additions and 3 deletions.
2 changes: 2 additions & 0 deletions libmamba/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ set(LIBMAMBA_SOURCES
${LIBMAMBA_SOURCE_DIR}/solv-cpp/pool.cpp
${LIBMAMBA_SOURCE_DIR}/solv-cpp/repo.cpp
${LIBMAMBA_SOURCE_DIR}/solv-cpp/solvable.cpp
${LIBMAMBA_SOURCE_DIR}/solv-cpp/solver.cpp
# C++ wrapping of libcurl
${LIBMAMBA_SOURCE_DIR}/core/curl.cpp
# C++ wrapping of compression libs (zstd and bzlib)
Expand Down Expand Up @@ -275,6 +276,7 @@ set(LIBMAMBA_PRIVATE_HEADERS
${LIBMAMBA_SOURCE_DIR}/solv-cpp/ids.hpp
${LIBMAMBA_SOURCE_DIR}/solv-cpp/pool.hpp
${LIBMAMBA_SOURCE_DIR}/solv-cpp/solvable.hpp
${LIBMAMBA_SOURCE_DIR}/solv-cpp/solver.hpp
${LIBMAMBA_SOURCE_DIR}/solv-cpp/repo.hpp
# C++ wrapping of compression libs (zstd and bzlib)
${LIBMAMBA_SOURCE_DIR}/core/compression.hpp
Expand Down
3 changes: 3 additions & 0 deletions libmamba/src/solv-cpp/ids.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ namespace mamba::solv
using DependencyId = ::Id;
using RepoId = ::Id;
using SolvableId = ::Id;
using RuleId = ::Id;
using ProblemId = ::Id;

using RelationFlag = int;
using DistType = int;
using SolverFlag = int;
}

#endif
14 changes: 14 additions & 0 deletions libmamba/src/solv-cpp/pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
#include <solv/pooltypes.h>
#include <solv/repo.h>
#include <solv/selection.h>
extern "C" // Incomplete header
{
#include <solv/conda.h>
}

#include "solv-cpp/pool.hpp"

Expand Down Expand Up @@ -112,6 +116,16 @@ namespace mamba::solv
return id;
}

auto ObjPool::add_conda_dependency(raw_str_view dep) -> DependencyId
{
return ::pool_conda_matchspec(raw(), dep);
}

auto ObjPool::add_conda_dependency(const std::string& dep) -> DependencyId
{
return add_conda_dependency(dep.c_str());
}

auto ObjPool::get_dependency_name(DependencyId id) const -> std::string_view
{
return ::pool_id2str(raw(), id);
Expand Down
13 changes: 12 additions & 1 deletion libmamba/src/solv-cpp/pool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
#include "solv-cpp/repo.hpp"
#include "solv-cpp/solvable.hpp"

using Pool = struct s_Pool;
extern "C"
{
using Pool = struct s_Pool;
}

namespace mamba::solv
{
Expand All @@ -33,6 +36,8 @@ namespace mamba::solv
{
public:

using raw_str_view = const char*;

ObjPool();
~ObjPool();

Expand Down Expand Up @@ -95,6 +100,12 @@ namespace mamba::solv
*/
auto add_dependency(StringId name_id, RelationFlag flag, StringId version_id) -> DependencyId;

/**
* Parse a dependency from string and add it to the pool.
*/
auto add_conda_dependency(raw_str_view dep) -> DependencyId;
auto add_conda_dependency(const std::string& dep) -> DependencyId;

/** Get the registered name of a dependency. */
auto get_dependency_name(DependencyId id) const -> std::string_view;

Expand Down
5 changes: 4 additions & 1 deletion libmamba/src/solv-cpp/repo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
#include "solv-cpp/ids.hpp"
#include "solv-cpp/solvable.hpp"

using Repo = struct s_Repo;
extern "C"
{
using Repo = struct s_Repo;
}

namespace fs
{
Expand Down
5 changes: 4 additions & 1 deletion libmamba/src/solv-cpp/solvable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@
#include "solv-cpp/ids.hpp"
#include "solv-cpp/queue.hpp"

using Solvable = struct s_Solvable;
extern "C"
{
using Solvable = struct s_Solvable;
}

namespace mamba::solv
{
Expand Down
115 changes: 115 additions & 0 deletions libmamba/src/solv-cpp/solver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// 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.

#include <cassert>

#include <solv/poolid.h>
#include <solv/solvable.h>
#include <solv/solver.h>
// broken headers go last
#include <solv/problems.h>
#include <solv/rules.h>

#include "solv-cpp/pool.hpp"
#include "solv-cpp/queue.hpp"
#include "solv-cpp/solver.hpp"

namespace mamba::solv
{
void ObjSolver::SolverDeleter::operator()(::Solver* ptr)
{
::solver_free(ptr);
}

ObjSolver::ObjSolver(const ObjPool& pool)
: m_solver(::solver_create(const_cast<::Pool*>(pool.raw())))
{
}

ObjSolver::~ObjSolver() = default;

auto ObjSolver::raw() -> ::Solver*
{
return m_solver.get();
}

void ObjSolver::set_flag(SolverFlag flag, bool value)
{
::solver_set_flag(raw(), flag, value);
}

auto ObjSolver::get_flag(SolverFlag flag) const -> bool
{
const auto val = ::solver_get_flag(const_cast<::Solver*>(raw()), flag);
assert((val == 0) || (val == 1));
return val != 0;
}

auto ObjSolver::raw() const -> const ::Solver*
{
return m_solver.get();
}

auto ObjSolver::solve(const ObjPool& /* pool */, const ObjQueue& jobs) -> bool
{
// pool is captured inside solver so we take it as a parameter to be explicit.
const auto n_pbs = ::solver_solve(raw(), const_cast<::Queue*>(jobs.raw()));
return n_pbs == 0;
}

auto ObjSolver::problem_count() const -> std::size_t
{
return ::solver_problem_count(const_cast<::Solver*>(raw()));
}

auto ObjSolver::problem_to_string(const ObjPool& /* pool */, ProblemId id) const -> std::string
{
// pool is captured inside solver so we take it as a parameter to be explicit.
return ::solver_problem2str(const_cast<::Solver*>(raw()), id);
}

auto ObjSolver::next_problem(ProblemId id) const -> ProblemId
{
return ::solver_next_problem(const_cast<::Solver*>(raw()), id);
}

auto ObjSolver::problem_rules(ProblemId id) const -> ObjQueue
{
ObjQueue rules = {};
::solver_findallproblemrules(const_cast<::Solver*>(raw()), id, rules.raw());
return rules;
}

auto ObjSolver::get_rule_info(const ObjPool& /* pool */, RuleId id) const -> ObjRuleInfo
{
// pool is captured inside solver so we take it as a parameter to be explicit.
SolvableId from_id = 0;
SolvableId to_id = 0;
DependencyId dep_id = 0;
const auto type = ::solver_ruleinfo(const_cast<::Solver*>(raw()), id, &from_id, &to_id, &dep_id);

return {
/* .from_id= */ (from_id != 0) ? std::optional{ from_id } : std::nullopt,
/* .to_id= */ (to_id != 0) ? std::optional{ to_id } : std::nullopt,
/* .dep_id= */ (dep_id != 0) ? std::optional{ dep_id } : std::nullopt,
/* .type= */ type,
/* .klass= */ ::solver_ruleclass(const_cast<::Solver*>(raw()), id),
};
}

auto ObjSolver::rule_info_to_string(const ObjPool& /* pool */, ObjRuleInfo ri) const -> std::string
{
// pool is captured inside solver so we take it as a parameter to be explicit.
return ::solver_ruleinfo2str(
const_cast<::Solver*>(raw()),
ri.type,
ri.from_id.value_or(0),
ri.to_id.value_or(0),
ri.dep_id.value_or(0)
);
}

}
101 changes: 101 additions & 0 deletions libmamba/src/solv-cpp/solver.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// 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_SOLV_SOLVER_HPP
#define MAMBA_SOLV_SOLVER_HPP

#include <memory>
#include <optional>
#include <string>

// START Only required for broken header <solv/rule.h>
#include <solv/poolid.h>
extern "C"
{
typedef struct s_Solvable Solvable;
typedef struct s_Map Map;
typedef struct s_Queue Queue;
}
// END
#include <solv/rules.h>

#include "solv-cpp/ids.hpp"
#include "solv-cpp/queue.hpp"

extern "C"
{
using Solver = struct s_Solver;
}

namespace mamba::solv
{
class ObjPool;
class ObjQueue;

struct ObjRuleInfo
{
std::optional<SolvableId> from_id;
std::optional<SolvableId> to_id;
std::optional<DependencyId> dep_id;
::SolverRuleinfo type;
::SolverRuleinfo klass;
};

class ObjSolver
{
public:

ObjSolver(const ObjPool& pool);
~ObjSolver();

auto raw() -> ::Solver*;
auto raw() const -> const ::Solver*;

void set_flag(SolverFlag flag, bool value);
[[nodiscard]] auto get_flag(SolverFlag flag) const -> bool;

[[nodiscard]] auto solve(const ObjPool& pool, const ObjQueue& jobs) -> bool;

[[nodiscard]] auto problem_count() const -> std::size_t;
[[nodiscard]] auto problem_to_string(const ObjPool& pool, ProblemId id) const -> std::string;
template <typename UnaryFunc>
void for_each_problem_id(UnaryFunc&& func) const;

/**
* Return an @ref ObjQueue of @ref RuleId with all rules involved in a current problem.
*/
[[nodiscard]] auto problem_rules(ProblemId id) const -> ObjQueue;
[[nodiscard]] auto get_rule_info(const ObjPool& pool, RuleId id) const -> ObjRuleInfo;
[[nodiscard]] auto rule_info_to_string(const ObjPool& pool, ObjRuleInfo id) const
-> std::string;

private:

struct SolverDeleter
{
void operator()(::Solver* ptr);
};

std::unique_ptr<::Solver, ObjSolver::SolverDeleter> m_solver = nullptr;

auto next_problem(ProblemId id = 0) const -> ProblemId;
};

/*********************************
* Implementation of ObjSolver *
*********************************/

template <typename UnaryFunc>
void ObjSolver::for_each_problem_id(UnaryFunc&& func) const
{
for (ProblemId id = next_problem(); id != 0; id = next_problem(id))
{
func(id);
}
}

}
#endif
1 change: 1 addition & 0 deletions libmamba/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ set(LIBMAMBA_TEST_SRCS
src/solv-cpp/test_pool.cpp
src/solv-cpp/test_repo.cpp
src/solv-cpp/test_solvable.cpp
src/solv-cpp/test_solver.cpp
# Utility library
src/util/test_flat_set.cpp
src/util/test_graph.cpp
Expand Down
7 changes: 7 additions & 0 deletions libmamba/tests/src/solv-cpp/test_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ TEST_SUITE("ObjPool")
CHECK_EQ(pool.get_dependency_relation(id_rel), " > ");
CHECK_EQ(pool.get_dependency_version(id_rel), "1.0.0");
CHECK_EQ(pool.dependency_to_string(id_rel), "mamba > 1.0.0");

SUBCASE("Parse a conda dependency")
{
const auto id_conda = pool.add_conda_dependency("rattler < 0.1");
CHECK_EQ(pool.get_dependency_name(id_conda), "rattler");
CHECK_EQ(pool.get_dependency_version(id_conda), "<0.1");
}
}

SUBCASE("Add repo")
Expand Down
Loading

0 comments on commit 2dec4ae

Please sign in to comment.