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

Enable weak constraints #273

Open
wants to merge 34 commits into
base: master
Choose a base branch
from
Open

Enable weak constraints #273

wants to merge 34 commits into from

Conversation

AntoniusW
Copy link
Collaborator

Adds weak constraints to Alpha. The parser is able to read them and in their presence the solver switches to a branch-and-bound algorithm. Returned answer sets are adorned with a valuation (weights at different levels as specified by the weak constraints).

- Refined grammar file.
- ParseTreeVisitor creates rules with WeakConstraintAtom in head.
- New WeakConstraint type representing parsed weak constraints.
- New WeakConstraintAtom as special head atom of weak constraints.
- New WeakConstraintNormalization transforming WeakConstraint rules into
  normal rules with WeakConstraintAtom in head.
- Removed dependence on Literals from IntervalTermToIntervalAtom and
  NaiveGrounder where Atoms are sufficient.
constraints to solver.

- Introduce AtomCallbackManager.
- Move callback functionality out of ChoiceManager.
- Assignment and TrailAssignment work with AtomCallbackManager.
- Add WeakConstraintsManager for weak constraint callbacks.
- Callbacks for choice atoms now handled in ChoicePoint directly.
- NoGoodGenerator generates nogoods representing weak constraints.
- Solver relays weak constraint information to WeakConstraintsManager.
to internal Program.

- Add containsWeakConstraints to InternalProgram, and modify
  AnalyzedProgram, Grounder, NaiveGrounder, StratifiedEvaluation, Alpha,
  ChoiceGrounder, DummyGrounder accordingly.
- Introduce WeightedAnswerSet, adapt BasicAnswerSet, DefaultSolver, Main
  to print its valuation.
- Fix bugs in NoGoodGenerator and AtomCallbackManager.
- DefaultSolver switches to branch-and-bound if weak constraints are in
  input program.
- WeakConstraintsManager maintains valuation of current and best known
  assignment/answer set.
- Fix issue #272 in DefaultSolver.
@AntoniusW AntoniusW marked this pull request as draft October 26, 2020 20:42
@AntoniusW AntoniusW linked an issue Oct 30, 2020 that may be closed by this pull request
# Conflicts:
#	src/main/java/at/ac/tuwien/kr/alpha/grounder/NaiveGrounder.java
- AnswerSet.compareTo checks for same class.
- WeightedAnswerSet implements compareTo, hashCode, and equals.
- WeakConstraintsManager fix possible NPE.
- TestUtils able to check that answer sets contain an optimum answer.
- WeakConstraintsTests created with some simple integration tests.
- WeightedAnswerSet employs TreeMap for weights at levels.
- Add WeightedAnswerSetTest unit tests.
- Refactor TestUtils, add helper to construct WeightedAnswerSet.
- WeakConstraintsManager adapted for correct ordering and negative
  levels.
- Added more tests.
@AntoniusW AntoniusW marked this pull request as ready for review June 1, 2021 08:52
…al bugs. Also adding more tests.

- WeakConstraintAtomCallback add toString().
- WeightAtLevelsManager only deals with weights and levels, and no longer needs to know about weak constraints.
- WeakConstraintsManager keeps track of true atoms above level of WeightAtLevelsManager and keeps weak constraints away from WeightAtLevelsManager.
- WeightAtLevelsManagerTest added.
- WeakConstraintsTests comes with significantly more tests.
# Conflicts:
#	src/main/java/at/ac/tuwien/kr/alpha/solver/DefaultSolver.java
#	src/test/java/at/ac/tuwien/kr/alpha/solver/OmigaBenchmarksTest.java
#	src/test/java/at/ac/tuwien/kr/alpha/test/util/TestUtils.java
@AntoniusW
Copy link
Collaborator Author

This PR should be ready to be reviewed now.

- WeightAtLevelsManager corrected logging, tolerates 0 weight at level 0.
- WeightAtLevelsManagerTest runs with checks now, added more tests.
- WeakConstraintsTests ignored for naive solver as that one does not optimize.
@AntoniusW
Copy link
Collaborator Author

Now also with test passing. :-)

@madmike200590
Copy link
Collaborator

