/// <summary> /// /// </summary> /// <param name="reader"></param> /// <param name="h"></param> public static void ParseVariable(XmlTextReader reader, AHybridAutomaton h) { if (h == null && Controller.Instance.Sys == null) { throw new System.Exception("Variable expression for automaton or entire system not well defined (appeared outside of automaton or system declaration)."); } else { String name = reader.GetAttribute(VariableAttributes.name.ToString()); String type = reader.GetAttribute(VariableAttributes.type.ToString()); String update_type = reader.GetAttribute(VariableAttributes.update_type.ToString()); String initially = reader.GetAttribute(VariableAttributes.initially.ToString()); if (h != null) // local variable { // todo: generalize to the actual general parser? we don't really want to allow such complex declarations of variables, but why not...? if (name.Contains("[") && name.Contains("]")) // indexed variable { String[] split = name.Split('[', ']'); String varName = split[0]; String indexName = split[1]; h.addIndexedVariable(varName, (Variable.VarType)Enum.Parse(typeof(Variable.VarType), type, true), (Variable.VarUpdateType)Enum.Parse(typeof(Variable.VarUpdateType), update_type, true), initially); // todo: parse the variables } } else if (Controller.Instance.Sys != null) // global variable { Variable v = new VariableGlobal(name, "", (Variable.VarType)Enum.Parse(typeof(Variable.VarType), type, true), (Variable.VarUpdateType)Enum.Parse(typeof(Variable.VarUpdateType), update_type, true), initially); } } }
/// <summary> /// Parse a location (mode) /// </summary> /// <param name="reader"></param> /// <param name="h"></param> /// <returns></returns> public static ConcreteLocation ParseLocation(XmlTextReader reader, AHybridAutomaton h) { if (h == null) { throw new System.ArgumentNullException("Error parsing transition: hybrid automaton not specified properly before reaching location."); } uint value = UInt32.Parse(reader.GetAttribute(LocationAttributes.id.ToString())); String label = reader.GetAttribute(LocationAttributes.name.ToString()); Boolean initial = Boolean.Parse(reader.GetAttribute(LocationAttributes.initial.ToString())); // dynamically create label name if none specified if (label.Length == 0) { label = "loc" + loc_counter; loc_counter++; } if (!Controller.Instance.LocationNumToName.ContainsKey(value)) { Controller.Instance.LocationNumToName.Add(value, label); } if (!Controller.Instance.LocationNameToNum.ContainsKey(label)) { Controller.Instance.LocationNameToNum.Add(label, value); } ConcreteLocation l = new ConcreteLocation(h, label, value, initial); // bound control location variable values: 0 <= q_i <= # states, 0 <= q_j <= # states, 0 <= q_k <= # states return(l); }
public AState(AHybridAutomaton h, String label, UInt32 value, Boolean initial) { this.Parent = h; this._label = label; this._value = value; this._initial = initial; //this.ValueTerm = Controller.Instance.Z3.MkInt(value); // TODO: location type... Instance.LocType this.ValueTerm = Controller.Instance.Z3.MkConst(label, Controller.Instance.LocType); this.LabelExpr = this.ValueTerm; this.BitVectorExpr = Controller.Instance.Z3.MkBV(value, Controller.Instance.LocSize); //Controller.Instance.Z3.Assumptions.Add(Controller.Instance.Z3.MkEq(this.ValueTerm, Controller.Instance.Z3.MkInt(value))); this._statePredicate = Controller.Instance.Z3.MkEq(Controller.Instance.IndexedVariables[new KeyValuePair <string, string>("q", "i")], this.ValueTerm); // add label to value map if (label == "") { label = "mode" + value.ToString(); } Controller.Instance.Locations.Add(label, this.ValueTerm); Controller.Instance.LocationNumTermToName.Add(this.ValueTerm, label); }
public AState(AHybridAutomaton h, String label, UInt32 value, Boolean initial, List <Transition> transitions) { this.Parent = h; this._label = label; this._value = value; this._initial = initial; this._transitions = transitions; }
/// <summary> /// Parse a transition /// </summary> /// <param name="reader"></param> /// <param name="h"></param> /// <param name="l"></param> /// <returns></returns> public static Transition ParseTransition(XmlTextReader reader, AHybridAutomaton h, ConcreteLocation l) { Transition t; // todo: refactor: check and throw if null on either, but also while checking if parent of l is not null (e.g., these transitions may be local or global) if (Controller.Instance.Sys != null || h != null) { t = new Transition(l); // l is null for global transitions, no parent if (h == null) { Controller.Instance.Sys.addTransition(t); } else { String des = reader.GetAttribute(TransitionAttributes.destination.ToString()); String src = reader.GetAttribute(TransitionAttributes.source.ToString()); String prs = reader.GetAttribute(TransitionAttributes.processes.ToString()); List <String> dess = new List <String>(); List <String> srcs = new List <String>(); List <String> processes = new List <string>(); if (!src.Contains(",")) { srcs.Add(src); } else { srcs.AddRange(src.Split(',')); } bool toSelf = false; if (des != null && des.Length > 0) { if (!des.Contains(",")) { dess.Add(des); } else { dess.AddRange(des.Split(',')); } } else { toSelf = true; // only self-loops des = src; dess = srcs; } t.Indices.Add("h"); // do not have to include h by default, as it is always the process moving t.Indices.AddRange(processes); // assume process h always included t.Indices = t.Indices.Distinct().ToList(); // ensure distinct List <AState> from = new List <AState>(); // have to find the frome state as well, because in hyxml syntax, transitions are not associated with locations foreach (AState s in h.Locations) { uint desParsed = 0; uint srcParsed = 0; foreach (String stmp in srcs) { UInt32.TryParse(stmp, out srcParsed); if (s.Label == stmp || (srcParsed != null && Regex.IsMatch(stmp, @"^[0-9]+$") && s.Value == UInt32.Parse(stmp))) { from.Add(s); } } foreach (String dtmp in dess) { UInt32.TryParse(dtmp, out desParsed); if (s.Label == dtmp || (desParsed != null && Regex.IsMatch(dtmp, @"^[0-9]+$") && s.Value == UInt32.Parse(dtmp))) { t.NextStates.Add(s); } } } if (from.Count > 0) { foreach (AState ftmp in from) { t.Parent = (ConcreteLocation)ftmp; if (toSelf) // only self-loops { t.NextStates = new List <AState>(); t.NextStates.Add(ftmp); } ftmp.addTransition(t); } } else { throw new System.Exception("Error parsing transition: could not find the source location."); } } } else { throw new System.Exception("Error parsing transition: either holism or hybrid automaton not specified properly before reaching transition."); } return(t); }
/// <summary> /// Parse location end tag /// </summary> /// <param name="l"></param> public static void ParseLocationEnd(XmlTextReader reader, AHybridAutomaton h, ConcreteLocation l) { h.addLocation(l); }
/// <summary> /// Parse an ODE /// </summary> /// <param name="reader"></param> /// <param name="h"></param> /// <param name="l"></param> public static void ParseDAI(XmlTextReader reader, AHybridAutomaton h, ConcreteLocation l) { if (h == null) { throw new System.ArgumentNullException("Error parsing transition: hybrid automaton not specified properly before reaching differential equation."); } if (l == null) { throw new System.ArgumentNullException("Error parsing transition: location not specified properly before reaching differential equation."); } // todo: this currently has a lot of assumptions about how the diffeq should appear // todo: probably the easiest way to accomodate this would be to require a different <dai> block in the xml file for each variable // but obviously this could have limitations for linear / affine dynamics, but... maybe not? // let's think about it more String variable = reader.GetAttribute(FlowAttributes.variable.ToString()); String flow = reader.GetAttribute(FlowAttributes.equn.ToString()); if (variable != null && flow != null && variable.Length > 0 && flow.Length > 0) { Antlr.Runtime.Tree.CommonTree tmptree = math.Expression.Parse(flow); List <String> vars = LogicalExpression.findContinuousVars(tmptree); List <String> pvars = LogicalExpression.findParams(tmptree); List <String> constants = LogicalExpression.findAllRealConstants(tmptree); Expr expr = LogicalExpression.CreateTerm(tmptree); List <Expr> flows = new List <Expr>(); Expr t1 = Controller.Instance.Z3.MkRealConst("t_1"); Flow f = new Flow(); // indexed if the variable appears e.g., as x[i], else assume global, e.g., x if (variable.Contains("[") && variable.Contains("]")) { String[] vns = variable.Split('['); String variableName = vns[0]; // todo: error handling f.Variable = h.GetVariableByName(variableName); // todo: error handling // prime all variables switch (Controller.Instance.DataOption) { case Controller.DataOptionType.array: { expr = expr.Substitute(Controller.Instance.DataA.IndexedVariableDecl[variableName], Controller.Instance.DataA.IndexedVariableDeclPrimed[variableName]); break; } case Controller.DataOptionType.uninterpreted_function: default: { Controller.Instance.Z3.replaceFuncDecl(ref expr, expr, Controller.Instance.DataU.IndexedVariableDecl[variableName], Controller.Instance.DataU.IndexedVariableDeclPrimed[variableName], false); break; } } // todo: rewrite in more general form for timed vs. rectangular if (constants.Count + pvars.Count < 1) { f.DynamicsType = Flow.DynamicsTypes.timed; } else if (constants.Count + pvars.Count == 1) { f.DynamicsType = Flow.DynamicsTypes.timed; if (pvars.Count == 1) { f.RectRateA = Controller.Instance.Params[pvars[0]]; f.RectRateB = Controller.Instance.Params[pvars[0]]; // \dot{x} \in [a,a] } if (constants.Count == 1) { f.RectRateA = Controller.Instance.Z3.MkReal(constants[0]); f.RectRateB = Controller.Instance.Z3.MkReal(constants[0]); } } else if (constants.Count + pvars.Count == 2) { f.DynamicsType = Flow.DynamicsTypes.rectangular; // todo: generalize if (pvars.Count >= 1) { f.RectRateA = Controller.Instance.Params[pvars[0]]; } if (pvars.Count >= 2) { f.RectRateB = Controller.Instance.Params[pvars[1]]; } if (constants.Count >= 1) { f.RectRateA = Controller.Instance.Z3.MkReal(constants[0]); } if (constants.Count >= 2) { f.RectRateB = Controller.Instance.Z3.MkReal(constants[1]); } } if (pvars.Count > 0) { foreach (var y in pvars) { // todo: generalize, this is pretty nasty, and currently only supports dynamics of the form: v[i] R y, where R is an order/equivalence relation (e.g., >, <, >=, <=, =, etc.) Expr addDeltaMin = Controller.Instance.Z3.MkAdd((ArithExpr)Controller.Instance.IndexedVariables[new KeyValuePair <string, string>(variableName, "i")], Controller.Instance.Z3.MkMul((ArithExpr)Controller.Instance.Params[y], (ArithExpr)t1)); expr = expr.Substitute(Controller.Instance.Params[y], addDeltaMin); } } else if (constants.Count > 0) { foreach (var cs in constants) { int cint = (int)float.Parse(cs); String cstr = float.Parse(cs).ToString(); if (cint == 1) { Expr c = Controller.Instance.Z3.MkReal(cstr); Expr addDeltaMin = Controller.Instance.Z3.MkAdd((ArithExpr)Controller.Instance.IndexedVariables[new KeyValuePair <string, string>(variableName, "i")], (ArithExpr)t1); expr = expr.Substitute(c, addDeltaMin); } else if (cint == -1) // todo: constants will never be negative currently due to the way findRealConstants function works (- is a unary term, so the constants are always positive with another unary minus outside) { Expr c = Controller.Instance.Z3.MkReal(cstr); Expr addDeltaMin = Controller.Instance.Z3.MkSub((ArithExpr)Controller.Instance.IndexedVariables[new KeyValuePair <string, string>(variableName, "i")], (ArithExpr)t1); expr = expr.Substitute(c, addDeltaMin); } else if (cint < 0) { Expr c = Controller.Instance.Z3.MkReal(cstr); Expr addDeltaMin = Controller.Instance.Z3.MkSub((ArithExpr)Controller.Instance.IndexedVariables[new KeyValuePair <string, string>(variableName, "i")], Controller.Instance.Z3.MkMul((ArithExpr)c, (ArithExpr)t1)); expr = expr.Substitute(c, addDeltaMin); } else { Expr c = Controller.Instance.Z3.MkReal(cstr); Expr addDeltaMin = Controller.Instance.Z3.MkAdd((ArithExpr)Controller.Instance.IndexedVariables[new KeyValuePair <string, string>(variableName, "i")], Controller.Instance.Z3.MkMul((ArithExpr)c, (ArithExpr)t1)); expr = expr.Substitute(c, addDeltaMin); } } } } else // global variables { String variableName = variable; f.Variable = Controller.Instance.Sys.GetVariableByName(variableName); // prime the continuous variable occurrences expr = expr.Substitute(Controller.Instance.GlobalVariables[variableName], Controller.Instance.GlobalVariablesPrimed[variableName]); if (pvars.Count > 0) { foreach (var y in pvars) { // todo: generalize, this is pretty nasty, and currently only supports dynamics of the form: v[i] R y, where R is an order/equivalence relation (e.g., >, <, >=, <=, =, etc.) Expr addDeltaMin = Controller.Instance.Z3.MkAdd((ArithExpr)Controller.Instance.Params[variableName], Controller.Instance.Z3.MkMul((ArithExpr)Controller.Instance.Params[y], (ArithExpr)t1)); expr = expr.Substitute(Controller.Instance.Params[y], addDeltaMin); } } else if (constants.Count > 0) { foreach (var cs in constants) { int cint = (int)float.Parse(cs); String cstr = float.Parse(cs).ToString(); f.DynamicsType = Flow.DynamicsTypes.timed; if (cint == 1) { Expr c = Controller.Instance.Z3.MkReal(cstr); f.RectRateA = c; Expr addDeltaMin = Controller.Instance.Z3.MkAdd((ArithExpr)Controller.Instance.GlobalVariables[variableName], (ArithExpr)t1); expr = expr.Substitute(c, addDeltaMin); } else if (cint == -1) { Expr c = Controller.Instance.Z3.MkReal(cstr); f.RectRateA = c; Expr addDeltaMin = Controller.Instance.Z3.MkSub((ArithExpr)Controller.Instance.GlobalVariables[variableName], (ArithExpr)t1); expr = expr.Substitute(c, addDeltaMin); } else if (cint < 0) { Expr c = Controller.Instance.Z3.MkReal(cstr); f.RectRateA = c; Expr addDeltaMin = Controller.Instance.Z3.MkSub((ArithExpr)Controller.Instance.GlobalVariables[variableName], Controller.Instance.Z3.MkMul((ArithExpr)c, (ArithExpr)t1)); expr = expr.Substitute(c, addDeltaMin); } else { Expr c = Controller.Instance.Z3.MkReal(cstr); f.RectRateA = c; Expr addDeltaMin = Controller.Instance.Z3.MkAdd((ArithExpr)Controller.Instance.GlobalVariables[variableName], Controller.Instance.Z3.MkMul((ArithExpr)c, (ArithExpr)t1)); expr = expr.Substitute(c, addDeltaMin); } } } } // todo: generalize: we assume anything with a 0 in it is constant dynamics //if (!Controller.Instance.Z3.findTerm(expr, Controller.Instance.RealZero, true)) if (!(f.RectRateA == Controller.Instance.RealZero || f.RectRateB == Controller.Instance.RealZero)) { f.Value = expr; /* * // todo: move zero diffeq detection to this part, as currently we may be removing some actual diffeqs if any of them are 0 * if (l.Flow != null) * { * l.Flow = l.Flow & expr; * } * else * { * l.Flow = expr; // todo: this doesn't work properly if we have multiple variables, due to the way we replace the flow in stopping conditions and invariants * // one solution is to use a list of flows * // another is to create a flow object, which is the more natural choice, and keep a list of flow objects (so they may have different types, e.g., timed vs rect vs linear) * } */ } else { f.DynamicsType = Flow.DynamicsTypes.constant; // no change f.RectRateA = Controller.Instance.RealZero; f.RectRateB = Controller.Instance.RealZero; Expr atmp = Controller.Instance.IndexedVariables[new KeyValuePair <string, string>(f.Variable.Name, "i")]; Expr btmp = Controller.Instance.IndexedVariablesPrimed[new KeyValuePair <string, string>(f.Variable.Name + Controller.PRIME_SUFFIX, "i")]; f.Value = Controller.Instance.Z3.MkEq(atmp, btmp); } l.Flows.Add(f); } }
public ConcreteLocation(AHybridAutomaton h, String label, UInt32 value, Boolean initial) : base(h, label, value, initial) { }