public StagedHoudiniPlan ApplyStages()
        {
            if (NoStages())
            {
            return null;
            }

            #region Assign candidates to stages at a given level of granularity

            switch(CommandLineOptions.Clo.StagedHoudini) {
              case COARSE_STAGES:
            Plan = ComputeCoarseStages();
            break;
              case FINE_STAGES:
            Plan = ComputeFineStages();
            break;
              case BALANCED_STAGES:
            Plan = ComputeBalancedStages();
            break;
              default:
            Debug.Assert(false);
            Plan = null;
            break;
            }

            foreach(var c in candidates) {
              Debug.Assert(Plan.StageForCandidate(c) != null);
            }
            #endregion

            #region Generate boolean variables to control stages
            var stageToActiveBoolean = new Dictionary<int, Constant>();
            var stageToCompleteBoolean = new Dictionary<int, Constant>();

            foreach (var stage in Plan)
            {
            var stageActive = new Constant(Token.NoToken,
                new TypedIdent(Token.NoToken, "_stage_" + stage.GetId() + "_active", Type.Bool),
                false);
            stageActive.AddAttribute("stage_active", new object[] { new LiteralExpr(Token.NoToken, BigNum.FromInt(stage.GetId())) });
            prog.TopLevelDeclarations.Add(stageActive);
            stageToActiveBoolean[stage.GetId()] = stageActive;

            var stageComplete = new Constant(Token.NoToken,
                new TypedIdent(Token.NoToken, "_stage_" + stage.GetId() + "_complete", Type.Bool),
                false);
            stageComplete.AddAttribute("stage_complete", new object[] { new LiteralExpr(Token.NoToken, BigNum.FromInt(stage.GetId())) });
            prog.TopLevelDeclarations.Add(stageComplete);
            stageToCompleteBoolean[stage.GetId()] = stageComplete;
            }
            #endregion

            #region Adapt candidate assertions to take account of stages
            foreach (var b in prog.TopLevelDeclarations.OfType<Implementation>().Select(Item => Item.Blocks).SelectMany(Item => Item))
            {
            List<Cmd> newCmds = new List<Cmd>();
            foreach (var cmd in b.Cmds)
            {
                var a = cmd as AssertCmd;
                string c;
                if (a != null && (Houdini.MatchCandidate(a.Expr, candidates, out c)))
                {
                    newCmds.Add(new AssertCmd(a.tok, Houdini.AddConditionToCandidate(a.Expr,
                        new IdentifierExpr(Token.NoToken, stageToActiveBoolean[Plan.StageForCandidate(c).GetId()]), c), a.Attributes));
                    newCmds.Add(new AssumeCmd(a.tok, Houdini.AddConditionToCandidate(a.Expr,
                        new IdentifierExpr(Token.NoToken, stageToCompleteBoolean[Plan.StageForCandidate(c).GetId()]), c), a.Attributes));
                }
                else
                {
                    newCmds.Add(cmd);
                }
            }
            b.Cmds = newCmds;
            }
            #endregion

            #region Adapt candidate pre/postconditions to take account of stages
            foreach (var p in prog.TopLevelDeclarations.OfType<Procedure>())
            {

              #region Handle the preconditions
              List<Requires> newRequires = new List<Requires>();
              foreach(Requires r in p.Requires) {
            string c;
            if (Houdini.MatchCandidate(r.Condition, candidates, out c)) {
              newRequires.Add(new Requires(r.tok, false,
                Houdini.AddConditionToCandidate(r.Condition,
                new IdentifierExpr(Token.NoToken, stageToActiveBoolean[Plan.StageForCandidate(c).GetId()]), c),
                r.Comment, r.Attributes));
              newRequires.Add(new Requires(r.tok, true,
                Houdini.AddConditionToCandidate(r.Condition,
                new IdentifierExpr(Token.NoToken, stageToCompleteBoolean[Plan.StageForCandidate(c).GetId()]), c),
                r.Comment, r.Attributes));
            } else {
              newRequires.Add(r);
            }
              }
              p.Requires = newRequires;
              #endregion

              #region Handle the postconditions
              List<Ensures> newEnsures = new List<Ensures>();
              foreach(Ensures e in p.Ensures) {
            string c;
            if (Houdini.MatchCandidate(e.Condition, candidates, out c)) {
              int stage = Plan.StageForCandidate(c).GetId();
              Constant activeBoolean = stageToActiveBoolean[stage];
              newEnsures.Add(new Ensures(e.tok, false,
                Houdini.AddConditionToCandidate(e.Condition,
                new IdentifierExpr(Token.NoToken, activeBoolean), c),
                e.Comment, e.Attributes));
              newEnsures.Add(new Ensures(e.tok, true,
                Houdini.AddConditionToCandidate(e.Condition,
                new IdentifierExpr(Token.NoToken, stageToCompleteBoolean[stage]), c),
                e.Comment, e.Attributes));
            } else {
              newEnsures.Add(e);
            }
              }
              p.Ensures = newEnsures;
              #endregion

            }
            #endregion

            return Plan;
        }
    public StagedHoudiniPlan ApplyStages() {

        if (NoStages())
        {
          Debug.Assert(false);
          var TrivialGraph = new Graph<ScheduledStage>();
          TrivialGraph.AddSource(new ScheduledStage(0, new HashSet<string>()));
          return new StagedHoudiniPlan(TrivialGraph);
        }

        #region Assign annotations to stages at a given level of granularity
      
        switch(CommandLineOptions.Clo.StagedHoudini) {
          case COARSE_STAGES:
            Plan = ComputeCoarseStages();
            break;
          case FINE_STAGES:
            Plan = ComputeFineStages();
            break;
          case BALANCED_STAGES:
            Plan = ComputeBalancedStages();
            break;
          default:
            Debug.Assert(false);
            Plan = null;
            break;
        }

        foreach(var c in AllAnnotationIdentifiers()) {
          Debug.Assert(Plan.StageForAnnotation(c) != null);
        }
        #endregion

        #region Generate boolean variables to control stages
        var stageToActiveBoolean = new Dictionary<int, Constant>();
        var stageToCompleteBoolean = new Dictionary<int, Constant>();

        foreach (var stage in Plan)
        {
            var stageActive = new Constant(Token.NoToken,
                new TypedIdent(Token.NoToken, "_stage_" + stage.GetId() + "_active", Type.Bool),
                false);
            stageActive.AddAttribute("stage_active", new object[] { new LiteralExpr(Token.NoToken, BigNum.FromInt(stage.GetId())) });
            prog.AddTopLevelDeclaration(stageActive);
            stageToActiveBoolean[stage.GetId()] = stageActive;

            var stageComplete = new Constant(Token.NoToken, 
                new TypedIdent(Token.NoToken, "_stage_" + stage.GetId() + "_complete", Type.Bool),
                false);
            stageComplete.AddAttribute("stage_complete", new object[] { new LiteralExpr(Token.NoToken, BigNum.FromInt(stage.GetId())) });
            prog.AddTopLevelDeclaration(stageComplete);
            stageToCompleteBoolean[stage.GetId()] = stageComplete;
        }
        #endregion

        #region Adapt annotation assertions to take account of stages
        foreach (var b in prog.Implementations.Select(Item => Item.Blocks).SelectMany(Item => Item))
        {
            List<Cmd> newCmds = new List<Cmd>();
            foreach (var cmd in b.Cmds)
            {
                var a = cmd as AssertCmd;
                string c;
                if (a != null) {
                    if (Houdini.MatchCandidate(a.Expr, CandidateIdentifiers, out c))
                    {
                        newCmds.Add(new AssertCmd(a.tok, Houdini.AddConditionToCandidate(a.Expr,
                            Expr.Ident(stageToActiveBoolean[Plan.StageForAnnotation(c).GetId()]), c), a.Attributes));
                        newCmds.Add(new AssumeCmd(a.tok, Houdini.AddConditionToCandidate(a.Expr,
                            Expr.Ident(stageToCompleteBoolean[Plan.StageForAnnotation(c).GetId()]), c), a.Attributes));
                    } else if (QKeyValue.FindBoolAttribute(a.Attributes, "originated_from_invariant")) {
                        string tag = GetTagFromNonCandidateAttributes(a.Attributes);
                        if (tag == null) {
                          newCmds.Add(a);
                        } else {
                          newCmds.Add(new AssertCmd(a.tok, Expr.Imp(
                              Expr.Ident(stageToActiveBoolean[Plan.StageForAnnotation(tag).GetId()]), a.Expr),
                              a.Attributes));
                          newCmds.Add(new AssumeCmd(a.tok, Expr.Imp(
                              Expr.Ident(stageToCompleteBoolean[Plan.StageForAnnotation(tag).GetId()]), a.Expr),
                              a.Attributes));
                        }
                    }
                }
                else
                {
                    newCmds.Add(cmd);
                }
            }
            b.Cmds = newCmds;
        }
        #endregion

        #region Adapt pre/postconditions to take account of stages
        foreach (var p in prog.NonInlinedProcedures())
        {

          #region Handle the preconditions
          {
            List<Requires> newRequires = new List<Requires>();
            foreach(Requires r in p.Requires) {
              string c;
              if (Houdini.MatchCandidate(r.Condition, CandidateIdentifiers, out c)) {
                newRequires.Add(new Requires(r.tok, false, 
                  Houdini.AddConditionToCandidate(r.Condition,
                  Expr.Ident(stageToActiveBoolean[Plan.StageForAnnotation(c).GetId()]), c),
                  r.Comment, r.Attributes));
                newRequires.Add(new Requires(r.tok, true, 
                  Houdini.AddConditionToCandidate(r.Condition,
                  Expr.Ident(stageToCompleteBoolean[Plan.StageForAnnotation(c).GetId()]), c),
                  r.Comment, r.Attributes));
              } else {
                string tag = GetTagFromNonCandidateAttributes(r.Attributes);
                if (tag == null) {
                  newRequires.Add(r);
                } else {
                  newRequires.Add(new Requires(r.tok, false, 
                    Expr.Imp(Expr.Ident(stageToActiveBoolean[Plan.StageForAnnotation(tag).GetId()]), r.Condition),
                    r.Comment, r.Attributes));
                  newRequires.Add(new Requires(r.tok, true, 
                    Expr.Imp(Expr.Ident(stageToCompleteBoolean[Plan.StageForAnnotation(tag).GetId()]), r.Condition),
                    r.Comment, r.Attributes));
                }
              }
            }
            p.Requires = newRequires;
          }
          #endregion

          #region Handle the postconditions
          {
            List<Ensures> newEnsures = new List<Ensures>();
            foreach(Ensures e in p.Ensures) {
              string c;
              if (Houdini.MatchCandidate(e.Condition, CandidateIdentifiers, out c)) {
                int stage = Plan.StageForAnnotation(c).GetId();
                newEnsures.Add(new Ensures(e.tok, false, 
                  Houdini.AddConditionToCandidate(e.Condition,
                  Expr.Ident(stageToActiveBoolean[stage]), c),
                  e.Comment, e.Attributes));
                newEnsures.Add(new Ensures(e.tok, true, 
                  Houdini.AddConditionToCandidate(e.Condition,
                  Expr.Ident(stageToCompleteBoolean[stage]), c),
                  e.Comment, e.Attributes));
              } else {
                string tag = GetTagFromNonCandidateAttributes(e.Attributes);
                if (tag == null) {
                  newEnsures.Add(e);
                } else {
                  newEnsures.Add(new Ensures(e.tok, false, 
                    Expr.Imp(Expr.Ident(stageToActiveBoolean[Plan.StageForAnnotation(tag).GetId()]), e.Condition),
                    e.Comment, e.Attributes));
                  newEnsures.Add(new Ensures(e.tok, true, 
                    Expr.Imp(Expr.Ident(stageToCompleteBoolean[Plan.StageForAnnotation(tag).GetId()]), e.Condition),
                    e.Comment, e.Attributes));
                }
              }
            }
            p.Ensures = newEnsures;
          }
          #endregion

        }
        #endregion

        return Plan;

    }