From 9ae2a77cb73b5361adb8f63b61942c2e2d8a98b3 Mon Sep 17 00:00:00 2001 From: Bernhard Kragl <bernhard.kragl@gmail.com> Date: Mon, 2 Mar 2020 18:57:10 +0100 Subject: [PATCH] Add support to inject lemmas into commutativity checks (#211) --- Source/Concurrency/CivlTypeChecker.cs | 32 +-- Source/Concurrency/CommutativityHints.cs | 259 ++++++++++++++++++ Source/Concurrency/Concurrency.csproj | 2 +- Source/Concurrency/MoverCheck.cs | 7 +- .../TransitionRelationComputation.cs | 20 +- Source/Concurrency/Witnesses.cs | 156 ----------- Source/Core/CivlAttributes.cs | 5 +- Test/civl/async/2pc-triggers.bpl | 15 +- Test/civl/async/2pc.bpl | 15 +- Test/civl/commutativity-lemma.bpl | 23 ++ Test/civl/commutativity-lemma.bpl.expect | 2 + Test/civl/verified-ft.bpl | 25 +- 12 files changed, 346 insertions(+), 215 deletions(-) create mode 100644 Source/Concurrency/CommutativityHints.cs delete mode 100644 Source/Concurrency/Witnesses.cs create mode 100644 Test/civl/commutativity-lemma.bpl create mode 100644 Test/civl/commutativity-lemma.bpl.expect diff --git a/Source/Concurrency/CivlTypeChecker.cs b/Source/Concurrency/CivlTypeChecker.cs index afec56fd6..e8afd2333 100644 --- a/Source/Concurrency/CivlTypeChecker.cs +++ b/Source/Concurrency/CivlTypeChecker.cs @@ -24,8 +24,7 @@ public class CivlTypeChecker public Dictionary<Procedure, AtomicAction> procToIsAbstraction; public Dictionary<Procedure, YieldingProc> procToYieldingProc; public Dictionary<Procedure, IntroductionProc> procToIntroductionProc; - public Dictionary<Tuple<AtomicAction, AtomicAction>, - List<WitnessFunction>> atomicActionPairToWitnessFunctions; + public CommutativityHints commutativityHints; public List<InductiveSequentialization> inductiveSequentializations; @@ -55,8 +54,6 @@ public CivlTypeChecker(Program program) this.procToYieldingProc = new Dictionary<Procedure, YieldingProc>(); this.procToIntroductionProc = new Dictionary<Procedure, IntroductionProc>(); this.implToPendingAsyncCollector = new Dictionary<Implementation, Variable>(); - this.atomicActionPairToWitnessFunctions = new Dictionary<Tuple<AtomicAction, AtomicAction>, - List<WitnessFunction>>(); this.inductiveSequentializations = new List<InductiveSequentialization>(); } @@ -91,7 +88,7 @@ public void TypeCheck() TypeCheckRefinementLayers(); - TypeCheckWitnessFunctions(); + TypeCheckCommutativityHints(); AttributeEraser.Erase(this); } @@ -129,21 +126,11 @@ private void TypeCheckRefinementLayers() } - private void TypeCheckWitnessFunctions() + private void TypeCheckCommutativityHints() { - WitnessFunctionVisitor wfv = new WitnessFunctionVisitor(this); - wfv.VisitFunctions(); - foreach (var witnessFunction in wfv.allWitnessFunctions) - { - var key = Tuple.Create( - witnessFunction.firstAction, - witnessFunction.secondAction); - if (!atomicActionPairToWitnessFunctions.ContainsKey(key)) - { - atomicActionPairToWitnessFunctions[key] = new List<WitnessFunction>(); - } - atomicActionPairToWitnessFunctions[key].Add(witnessFunction); - } + CommutativityHintVisitor visitor = new CommutativityHintVisitor(this); + visitor.VisitFunctions(); + this.commutativityHints = visitor.commutativityHints; } private void TypeCheckGlobalVariables() @@ -893,6 +880,13 @@ public AtomicAction FindIsAbstraction(string name) return procToIsAbstraction.Values.FirstOrDefault(a => a.proc.Name == name); } + public AtomicAction FindAtomicActionOrAbstraction(string name) + { + var action = FindAtomicAction(name); + if (action != null) return action; + return FindIsAbstraction(name); + } + public IEnumerable<AtomicAction> AllActions => procToAtomicAction.Union(procToIsInvariant).Union(procToIsAbstraction) .Select(x => x.Value); diff --git a/Source/Concurrency/CommutativityHints.cs b/Source/Concurrency/CommutativityHints.cs new file mode 100644 index 000000000..f5ca4cb88 --- /dev/null +++ b/Source/Concurrency/CommutativityHints.cs @@ -0,0 +1,259 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + +namespace Microsoft.Boogie +{ + public class CommutativityHint + { + public readonly Function function; + public readonly AtomicAction firstAction; + public readonly AtomicAction secondAction; + public List<Expr> args; + + public CommutativityHint(Function function, + AtomicAction firstAction, AtomicAction secondAction, List<Expr> args) + { + this.function = function; + this.firstAction = firstAction; + this.secondAction = secondAction; + this.args = args; + } + } + + public class CommutativityWitness : CommutativityHint + { + public readonly Variable witnessedVariable; + + public CommutativityWitness(Function function, Variable witnessedVariable, + AtomicAction firstAction, AtomicAction secondAction, List<Expr> args) + : base(function, firstAction, secondAction, args) + { + this.witnessedVariable = witnessedVariable; + } + + public CommutativityWitness(Variable witnessedVariable, CommutativityHint h) + : this(h.function, witnessedVariable, h.firstAction, h.secondAction, h.args) {} + } + + public class CommutativityHints + { + private Dictionary<Tuple<AtomicAction, AtomicAction>, List<CommutativityWitness>> witnesses; + private Dictionary<Tuple<AtomicAction, AtomicAction>, List<CommutativityHint>> lemmas; + + public CommutativityHints() + { + witnesses = new Dictionary<Tuple<AtomicAction, AtomicAction>, List<CommutativityWitness>>(); + lemmas = new Dictionary<Tuple<AtomicAction, AtomicAction>, List<CommutativityHint>>(); + } + + private Tuple<AtomicAction, AtomicAction> Key(AtomicAction first, AtomicAction second) + { + return Tuple.Create(first, second); + } + + public void AddWitness(CommutativityWitness witness) + { + var key = Key(witness.firstAction, witness.secondAction); + if (!witnesses.ContainsKey(key)) + { + witnesses[key] = new List<CommutativityWitness>(); + } + witnesses[key].Add(witness); + } + + public void AddLemma(CommutativityHint lemma) + { + var key = Key(lemma.firstAction, lemma.secondAction); + if (!lemmas.ContainsKey(key)) + { + lemmas[key] = new List<CommutativityHint>(); + } + lemmas[key].Add(lemma); + } + + public IEnumerable<CommutativityWitness> GetWitnesses(AtomicAction first, AtomicAction second) + { + witnesses.TryGetValue(Key(first, second), out List<CommutativityWitness> list); + if (list == null) return Enumerable.Empty<CommutativityWitness>(); + return list; + } + + public IEnumerable<CommutativityHint> GetLemmas(AtomicAction first, AtomicAction second) + { + lemmas.TryGetValue(Key(first, second), out List<CommutativityHint> list); + if (list == null) return Enumerable.Empty<CommutativityHint>(); + return list; + } + } + + class CommutativityHintVisitor + { + private const string FirstProcInputPrefix = "first_"; + private const string SecondProcInputPrefix = "second_"; + private const string PostStateSuffix = "'"; + + private readonly CivlTypeChecker ctc; + public CommutativityHints commutativityHints; + + private AtomicAction firstAction; + private AtomicAction secondAction; + private List<Expr> args; + + public CommutativityHintVisitor(CivlTypeChecker ctc) + { + this.ctc = ctc; + commutativityHints = new CommutativityHints(); + } + + public void VisitFunctions() + { + foreach (var f in ctc.program.Functions) + { + VisitFunction(f); + } + } + + private void VisitFunction(Function function) + { + Debug.Assert(function.OutParams.Count == 1); + List<CommutativityHint> hints = new List<CommutativityHint>(); + // First we collect all {:commutativity "first_action", "second_action"} attributes + for (QKeyValue kv = function.Attributes; kv != null; kv = kv.Next) + { + if (kv.Key != CivlAttributes.COMMUTATIVITY) + continue; + if (kv.Params.Count == 2 && + kv.Params[0] is string firstActionName && + kv.Params[1] is string secondActionName) + { + firstAction = ctc.FindAtomicActionOrAbstraction(firstActionName); + secondAction = ctc.FindAtomicActionOrAbstraction(secondActionName); + if (firstAction == null) + { + ctc.Error(kv, $"Could not find atomic action {firstActionName}"); + } + if (secondAction == null) + { + ctc.Error(kv, $"Could not find atomic action {secondActionName}"); + } + if (firstAction != null && secondAction != null) + { + CheckInParams(function.InParams); + } + hints.Add(new CommutativityHint(function, firstAction, secondAction, args)); + } + else + { + ctc.Error(kv, "Commutativity attribute expects two action names as parameters"); + } + } + + // And then we look for either {:witness "globalVar"} or {:lemma} + for (QKeyValue kv = function.Attributes; kv != null; kv = kv.Next) + { + if (kv.Key == CivlAttributes.WITNESS) + { + if (kv.Params.Count == 1 && + kv.Params[0] is string witnessedVariableName) + { + Variable witnessedVariable = ctc.sharedVariables.Find(v => v.Name == witnessedVariableName); + if (witnessedVariable == null) + { + ctc.Error(kv, $"Could not find shared variable {witnessedVariableName}"); + } + else if (!function.OutParams[0].TypedIdent.Type.Equals(witnessedVariable.TypedIdent.Type)) + { + ctc.Error(function, "Result type does not match witnessed variable"); + } + else + { + hints.ForEach(h => commutativityHints.AddWitness(new CommutativityWitness(witnessedVariable, h))); + } + } + else + { + ctc.Error(kv, "Witness attribute expects the name of a global variable as parameter"); + } + break; + } + else if (kv.Key == CivlAttributes.LEMMA) + { + if (kv.Params.Count == 0) + { + if (!function.OutParams[0].TypedIdent.Type.Equals(Type.Bool)) + { + ctc.Error(function, "Result type of lemma must be bool"); + } + else + { + hints.ForEach(h => commutativityHints.AddLemma(h)); + } + } + else + { + ctc.Error(kv, "Lemma attribute does not expect any parameters"); + } + break; + } + } + } + + private void CheckInParams(List<Variable> inParams) + { + args = new List<Expr>(); + foreach (var param in inParams) + { + Expr arg = null; + if (param.Name.StartsWith(FirstProcInputPrefix, StringComparison.Ordinal)) + { + arg = CheckLocal(param, firstAction.firstImpl, FirstProcInputPrefix); + } + else if (param.Name.StartsWith(SecondProcInputPrefix, StringComparison.Ordinal)) + { + arg = CheckLocal(param, secondAction.secondImpl, SecondProcInputPrefix); + } + else + { + arg = CheckGlobal(param); + } + args.Add(arg); + } + } + + private Expr CheckLocal(Variable param, Implementation impl, string prefix) + { + var var = FindVariable(param.Name, param.TypedIdent.Type, + impl.InParams.Union(impl.OutParams)); + if (var != null) + return Expr.Ident(var); + var name = param.Name.Remove(0, prefix.Length); + ctc.Error(param, $"Action {impl.Name} does not have parameter {name}:{param.TypedIdent.Type}"); + return null; + } + + private Expr CheckGlobal(Variable param) + { + bool postState = param.Name.EndsWith(PostStateSuffix, StringComparison.Ordinal); + var name = param.Name; + if (postState) + name = name.Substring(0, name.Length - 1); + var var = FindVariable(name, param.TypedIdent.Type, ctc.sharedVariables); + if (var != null) + { + if (!postState) + return ExprHelper.Old(Expr.Ident(var)); + else + return Expr.Ident(var); + } + ctc.Error(param, $"No shared variable {name}:{param.TypedIdent.Type}"); + return null; + } + + private Variable FindVariable(string name, Type type, IEnumerable<Variable> vars) + { + return vars.FirstOrDefault(i => i.Name == name && i.TypedIdent.Type.Equals(type)); + } + } +} diff --git a/Source/Concurrency/Concurrency.csproj b/Source/Concurrency/Concurrency.csproj index e13116c08..baa73eb01 100644 --- a/Source/Concurrency/Concurrency.csproj +++ b/Source/Concurrency/Concurrency.csproj @@ -67,7 +67,7 @@ <Compile Include="YieldingProcDuplicator.cs" /> <Compile Include="YieldTypeChecker.cs" /> <Compile Include="CivlUtil.cs" /> - <Compile Include="Witnesses.cs" /> + <Compile Include="CommutativityHints.cs" /> <Compile Include="CivlCoreTypes.cs" /> <Compile Include="InductiveSequentialization.cs" /> <Compile Include="PendingAsyncChecker.cs" /> diff --git a/Source/Concurrency/MoverCheck.cs b/Source/Concurrency/MoverCheck.cs index cb165bf99..515a9e147 100644 --- a/Source/Concurrency/MoverCheck.cs +++ b/Source/Concurrency/MoverCheck.cs @@ -147,8 +147,7 @@ private void CreateCommutativityChecker(AtomicAction first, AtomicAction second) foreach (AssertCmd assertCmd in Enumerable.Union(first.firstGate, second.secondGate)) requires.Add(new Requires(false, assertCmd.Expr)); - civlTypeChecker.atomicActionPairToWitnessFunctions.TryGetValue( - Tuple.Create(first, second), out List<WitnessFunction> witnesses); + var witnesses = civlTypeChecker.commutativityHints.GetWitnesses(first, second); var transitionRelation = TransitionRelationComputation. Commutativity(second, first, frame, witnesses); @@ -165,6 +164,10 @@ private void CreateCommutativityChecker(AtomicAction first, AtomicAction second) second.secondImpl.OutParams.Select(Expr.Ident).ToList() ) { Proc = second.proc } }; + foreach (var lemma in civlTypeChecker.commutativityHints.GetLemmas(first,second)) + { + cmds.Add(CmdHelper.AssumeCmd(ExprHelper.FunctionCall(lemma.function, lemma.args.ToArray()))); + } var block = new Block(Token.NoToken, "init", cmds, new ReturnCmd(Token.NoToken)); var secondInParamsFiltered = second.secondImpl.InParams.Where(v => linearTypeChecker.FindLinearKind(v) != LinearKind.LINEAR_IN); diff --git a/Source/Concurrency/TransitionRelationComputation.cs b/Source/Concurrency/TransitionRelationComputation.cs index 481c45b3e..8e56e15de 100644 --- a/Source/Concurrency/TransitionRelationComputation.cs +++ b/Source/Concurrency/TransitionRelationComputation.cs @@ -12,7 +12,7 @@ public class TransitionRelationComputation private readonly Dictionary<Variable, Function> triggers; private readonly HashSet<Variable> frame; private readonly HashSet<Variable> allInParams, allOutParams, allLocVars; - private readonly Dictionary<Variable, List<WitnessFunction>> globalVarToWitnesses; + private readonly Dictionary<Variable, List<CommutativityWitness>> globalVarToWitnesses; private readonly bool ignorePostState; private readonly string messagePrefix; @@ -36,7 +36,7 @@ public class TransitionRelationComputation private TransitionRelationComputation( Implementation first, Implementation second, - IEnumerable<Variable> frame, List<WitnessFunction> witnesses, Dictionary<Variable, Function> triggers, bool ignorePostState, + IEnumerable<Variable> frame, IEnumerable<CommutativityWitness> witnesses, Dictionary<Variable, Function> triggers, bool ignorePostState, string messagePrefix) { this.first = first; @@ -59,7 +59,7 @@ private TransitionRelationComputation( this.checkingContext = new CheckingContext(null); this.pathTranslations = new List<Expr>(); - this.globalVarToWitnesses = new Dictionary<Variable, List<WitnessFunction>>(); + this.globalVarToWitnesses = new Dictionary<Variable, List<CommutativityWitness>>(); if (witnesses != null) { foreach (var witness in witnesses) @@ -67,7 +67,7 @@ private TransitionRelationComputation( var gVar = witness.witnessedVariable; if (!globalVarToWitnesses.ContainsKey(gVar)) { - globalVarToWitnesses[gVar] = new List<WitnessFunction>(); + globalVarToWitnesses[gVar] = new List<CommutativityWitness>(); } globalVarToWitnesses[gVar].Add(witness); } @@ -76,7 +76,7 @@ private TransitionRelationComputation( private static Expr ComputeTransitionRelation( Implementation first, Implementation second, - IEnumerable<Variable> frame, Dictionary<Variable, Function> triggers, List<WitnessFunction> witnesses, bool ignorePostState, + IEnumerable<Variable> frame, Dictionary<Variable, Function> triggers, IEnumerable<CommutativityWitness> witnesses, bool ignorePostState, string messagePrefix) { var trc = new TransitionRelationComputation(first, second, frame, witnesses, triggers, ignorePostState, messagePrefix); @@ -88,7 +88,7 @@ private static Expr ComputeTransitionRelation( } public static Expr Commutativity(AtomicAction first, AtomicAction second, - HashSet<Variable> frame, List<WitnessFunction> witnesses) + HashSet<Variable> frame, IEnumerable<CommutativityWitness> witnesses) { var triggers = first.triggerFunctions.Union(second.triggerFunctions).ToDictionary(kv => kv.Key, kv => kv.Value); return ComputeTransitionRelation( @@ -484,7 +484,7 @@ private void ReplacePreOrPostStateVars() private void ComputeWitnessedTransitionRelationExprs() { witnessedTransitionRelations = new List<Expr>(); - Dictionary<Variable, List<WitnessFunction>> varToWitnesses = trc.FrameWithWitnesses. + Dictionary<Variable, List<CommutativityWitness>> varToWitnesses = trc.FrameWithWitnesses. Where(x => NotEliminatedVars.Contains(frameIntermediateCopy[x])). ToDictionary( x => frameIntermediateCopy[x], @@ -492,12 +492,12 @@ private void ComputeWitnessedTransitionRelationExprs() foreach (var witnessSet in varToWitnesses.Values.CartesianProduct()) { Dictionary<Variable, Expr> witnessSubst = new Dictionary<Variable, Expr>(); - foreach (Tuple<Variable, WitnessFunction> pair in + foreach (Tuple<Variable, CommutativityWitness> pair in Enumerable.Zip(varToWitnesses.Keys, witnessSet, Tuple.Create)) { - WitnessFunction witnessFunction = pair.Item2; + CommutativityWitness witness = pair.Item2; witnessSubst[pair.Item1] = ExprHelper.FunctionCall( - witnessFunction.function, witnessFunction.args.ToArray() + witness.function, witness.args.ToArray() ); } witnessedTransitionRelations.Add( diff --git a/Source/Concurrency/Witnesses.cs b/Source/Concurrency/Witnesses.cs deleted file mode 100644 index 878cad05e..000000000 --- a/Source/Concurrency/Witnesses.cs +++ /dev/null @@ -1,156 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; - -namespace Microsoft.Boogie -{ - public class WitnessFunction - { - public readonly Function function; - public readonly Variable witnessedVariable; - public readonly AtomicAction firstAction; - public readonly AtomicAction secondAction; - public List<Expr> args; - - public WitnessFunction(Function function, Variable witnessedVariable, - AtomicAction firstAction, AtomicAction secondAction, List<Expr> args) - { - this.function = function; - this.witnessedVariable = witnessedVariable; - this.firstAction = firstAction; - this.secondAction = secondAction; - this.args = args; - } - } - - class WitnessFunctionVisitor - { - private const string FirstProcInputPrefix = "first_"; - private const string SecondProcInputPrefix = "second_"; - private const string PostStateSuffix = "'"; - - private readonly CivlTypeChecker ctc; - internal List<WitnessFunction> allWitnessFunctions; - - private Variable witnessedVariable; - private AtomicAction firstAction; - private AtomicAction secondAction; - private List<Expr> args; - - public WitnessFunctionVisitor(CivlTypeChecker ctc) - { - this.ctc = ctc; - allWitnessFunctions = new List<WitnessFunction>(); - } - - public void VisitFunctions() - { - foreach (var f in ctc.program.Functions) - { - VisitFunction(f); - } - } - - private void VisitFunction(Function function) - { - Debug.Assert(function.OutParams.Count == 1); - for (QKeyValue kv = function.Attributes; kv != null; kv = kv.Next) - { - if (kv.Key != CivlAttributes.WITNESS) - continue; - if (kv.Params.Count == 3 && - kv.Params[0] is string witnessedVariableName && - kv.Params[1] is string firstActionName && - kv.Params[2] is string secondActionName) - { - witnessedVariable = ctc.sharedVariables.Find(v => v.Name == witnessedVariableName); - if (witnessedVariable == null) - { - ctc.Error(kv, $"Could not find shared variable {witnessedVariableName}"); - } - else if (!function.OutParams[0].TypedIdent.Type.Equals(witnessedVariable.TypedIdent.Type)) - { - ctc.Error(function, "Result type does not match witnessed variable"); - } - firstAction = ctc.FindAtomicAction(firstActionName); - secondAction = ctc.FindAtomicAction(secondActionName); - if (firstAction == null) - { - ctc.Error(kv, $"Could not find atomic action {firstActionName}"); - } - if (secondAction == null) - { - ctc.Error(kv, $"Could not find atomic action {firstActionName}"); - } - if (firstAction != null && secondAction != null) - { - CheckInParams(function.InParams); - } - allWitnessFunctions.Add(new WitnessFunction(function, witnessedVariable, - firstAction, secondAction, args)); - } - else - { - ctc.Error(kv, "Witness attribute expects three string parameters"); - } - } - } - - private void CheckInParams(List<Variable> inParams) - { - args = new List<Expr>(); - foreach (var param in inParams) - { - Expr arg = null; - if (param.Name.StartsWith(FirstProcInputPrefix, StringComparison.Ordinal)) - { - arg = CheckLocal(param, firstAction.firstImpl, FirstProcInputPrefix); - } - else if (param.Name.StartsWith(SecondProcInputPrefix, StringComparison.Ordinal)) - { - arg = CheckLocal(param, secondAction.secondImpl, SecondProcInputPrefix); - } - else - { - arg = CheckGlobal(param); - } - args.Add(arg); - } - } - - private Expr CheckLocal(Variable param, Implementation impl, string prefix) - { - var var = FindVariable(param.Name, param.TypedIdent.Type, - impl.InParams.Union(impl.OutParams)); - if (var != null) - return Expr.Ident(var); - var name = param.Name.Remove(0, prefix.Length); - ctc.Error(param, $"Action {impl.Name} does not have parameter {name}:{param.TypedIdent.Type}"); - return null; - } - - private Expr CheckGlobal(Variable param) - { - bool postState = param.Name.EndsWith(PostStateSuffix, StringComparison.Ordinal); - var name = param.Name; - if (postState) - name = name.Substring(0, name.Length - 1); - var var = FindVariable(name, param.TypedIdent.Type, ctc.sharedVariables); - if (var != null) - { - if (!postState) - return ExprHelper.Old(Expr.Ident(var)); - else - return Expr.Ident(var); - } - ctc.Error(param, $"No shared variable {name}:{param.TypedIdent.Type}"); - return null; - } - - private Variable FindVariable(string name, Type type, IEnumerable<Variable> vars) - { - return vars.FirstOrDefault(i => i.Name == name && i.TypedIdent.Type.Equals(type)); - } - } -} diff --git a/Source/Core/CivlAttributes.cs b/Source/Core/CivlAttributes.cs index d7e815b14..11129463e 100644 --- a/Source/Core/CivlAttributes.cs +++ b/Source/Core/CivlAttributes.cs @@ -27,6 +27,8 @@ public static class CivlAttributes public const string LINEAR_OUT = "linear_out"; public const string BACKWARD = "backward"; + public const string COMMUTATIVITY = "commutativity"; + public const string LEMMA = "lemma"; public const string WITNESS = "witness"; public const string PENDING_ASYNC = "pending_async"; @@ -39,7 +41,8 @@ public static class CivlAttributes public const string CHOICE = "choice"; private static string[] CIVL_ATTRIBUTES = - {LAYER, YIELDS, ATOMIC, LEFT, RIGHT, BOTH, REFINES, WITNESS, + {LAYER, YIELDS, ATOMIC, LEFT, RIGHT, BOTH, REFINES, + COMMUTATIVITY, LEMMA, WITNESS, PENDING_ASYNC, IS, IS_INVARIANT, IS_ABSTRACTION, ELIM, CHOICE }; private static string[] LINEAR_ATTRIBUTES = diff --git a/Test/civl/async/2pc-triggers.bpl b/Test/civl/async/2pc-triggers.bpl index 03ad0cc97..1b3849ea8 100644 --- a/Test/civl/async/2pc-triggers.bpl +++ b/Test/civl/async/2pc-triggers.bpl @@ -173,13 +173,14 @@ procedure {:yields} {:layer 11} YieldConsistent_11 () // ########################################################################### function -{:witness "state","atomic_Coordinator_VoteNo","atomic_Coordinator_VoteNo"} -{:witness "state","atomic_Coordinator_VoteYes","atomic_Coordinator_VoteNo"} -{:witness "state","atomic_Coordinator_VoteNo","atomic_Coordinator_VoteYes"} -{:witness "state","atomic_Coordinator_VoteYes","atomic_Coordinator_VoteYes"} -{:witness "state","atomic_SetParticipantAborted","atomic_Coordinator_VoteYes"} -{:witness "state","atomic_SetParticipantAborted","atomic_Coordinator_VoteNo"} -{:witness "state","atomic_Participant_VoteReq","atomic_Participant_VoteReq"} +{:witness "state"} +{:commutativity "atomic_Coordinator_VoteNo","atomic_Coordinator_VoteNo"} +{:commutativity "atomic_Coordinator_VoteYes","atomic_Coordinator_VoteNo"} +{:commutativity "atomic_Coordinator_VoteNo","atomic_Coordinator_VoteYes"} +{:commutativity "atomic_Coordinator_VoteYes","atomic_Coordinator_VoteYes"} +{:commutativity "atomic_SetParticipantAborted","atomic_Coordinator_VoteYes"} +{:commutativity "atomic_SetParticipantAborted","atomic_Coordinator_VoteNo"} +{:commutativity "atomic_Participant_VoteReq","atomic_Participant_VoteReq"} witness (state:GState, state':GState, second_xid:Xid) : GState { state[second_xid := state'[second_xid]] diff --git a/Test/civl/async/2pc.bpl b/Test/civl/async/2pc.bpl index 8dc78f0af..4c247e720 100644 --- a/Test/civl/async/2pc.bpl +++ b/Test/civl/async/2pc.bpl @@ -163,13 +163,14 @@ procedure {:yields} {:layer 11} YieldConsistent_11 () // ########################################################################### function -{:witness "state","atomic_Coordinator_VoteNo","atomic_Coordinator_VoteNo"} -{:witness "state","atomic_Coordinator_VoteYes","atomic_Coordinator_VoteNo"} -{:witness "state","atomic_Coordinator_VoteNo","atomic_Coordinator_VoteYes"} -{:witness "state","atomic_Coordinator_VoteYes","atomic_Coordinator_VoteYes"} -{:witness "state","atomic_SetParticipantAborted","atomic_Coordinator_VoteYes"} -{:witness "state","atomic_SetParticipantAborted","atomic_Coordinator_VoteNo"} -{:witness "state","atomic_Participant_VoteReq","atomic_Participant_VoteReq"} +{:witness "state"} +{:commutativity "atomic_Coordinator_VoteNo","atomic_Coordinator_VoteNo"} +{:commutativity "atomic_Coordinator_VoteYes","atomic_Coordinator_VoteNo"} +{:commutativity "atomic_Coordinator_VoteNo","atomic_Coordinator_VoteYes"} +{:commutativity "atomic_Coordinator_VoteYes","atomic_Coordinator_VoteYes"} +{:commutativity "atomic_SetParticipantAborted","atomic_Coordinator_VoteYes"} +{:commutativity "atomic_SetParticipantAborted","atomic_Coordinator_VoteNo"} +{:commutativity "atomic_Participant_VoteReq","atomic_Participant_VoteReq"} witness (state:GState, state':GState, second_xid:Xid) : GState { state[second_xid := state'[second_xid]] diff --git a/Test/civl/commutativity-lemma.bpl b/Test/civl/commutativity-lemma.bpl new file mode 100644 index 000000000..9027364e6 --- /dev/null +++ b/Test/civl/commutativity-lemma.bpl @@ -0,0 +1,23 @@ +// RUN: %boogie -noinfer "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +// Contrived example to illustrate the injection of lemmas into commutativity checks + +var {:layer 0,1} x : int; + +function f(x: int, i: int) : int; + +function {:inline} +{:lemma} +{:commutativity "inc", "inc"} +lemma (x: int, first_i: int, second_i: int) : bool +{ + f(x, first_i) == x + first_i && + f(x + first_i, second_i) == x + first_i + second_i && + f(x, second_i) == x + second_i && + f(x + second_i, first_i) == x + second_i + first_i +} + +procedure {:right} {:layer 1} inc (i: int) +modifies x; +{ x := f(x, i); } diff --git a/Test/civl/commutativity-lemma.bpl.expect b/Test/civl/commutativity-lemma.bpl.expect new file mode 100644 index 000000000..37fad75c9 --- /dev/null +++ b/Test/civl/commutativity-lemma.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 1 verified, 0 errors diff --git a/Test/civl/verified-ft.bpl b/Test/civl/verified-ft.bpl index 36cf6810b..86b3a77fc 100644 --- a/Test/civl/verified-ft.bpl +++ b/Test/civl/verified-ft.bpl @@ -1197,18 +1197,19 @@ function {:inline false} f(i: int): bool { true } function -{:witness "shadow.VC","AtomicVC.Inc","AtomicVC.Copy"} -{:witness "shadow.VC","AtomicVC.Inc","AtomicVC.Join"} -{:witness "shadow.VC","AtomicVCSetElem","AtomicVC.Copy"} -{:witness "shadow.VC","AtomicVCSetElem","AtomicVC.Join"} -{:witness "shadow.VC","AtomicVCSetElemShared","AtomicVC.Copy"} -{:witness "shadow.VC","AtomicVCSetElemShared","AtomicVC.Join"} -{:witness "shadow.VC","AtomicVCInit","AtomicVC.Copy"} -{:witness "shadow.VC","AtomicVCInit","AtomicVC.Join"} -{:witness "shadow.VC","AtomicVC.Copy","AtomicVC.Copy"} -{:witness "shadow.VC","AtomicVC.Copy","AtomicVC.Join"} -{:witness "shadow.VC","AtomicVC.Join","AtomicVC.Copy"} -{:witness "shadow.VC","AtomicVC.Join","AtomicVC.Join"} +{:witness "shadow.VC"} +{:commutativity "AtomicVC.Inc","AtomicVC.Copy"} +{:commutativity "AtomicVC.Inc","AtomicVC.Join"} +{:commutativity "AtomicVCSetElem","AtomicVC.Copy"} +{:commutativity "AtomicVCSetElem","AtomicVC.Join"} +{:commutativity "AtomicVCSetElemShared","AtomicVC.Copy"} +{:commutativity "AtomicVCSetElemShared","AtomicVC.Join"} +{:commutativity "AtomicVCInit","AtomicVC.Copy"} +{:commutativity "AtomicVCInit","AtomicVC.Join"} +{:commutativity "AtomicVC.Copy","AtomicVC.Copy"} +{:commutativity "AtomicVC.Copy","AtomicVC.Join"} +{:commutativity "AtomicVC.Join","AtomicVC.Copy"} +{:commutativity "AtomicVC.Join","AtomicVC.Join"} witness (shadow.VC:[Shadowable]VC, shadow.VC':[Shadowable]VC, second_v1:Shadowable) : [Shadowable]VC { shadow.VC[second_v1 := shadow.VC'[second_v1]]