Пример #1
0
        private static void Benchmark(List <MuFormula> list)
        {
            Log("Formula; LTS Size; Algorithm; Time");

            double[,] results = new double[list.Count * 2, 13];
            bool lastResult = false;

            foreach (var formula in list)
            {
                int num_runs = 4;
                for (int i = 2; i <= 13; i++)
                {
                    if (i >= 11)
                    {
                        num_runs = 1;
                    }
                    var sw  = Stopwatch.StartNew();
                    var lts = LTS.Parse("../demanding/demanding_" + i.ToString(CultureInfo.InvariantCulture) + ".aut");
                    Log("Read input set in {0}ms", sw.ElapsedMilliseconds);

                    sw.Reset(); sw.Start();
                    for (int j = 0; j < num_runs; j++)
                    {
                        lastResult = NaiveSolver.Solve(formula, lts, new Environment()).Contains(lts.InitialState);
                    }
                    results[list.IndexOf(formula) * 2 + 0, i - 2] = (double)sw.ElapsedMilliseconds / num_runs;
                    Log("{0}\t{1}\t{2}\t{3}\t{4}", list.IndexOf(formula) + 1, i, "Naive      ", (double)sw.ElapsedMilliseconds / (double)num_runs, lastResult);

                    sw.Reset(); sw.Start();
                    for (int j = 0; j < num_runs; j++)
                    {
                        lastResult = EmersonLei.Solve(formula, lts, new Environment()).Contains(lts.InitialState);
                    }
                    results[list.IndexOf(formula) * 2 + 1, i - 2] = (double)sw.ElapsedMilliseconds / num_runs;
                    Log("{0}\t{1}\t{2}\t{3}\t{4}", list.IndexOf(formula) + 1, i, "Emerson-Lei", (double)sw.ElapsedMilliseconds / (double)num_runs, lastResult);

                    logWriter.Flush();
                    lts = null;
                }
            }

            Log("");
            Log("");
            Log("Results table:");
            Log("lts size\tformula1 naive\tformula1 emers\tformula2 naive\tformula2 emers\tformula3 naive\tformula3 emers\tformula4 naive\tformula4 emers");
            for (int j = 0; j < results.GetLength(1); j++)
            {
                var sb = new StringBuilder();
                sb.Append((j + 2).ToString());
                for (int i = 0; i < results.GetLength(0); i++)
                {
                    sb.AppendFormat("\t{0}", results[i, j]);
                }
                Log(sb.ToString());
            }
        }
Пример #2
0
        static LTS ChessBoard(int boardSize)
        {
            // this procedure outputs a board of size boardSize x boardSize in aldebaran format
            var lts      = new LTS();
            var board    = new LTSState[boardSize, boardSize];
            int stateNum = 0;
            var initial  = new LTSState(stateNum++.ToString(), lts);

            lts.InitialState = initial;
            for (int i = 0; i < boardSize; i++)
            {
                for (int j = 0; j < boardSize; j++)
                {
                    var cell = new LTSState(stateNum++.ToString(), lts);
                    board[i, j] = cell;
                    lts.States.Add(cell);
                }
            }

            lts.States.Add(initial);
            for (int i = 0; i < boardSize; i++)
            {
                lts.Transitions.Add(new LTSTransition(initial, board[boardSize - 1, i], "start(" + (boardSize - 1) + "," + i + ")"));
                if (i != boardSize - 1)                 // don't want 2 transitions to same init
                {
                    lts.Transitions.Add(new LTSTransition(initial, board[i, boardSize - 1], "start(" + i + "," + (boardSize - 1) + ")"));
                }
            }

            for (int y = boardSize - 1; y >= 0; y--)
            {
                for (int x = boardSize - 1; x >= 0; x--)
                {
                    var thisCell = board[x, y];
                    // horizontal moves
                    for (int i = x - 1; i >= 0; i--)
                    {
                        lts.Transitions.Add(new LTSTransition(thisCell, string.Format("to({0},{1})", i, y), board[i, y]));
                    }
                    // vertical moves
                    for (int j = y - 1; j >= 0; j--)
                    {
                        lts.Transitions.Add(new LTSTransition(thisCell, string.Format("to({0},{1})", x, j), board[x, j]));
                    }
                    // diagonal moves
                    int k = x - 1, l = y - 1;
                    while (k >= 0 && l >= 0)
                    {
                        lts.Transitions.Add(new LTSTransition(thisCell, string.Format("to({0},{1})", k, l), board[k--, l--]));
                    }
                }
            }

            return(lts);
        }
