/// <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); }
/// <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; }