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

Add an experimental backend that uses Lean to discharge goals #850

Merged
merged 33 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
bf36ddf
Translator sufficient for Bubble.bpl to typecheck
atomb Dec 13, 2023
8309d33
Now Bubble.bpl verifies after translation
atomb Dec 14, 2023
4b2eb9e
Control Lean printing with an option
atomb Dec 19, 2023
89b3595
Translator sufficient to verify all but one textbook example
atomb Dec 19, 2023
f6f8ff6
Reorganize unsupported overrides
atomb Dec 19, 2023
637c415
Various improvements
atomb Dec 20, 2023
e4c34dc
Successfully process trivial Dafny program
atomb Dec 22, 2023
2556b26
Cleanups
atomb Dec 22, 2023
7049b6d
Update exception messages
atomb Feb 13, 2024
b2c5b14
Move prelude to external file
atomb Feb 13, 2024
d2193dd
Add configuration files to check Prelude.lean
atomb Feb 13, 2024
7c096c0
Cleanup comments, strings, exceptions
atomb Feb 13, 2024
7fea48d
Clean up error handling
atomb Feb 14, 2024
05b616c
Reorder cases and improve error messages
atomb Feb 14, 2024
005d80d
Add test suite for LeanAuto backend
atomb Feb 14, 2024
df6bb76
Add README for LeanAuto
atomb Feb 14, 2024
6628fea
Add workflow to test the LeanAuto backend
atomb Feb 14, 2024
300ed90
Fill in proofs and definitions in Lean prelude
atomb Feb 14, 2024
359da35
Clean up lakefile
atomb Feb 14, 2024
4fc941d
Fix Lean installation
atomb Feb 14, 2024
bf46f95
Change setup-lean action name
atomb Feb 14, 2024
154fee4
Ensure Lean dependencies are actually built
atomb Feb 14, 2024
9d58eb5
Pin the version of lean-auto for reproducibility
atomb Feb 14, 2024
2896020
Merge remote-tracking branch 'upstream/master' into basic-lean-auto
atomb Mar 6, 2024
a2a40d6
Rename LeanGenerator -> LeanAutoGenerator
atomb Mar 6, 2024
49e1eec
Rename some methods
atomb Mar 6, 2024
2f8b3a9
Move use of passive program to a separate method
atomb Mar 6, 2024
fd7b4c9
Clarify comment
atomb Mar 7, 2024
dd8359f
Merge remote-tracking branch 'upstream/master' into basic-lean-auto
atomb Mar 7, 2024
dc6b667
Merge branch 'master' into basic-lean-auto
atomb Mar 13, 2024
4cc7547
Generalized processing of passive programs
atomb Mar 19, 2024
29979dc
Allow `goto` to have no targets
atomb Mar 19, 2024
fbafb12
Use `foreach` instead of `ForEach`
atomb Mar 19, 2024
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
45 changes: 39 additions & 6 deletions Source/ExecutionEngine/CommandLineOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
using System.Collections.Specialized;
using System.Diagnostics.Contracts;
using System.IO;
using Microsoft.Boogie.LeanAuto;
using Microsoft.Boogie.SMTLib;
using VC;

