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

Implement subset minimal unsat core #765

Merged
merged 4 commits into from
Sep 19, 2024

Conversation

Tomaqa
Copy link
Member

@Tomaqa Tomaqa commented Sep 8, 2024

No description provided.

@Tomaqa Tomaqa linked an issue Sep 8, 2024 that may be closed by this pull request
@Tomaqa Tomaqa force-pushed the 753-implement-subset-minimal-unsat-core branch 10 times, most recently from 80f52c4 to 15b1687 Compare September 10, 2024 14:54
@Tomaqa
Copy link
Member Author

Tomaqa commented Sep 10, 2024

The solution currently uses MainSolver as an auxiliary SMT solver. However, I believe it would be more efficient to use just SimpSMTSolver, but it seems that it is not as straightforward to do as it may seem.

I decided to make a separate derived class for minimal unsat cores because it requires the other SMT solver to be used, unlike other unsat cores. I think it would be inconvenient to require the user to provide an SMT solver although it might not have been used.

@Tomaqa Tomaqa force-pushed the 753-implement-subset-minimal-unsat-core branch from 15b1687 to 42b9678 Compare September 11, 2024 20:53
@Tomaqa Tomaqa marked this pull request as ready for review September 12, 2024 08:49
@Tomaqa Tomaqa changed the base branch from master to term-names September 12, 2024 08:49
Comment on lines 1290 to 1301
if (not config.print_cores_full()) {
for (PTRef fla : unsatCore->getNamedTerms()) {
assert(termNames.contains(fla));
auto const & name = termNames.nameForTerm(fla);
std::cout << name << ' ';
}
} else {
for (PTRef fla : unsatCore->getTerms()) {
if (termNames.contains(fla)) {
std::cout << termNames.nameForTerm(fla);
}
else {
std::cout << logic->printTerm(fla);
}
std::cout << ' ';
}
Copy link
Member

Choose a reason for hiding this comment

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

Why is this needed?

Copy link
Member Author

@Tomaqa Tomaqa Sep 13, 2024

Choose a reason for hiding this comment

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

In the first branch, we use named terms so all of them must be in termNames. In second branch, we iterate over all terms so not all of them are necessarily in termNames. If it is not, we just print out string representation of the term, because we do not have any name for it.

Copy link
Member

Choose a reason for hiding this comment

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

I still don't get it.
I don't see why you need to change the existing functionality.
What does the new option mean?

We should be printing only names, not the terms themselves, no?

Copy link
Member Author

Choose a reason for hiding this comment

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

This commit implements option :print-cores-full from https://cvc5.github.io/blog/2024/04/15/interfaces-for-understanding-cvc5.html

Copy link
Member

Choose a reason for hiding this comment

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

I see, can you please document the meaning of this option? And maybe also the minimal-unsat-cores, to make it clear that these are subset minimal, and not global minimum.

Copy link
Member Author

Choose a reason for hiding this comment

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

Moved to #771

@Tomaqa Tomaqa force-pushed the 753-implement-subset-minimal-unsat-core branch 2 times, most recently from 64ca27f to cea4259 Compare September 13, 2024 13:09
@Tomaqa Tomaqa deleted the branch master September 13, 2024 13:19
@Tomaqa Tomaqa closed this Sep 13, 2024
@Tomaqa Tomaqa reopened this Sep 13, 2024
@Tomaqa Tomaqa changed the base branch from term-names to master September 13, 2024 13:22
Copy link
Member

Choose a reason for hiding this comment

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

Do we need these large files? I would prefer to minimize as much as possible the regression tests that we add.

Copy link
Member Author

Choose a reason for hiding this comment

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

I removed them from this PR. However, I think some of them will be needed to track the minimization process more thoroughly. They could be simplified, though.

Copy link
Member Author

Choose a reason for hiding this comment

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

-> #770

@Tomaqa Tomaqa force-pushed the 753-implement-subset-minimal-unsat-core branch from cea4259 to 9a840f7 Compare September 17, 2024 10:28
Copy link
Member

@blishko blishko 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!
But it seems the two options that you are introducing does not work together correctly.
Maybe the full cores should be introduced in a separate PR? Since it is orthogonal functionality.

Another note is that we should investigate using the Quickxplain algorithm to compute minimal unsat cores.

auto unsatCoreBuilder = [&]() -> std::variant<UnsatCoreBuilder, MinUnsatCoreBuilder> {
if (not config.minimal_unsat_cores()) { return UnsatCoreBuilder{config, proof, pmanager, termNames}; }

auto auxSMTSolver = std::make_unique<MainSolver>(logic, config, "unsat core solver");
Copy link
Member

Choose a reason for hiding this comment

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

It might be more efficient to give this new solver a fresh config. Specifically, the new solver does not need to compute unsat cores anymore.

Copy link
Member Author

Choose a reason for hiding this comment

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

That is a good point.

Copy link
Member Author

Choose a reason for hiding this comment

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

Based on this, I actually reconsidered the design and I think both builder classes can be merged. Since we use MainSolver and not SimpSMTSolver, it is sufficient to extend UnsatCoreBuilder constructor of just Logic & parameter, which is fine. The internal SMT solver can be constructed inside only if minimization is desired. Do you agree?

Copy link
Member

Choose a reason for hiding this comment

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

That would be very good, I think!

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

assert(size_t(namedTerms.size()) == namedTermsIdxs.size());
}

void MinUnsatCoreBuilder::minimizeAlgNaive() {
Copy link
Member

Choose a reason for hiding this comment

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

This algorithm only minimizes the named terms, no?
Thus this does not compute minimal explanation if used together with the option print-cores-full, no?

Copy link
Member Author

@Tomaqa Tomaqa Sep 17, 2024

Choose a reason for hiding this comment

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

It computes the same minimal explanation of named terms, but the response includes also unnamed terms. I am not sure how CVC5 implements this combination of options, but strictly following their definition would mean ignoring named terms completely, including the minimization process.

Copy link
Member

Choose a reason for hiding this comment

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

My intuition is that if print-cores-full is set then the names should be ignored and, if minimal cores are required then the minimization algorithm should operate on all terms, not only the named ones.

Copy link
Member Author

@Tomaqa Tomaqa Sep 19, 2024

Choose a reason for hiding this comment

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

-> #771

blishko
blishko previously approved these changes Sep 19, 2024
Copy link
Member

@blishko blishko left a comment

Choose a reason for hiding this comment

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

LGTM!
I would make the solver and config local to the method where they are needed. Feels like the class would simpler that way.
But I am also fine with how it is now.

src/api/MainSolver.cc Show resolved Hide resolved
setSmtSolver();
}

void UnsatCoreBuilder::minimizeAlgNaive() {
Copy link
Member

Choose a reason for hiding this comment

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

To me it seems like it would be better if the new config and new solver were local to this method. Then, there would be no need for the set methods.

Copy link
Member Author

Choose a reason for hiding this comment

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

But then it would not be usable in functions other than minimizeAlgNaive, and I plan to add more functions and select one of them based on the configuration.

Copy link
Member

Choose a reason for hiding this comment

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

Then each method can have its own local solver.
The solver is not supposed to be shared between different methods, no?

Copy link
Member Author

Choose a reason for hiding this comment

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

Probably not among distinct algorithms, but more sophisticated minimization algorithms may be divided into more functions or even use subclasses and it would require to always pass the local variable as a parameter. I would do that only if it would turn out to be reasonably more efficient than using the current member variable. Or are your concerns other than performance?

Copy link
Member

@blishko blishko Sep 19, 2024

Choose a reason for hiding this comment

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

My concerns are readability and simplicity.
And local reasoning.

Copy link
Member Author

Choose a reason for hiding this comment

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

Another thought: minimization stuff can be enclosed in a nested class (e.g. Minimize) where common functionalities among various strategies can be shared using inheritance, and member variables within the class can be "local" in a sense - within the scope of minimization. Also minimizeInit may be replaced by constructor, minimizeFinish by destructor, etc. It would still not use the variables as local variables within a function, but the scope of the variables would still be limited.

Copy link
Member

Choose a reason for hiding this comment

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

How about we merge this now and you can rethink the design when you want to add another minimization strategy?

Copy link
Member Author

Choose a reason for hiding this comment

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

I got a similar idea. I will make it local for now and we will see what to do next.

@Tomaqa Tomaqa force-pushed the 753-implement-subset-minimal-unsat-core branch from b7352f4 to effdd77 Compare September 19, 2024 10:14
Copy link
Member

@blishko blishko left a comment

Choose a reason for hiding this comment

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

LGTM!

@Tomaqa Tomaqa closed this Sep 19, 2024
@Tomaqa Tomaqa deleted the 753-implement-subset-minimal-unsat-core branch September 19, 2024 13:36
@Tomaqa Tomaqa restored the 753-implement-subset-minimal-unsat-core branch September 19, 2024 13:37
@Tomaqa Tomaqa reopened this Sep 19, 2024
@Tomaqa Tomaqa merged commit effdd77 into master Sep 19, 2024
9 checks passed
@Tomaqa Tomaqa deleted the 753-implement-subset-minimal-unsat-core branch September 19, 2024 13:38
@Tomaqa Tomaqa restored the 753-implement-subset-minimal-unsat-core branch September 19, 2024 13:38
@Tomaqa Tomaqa deleted the 753-implement-subset-minimal-unsat-core branch September 19, 2024 13:41
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.

Implement subset-minimal unsat core
2 participants