Пример #3
0
		private static LTSState GetState(string stateName, LTS lts) {
			LTSState state;
			if (lts.StatesMap.TryGetValue(stateName, out state))
				return state;
			else {
				state = new LTSState(stateName, lts);
				lts.StatesMap[stateName] = state;
				lts.States.Add(state);
			}
			return state;
		}
Пример #4
0
        public static HashSet<LTSState> LFP(PredicateTransformer tau, LTS lts, Environment env)
        {
            var Q = Tuple.Create(new HashSet<LTSState>(), lts, env);
            var QPrime = tau(Q);

            while (QPrime.Item1.Count() != Q.Item1.Count()) {
                Q = QPrime;
                QPrime = tau(QPrime);
            }

            return Q.Item1;
        }
Пример #5
0
        public static HashSet <LTSState> GFP(PredicateTransformer tau, LTS lts, Environment env)
        {
            var Q      = Tuple.Create(new HashSet <LTSState>(lts.States), lts, env);
            var QPrime = tau(Q);

            while (QPrime.Item1.Count() != Q.Item1.Count())
            {
                Q      = QPrime;
                QPrime = tau(QPrime);
            }

            return(Q.Item1);
        }
Пример #6
0
        private static void OutputResult(MuFormula f, LTS lts)
        {
            Log("Formula {0}", f);
            Log("\t ND: {0}, AD: {1}, DAD: {2}", f.NestingDepth, f.AlternationDepth, f.DependentAlternationDepth);

            var naiveSol = NaiveSolver.Solve(f, lts, new Environment());

            Log("\tNAIVE: {0}", naiveSol.Contains(lts.InitialState));

            var emersonLeiSol = EmersonLei.Solve(f, lts, new Environment());

            Log("\tEMLEI: {0}", emersonLeiSol.Contains(lts.InitialState));
        }
Пример #7
0
 private static void Init(IEnumerable <Variable> variables, LTS lts, Environment env)
 {
     foreach (var v in variables)
     {
         if (v.Binder is Mu)
         {
             env[v] = new HashSet <LTSState>();
         }
         else if (v.Binder is Nu)
         {
             env[v] = lts.States;
         }
     }
 }
Пример #8
0
        private static LTSState GetState(string stateName, LTS lts)
        {
            LTSState state;

            if (lts.StatesMap.TryGetValue(stateName, out state))
            {
                return(state);
            }
            else
            {
                state = new LTSState(stateName, lts);
                lts.StatesMap[stateName] = state;
                lts.States.Add(state);
            }
            return(state);
        }
Пример #9
0
        public static LTS Parse(string file)
        {
            // parse aldebran format
            var    ret     = new LTS();
            var    sr      = new StreamReader(file, Encoding.Default);
            var    lineRE  = new Regex(@"\((\w+)\s*,\s*""([^\""]+?)""\s*,\s*(\w+)\s*\)");
            string initial = string.Empty;

            while (!sr.EndOfStream)
            {
                var line = sr.ReadLine();
                if (line.StartsWith("des"))
                {
                    var m = Regex.Match(line, @"des\s*\((\w+?),(\w+?),(\w+?)\)");
                    if (m.Success)
                    {
                        initial = m.Groups[1].Captures[0].Value;
                    }
                    continue;
                }

                var match = lineRE.Match(line);
                if (match.Success)
                {
                    string start = match.Groups[1].Captures[0].Value;
                    string label = match.Groups[2].Captures[0].Value;
                    string end   = match.Groups[3].Captures[0].Value;

                    LTSState      startState = GetState(start, ret);
                    LTSState      endState   = GetState(end, ret);
                    LTSTransition trans      = new LTSTransition(startState, label, endState);

                    ret.Actions.Add(label);
                    ret.Transitions.Add(trans);
                    startState.AddOutTransition(trans);
                    //endState.AddInTransition(trans);
                }
                else
                {
                    int i = 0;
                }
            }

            ret.InitialState = GetState(initial, ret);
            return(ret);
        }
