/// <summary> /// Produces a witness body given input restrictions, output /// restrictions and a transform. /// </summary> /// <param name="inputBodyRestriction"></param> /// <param name="bodyTransform"></param> /// <param name="outputBodyRestriction"></param> /// <returns></returns> public static Z3Body GenerateWitness( CompositeBodyRestriction inputBodyRestriction, BodyTransform bodyTransform, CompositeBodyRestriction outputBodyRestriction) { var body = Z3Body.MkZ3Const(); var transformedBody = bodyTransform.Transform(body); var expr1 = inputBodyRestriction.Evaluate(body); var expr2 = outputBodyRestriction.Evaluate(transformedBody); var expr = Z3.Context.MkAnd(expr1, expr2); var evaluatedJoints = JointTypeHelper.MergeJointTypeLists( inputBodyRestriction.GetJointTypes(), bodyTransform.GetJointTypes(), outputBodyRestriction.GetJointTypes()); var checkResult = CheckStatus(expr); if (checkResult.Status == Status.SATISFIABLE) { var witness = CreateBodyWitness( body, checkResult.Model, evaluatedJoints, JointTypeHelper.CreateDefaultZ3Body()); return(witness); } else { return(null); } }
/// <summary> /// Generates a witness body tha matches the restrictions that /// are passed in. /// </summary> /// <param name="bodyRestriction"></param> /// <returns></returns> public static Z3Body GenerateWitness(IBodyRestriction bodyRestriction) { var body = Z3Body.MkZ3Const(); var expr = bodyRestriction.Evaluate(body); var checkResult = CheckStatus(expr); var witness = CreateBodyWitness( body, checkResult.Model, bodyRestriction.GetJointTypes(), JointTypeHelper.CreateDefaultZ3Body()); return(witness); }
/// <summary> /// Checks if the pose is within default safety /// restrictions when the transform and restrictions /// are applied. /// </summary> /// <returns>True if it's safe</returns> public static bool IsWithinSafetyRestrictions(Pose pose, out Z3Body witness) { Z3Body input = Z3Body.MkZ3Const(); Z3Body transformed = pose.Transform.Transform(input); IBodyRestriction safe = Safety.DefaultSafetyRestriction(); BoolExpr inputSafe = safe.Evaluate(input); BoolExpr transformedRestricted = pose.Restriction.Evaluate(transformed); // Try to generate a unsafe witness using the transform BoolExpr outputUnsafe = Z3.Context.MkNot(safe.Evaluate(transformed)); // Put together all expressions and search for unsat BoolExpr expr = Z3.Context.MkAnd(inputSafe, transformedRestricted, outputUnsafe); SolverCheckResult solverResult = Z3AnalysisInterface.CheckStatus(expr); if (solverResult.Status == Status.SATISFIABLE) { //Z3Body witness = Z3AnalysisInterface.CreateBodyWitness( transformed, solverResult.Model, pose.GetAllJointTypes(), JointTypeHelper.CreateDefaultZ3Body()); return(false); } else if (solverResult.Status == Status.UNKNOWN) { //Z3Body witness = JointTypeHelper.CreateDefaultZ3Body(); return(false); } else { Contract.Assert(solverResult.Status == Status.UNSATISFIABLE); witness = null; return(true); } }
/// <summary> /// Check for pairwise ambiguity /// </summary> /// <returns></returns> public static bool HasPairwiseConflicts(App app, out List <PairwiseConflictException> allExceptions, out List <AmbiguityTime> ambiguityTimes, int precision = 15) { List <Gesture> conflictGestures = (List <Gesture>)app.Gestures; bool result = false; allExceptions = new List <PairwiseConflictException>(); ambiguityTimes = new List <AmbiguityTime>(); for (int i = 0; i < conflictGestures.Count - 1; i++) { for (int j = i + 1; j < conflictGestures.Count; j++) { var gesture1 = conflictGestures[i]; var gesture2 = conflictGestures[j]; // Create const input body var input = Z3Body.MkZ3Const(); var allJoints = EnumUtil.GetValues <JointType>().ToList(); Z3Body transformed1 = null; Z3Body transformed2 = null; BoolExpr evaluation1 = Z3Math.True; BoolExpr evaluation2 = Z3Math.True; // Pass input through both gestures gesture1.FinalResult(input, out transformed1, out evaluation1); gesture2.FinalResult(input, out transformed2, out evaluation2); // Check if it is possible that both outputs are equals // This is performed by checking if is possible that all expressions are true var isNearExpr = transformed1.IsNearerThan( transformed2, precision); var expr = Z3.Context.MkAnd(isNearExpr, evaluation1, evaluation2); // If we are dumping Z3 constraints, then convert the expression to a SMTLIB formatted string // and dump it to disk. Note this is not included in the timing for the individual pair of gestures, // but it _is_ included in the timing for the app overall. if (DumpZ3Constraints) { string exprName = String.Join("X", gesture1.Name, gesture2.Name); string exprPath = exprName + ".smt2"; Z3AnalysisInterface.WriteExprToDisk(expr, exprName, exprPath); } // Check if we have an ambiguity conflict. Record the time it takes. var stopwatch = new Stopwatch(); stopwatch.Start(); var checkResult = Z3AnalysisInterface.CheckStatus(expr); stopwatch.Stop(); if (checkResult.Status == Status.SATISFIABLE) { var witness = Z3AnalysisInterface.CreateBodyWitness( input, checkResult.Model, allJoints, JointTypeHelper.CreateDefaultZ3Body()); var exception = new PairwiseConflictException( "Conflict detected between pair of gestures", gesture1, gesture2, witness); allExceptions.Add(exception); result = true; } // TODO the witness here should exist, this case shouldn't be needed else if (checkResult.Status == Status.UNKNOWN) { var witness = JointTypeHelper.CreateDefaultZ3Body(); var exception = new PairwiseConflictException( "Conflict detected between pair of gestures, the reason is unknown", gesture1, gesture2, witness); allExceptions.Add(exception); result = true; } ambiguityTimes.Add(new AmbiguityTime { Gesture1 = gesture1, Gesture2 = gesture2, Time = stopwatch.ElapsedMilliseconds, Conflict = result, CheckResult = checkResult }); } } return(result); }