Skip to content

Commit

Permalink
Add API for changing the set of atoms to project on.
Browse files Browse the repository at this point in the history
* Add clingo_control_update_project() for appending to or replacing
  the set of atoms to project on.

* Add add_project() and replace_project() to python control API.
  • Loading branch information
BenKaufmann committed Nov 26, 2024
1 parent 9efccde commit 1ee8c90
Show file tree
Hide file tree
Showing 10 changed files with 2,976 additions and 2,716 deletions.
2,788 changes: 1,430 additions & 1,358 deletions app/pyclingo/_clingo.c

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions libclingo/clingo.h
Original file line number Diff line number Diff line change
Expand Up @@ -2919,6 +2919,19 @@ CLINGO_VISIBILITY_DEFAULT bool clingo_control_release_external(clingo_control_t
//! @return whether the call was successful; might set one of the following error codes:
//! - ::clingo_error_bad_alloc
CLINGO_VISIBILITY_DEFAULT bool clingo_control_remove_minimize(clingo_control_t *control);
//! Add to or replace the set of projection variables.
//!
//! If `append` is true, the function adds the given atoms to the set of projection variables. Otherwise, it discards
//! any previously added projection variables and sets the given atoms as the new set of projection variables.
//!
//! @param[in] control the target
//! @param[in] atoms the projection atoms to add/set
//! @param[in] size the number of atoms
//! @param[in] append whether to append to (true) or replace (false) any previously added projection variables
//! @return whether the call was successful; might set one of the following error codes:
//! - ::clingo_error_bad_alloc
CLINGO_VISIBILITY_DEFAULT bool clingo_control_update_project(clingo_control_t *control, clingo_atom_t const* atoms, size_t size, bool append);

//! Register a custom propagator with the control object.
//!
//! If the sequential flag is set to true, the propagator is called
Expand Down
1 change: 1 addition & 0 deletions libclingo/clingo/clingocontrol.hh
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ public:
assignExternal(res.first->uid(), val);
}
}
void updateProject(Potassco::AtomSpan project, bool append) override;
void removeMinimize() override;
Symbol getConst(std::string const &name) const override;
bool isConflicting() const noexcept override;
Expand Down
1 change: 1 addition & 0 deletions libclingo/clingo/control.hh
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ struct clingo_control {
virtual bool blocked() = 0;
virtual void assignExternal(Potassco::Atom_t ext, Potassco::Value_t val) = 0;
virtual void assignExternal(Gringo::Symbol ext, Potassco::Value_t val) = 0;
virtual void updateProject(Potassco::AtomSpan project, bool append) = 0;
virtual void removeMinimize() = 0;
virtual bool isConflicting() const noexcept = 0;
virtual Potassco::AbstractStatistics const *statistics() const = 0;
Expand Down
10 changes: 10 additions & 0 deletions libclingo/src/clingocontrol.cc
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,16 @@ void ClingoControl::assignExternal(Potassco::Atom_t ext, Potassco::Value_t val)
}
}

void ClingoControl::updateProject(Potassco::AtomSpan project, bool append) {
auto *backend = update() ? out_->backend() : nullptr;
if (backend != nullptr) {
if (!append && clingoMode_) {
claspProgram()->removeProject();
}
backend->project(project);
}
}

