X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=tabulate.py;h=79d615320d7fe5d16a39aaf520c5022930cc0fc5;hb=621cca6b657fd955da0f1e309b0df5d6cf0901e7;hp=29caaae9144f218af521616c0b7bdcb63dd3f1e4;hpb=d5c74ce0d5b2f1ed3ca3bfd75d642a3d0155e4ab;p=matchsticks-search.git diff --git a/tabulate.py b/tabulate.py index 29caaae..79d6153 100755 --- a/tabulate.py +++ b/tabulate.py @@ -41,38 +41,51 @@ def verify(n, m, dissection): assert total == n assert collections[0] == collections[1] +def factor_dissector(n,m): + ret = [] + gcd = fractions.gcd(n,m) + for i in range(1, gcd+1): + if gcd % i != 0: continue + prev = dissections[n/i, m/i] + ret.append(([[(i*count, [piece*i for piece in pieces]) + for count, pieces in prev[0]], + [(i*count, [piece*i for piece in pieces]) + for count, pieces in prev[1]]], + "multiply solution for (%d,%d) by %d" % (n/i, m/i, i))) + def add_m_dissector(n,m): if n <= 2*m: - return None + return [] prev = dissections[(n-m, m)] ret = [prev[0][:], prev[1][:]] for i in range(len(ret[0])): ret[0][i] = (ret[0][i][0], ret[0][i][1] + [m]) ret[1].append((m, (m,))) - return ret + return [(ret, "extend solution for (%d,%d) by %d" % (n-m, m, m))] def gcd_dissector(n,m): gcd = fractions.gcd(n,m) - return [[(m, (gcd,) * (n/gcd))], - [(n, (gcd,) * (m/gcd))]] + return [([[(m, (gcd,) * (n/gcd))], + [(n, (gcd,) * (m/gcd))]], "trivial gcd solution")] def invent_dissection(n,m): # Try to come up with a dissection by assorted simple methods. best = 0 - for dissector, this_reason in [ - (gcd_dissector, "trivial gcd solution"), - (add_m_dissector, "extend solution for (%d,%d)" % (n-m, m)), - ]: - dissection = dissector(n, m) - if dissection is None: continue - verify(n, m, dissection) - this_best = find_min_frag(dissection) - if best < this_best: - best, best_reason = this_best, this_reason + for dissector in [gcd_dissector, add_m_dissector]: + for dissection, this_reason in dissector(n, m): + if dissection is None: continue + verify(n, m, dissection) + this_best = find_min_frag(dissection) + if best < this_best: + best, best_reason = this_best, this_reason assert best > 0 return dissection, this_reason -def read(n,m): +details = {} # maps (n,m) to a snippet of HTML + +def read_and_build_table_cell(n,m): + ret = "" + best = 0 # Look for appropriate file(s). @@ -113,9 +126,10 @@ def read(n,m): if best == 0: # We don't have a stored solution at all, so make up something # plausible if we can. - dissection, best_nature = invent_dissection(n, m) + dissection, auto_reason = invent_dissection(n, m) best = find_min_frag(dissection) dissections[(n,m)] = dissection + best_nature = 'a' bound, bound_type = bounds.upper_bound(n, m) @@ -130,54 +144,70 @@ def read(n,m): show_bound = "" else: tdclass = "range" - show_bound = " – %s" - sys.stdout.write("" % tdclass) - sys.stdout.write(str(best)) + show_bound = " – %s" + ret += "" % (tdclass, n, m) + ret += str(best) if show_bound != "": - sys.stdout.write(show_bound % str(bound)) - sys.stdout.write("\n") + ret += show_bound % str(bound) + ret += "\n" + + dump = "

n=%d, m=%d

\n" % (n, m, n, m) + dump += "

Best dissection known for %d into %d: minimum fragment is %s.\n" % (n, m, str(best)) + dump += "

\n" + if best == bound: + dump += "

This dissection is confidently believed optimal because an upper bound proof (%s) matches it.\n" % bound_type + elif best_nature == 'e': + dump += "

This dissection is believed optimal because it was found by an exhaustive search program, although the best upper bound proof (%s) gives an upper bound of %s.\n" % (bound_type, bound) + tdclass = "believed" + show_bound = "" + elif best_nature == 'p': + dump += "

This dissection was found by a search program which may not be exhaustive (if the conjectured denominator bound is false) and hence may not be optimal, though we think it probably is. The best upper bound proof (%s) gives an upper bound of %s.\n" % (bound_type, bound) + else: + dump += "

This dissection was found " + if best_nature == 'm': + dump += "by hand" + else: + dump += "by a simplistic automated method (%s)" % auto_reason + dump += ", and is not known to be optimal. The best upper bound proof (%s) gives an upper bound of %s.\n" % (bound_type, bound) + + details[(n, m)] = dump + + return ret def main(args): - limit = 24 # FIXME: configurable - sys.stdout.write("""\ - - -Known bounds for stick-dissecting problem - - - - -""") - sys.stdout.write("\n") - sys.stdout.write("\n") + limit = 31 # FIXME: configurable + + subst = {} + + table = "
n \\ m
" + table += "\n" + table += "\n" for m in range(2,limit-1): - sys.stdout.write("\n" % m) - sys.stdout.write("\n") + table += "\n" % m + table += "\n" for n in range(2,limit): - sys.stdout.write("\n") - sys.stdout.write("\n" % n) + table += "\n" + table += "\n" % n for m in range(2,n): - read(n, m) - sys.stdout.write("\n") - sys.stdout.write("
n \\ m%d
%d
%d
%d
\n") - sys.stdout.write("\n") + table += read_and_build_table_cell(n, m) + table += "\n" + table += "\n" + subst["TABLE"] = table + + subst["DISSECTIONS"] = "".join([data for ((n, m), data) in sorted(details.items())]) + + with open("template.html") as f: + for line in f: + if line[:1] == "%" and line[-2:] == "%\n": + sys.stdout.write(subst[line[1:-2]]) + else: + sys.stdout.write(line) if __name__ == "__main__": main(sys.argv[1:])