@@ -564,6 +564,181 @@ object Refactor {
564564 )
565565 }
566566
567+ /**
568+ * Given a program `a;x:=*`, adds a `x:=*` within `a` at position `pos`
569+ * @note
570+ * `pos` refers to the position in `a;x:=*`, not in `a`
571+ * @see
572+ * [[moveRandomIn ]] and [[moveRandomOut ]]
573+ */
574+ def moveRandom (a : Program , pos : PosInExpr ): ProvableSig = {
575+ a match {
576+ case Compose (b, AssignAny (x)) if pos.head == 0 =>
577+ b.at(pos.child) match {
578+ case (ctx, c : Program ) =>
579+ val a_updated = Compose (ctx(Compose (c, AssignAny (x))), AssignAny (x))
580+ proveBy(
581+ ProgramEquivalence (a_updated, a),
582+ moveRandomAux(ctx, c, x, PosInExpr (0 :: Nil )) & useAt(prgEqRefl)(1 ),
583+ )
584+ case (ctx, e) => ???
585+ }
586+
587+ case _ => ???
588+ }
589+ }
590+
591+ def moveRandomAux (ctx : Context [Program ], p : Program , x : Variable , pos : PosInExpr ): BelleExpr = {
592+ ctx.ctx match {
593+ case DotProgram =>
594+ val ax = x match {
595+ case _ : BaseVariable => prgEqRandomIdem
596+ case _ : DifferentialSymbol => prgEqRandomDIdem
597+ }
598+ useAt(refSeqAssoc)(1 , pos) & useAt(ax)(1 , pos ++ 1 )
599+ case Choice (a, b) =>
600+ val (nextPrg, nextPos) =
601+ if (! symbols(a).contains(DotProgram )) { (b, 1 ) }
602+ else if (! symbols(b).contains(DotProgram )) { (a, 0 ) }
603+ else ???
604+ useAt(refDistrR)(1 , pos) & moveRandomAux(Context (nextPrg), p, x, pos ++ nextPos) &
605+ useAt(refDistrR, PosInExpr (0 :: Nil ))(1 , pos)
606+ case Compose (a, c) if ! symbols(a).contains(DotProgram ) =>
607+ useAt(refSeqAssoc)(1 , pos) & moveRandomAux(Context (c), p, x, pos ++ 1 ) &
608+ useAt(refSeqAssoc, PosInExpr (0 :: Nil ))(1 , pos)
609+ case Compose (c, a) if ! symbols(a).contains(DotProgram ) =>
610+ val ax = x match {
611+ case _ : BaseVariable => refAnyFresh
612+ case _ : DifferentialSymbol => refAnyDFresh
613+ }
614+ useAt(refSeqAssoc)(1 , pos) & useAt(ax, PosInExpr (1 :: Nil ))(1 , pos ++ 1 ) &
615+ useAt(refSeqAssoc, PosInExpr (0 :: Nil ))(1 , pos) & moveRandomAux(Context (c), p, x, pos ++ 0 ) &
616+ useAt(refSeqAssoc)(1 , pos) & useAt(ax)(1 , pos ++ 1 ) & useAt(refSeqAssoc, PosInExpr (0 :: Nil ))(1 , pos)
617+ case Loop (c) =>
618+ val axLoop = x match {
619+ case _ : BaseVariable => moveRandomLoop
620+ case _ : DifferentialSymbol => moveRandomLoopD
621+ }
622+ val assgn = AssignAny (x)
623+ val prg = Context (c)(Compose (p, assgn)) // C(p;x:=*)
624+
625+ // x:=*;C(p;x:=*)*;x:=* == C(p;x:=*)*;x:=*
626+ val fuseBefore = fuseRandom(Loop (prg), x)
627+ // (C(p;x:=*);x:=*)*;x:=* == (C(p;x:=*))*;x:=*
628+ val loopCommBefore = proveBy(
629+ ProgramEquivalence (Compose (Loop (Compose (prg, assgn)), assgn), Compose (Loop (prg), assgn)),
630+ useAt(axLoop, PosInExpr (1 :: Nil ))(1 ) & G (1 ) & G (1 ) & byUS(fuseBefore),
631+ )
632+
633+ // x:=*;C(p)*;x:=* == C(p)*;x:=*
634+ val fuseAfter = fuseRandom(Loop (Context (c)(p)), x)
635+ // (C(p);x:=*)*;x:=* == (C(p))*;x:=*
636+ val loopCommAfter = proveBy(
637+ ProgramEquivalence (Compose (Loop (Compose (Context (c)(p), assgn)), assgn), Compose (ctx(p), assgn)),
638+ useAt(axLoop, PosInExpr (1 :: Nil ))(1 ) & G (1 ) & G (1 ) & byUS(fuseAfter),
639+ )
640+ // Merging the proof
641+ useAt(loopCommBefore, PosInExpr (1 :: Nil ))(1 , pos) & moveRandomAux(Context (c), p, x, pos ++ 0 ++ 0 ) &
642+ useAt(loopCommAfter, PosInExpr (0 :: Nil ))(1 , pos)
643+ case _ => ???
644+ }
645+ }
646+
647+ /**
648+ * For a subprogram `a;x:=*` at position `posOut`, copies `x:=*` inside `a` just after the position `posIn`
649+ * @note
650+ * if successful, the nondeterministic assignment will be at `posOut ++ posIn ++ (1 :: Nil)`
651+ */
652+ def moveRandomIn (posIn : PosInExpr ): DependentPositionWithAppliedInputTactic = " moveRandomIn" .byWithInputs(
653+ List (posIn),
654+ (posOut : Position , sequent : Sequent ) => {
655+ sequent.at(posOut) match {
656+ case (_, a : Program ) =>
657+ val pr = moveRandom(a, posIn)
658+ useAt(pr, PosInExpr (1 :: Nil ))(posOut)
659+ case _ => ???
660+ }
661+ },
662+ )
663+
664+ @ Derivation
665+ val moveRandomInInfo : PositionTacticInfo = PositionTacticInfo .create(
666+ name = " moveRandomIn" ,
667+ displayName = Some (" Move Nondeterministic In" ),
668+ displayLevel = DisplayLevel .Menu ,
669+ displayConclusion = " __C(a);x:=*__ == C(a;x:=*);x:=*" ,
670+ constructor = TacticConstructor1 .create(PosInExprArg (" pos" ))(moveRandomIn),
671+ )
672+
673+ /**
674+ * For a subprogram `C(a;x:=*);x:=*` at position `posOut`, removes the `x:=*` after `a`
675+ * @note
676+ * `posIn` refers to the position of the hole of `C`. If successful, `a` will be a position `posOut ++ posIn`.
677+ */
678+ def moveRandomOut (posIn : PosInExpr ): DependentPositionWithAppliedInputTactic = " moveRandomOut" .byWithInputs(
679+ List (posIn),
680+ (posOut : Position , sequent : Sequent ) => {
681+ sequent.at(posOut) match {
682+ case (_, a : Program ) =>
683+ // Remove AssignAny
684+ val resPrg = a.at(posIn) match {
685+ case (ctx, Compose (b, AssignAny (_))) => ctx(b)
686+ case _ => ???
687+ }
688+ val pr = moveRandom(resPrg, posIn)
689+ useAt(pr, PosInExpr (0 :: Nil ))(posOut)
690+ case _ => ???
691+ }
692+ },
693+ )
694+
695+ @ Derivation
696+ val moveRandomOutInfo : PositionTacticInfo = PositionTacticInfo .create(
697+ name = " moveRandomOut" ,
698+ displayName = Some (" Move Nondeterministic Out" ),
699+ displayLevel = DisplayLevel .Menu ,
700+ displayConclusion = " C(a);x:=* == __C(a;x:=*);x:=*__" ,
701+ constructor = TacticConstructor1 .create(PosInExprArg (" pos" ))(moveRandomOut),
702+ )
703+
704+ lazy val moveRandomLoop : ProvableSig = proveBy(
705+ " [{a{|^@|};x_:=*;}*][a{|^@|};]{x_:=*;{a{|^@|};}*;x_:=*;}=={{a{|^@|};}*x_:=*;}->{a{|^@|};x_:=*;}*;x_:=*; == {a{|^@|};}*;x_:=*;"
706+ .asFormula,
707+ implyR(1 ) & useAt(refAntiSym)(1 ) & andR(1 ) & Idioms .< (
708+ refTrans(" {a{|^@|};x_:=*;}*{a{|^@|};}*x_:=*;" .asProgram)(1 ) & andR(1 ) & Idioms .< (
709+ useAt(refUnfoldL, PosInExpr (1 :: Nil ))(1 , 1 :: 1 :: 0 :: Nil ) & useAt(hideChoiceR)(1 , 1 :: 1 :: 0 :: Nil ) &
710+ useAt(refSeqIdL)(1 , 1 :: 1 :: Nil ) & cohide(1 ) & useAt(refRefl)(1 ),
711+ useAt(refLoopL)(1 ) & implyRi & useAt(K )(1 ) & G (1 ) & implyR(1 ) & useAt(refSeqAssoc)(1 , 0 :: Nil ) &
712+ refTrans(" a{|^@|};{a{|^@|};}*;x_:=*;" .asProgram)(1 ) & andR(1 ) & Idioms .< (
713+ focus(1 , 0 :: 1 :: Nil ) & useAt(refEq)(- 1 , 1 :: Nil ) & id,
714+ useAt(refUnfoldL, PosInExpr (1 :: Nil ))(1 , 1 :: 0 :: Nil ) & useAt(hideChoiceL)(1 , 1 :: 0 :: Nil ) &
715+ useAt(refSeqAssoc)(1 , 1 :: Nil ) & cohide(1 ) & useAt(refRefl)(1 ),
716+ ),
717+ ),
718+ useAt(skipRandom)(1 , 1 :: 0 :: 0 :: 1 :: Nil ) & useAt(refSeqIdR)(1 , 1 :: 0 :: 0 :: Nil ) &
719+ cohide(1 ) & useAt(refRefl)(1 ),
720+ ),
721+ )
722+
723+ lazy val moveRandomLoopD : ProvableSig = proveBy(
724+ " [{a{|^@|};x_':=*;}*][a{|^@|};]{x_':=*;{a{|^@|};}*;x_':=*;}=={{a{|^@|};}*x_':=*;}->{a{|^@|};x_':=*;}*;x_':=*; == {a{|^@|};}*;x_':=*;"
725+ .asFormula,
726+ implyR(1 ) & useAt(refAntiSym)(1 ) & andR(1 ) & Idioms .< (
727+ refTrans(" {a{|^@|};x_':=*;}*{a{|^@|};}*x_':=*;" .asProgram)(1 ) & andR(1 ) & Idioms .< (
728+ useAt(refUnfoldL, PosInExpr (1 :: Nil ))(1 , 1 :: 1 :: 0 :: Nil ) & useAt(hideChoiceR)(1 , 1 :: 1 :: 0 :: Nil ) &
729+ useAt(refSeqIdL)(1 , 1 :: 1 :: Nil ) & cohide(1 ) & useAt(refRefl)(1 ),
730+ useAt(refLoopL)(1 ) & implyRi & useAt(K )(1 ) & G (1 ) & implyR(1 ) & useAt(refSeqAssoc)(1 , 0 :: Nil ) &
731+ refTrans(" a{|^@|};{a{|^@|};}*;x_':=*;" .asProgram)(1 ) & andR(1 ) & Idioms .< (
732+ focus(1 , 0 :: 1 :: Nil ) & useAt(refEq)(- 1 , 1 :: Nil ) & id,
733+ useAt(refUnfoldL, PosInExpr (1 :: Nil ))(1 , 1 :: 0 :: Nil ) & useAt(hideChoiceL)(1 , 1 :: 0 :: Nil ) &
734+ useAt(refSeqAssoc)(1 , 1 :: Nil ) & cohide(1 ) & useAt(refRefl)(1 ),
735+ ),
736+ ),
737+ useAt(skipRandomD)(1 , 1 :: 0 :: 0 :: 1 :: Nil ) & useAt(refSeqIdR)(1 , 1 :: 0 :: 0 :: Nil ) &
738+ cohide(1 ) & useAt(refRefl)(1 ),
739+ ),
740+ )
741+
567742 /**
568743 * Generalisation of [[refAnyFresh ]] to the specific cases where the only occurrences of `x` are of the form:
569744 * - `x:=*`
@@ -678,112 +853,4 @@ object Refactor {
678853 }
679854 }
680855 }
681-
682- lazy val randomLoop : ProvableSig = proveBy(
683- " [{a_{|^@|};x_:=*;}*][a_{|^@|};]{x_:=*;{a_{|^@|};}*}=={{a_{|^@|};}*x_:=*;}->{a_{|^@|};x_:=*;}*;x_:=*; == {a_{|^@|};}*;x_:=*;"
684- .asFormula,
685- implyR(1 ) & useAt(refAntiSym)(1 ) & andR(1 ) & Idioms .< (
686- refTrans(" {a_{|^@|};x_:=*;}*{a_{|^@|};}*x_:=*;" .asProgram)(1 ) & andR(1 ) & Idioms .< (
687- useAt(refUnfoldL, PosInExpr (1 :: Nil ))(1 , 1 :: 1 :: 0 :: Nil ) & useAt(hideChoiceR)(1 , 1 :: 1 :: 0 :: Nil ) &
688- useAt(refSeqIdL)(1 , 1 :: 1 :: Nil ) & cohide(1 ) & useAt(refRefl)(1 ),
689- useAt(refLoopL)(1 ) & implyRi & useAt(K )(1 ) & G (1 ) & implyR(1 ) & useAt(refSeqAssoc)(1 , 0 :: Nil ) &
690- useAt(refSeqAssoc, PosInExpr (0 :: Nil ))(1 , 0 :: 1 :: Nil ) &
691- refTrans(" a_{|^@|};{{a_{|^@|};}*x_:=*;}x_:=*;" .asProgram)(1 ) & andR(1 ) & Idioms .< (
692- focus(1 , 0 :: 1 :: 0 :: Nil ) & useAt(refEq)(- 1 , 1 :: Nil ) & id,
693- useAt(refSeqAssoc)(1 , 0 :: 1 :: Nil ) & useAt(refSeqAssoc, PosInExpr (0 :: Nil ))(1 , 0 :: Nil ) &
694- useAt(prgEqRandomIdem)(1 , 0 :: 1 :: Nil ) & useAt(refUnfoldL, PosInExpr (1 :: Nil ))(1 , 1 :: 0 :: Nil ) &
695- useAt(hideChoiceL)(1 , 1 :: 0 :: Nil ) & cohide(1 ) & useAt(refRefl)(1 ),
696- ),
697- ),
698- useAt(refSeqIdR, PosInExpr (1 :: Nil ))(1 , 0 :: 0 :: 0 :: Nil ) & focus(1 , List (0 , 0 , 0 , 1 )) &
699- useAt(skipRandom)(1 , 1 :: 1 :: 1 :: Nil ) & G (1 ) & G (1 ) & useAt(refRefl)(1 ),
700- ),
701- )
702-
703- lazy val randomDLoop : ProvableSig = proveBy(
704- " [{a_{|^@|};x_':=*;}*][a_{|^@|};]{x_':=*;{a_{|^@|};}*}=={{a_{|^@|};}*x_':=*;}->{a_{|^@|};x_':=*;}*;x_':=*; == {a_{|^@|};}*;x_':=*;"
705- .asFormula,
706- implyR(1 ) & useAt(refAntiSym)(1 ) & andR(1 ) & Idioms .< (
707- refTrans(" {a_{|^@|};x_':=*;}*{a_{|^@|};}*x_':=*;" .asProgram)(1 ) & andR(1 ) & Idioms .< (
708- useAt(refUnfoldL, PosInExpr (1 :: Nil ))(1 , 1 :: 1 :: 0 :: Nil ) & useAt(hideChoiceR)(1 , 1 :: 1 :: 0 :: Nil ) &
709- useAt(refSeqIdL)(1 , 1 :: 1 :: Nil ) & cohide(1 ) & useAt(refRefl)(1 ),
710- useAt(refLoopL)(1 ) & implyRi & useAt(K )(1 ) & G (1 ) & implyR(1 ) & useAt(refSeqAssoc)(1 , 0 :: Nil ) &
711- useAt(refSeqAssoc, PosInExpr (0 :: Nil ))(1 , 0 :: 1 :: Nil ) &
712- refTrans(" a_{|^@|};{{a_{|^@|};}*x_':=*;}x_':=*;" .asProgram)(1 ) & andR(1 ) & Idioms .< (
713- focus(1 , 0 :: 1 :: 0 :: Nil ) & useAt(refEq)(- 1 , 1 :: Nil ) & id,
714- useAt(refSeqAssoc)(1 , 0 :: 1 :: Nil ) & useAt(refSeqAssoc, PosInExpr (0 :: Nil ))(1 , 0 :: Nil ) &
715- useAt(prgEqRandomDIdem)(1 , 0 :: 1 :: Nil ) & useAt(refUnfoldL, PosInExpr (1 :: Nil ))(1 , 1 :: 0 :: Nil ) &
716- useAt(hideChoiceL)(1 , 1 :: 0 :: Nil ) & cohide(1 ) & useAt(refRefl)(1 ),
717- ),
718- ),
719- useAt(refSeqIdR, PosInExpr (1 :: Nil ))(1 , 0 :: 0 :: 0 :: Nil ) & focus(1 , List (0 , 0 , 0 , 1 )) &
720- useAt(skipRandomD)(1 , 1 :: 1 :: 1 :: Nil ) & G (1 ) & G (1 ) & useAt(refRefl)(1 ),
721- ),
722- )
723-
724- /** Given a program `a;x:=*`, adds a `x:=*` within `a` at position `pos` */
725- def moveRandom (a : Program , pos : PosInExpr ): ProvableSig = {
726- a match {
727- case Compose (b, AssignAny (x)) if pos.head == 0 =>
728- b.at(pos.child) match {
729- case (ctx, c : Program ) =>
730- val a_updated = Compose (ctx(Compose (c, AssignAny (x))), AssignAny (x))
731- proveBy(
732- ProgramEquivalence (a_updated, a),
733- moveRandomAux(ctx, c, x, PosInExpr (0 :: Nil )) & useAt(prgEqRefl)(1 ),
734- )
735- case (ctx, e) => ???
736- }
737-
738- case _ => ???
739- }
740- }
741-
742- def moveRandomAux (ctx : Context [Program ], p : Program , x : Variable , pos : PosInExpr ): BelleExpr = {
743- ctx.ctx match {
744- case DotProgram =>
745- val ax = x match {
746- case _ : BaseVariable => prgEqRandomIdem
747- case _ : DifferentialSymbol => prgEqRandomDIdem
748- }
749- useAt(refSeqAssoc)(1 , pos) & useAt(ax)(1 , pos ++ 1 )
750- case Choice (a, b) =>
751- val (nextPrg, nextPos) =
752- if (! symbols(a).contains(DotProgram )) { (b, 1 ) }
753- else if (! symbols(b).contains(DotProgram )) { (a, 0 ) }
754- else ???
755- useAt(refDistrR)(1 , pos) & moveRandomAux(Context (nextPrg), p, x, pos ++ nextPos) &
756- useAt(refDistrR, PosInExpr (0 :: Nil ))(1 , pos)
757- case Compose (a, c) if ! symbols(a).contains(DotProgram ) =>
758- useAt(refSeqAssoc)(1 , pos) & moveRandomAux(Context (c), p, x, pos ++ 1 ) &
759- useAt(refSeqAssoc, PosInExpr (0 :: Nil ))(1 , pos)
760- case Compose (c, a) if ! symbols(a).contains(DotProgram ) =>
761- val ax = x match {
762- case _ : BaseVariable => refAnyFresh
763- case _ : DifferentialSymbol => refAnyDFresh
764- }
765- useAt(refSeqAssoc)(1 , pos) & useAt(ax, PosInExpr (1 :: Nil ))(1 , pos ++ 1 ) &
766- useAt(refSeqAssoc, PosInExpr (0 :: Nil ))(1 , pos) & moveRandomAux(Context (c), p, x, pos ++ 0 ) &
767- useAt(refSeqAssoc)(1 , pos) & useAt(ax)(1 , pos ++ 1 ) & useAt(refSeqAssoc, PosInExpr (0 :: Nil ))(1 , pos)
768- case Loop (c) =>
769- val (axLoop, axFresh) = x match {
770- case _ : BaseVariable => (randomLoop, refAnyFresh)
771- case _ : DifferentialSymbol => (randomDLoop, refAnyDFresh)
772- }
773- val assgn = AssignAny (x)
774- val prg = Context (c)(Compose (p, assgn))
775- val test = refAnyGenAux(Loop (prg), x)
776- val loopCommBefore = proveBy(
777- ProgramEquivalence (Compose (Loop (Compose (prg, assgn)), assgn), Compose (Loop (prg), assgn)),
778- useAt(axLoop, PosInExpr (1 :: Nil ))(1 ) & G (1 ) & G (1 ) & byUS(test),
779- )
780- val loopCommAfter = proveBy(
781- ProgramEquivalence (Compose (Loop (Compose (Context (c)(p), assgn)), assgn), Compose (ctx(p), assgn)),
782- useAt(axLoop, PosInExpr (1 :: Nil ))(1 ) & G (1 ) & G (1 ) & byUS(axFresh),
783- )
784- useAt(loopCommBefore, PosInExpr (1 :: Nil ))(1 , pos) & moveRandomAux(Context (c), p, x, pos ++ 0 ++ 0 ) &
785- useAt(loopCommAfter, PosInExpr (0 :: Nil ))(1 , pos)
786- case _ => ???
787- }
788- }
789856}
0 commit comments