Пример #10
0
        static LTS ChessBoard(int boardSize)
        {
            // this procedure outputs a board of size boardSize x boardSize in aldebaran format
            var lts = new LTS();
            var board = new LTSState[boardSize, boardSize];
            int stateNum = 0;
            var initial = new LTSState(stateNum++.ToString(), lts);
            lts.InitialState = initial;
            for (int i = 0; i < boardSize; i++) {
                for (int j = 0; j < boardSize; j++) {
                    var cell = new LTSState(stateNum++.ToString(), lts);
                    board[i, j] = cell;
                    lts.States.Add(cell);
                }
            }

            lts.States.Add(initial);
            for (int i = 0; i < boardSize; i++) {
                lts.Transitions.Add(new LTSTransition(initial, board[boardSize - 1, i], "start(" + (boardSize - 1) + "," + i + ")"));
                if (i != boardSize - 1) // don't want 2 transitions to same init
                    lts.Transitions.Add(new LTSTransition(initial, board[i, boardSize - 1], "start(" + i + "," + (boardSize - 1) + ")"));
            }

            for (int y = boardSize - 1; y >= 0; y--) {
                for (int x = boardSize - 1; x >= 0; x--) {
                    var thisCell = board[x, y];
                    // horizontal moves
                    for (int i = x - 1; i >= 0; i--)
                        lts.Transitions.Add(new LTSTransition(thisCell, string.Format("to({0},{1})", i, y), board[i, y]));
                    // vertical moves
                    for (int j = y - 1; j >= 0; j--)
                        lts.Transitions.Add(new LTSTransition(thisCell, string.Format("to({0},{1})", x, j), board[x, j]));
                    // diagonal moves
                    int k = x - 1, l = y - 1;
                    while (k >= 0 && l >= 0)
                        lts.Transitions.Add(new LTSTransition(thisCell, string.Format("to({0},{1})", k, l), board[k--, l--]));
                }
            }

            return lts;
        }
Пример #11
0
		public static LTS Parse(string file) {
			// parse aldebran format
			var ret = new LTS();
			var sr = new StreamReader(file, Encoding.Default);
			var lineRE = new Regex(@"\((\w+)\s*,\s*""([^\""]+?)""\s*,\s*(\w+)\s*\)");
			string initial = string.Empty;

			while (!sr.EndOfStream) {
				var line = sr.ReadLine();
				if (line.StartsWith("des")) {
					var m = Regex.Match(line, @"des\s*\((\w+?),(\w+?),(\w+?)\)");
					if (m.Success) {
						initial = m.Groups[1].Captures[0].Value;
					}
					continue;
				}

				var match = lineRE.Match(line);
				if (match.Success) {
					string start = match.Groups[1].Captures[0].Value;
					string label = match.Groups[2].Captures[0].Value;
					string end = match.Groups[3].Captures[0].Value;

					LTSState startState = GetState(start, ret);
					LTSState endState = GetState(end, ret);
					LTSTransition trans = new LTSTransition(startState, label, endState);

					ret.Actions.Add(label);
					ret.Transitions.Add(trans);
					startState.AddOutTransition(trans);
					//endState.AddInTransition(trans);
				}
				else {
					int i = 0;
				}
			}

			ret.InitialState = GetState(initial, ret);
			return ret;
		}