I'm not yet through with the complete review, but I think I found a bug in one my tests:
The following program only has 4 answer sets with weak constraints:

{a; b; c}.

:~ a. [1]
:~ b. [2]
:~ c. [3]

Alpha output is:

michael@michael-laptop:~/asp_snippets/weak_constraints$ java -jar Alpha-bundled.jar -i wc-test.asp
  376 I lections.Reflections Reflections took 98 ms to scan 1 urls, producing 1 keys and 8 values  
Answer set 1:
{ a, c }
Optimization: [4@0]
Answer set 2:
{ c }
Optimization: [3@0]
Answer set 3:
{ a }
Optimization: [1@0]
Answer set 4:
{  }
Optimization: []
SATISFIABLE

Since I didn't specify any limit on answer sets computed, I'd expect to get all of them with their associated weigths. Is that a misunderstanding on my part?

The program without weak constraints, i.e. {a; b; c}. yields the expected 8 answer sets:

michael@michael-laptop:~/asp_snippets/weak_constraints$ java -jar Alpha-bundled.jar -i wc-test.asp
  399 I lections.Reflections Reflections took 110 ms to scan 1 urls, producing 1 keys and 8 values  
Answer set 1:
{ a, c }
Answer set 2:
{ c }
Answer set 3:
{ a }
Answer set 4:
{  }
Answer set 5:
{ a, b, c }
Answer set 6:
{ a, b }
Answer set 7:
{ b, c }
Answer set 8:
{ b }
SATISFIABLE

I haven't done any detailed analysis on this yet, but wanted to raise it anyway so you can take a look as well.

@AntoniusW
Copy link
Collaborator Author

To me that looks perfectly fine. The solver sees the weak constraints and switches over to optimisation using a branch-and-bound algorithm. That means branches whose valuation is higher than the currently-best-known valuation are cut off immediately and not expanded. So one usually expects a sequence of answer-sets with increasingly better valuation (i.e., less violations). Since the last answer-set has zero violated weak constraints (hence a valuation of 0 at all levels), it is the best answer-set and the solver stops there.

Note that this behaviour is similar to what other ASP solvers do. Enumerating all answer-sets is usually infeasible when optimization is enabled and by using optimization (i.e., weak constraints) one tells the solver that one is interested in good answers only.

# Conflicts:
#	src/main/java/at/ac/tuwien/kr/alpha/grounder/NaiveGrounder.java
#	src/main/java/at/ac/tuwien/kr/alpha/grounder/transformation/IntervalTermToIntervalAtom.java
#	src/main/java/at/ac/tuwien/kr/alpha/grounder/transformation/NormalizeProgramTransformation.java
#	src/test/java/at/ac/tuwien/kr/alpha/test/util/TestUtils.java
- WeakConstraint fixed toString.
- AggregateOperatorNormalization returns WeakConstraint if rule is of that type.
- IntervalTermToIntervalAtom rewriting of head no longer needs Literals.
@madmike200590
Copy link
Collaborator

madmike200590 commented Sep 20, 2021

To me that looks perfectly fine. The solver sees the weak constraints and switches over to optimisation using a branch-and-bound algorithm. That means branches whose valuation is higher than the currently-best-known valuation are cut off immediately and not expanded. So one usually expects a sequence of answer-sets with increasingly better valuation (i.e., less violations). Since the last answer-set has zero violated weak constraints (hence a valuation of 0 at all levels), it is the best answer-set and the solver stops there.

Note that this behaviour is similar to what other ASP solvers do. Enumerating all answer-sets is usually infeasible when optimization is enabled and by using optimization (i.e., weak constraints) one tells the solver that one is interested in good answers only.

As per our discussion last week, I think we need the following changes:

  • default behavior when Alpha is called without a specific number of answer sets to compute: Same as for programs without weak constraints, this should enumerate all answer sets along with their respective weights (needed for development/debugging)
  • manual initial bound for answer set search: Add a commandline flag "-mw"/"--maxWeight" that, when used in conjuction with "-n" (number of answer sets) instructs Alpha to find n answer sets where no answer set must exceed the given weight (i.e. use the value of mw as initial bound for branch&bound)
  • bugfix: When Alpha finds an optimum solution, this should be reported textually (currently only says "SATISFIABLE", see above example)

