8 segment_fmt = 
"{j}a_aa" 
   10 edge_fmt = 
"{j}a * {b}a_{c}a + {j}{b} * {c}a_aa - {j}{c} * {b}a_aa" 
   15 plane_tests = [
"C.dot (a_cross_b)", 
"D.dot(a_cross_c)", 
"-D.dot(a_cross_b)"]
 
   18     + [edge_fmt.format(**{
"j": j, 
"b": 
"b", 
"c": 
"c"}) 
for j 
in [
"b", 
"c"]]
 
   19     + [edge_fmt.format(**{
"j": j, 
"b": 
"c", 
"c": 
"d"}) 
for j 
in [
"c", 
"d"]]
 
   20     + [edge_fmt.format(**{
"j": j, 
"b": 
"d", 
"c": 
"b"}) 
for j 
in [
"d", 
"b"]]
 
   21     + [segment_fmt.format(**{
"j": j}) 
for j 
in [
"b", 
"c", 
"d"]]
 
   24     [
"ABC.AO >= 0", 
"ACD.AO >= 0", 
"ADB.AO >= 0"]
 
   25     + [
"(ABC ^ {}).AO >= 0".format(n) 
for n 
in [
"AB", 
"AC"]]
 
   26     + [
"(ACD ^ {}).AO >= 0".format(n) 
for n 
in [
"AC", 
"AD"]]
 
   27     + [
"(ADB ^ {}).AO >= 0".format(n) 
for n 
in [
"AD", 
"AB"]]
 
   28     + [
"AB.AO >= 0", 
"AC.AO >= 0", 
"AD.AO >= 0"]
 
   63 assert len(tests) == len(checks)
 
   64 assert sorted(tests) == list(range(len(tests)))
 
   76 cases = list(range(len(regions)))
 
  186     [[1, 4, 5, 6], [-7]],
 
  187     [[2, 6, 9, 8], [-9]],
 
  188     [[3, 8, 9, 4], [-5]],
 
  237     [[10, 3, 9, -12, 4, -5], [1]],
 
  238     [[10, -3, 1, -4], [9]],
 
  239     [[10, -3, -1, 2, -6, 11], [5]],
 
  240     [[-10, 11, 2, -12, -5, -1], [6]],
 
  241     [[-10, 11, -2, 1, 5], [-6]],
 
  242     [[-10, -11, 12, 1, -7, -2, 4], [-5]],
 
  243     [[-10, -11, 12, -3, 2, 7], [-8]],
 
  244     [[-10, -11, 12, -3, -2], [-1]],
 
  248 def set_test_values(current_tests, test_values, itest, value):
 
  249     def satisfies(values, indices):
 
  251             if k > 0 
and values[k - 1] 
is not True:
 
  253             if k < 0 
and values[-k - 1] 
is not False:
 
  257     remaining_tests = list(current_tests)
 
  258     next_test_values = list(test_values)
 
  260     remaining_tests.remove(itest)
 
  261     next_test_values[itest] = value
 
  265         for impl 
in implications:
 
  266             if satisfies(next_test_values, impl[0]):
 
  268                     k = (id - 1) 
if id > 0 
else (-id - 1)
 
  269                     if k 
in remaining_tests:
 
  270                         next_test_values[k] = id > 0
 
  271                         remaining_tests.remove(k)
 
  274                         if next_test_values[k] != (id > 0):
 
  275                             raise ValueError(
"Absurd case")
 
  276     return remaining_tests, next_test_values
 
  279 def set_tests_values(current_tests, test_values, itests, values):
 
  280     for itest, value 