namespace Microsoft.Boogie
{
Expand Down Expand Up @@ -64,7 +66,6 @@ void ObjectInvariant2()
public bool VerifySeparately { get; set; }
public string PrintFile { get; set; }
public string PrintPrunedFile { get; set; }
public string LeanFile { get; set; }

/**
* Whether to emit {:qid}, {:skolemid} and set-info :boogie-vc-id
Expand Down Expand Up @@ -92,6 +93,37 @@ public bool PrintPassive {
set => printPassive = value;
}

public List<Action<ExecutionEngineOptions, ProcessedProgram>> UseResolvedProgram { get; } = new();

static void PassifyAllImplementations(ExecutionEngineOptions options, ProcessedProgram processedProgram)
{
// All three of these objects can be new instances because they're essentially not used by PrepareImplementation.
var callback = new VerifierCallback(options.PrintProverWarnings);
var checkerPool = new CheckerPool(options);
var vcGenerator = new VerificationConditionGenerator(processedProgram.Program, checkerPool);

foreach(var implementation in processedProgram.Program.Implementations) {
vcGenerator.PrepareImplementation(new ImplementationRun(implementation, options.OutputWriter),
callback, out _, out _, out _);
}
}

public static void PrintPassiveProgram(ExecutionEngineOptions options, ProcessedProgram processedProgram)
{
options.PrintUnstructured = 1;
PassifyAllImplementations(options, processedProgram);
ExecutionEngine.PrintBplFile(options, options.PrintFile, processedProgram.Program, true, true, options.PrettyPrint);
}

public static void PrintPassiveProgramAsLean(string fileName, ExecutionEngineOptions options, ProcessedProgram processedProgram)
{
var writer = new StreamWriter(fileName);
PassifyAllImplementations(options, processedProgram);
LeanAutoGenerator.EmitPassiveProgramAsLean(options, processedProgram.Program, writer);
writer.Close();

}

public bool PrintLambdaLifting { get; set; }
public bool FreeVarLambdaLifting { get; set; }
public string ProverLogFilePath { get; set; }
Expand Down Expand Up @@ -406,7 +438,7 @@ public bool TrustRefinement {
get => trustRefinement;
set => trustRefinement = value;
}

public int TrustLayersUpto { get; set; } = -1;

public int TrustLayersDownto { get; set; } = int.MaxValue;
Expand Down Expand Up @@ -682,9 +714,10 @@ protected override bool ParseOption(string name, CommandLineParseState ps)
return true;

case "printLean":
if (ps.ConfirmArgumentCount(1))
{
LeanFile = args[ps.i];
if (ps.ConfirmArgumentCount(1)) {
var fileName = args[ps.i];
UseResolvedProgram.Add((o, p) =>
PrintPassiveProgramAsLean(fileName, o, p));
}

return true;
Expand Down Expand Up @@ -1285,7 +1318,7 @@ protected override bool ParseOption(string name, CommandLineParseState ps)
if (ps.CheckBooleanFlag("printDesugared", x => printDesugarings = x) ||
ps.CheckBooleanFlag("printLambdaLifting", x => PrintLambdaLifting = x) ||
ps.CheckBooleanFlag("printInstrumented", x => printInstrumented = x) ||
ps.CheckBooleanFlag("printPassive", x => printPassive = x) ||
ps.CheckBooleanFlag("printPassive", x => UseResolvedProgram.Add(PrintPassiveProgram)) ||
ps.CheckBooleanFlag("printWithUniqueIds", x => printWithUniqueAstIds = x) ||
ps.CheckBooleanFlag("wait", x => Wait = x) ||
ps.CheckBooleanFlag("trace", x => Verbosity = CoreOptions.VerbosityLevel.Trace) ||
Expand Down
24 changes: 4 additions & 20 deletions Source/ExecutionEngine/ExecutionEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,10 @@ public async Task<PipelineOutcome> InferAndVerify(

var processedProgram = PreProcessProgramVerification(program);

if (Options.UseResolvedProgram.Any()) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could drop the if and always do the foreach.

Options.UseResolvedProgram.ForEach(action => action(Options, processedProgram));
Copy link
Collaborator

@keyboardDrummer keyboardDrummer Mar 19, 2024

Choose a reason for hiding this comment

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

I would use a C# foreach construct here, but it's a bit of style thing. One advantage is that it's nicer to step through the iterations with a debugger. Another is that IDEs will be able to analyze it better.

}

if (!Options.Verify)
{
return PipelineOutcome.Done;
Expand All @@ -572,12 +576,6 @@ public async Task<PipelineOutcome> InferAndVerify(

var outcome = await VerifyEachImplementation(output, processedProgram, stats, programId, er, requestId, stablePrioritizedImpls);

// We unfortunately have to do any processing of the passive program
// after running VerifyEachImplementation, because it passifies the
// program in place. We should eventually refactor the code to
// passify the program as an independent step.
UsePassiveProgram(processedProgram.Program);

if (1 < Options.VerifySnapshots && programId != null)
{
program.FreezeTopLevelDeclarations();
Expand All @@ -589,20 +587,6 @@ public async Task<PipelineOutcome> InferAndVerify(
return outcome;
}

private void UsePassiveProgram(Program passiveProgram)
{
if (Options.PrintPassive) {
Options.PrintUnstructured = 1;
PrintBplFile(Options.PrintFile, passiveProgram, true, true, Options.PrettyPrint);
}

if (Options.LeanFile is not null) {
var writer = new StreamWriter(Options.LeanFile);
LeanAutoGenerator.EmitPassiveProgramAsLean(Options, passiveProgram, writer);
writer.Close();
}
}

private ProcessedProgram PreProcessProgramVerification(Program program)
{
// Doing lambda expansion before abstract interpretation means that the abstract interpreter
Expand Down
3 changes: 2 additions & 1 deletion Source/ExecutionEngine/ExecutionEngineOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ public interface ExecutionEngineOptions : HoudiniOptions, ConcurrencyOptions
string DescriptiveToolName { get; }
bool TraceProofObligations { get; }
string PrintFile { get; }
string LeanFile { get; }
List<Action<ExecutionEngineOptions, ProcessedProgram>> UseResolvedProgram { get; }

string PrintCFGPrefix { get; }
string CivlDesugaredFile { get; }
bool CoalesceBlocks { get; }
Expand Down
10 changes: 7 additions & 3 deletions Source/Provers/LeanAuto/LeanAutoGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,13 @@ public override Cmd VisitAssumeCmd(AssumeCmd node)

public override GotoCmd VisitGotoCmd(GotoCmd node)
{
var gotoText = node.labelTargets.Select(l =>
$"goto {BlockName(l)}").Aggregate((a, b) => $"{a} {AndString} {b}");
Indent(2, gotoText);
string cmd = node.labelTargets.Any()
? node
.labelTargets
.Select(l => $"goto {BlockName(l)}")
.Aggregate((a, b) => $"{a} {AndString} {b}")
: "ret";
Indent(2, cmd);
return node;
}

Expand Down
Loading