# Conflicts:
#	src/main/java/at/ac/tuwien/kr/alpha/solver/DefaultSolver.java
…s OptimizingSolver if weak constraints are present.

- OptimizingSolver extends DefaultSolver, implements branch-and-bound search.
- DefaultSolver visibility of methods/fields adapted for inheritance.
- AnswerSet provides getPredicateInstances for construction of WeightedAnswerSet from BasicAnswerSet.
- Fix logging level in WeakConstraintsManager and WeakConstraintsTests.
@codecov
Copy link

codecov bot commented Oct 6, 2021

Codecov Report

Base: 66.83% // Head: 67.32% // Increases project coverage by +0.49% 🎉

Coverage data is based on head (e7558d0) compared to base (3028684).
Patch coverage: 73.55% of modified lines in pull request are covered.

Additional details and impacted files
@@             Coverage Diff              @@
##             master     #273      +/-   ##
============================================
+ Coverage     66.83%   67.32%   +0.49%     
- Complexity     2108     2286     +178     
============================================
  Files           184      195      +11     
  Lines          8379     8980     +601     
  Branches       1464     1583     +119     
============================================
+ Hits           5600     6046     +446     
- Misses         2411     2515     +104     
- Partials        368      419      +51     
Impacted Files Coverage Δ
...-app/src/main/java/at/ac/tuwien/kr/alpha/Main.java 31.13% <0.00%> (-1.23%) ⬇️
...kr/alpha/commons/programs/ASPCore2ProgramImpl.java 0.00% <0.00%> (ø)
...ien/kr/alpha/commons/programs/AbstractProgram.java 0.00% <0.00%> (ø)
...n/kr/alpha/commons/programs/NormalProgramImpl.java 0.00% <0.00%> (ø)
.../ac/tuwien/kr/alpha/commons/programs/Programs.java 0.00% <0.00%> (ø)
.../kr/alpha/commons/programs/atoms/AbstractAtom.java 33.33% <ø> (ø)
...r/alpha/commons/programs/rules/WeakConstraint.java 0.00% <0.00%> (ø)
...at/ac/tuwien/kr/alpha/core/solver/NaiveSolver.java 93.11% <0.00%> (-0.43%) ⬇️
...uwien/kr/alpha/core/solver/WritableAssignment.java 76.92% <ø> (ø)
.../at/ac/tuwien/kr/alpha/commons/BasicAnswerSet.java 26.53% <33.33%> (+0.44%) ⬆️
... and 32 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

@madmike200590
Copy link
Collaborator

As per our discussion last week, I think we need the following changes:

  • default behavior when Alpha is called without a specific number of answer sets to compute: Same as for programs without weak constraints, this should enumerate all answer sets along with their respective weights (needed for development/debugging)
  • manual initial bound for answer set search: Add a commandline flag "-mw"/"--maxWeight" that, when used in conjuction with "-n" (number of answer sets) instructs Alpha to find n answer sets where no answer set must exceed the given weight (i.e. use the value of mw as initial bound for branch&bound)
  • bugfix: When Alpha finds an optimum solution, this should be reported textually (currently only says "SATISFIABLE", see above example)

@AntoniusW I just noticed that this is still tagged as pending my review - have the aforementioned changes been made, i.e. can we move this forward?

- OptimizingSolver directly uses WeakConstraintsManager from DefaultSolver.
- Small polish on WeakConstraintRecorder.
…nd print valuation of answer sets if weak constraints are present.