in zip(itests, values):
 
  281         current_tests, test_values = set_test_values(
 
  282             current_tests, test_values, itest, value
 
  284     return current_tests, test_values
 
  287 def apply_test_values(cases, test_values):
 
  288     def canSatisfy(values, indices):
 
  290             if k > 0 
and values[k - 1] 
is False:
 
  292             if k < 0 
and values[-k - 1] 
is True:
 
  296     def satisfies(values, indices):
 
  298             if k > 0 
and values[k - 1] 
is not True:
 
  300             if k < 0 
and values[-k - 1] 
is not False:
 
  307         defi = definitions[case]
 
  308         conds = conditions[case]
 
  309         rejs = rejections[case]
 
  310         if satisfies(test_values, defi):
 
  313         if not canSatisfy(test_values, defi):
 
  316             if satisfies(test_values, cond):
 
  321             if satisfies(test_values, rej):
 
  326             left_cases.append(case)
 
  330 def max_number_of_tests(
 
  337     prevBestScore=float(
"inf"),
 
  340     for test 
in current_tests:
 
  341         assert test_values[test] 
is None, 
"Test " + 
str(test) + 
" already performed" 
  343     left_cases = apply_test_values(cases, test_values)
 
  345     if len(left_cases) == 1:
 
  347             "case": left_cases[0],
 
  349     elif len(left_cases) == 0:
 
  353                 "applied " + 
str(test_values),
 
  354                 "to " + 
", ".join([regions[c] 
for c 
in cases]),
 
  358     assert len(current_tests) > 0, 
"No more test but " + 
str(left_cases) + 
" remains" 
  360     currentBestScore = prevBestScore
 
  361     bestScore = float(
"inf")
 
  362     bestOrder = [
None, 
None]
 
  363     for i, test 
in enumerate(current_tests):
 
  364         assert bestScore >= currentBestScore
 
  366         currentScore = prevScore + len(left_cases) * weights[test]
 
  368         if currentScore > currentBestScore:  
 
  372             remaining_tests, next_test_values = set_test_values(
 
  373                 current_tests, test_values, test, 
True 
  376             remaining_tests = 
None 
  378         if remaining_tests 
is not None:
 
  381             score_if_t, order_if_t = max_number_of_tests(
 
  388             if score_if_t >= currentBestScore:  
 
  391             score_if_t, order_if_t = prevScore, 
None 
  394             remaining_tests, next_test_values = set_test_values(
 
  395                 current_tests, test_values, test, 
False 
  398             remaining_tests = 
None 
  400         if remaining_tests 
is not None:
 
  403             score_if_f, order_if_f = max_number_of_tests(
 
  411             score_if_f, order_if_f = prevScore, 
None 
  413         currentScore = max(score_if_t, score_if_f)
 
  414         if currentScore < bestScore:
 
  415             if currentScore < currentBestScore:
 
  416                 bestScore = currentScore
 
  417                 bestOrder = {
"test": test, 
"true": order_if_t, 
"false": order_if_f}
 
  419                 currentBestScore = currentScore
 
  420                 if len(tests) == len(current_tests):
 
  421                     print(
"New best score: {}".format(currentBestScore))
 
  423     return bestScore, bestOrder
 
  426 def printComments(order, indent, file):
 
  427     if "comments" in order:
 
  428         for comment 
in order[
"comments"]:
 
  429             print(indent + 
"// " + comment, file=file)
 
  432 def printOrder(order, indent="", start=True, file=sys.stdout, curTests=[]):
 
  435             "bool GJK::projectTetrahedraOrigin(const Simplex& current, Simplex& next)",
 
  438         print(
"{", file=file)
 
  440             indent + 
"// The code of this function was generated using doc/gjk.py",
 
  443         print(indent + 
"const vertex_id_t a = 3, b = 2, c = 1, d = 0;", file=file)
 
  447                 + 
"const Vec3s& {} (current.vertex[{}]->w);".format(v.upper(), v),
 
  450         print(indent + 
"const CoalScalar aa = A.squaredNorm();".format(), file=file)
 
  456                         + 
"const CoalScalar {0}{1}    = {2}.dot({3});".format(
 
  457                             v, m, v.upper(), m.upper()
 
  463                         indent + 
"const CoalScalar& {0}{1}    = {1}{0};".format(v, m),
 
  466             print(indent + 
"const CoalScalar {0}a_aa = {0}a - aa;".format(v), file=file)
 
  467         for l0, l1 
in zip(
"bcd", 
"cdb"):
 
  469                 indent + 
"const CoalScalar {0}a_{1}a = {0}a - {1}a;".format(l0, l1),
 
  474                 indent + 
"const Vec3s a_cross_{0} = A.cross({1});".format(v, v.upper()),
 
  478         print(
"#define REGION_INSIDE()               " + indent + 
"\\", file=file)
 
  479         print(indent + 
"  ray.setZero();                      \\", file=file)
 
  480         print(indent + 
"  next.vertex[0] = current.vertex[d]; \\", file=file)
 
  481         print(indent + 
"  next.vertex[1] = current.vertex[c]; \\", file=file)
 
  482         print(indent + 
"  next.vertex[2] = current.vertex[b]; \\", file=file)
 
  483         print(indent + 
"  next.vertex[3] = current.vertex[a]; \\", file=file)
 
  484         print(indent + 
"  next.rank=4;                        \\", file=file)
 
  485         print(indent + 
"  return true;", file=file)
 
  492                 indent + 
"// There are no case corresponding to this set of tests.",
 
  495             printComments(order, indent, file)
 
  496             print(indent + 
"assert(false);", file=file)
 
  498         region = regions[case]
 
  499         print(indent + 
"// Region " + region, file=file)
 
  500         printComments(order, indent, file)
 
  501         toFree = [
"b", 
"c", 
"d"]
 
  502         if region == 
"Inside":
 
  503             print(indent + 
"REGION_INSIDE()", file=file)
 
  506             print(indent + 
"originToPoint (current, a, A, next, ray);", file=file)
 
  507         elif len(region) == 2:
 
  513                 "(current, a, {b}, A, {B}, {B}-A, -{b}a_aa, next, ray);".format(
 
  514                     **{
"b": B.lower(), 
"B": B}
 
  518             toFree.remove(B.lower())
 
  519         elif len(region) == 3:
 
  522             test = plane_tests[[
"ABC", 
"ACD", 
"ADB"].
index(region)]
 
  523             if test.startswith(
"-"):
 
  529                 + 
"originToTriangle " 
  530                 "(current, a, {b}, {c}, ({B}-A).cross({C}-A), {t}, next, ray);".format(
 
  531                     **{
"b": B.lower(), 
"c": C.lower(), 
"B": B, 
"C": C, 
"t": test}
 
  535             toFree.remove(B.lower())
 
  536             toFree.remove(C.lower())
 
  538             assert False, 
"Unknown region " + region
 
  541                 indent + 
"free_v[nfree++] = current.vertex[{}];".format(pt), file=file
 
  544         assert "test" in order 
and "true" in order 
and "false" in order
 
  545         check = checks[order[
"test"]]
 
  546         check_hr = checks_hr[order[
"test"]]
 
  547         printComments(order, indent, file)
 
  548         nextTests_t = curTests + [
 
  549             "a" + 
str(order[
"test"] + 1),
 
  551         nextTests_f = curTests + [
 
  552             "!a" + 
str(order[
"test"] + 1),
 
  554         if order[
"true"] 
is None:
 
  555             if order[
"false"] 
is None:
 
  558                     + 
"""assert(false && "Case {} should never happen.");""".format(
 
  565                     + 
"assert(!({} <= 0)); // Not {} / {}".format(
 
  566                         check, check_hr, 
".".join(nextTests_f)
 
  575                     curTests=nextTests_f,
 
  577         elif order[
"false"] 
is None:
 
  580                 + 
"assert({} <= 0); // {} / {}".format(
 
  581                     check, check_hr, 
".".join(nextTests_t)
 
  590                 curTests=nextTests_t,
 
  595                 + 
"if ({} <= 0) {{ // if {} / {}".format(
 
  596                     check, check_hr, 
".".join(nextTests_t)
 
  605                 curTests=nextTests_t,
 
  609                 + 
"}} else {{ // not {} / {}".format(check_hr, 
".".join(nextTests_f)),
 
  617                 curTests=nextTests_f,
 
  619             print(indent + 
"}} // end of {}".format(check_hr), file=file)
 
  623         print(
"#undef REGION_INSIDE", file=file)
 
  624         print(indent + 
"return false;", file=file)
 
  625         print(
"}", file=file)
 
  630     cases = list(range(len(regions)))
 
  632     left_cases = apply_test_values(
 
  649     assert len(left_cases) > 1
 
  654 score, order = max_number_of_tests(tests, cases)
 
  657 printOrder(order, indent=
"  ")