Пример #12
0
        static void Main(string[] args)
        {
            var p = new MuCalculusParser();

            p.Setup();
            bool b = p.Parse(new StringReader("nu X.((mu Y . [b]Y) && nu Z.((<b> X) && (<a>(Z && <a> X))))\r\n"));

            string ltsPath      = args[0];
            string formulasPath = args[1];

            Log("LTS: {0}", ltsPath);
            var parser = new MuCalculusParser();

            parser.Setup();
            var  fileStream  = new FileStream(formulasPath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
            bool parseResult = parser.Parse(new StreamReader(fileStream, Encoding.Default));

            fileStream.Close();
            if (!parseResult)
            {
                Log("Failed to parse!");
            }

            LTS lts = LTS.Parse(ltsPath);

            foreach (MuFormula f in parser.formulas)
            {
                Log("----------------------------------");
                OutputResult(f, lts);
            }
            Log();
            Log();
            logWriter.Flush();

            logWriter.Close();
            Console.ReadKey();
        }
Пример #13
0
        public static HashSet <LTSState> Solve(MuFormula formula, LTS lts, Environment env)
        {
            if (formula is Proposition)
            {
                var prop = formula as Proposition;
                return(bool.Parse(prop.Value) ? lts.States : new HashSet <LTSState>());
            }

            else if (formula is Variable)
            {
                return(env.GetVariable(formula as Variable));
            }

            else if (formula is Negation)
            {
                var neg = formula as Negation;
                return(new HashSet <LTSState>(lts.States.Except(
                                                  Solve(neg.Formula, lts, env))));
            }

            else if (formula is Conjunction)
            {
                var conj        = formula as Conjunction;
                var leftStates  = Solve(conj.Left, lts, env);
                var rightStates = Solve(conj.Right, lts, env);
                return(new HashSet <LTSState>(leftStates.Intersect(rightStates)));
            }


            else if (formula is Disjunction)
            {
                var disj        = formula as Disjunction;
                var leftStates  = Solve(disj.Left, lts, env);
                var rightStates = Solve(disj.Right, lts, env);
                return(new HashSet <LTSState>(leftStates.Union(rightStates)));
            }

            else if (formula is Box)
            {
                var box = formula as Box;

                // box a f = { s | forall t. s -a-> t ==> t in [[f]]e }
                // i.e. the set of states for which all a-transitions go to a state in which f holds
                var fe = Solve(box.Formula, lts, env);

                return(new HashSet <LTSState>(lts.States.Where(
                                                  // states where, for all outtransitions with action a, the Formula holds in the direct successor
                                                  state => state.GetOutTransitions(box.RegularFormula).All(tr => fe.Contains(tr.Right))
                                                  )));
            }

            else if (formula is Diamond)
            {
                var diamond   = formula as Diamond;
                var shorthand = new Negation(
                    // <a>f == [a](not f)
                    new Box(diamond.RegularFormula, new Negation(diamond.Formula))
                    );
                return(Solve(shorthand, lts, env));
            }

            else if (formula is Mu)
            {
                var mu = formula as Mu;
                env[mu.Variable] = new HashSet <LTSState>();

                return(FixedPoint.LFP(delegate(Tuple <HashSet <LTSState>, LTS, Environment> tuple) {
                    // repeats tau: X := solve(f)
                    var X = tuple.Item1;
                    X = Solve(mu.Formula, lts, env);
                    env[mu.Variable] = X;
                    return Tuple.Create(X, lts, env);
                }, lts, env));
            }

            else if (formula is Nu)
            {
                var nu = formula as Nu;
                env[nu.Variable] = lts.States;

                return(FixedPoint.GFP(delegate(Tuple <HashSet <LTSState>, LTS, Environment> tuple) {
                    // repeats tau: X := solve(f)
                    var X = tuple.Item1;
                    X = Solve(nu.Formula, lts, env);
                    env[nu.Variable] = X;

                    return Tuple.Create(X, lts, env);
                }, lts, env));
            }

            throw new InvalidDataException("not a valid formula in our grammar");
        }
Пример #14
0
 public LTSState(string name, LTS lts)
 {
     Name = name;
     LTS = lts;
 }
Пример #15
0
        public static HashSet <LTSState> Solve(MuFormula formula, LTS lts, Environment env, bool init = true)
        {
            if (init)
            {
                var allVariables = new List <Variable>();
                if (formula is Variable)
                {
                    allVariables.Add((Variable)formula);
                }
                allVariables.AddRange(formula.AllSubFormulas.OfType <Variable>());
                allVariables.AddRange(formula.AllSubFormulas.OfType <Mu>().Select(mu => mu.Variable));
                allVariables.AddRange(formula.AllSubFormulas.OfType <Nu>().Select(nu => nu.Variable));
                Init(allVariables.Distinct(), lts, env);
            }

            if (formula is Proposition)
            {
                var prop = formula as Proposition;
                return(bool.Parse(prop.Value) ? lts.States : new HashSet <LTSState>());
            }

            else if (formula is Variable)
            {
                return(env.GetVariable(formula as Variable));
            }

            else if (formula is Negation)
            {
                var neg = formula as Negation;
                return(new HashSet <LTSState>(lts.States.Except(
                                                  Solve(neg.Formula, lts, env, false))));
            }

            else if (formula is Conjunction)
            {
                var conj        = formula as Conjunction;
                var leftStates  = Solve(conj.Left, lts, env, false);
                var rightStates = Solve(conj.Right, lts, env, false);
                return(new HashSet <LTSState>(leftStates.Intersect(rightStates)));
            }


            else if (formula is Disjunction)
            {
                var disj        = formula as Disjunction;
                var leftStates  = Solve(disj.Left, lts, env, false);
                var rightStates = Solve(disj.Right, lts, env, false);
                return(new HashSet <LTSState>(leftStates.Union(rightStates)));
            }

            else if (formula is Box)
            {
                var box = formula as Box;

                // box a f = { s | forall t. s -a-> t ==> t in [[f]]e }
                // i.e. the set of states for which all a-transitions go to a state in which f holds
                var fe = Solve(box.Formula, lts, env, false);

                var hashSet = new HashSet <LTSState>();
                foreach (var state in lts.States)
                {
                    var outTransitions = state.GetOutTransitions(box.RegularFormula);
                    if (outTransitions.All(tr => fe.Contains(tr.Right)))
                    {
                        hashSet.Add(state);
                    }
                }
                return(hashSet);
            }

            else if (formula is Diamond)
            {
                var diamond   = formula as Diamond;
                var shorthand = new Negation(
                    // <a>f == [a](not f)
                    new Box(diamond.RegularFormula, new Negation(diamond.Formula))
                    );
                return(Solve(shorthand, lts, env, false));
            }

            else if (formula is Mu)
            {
                var mu = formula as Mu;
                if (mu.Parent is Nu)
                {
                    // surrounding binder is nu
                    // reset open subformulae of form mu Xk.g set env[k]=false
                    foreach (var innerMu in formula.AllSubFormulas.OfType <Mu>().Where(m => m.FreeVariables.Count > 0))
                    {
                        env[innerMu.Variable] = new HashSet <LTSState>();
                    }
                }


                HashSet <LTSState> Xold;
                do
                {
                    Xold             = env.GetVariable(mu.Variable);
                    env[mu.Variable] = Solve(mu.Formula, lts, env, false);
                } while (Xold.Count != env[mu.Variable].Count);
                return(env[mu.Variable]);
            }

            else if (formula is Nu)
            {
                var nu = formula as Nu;
                if (nu.Parent is Mu)
                {
                    // surrounding binder is mu
                    // reset open subformulae of form nu Xk.g set env[k]=true
                    foreach (var innerNu in formula.AllSubFormulas.OfType <Nu>().Where(m => m.FreeVariables.Count > 0))
                    {
                        env[innerNu.Variable] = lts.States;
                    }
                }

                HashSet <LTSState> Xold;
                do
                {
                    Xold             = env.GetVariable(nu.Variable);
                    env[nu.Variable] = Solve(nu.Formula, lts, env, false);
                } while (Xold.Count != env[nu.Variable].Count);
                return(env[nu.Variable]);
            }


            throw new InvalidDataException("formula not valid in our grammar");
        }
Пример #16
0
 private static void Init(IEnumerable<Variable> variables, LTS lts, Environment env)
 {
     foreach (var v in variables) {
         if (v.Binder is Mu)
             env[v] = new HashSet<LTSState>();
         else if (v.Binder is Nu)
             env[v] = lts.States;
     }
 }
Пример #17
0
 public LTSState(string name, LTS lts)
 {
     Name = name;
     LTS  = lts;
 }
Пример #18
0
        private static void OutputResult(MuFormula f, LTS lts)
        {
            Log("Formula {0}", f);
            Log("\t ND: {0}, AD: {1}, DAD: {2}", f.NestingDepth, f.AlternationDepth, f.DependentAlternationDepth);

            var naiveSol = NaiveSolver.Solve(f, lts, new Environment());
            Log("\tNAIVE: {0}", naiveSol.Contains(lts.InitialState));

            var emersonLeiSol = EmersonLei.Solve(f, lts, new Environment());
            Log("\tEMLEI: {0}", emersonLeiSol.Contains(lts.InitialState));
        }
Пример #19
0
        public static HashSet<LTSState> Solve(MuFormula formula, LTS lts, Environment env, bool init = true)
        {
            if (init) {
                var allVariables = new List<Variable>();
                if (formula is Variable) allVariables.Add((Variable)formula);
                allVariables.AddRange(formula.AllSubFormulas.OfType<Variable>());
                allVariables.AddRange(formula.AllSubFormulas.OfType<Mu>().Select(mu => mu.Variable));
                allVariables.AddRange(formula.AllSubFormulas.OfType<Nu>().Select(nu => nu.Variable));
                Init(allVariables.Distinct(), lts, env);
            }

            if (formula is Proposition) {
                var prop = formula as Proposition;
                return bool.Parse(prop.Value) ? lts.States : new HashSet<LTSState>();
            }

            else if (formula is Variable) {
                return env.GetVariable(formula as Variable);
            }

            else if (formula is Negation) {
                var neg = formula as Negation;
                return new HashSet<LTSState>(lts.States.Except(
                    Solve(neg.Formula, lts, env, false)));
            }

            else if (formula is Conjunction) {
                var conj = formula as Conjunction;
                var leftStates = Solve(conj.Left, lts, env, false);
                var rightStates = Solve(conj.Right, lts, env, false);
                return new HashSet<LTSState>(leftStates.Intersect(rightStates));
            }

            else if (formula is Disjunction) {
                var disj = formula as Disjunction;
                var leftStates = Solve(disj.Left, lts, env, false);
                var rightStates = Solve(disj.Right, lts, env, false);
                return new HashSet<LTSState>(leftStates.Union(rightStates));
            }

            else if (formula is Box) {
                var box = formula as Box;

                // box a f = { s | forall t. s -a-> t ==> t in [[f]]e }
                // i.e. the set of states for which all a-transitions go to a state in which f holds
                var fe = Solve(box.Formula, lts, env, false);

                var hashSet = new HashSet<LTSState>();
                foreach (var state in lts.States) {
                    var outTransitions = state.GetOutTransitions(box.RegularFormula);
                    if (outTransitions.All(tr => fe.Contains(tr.Right)))
                        hashSet.Add(state);
                }
                return hashSet;
            }

            else if (formula is Diamond) {
                var diamond = formula as Diamond;
                var shorthand = new Negation(
                    // <a>f == [a](not f)
                    new Box(diamond.RegularFormula, new Negation(diamond.Formula))
                    );
                return Solve(shorthand, lts, env, false);
            }

            else if (formula is Mu) {
                var mu = formula as Mu;
                if (mu.Parent is Nu) {
                    // surrounding binder is nu
                    // reset open subformulae of form mu Xk.g set env[k]=false
                    foreach (var innerMu in formula.AllSubFormulas.OfType<Mu>().Where(m => m.FreeVariables.Count > 0))
                        env[innerMu.Variable] = new HashSet<LTSState>();
                }

                HashSet<LTSState> Xold;
                do {
                    Xold = env.GetVariable(mu.Variable);
                    env[mu.Variable] = Solve(mu.Formula, lts, env, false);
                } while (Xold.Count != env[mu.Variable].Count);
                return env[mu.Variable];
            }

            else if (formula is Nu) {
                var nu = formula as Nu;
                if (nu.Parent is Mu) {
                    // surrounding binder is mu
                    // reset open subformulae of form nu Xk.g set env[k]=true
                    foreach (var innerNu in formula.AllSubFormulas.OfType<Nu>().Where(m => m.FreeVariables.Count > 0))
                        env[innerNu.Variable] = lts.States;
                }

                HashSet<LTSState> Xold;
                do {
                    Xold = env.GetVariable(nu.Variable);
                    env[nu.Variable] = Solve(nu.Formula, lts, env, false);
                } while (Xold.Count != env[nu.Variable].Count);
                return env[nu.Variable];
            }

            throw new InvalidDataException("formula not valid in our grammar");
        }
Пример #20
0
        public static HashSet<LTSState> Solve(MuFormula formula, LTS lts, Environment env)
        {
            if (formula is Proposition) {
                var prop = formula as Proposition;
                return bool.Parse(prop.Value) ? lts.States : new HashSet<LTSState>();
            }

            else if (formula is Variable) {
                return env.GetVariable(formula as Variable);
            }

            else if (formula is Negation) {
                var neg = formula as Negation;
                return new HashSet<LTSState>(lts.States.Except(
                    Solve(neg.Formula, lts, env)));
            }

            else if (formula is Conjunction) {
                var conj = formula as Conjunction;
                var leftStates = Solve(conj.Left, lts, env);
                var rightStates = Solve(conj.Right, lts, env);
                return new HashSet<LTSState>(leftStates.Intersect(rightStates));
            }

            else if (formula is Disjunction) {
                var disj = formula as Disjunction;
                var leftStates = Solve(disj.Left, lts, env);
                var rightStates = Solve(disj.Right, lts, env);
                return new HashSet<LTSState>(leftStates.Union(rightStates));
            }

            else if (formula is Box) {
                var box = formula as Box;

                // box a f = { s | forall t. s -a-> t ==> t in [[f]]e }
                // i.e. the set of states for which all a-transitions go to a state in which f holds
                var fe = Solve(box.Formula, lts, env);

                return new HashSet<LTSState>(lts.States.Where(
                    // states where, for all outtransitions with action a, the Formula holds in the direct successor
                    state => state.GetOutTransitions(box.RegularFormula).All(tr => fe.Contains(tr.Right))
                ));
            }

            else if (formula is Diamond) {
                var diamond = formula as Diamond;
                var shorthand = new Negation(
                    // <a>f == [a](not f)
                    new Box(diamond.RegularFormula, new Negation(diamond.Formula))
                    );
                return Solve(shorthand, lts, env);
            }

            else if (formula is Mu) {
                var mu = formula as Mu;
                env[mu.Variable] = new HashSet<LTSState>();

                return FixedPoint.LFP(delegate(Tuple<HashSet<LTSState>, LTS, Environment> tuple) {
                    // repeats tau: X := solve(f)
                    var X = tuple.Item1;
                    X = Solve(mu.Formula, lts, env);
                    env[mu.Variable] = X;
                    return Tuple.Create(X, lts, env);
                }, lts, env);
            }

            else if (formula is Nu) {
                var nu = formula as Nu;
                env[nu.Variable] = lts.States;

                return FixedPoint.GFP(delegate(Tuple<HashSet<LTSState>, LTS, Environment> tuple) {
                    // repeats tau: X := solve(f)
                    var X = tuple.Item1;
                    X = Solve(nu.Formula, lts, env);
                    env[nu.Variable] = X;

                    return Tuple.Create(X, lts, env);
                }, lts, env);

            }

            throw new InvalidDataException("not a valid formula in our grammar");
        }