- CommandLineParser and SystemConfig handle options enabling optimization and maximum upper bound.
- WeakConstraintsManager interface introduced.
- WeakConstraintsManagerForBoundedOptimality for branch-and-bound search extracted.
- WeakConstraintsManagerForUnboundedEnumeration for computing weights/levels of answer sets of programs with weak constraints.
- WeightAtLevelsManager accepts maximum upper bound from comma-seperated weight@level pairs.
- DefaultSolver adds weight/levels to answer sets if weak constraints are present.
- OptimizingSolver handles maximum upper bound if specified.
- SolverFactory returns OptimizingSolver based on flag, not presence of weak constraints in input.
- Added initialization tests to WeightAtLevelsManagerTest.
- Added to TestUtils methods for regression testing the OptimizingSolver, and using them in WeakConstraintsTests.
# Conflicts:
#	alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/config/SystemConfig.java
#	alpha-cli-app/src/main/java/at/ac/tuwien/kr/alpha/Main.java
#	alpha-cli-app/src/main/java/at/ac/tuwien/kr/alpha/app/config/CommandLineParser.java
#	alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/BasicAnswerSet.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/WeakConstraintAtom.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/WeightedAnswerSet.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/Grounder.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/NaiveGrounder.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/NoGoodGenerator.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/WeakConstraintRecorder.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/parser/ParseTreeVisitor.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/AnalyzedProgram.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/InternalProgram.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/IntervalTermToIntervalAtom.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/WeakConstraintNormalization.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/WeakConstraint.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/AtomCallbackManager.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/DefaultSolver.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/OptimizingSolver.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/optimization/WeakConstraintAtomCallback.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/optimization/WeakConstraintsManager.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/optimization/WeakConstraintsManagerForBoundedOptimality.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/optimization/WeakConstraintsManagerForUnboundedEnumeration.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/optimization/WeightAtLevelsManager.java
#	alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/WeightedAnswerSetTest.java
#	alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/ChoiceGrounder.java
#	alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/DummyGrounder.java
#	alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/WeakConstraintsTests.java
#	alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/optimization/WeightAtLevelsManagerTest.java
#	alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/test/util/TestUtils.java
#	src/main/java/at/ac/tuwien/kr/alpha/api/Alpha.java
#	src/main/java/at/ac/tuwien/kr/alpha/common/AnswerSet.java
#	src/main/java/at/ac/tuwien/kr/alpha/grounder/transformation/aggregates/AggregateOperatorNormalization.java
@AntoniusW
Copy link
Collaborator Author

@AntoniusW I just noticed that this is still tagged as pending my review - have the aforementioned changes been made, i.e. can we move this forward?

@madmike200590, I think it is ready now. The functionality to not run optimization but still get valuations of answer sets should work now. An (exclusive) upper bound can also be set manually. Furthermore, current master has been merged and this branch now follows the modularization introduced in master. The code is ready for another round of reviews (and subsequent merging).

# Conflicts:
#	alpha-cli-app/src/main/java/at/ac/tuwien/kr/alpha/Main.java
#	alpha-cli-app/src/main/java/at/ac/tuwien/kr/alpha/app/config/CommandLineParser.java
#	alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/ASPCore2ProgramImpl.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/NaiveGrounder.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/NoGoodGenerator.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/parser/ParseTreeVisitor.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/InternalProgram.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/NormalProgramImpl.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/WeakConstraintAtom.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ArithmeticTermsRewriting.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/IntervalTermToIntervalAtom.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/VariableEqualityRemoval.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateOperatorNormalization.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/AbstractAggregateEncoder.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/StringtemplateBasedAggregateEncoder.java
#	alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/DefaultSolver.java
#	alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/ChoiceGrounder.java
#	alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/SolverTests.java
#	alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/test/util/TestUtils.java
#	alpha-solver/src/main/java/at/ac/tuwien/kr/alpha/api/impl/AlphaImpl.java
#	alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/api/impl/AlphaImplTest.java
- Add Solver::didExhaustSearchSpace method, realize it in Solver implementations and use it in Main.
Copy link
Collaborator

@madmike200590 madmike200590 left a comment

Choose a reason for hiding this comment

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

Looks good from my initial tests!
One small thing to fix - commandline argument parsing for weight/level pairs is a bit "over the place"

* @param weightAtLevels
* @return a TreeMap containing
*/
public static TreeMap<Integer, Integer> weightPerLevelFromString(String weightAtLevels) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is the wrong place to parse command-line arguments. The parsing of this string should happen in CommandLineParser. Internally, weights per level should only be passed around as some kind of Maps.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is a good catch and I was considering different options for where to put this code. The main problem is, that the same functionality is needed in WeakConstraintsTests in the tests of the core module. Relying on code from the cli-app module there felt like a bad idea and the other option would be having the code duplicated. What would you suggest for this kind of dependency?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Flag DebugEnableInternalChecks partially ignored
2 participants