void ClingoControl::removeMinimize() {
if (clingoMode_) {
out_->removeMinimize();
Expand Down
5 changes: 5 additions & 0 deletions libclingo/src/control.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1976,6 +1976,11 @@ extern "C" bool clingo_control_remove_minimize(clingo_control_t *ctl) {
GRINGO_CLINGO_CATCH;
}

extern "C" bool clingo_control_update_project(clingo_control_t *ctl, clingo_atom_t const* atoms, size_t size, bool append) {
GRINGO_CLINGO_TRY { ctl->updateProject({atoms, size}, append); }
GRINGO_CLINGO_CATCH;
}

extern "C" bool clingo_program_builder_init(clingo_control_t *ctl, clingo_program_builder_t **ret) {
GRINGO_CLINGO_TRY { *ret = static_cast<clingo_program_builder_t*>(ctl); }
GRINGO_CLINGO_CATCH;
Expand Down
11 changes: 11 additions & 0 deletions libclingo/src/gringo_app.cc
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,17 @@ struct IncrementalControl : Control, private Output::ASPIFOutBackend {
assignExternal(res.first->uid(), val);
}
}
void updateProject(Potassco::AtomSpan project, bool append) override {
if (append) {
update();
if (auto *b = out.backend()) {
b->project(project);
}
}
else {
throw std::runtime_error("replacing projection atoms is not supported");
}
}
void removeMinimize() override { throw std::runtime_error("removing minimize constraints is not supported"); }
SymbolicAtoms const &getDomain() const override { throw std::runtime_error("domain introspection not supported"); }
ConfigProxy &getConf() override { throw std::runtime_error("configuration not supported"); }
Expand Down
2,788 changes: 1,430 additions & 1,358 deletions libpyclingo/_clingo.c

Large diffs are not rendered by default.

50 changes: 50 additions & 0 deletions libpyclingo/clingo/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,56 @@ def remove_minimize(self) -> None:
_lib.clingo_control_remove_minimize(self._rep)
)

def _update_project(self, atoms: Sequence[Union[Symbol, int]], append: bool) -> None:
p_proj = _ffi.new("clingo_atom_t[]", len(atoms))
for i, lit in enumerate(atoms):
p_proj[i] = self._program_atom(lit)

_handle_error(
_lib.clingo_control_update_project(
self._rep, p_proj, len(atoms), append
)
)

def add_project(self, atoms: Sequence[Union[Symbol, int]]) -> None:
"""
Add atoms to project on to the program.
Parameters
----------
atoms
List of atoms or program literals (see `clingo.symbolic_atoms.SymbolicAtom.literal`) to project on.
Notes
-----
The function extends the set of atoms to project on with the given atoms.
See Also
--------
Control.replace_project
"""
self._update_project(atoms, append=True)

def replace_project(self, atoms: Sequence[Union[Symbol, int]]) -> None:
"""
Set atoms to project on.
Parameters
----------
atoms
List of atoms or program literals (see `clingo.symbolic_atoms.SymbolicAtom.literal`) to project on.
Notes
-----
The function sets the atoms to project on to the given atoms thereby replacing any previously added project
statements.
See Also
--------
Control.add_project
"""
self._update_project(atoms, append=False)

def assign_external(
self, external: Union[Symbol, int], truth: Optional[bool]
) -> None:
Expand Down
25 changes: 25 additions & 0 deletions libpyclingo/clingo/tests/test_solving.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,31 @@ def on_model(m: Model):
self.ctl.ground([("base", [])])
self.ctl.solve(on_model=on_model)

def test_update_projection(self):
self.ctl.configuration.solve.project = "auto"
self.ctl.configuration.solve.models = "0"
self.ctl.add("base", [], "{a;b;c;d}. #project a/0. #project b/0.")
self.ctl.ground([("base", [])])
self.ctl.solve(on_model=self.mcb.on_model)
self.assertEqual(self.mcb.models, _p([], ["a"], ["a", "b"], ["b"]))

pro = []
for atom in self.ctl.symbolic_atoms.by_signature("c", 0):
pro.append(atom.literal)
pro.append(Function("d"))

self.ctl.replace_project(pro)
self.mcb = _MCB()
self.ctl.solve(on_model=self.mcb.on_model)
self.assertEqual(self.mcb.models, _p([], ["c"], ["c", "d"], ["d"]))

self.mcb = _MCB()
pro = [Function("a")]
self.ctl.add_project(pro)
self.ctl.solve(on_model=self.mcb.on_model)
self.assertEqual(self.mcb.models, _p([], ["a"], ["a", "c"], ["a", "c", "d"], ["a", "d"], ["c"], ["c", "d"], ["d"]))


def test_control_clause(self):
"""
Test adding clauses while solving.
Expand Down

0 comments on commit 1ee8c90

Please sign in to comment.