/// <summary> /// Concertize the SFA by including at most k characters in the label. /// </summary> /// <param name="k">upper limit on the number of included characters in the output automaton, when 0 or negative then include all elements</param> /// <returns></returns> public Automaton <BDD> Concretize(int k = 0) { //if (k <= 0) // throw new AutomataException(AutomataExceptionKind.InvalidArgument); var mem = new Dictionary <TERM, BDD>(); var concrete_moves = new List <Move <BDD> >(); var moveMap = new Dictionary <Tuple <int, int>, BDD>(); Action <int, int, BDD> AddMove = (from, to, guard) => { BDD pred; var key = new Tuple <int, int>(from, to); if (moveMap.TryGetValue(key, out pred)) { pred = solver.CharSetProvider.MkOr(pred, guard); } else { pred = guard; } moveMap[key] = pred; }; Predicate <TERM> IsGround = t => { foreach (var v in solver.GetVars(t)) { return(false); } return(true); }; foreach (var move in automaton.GetMoves()) { if (move.IsEpsilon) { concrete_moves.Add(Move <BDD> .Epsilon(move.SourceState, move.TargetState)); continue; } BDD set; if (mem.TryGetValue(move.Label, out set)) { AddMove(move.SourceState, move.TargetState, set); //concrete_moves.Add(Move<BvSet>.M(move.SourceState, move.TargetState, set)); continue; } if (k > 0) { if (IsGround(move.Label)) //must be satisfiable so same as true { set = solver.CharSetProvider.MkRangeConstraint((char)0, (char)(k - 1)); mem[move.Label] = set; AddMove(move.SourceState, move.TargetState, set); //concrete_moves.Add(Move<BvSet>.M(move.SourceState, move.TargetState, set)); continue; } var elems = new List <uint>(); foreach (var v in solver.MainSolver.FindAllMembers(move.Label)) { elems.Add(solver.GetNumeralUInt(v.Value)); if (elems.Count == k) { break; } } set = solver.CharSetProvider.MkSetFromElements(elems, ((int)solver.CharSetProvider.Encoding) - 1); mem[move.Label] = set; AddMove(move.SourceState, move.TargetState, set); //concrete_moves.Add(Move<BvSet>.M(move.SourceState, move.TargetState, set)); } else { BDD cond = solver.ConvertToCharSet(solver.CharSetProvider, move.Label); if (cond != null) { throw new AutomataException(AutomataExceptionKind.ConditionCannotBeConvertedToCharSet); } mem[move.Label] = cond; AddMove(move.SourceState, move.TargetState, cond); //concrete_moves.Add(Move<BvSet>.M(move.SourceState, move.TargetState, cond)); } } foreach (var entry in moveMap) { concrete_moves.Add(Move <BDD> .Create(entry.Key.Item1, entry.Key.Item2, entry.Value)); } var res = Automaton <BDD> .Create(this.solver.CharSetProvider, this.automaton.InitialState, this.automaton.GetFinalStates(), concrete_moves); return(res); }