Example #1
0
def __generate_input_graph(argstr, cleanup_generated_input):
    """Generate a graph from the specified string of arguments and return the file it is saved in."""
    global __input_graph_to_cleanup

    try:
        if cleanup_generated_input:
            input_graph = random_tmp_filename(10, 'input')
            args = (argstr + ' -mqto ' + input_graph).split()
            __input_graph_to_cleanup = input_graph
        else:
            args = (argstr + ' -mqt').split()
            input_graph = generate_input(args, get_output_name_only=True)
            __input_graph_to_cleanup = None

        errstr = "unknown error"
        ret = generate_input(args)
    except Exception, errstr:
        ret = -1
Example #2
0
def __generate_input_graph(argstr, cleanup_generated_input):
    """Generate a graph from the specified string of arguments and return the file it is saved in."""
    global __input_graph_to_cleanup

    try:
        if cleanup_generated_input:
            input_graph = random_tmp_filename(10, 'input')
            args = (argstr + ' -mqto ' + input_graph).split()
            __input_graph_to_cleanup = input_graph
        else:
            args = (argstr + ' -mqt').split()
            input_graph = generate_input(args, get_output_name_only=True)
            __input_graph_to_cleanup = None

        errstr = "unknown error"
        ret = generate_input(args)
    except Exception, errstr:
        ret = -1
Example #3
0
fmt = 'got %u variations, now adding %u complete graphs for a total of %u variations'
print fmt % (len(variations), len(edges), len(variations) + len(edges))

# add the complete graphs
for e in edges:
    v = ceil(vertices_in_complete_undirected_graph(e))
    e = edges_in_complete_undirected_graph(v)
    variations.append((e, v))

# compute expected size
tot_sz = 0
max_sz = 0
for (e, v) in variations:
    # per edge size cost is chars for two vertices, an edge weight, and spacing
    my_sz = (e * (2 * len(str(v)) + 8 + 3))
    max_sz = max(max_sz, my_sz)
    tot_sz += my_sz

tot_sz /= (1024 * 1024 * 1024)
max_sz /= (1024 * 1024)
print 'aggregate input size is %uGB (max input file size is %uMB)' % (
    int(tot_sz), int(max_sz))

# generate the graphs
for i in range(1, num_versions + 1):
    ifl = get_path_to_project_root() + 'input/nperf-%u.inputs' % i
    print 'generating inputs for ' + ifl
    for (e, v) in variations:
        argstr = '--dont-generate -q -l %s -n %u %u' % (ifl, e, v)
        generate_input(argstr.split())
Example #4
0
def main(argv=sys.argv[1:]):
    usage = """usage: %prog [options] NUM_VERTICES
Uses generate_input.py to generate a variety of edge densities for a given
number of vertices.  The edge densities used will be the maximum edge density
(-m) down to 0.0 (excluded unless -z is specified) in steps of -d.

Example: Generate 5 inputs and log them to the corr.inputs file with correctness
         values for 10 vertices and for densities 1.0, 0.75, 0.5, and 0.25:
         %prog -n5 -g '-l ../input/corr.inputs -c' 10"""
    parser = OptionParser(usage)
    parser.add_option("-d", "--density-interval",
                      type="float", default=0.25, metavar="D",
                      help="spacing between inputs in terms of the edge density interval [default: %default]")
    parser.add_option("-g", "--generate-input",
                      metavar="GEN_ARGS", default="",
                      help="extra arguments to pass to generate_input.py")
    parser.add_option("-m", "--max-density",
                      type="float", default=1.0, metavar="D",
                      help="maximum edge density [default: %default]")
    parser.add_option("-n", "--num-runs-per-edge-density",
                      type="int", default=1, metavar="n",
                      help="number of inputs to generate for each edge density [default: %default]")
    parser.add_option("-z", "--zero",
                      action="store_true", default=False,
                      help="generate zero-density (spanning tree) graphs too")

    (options, args) = parser.parse_args(argv)
    if len(args) < 1:
        parser.error("missing NUM_VERTICES")
    elif len(args) > 1:
        parser.error("too many arguments")
    try:
        v = int(args[0])
        if v <= 0:
            parser.error('NUM_VERTICES must be at least 1')
    except ValueError:
        parser.error('NUM_VERTICES must be an integer')

    di = options.density_interval
    if di < 0.0 or di > 1.0:
        parser.error('-d must be between 0 and 1 inclusive')

    n = options.num_runs_per_edge_density
    if n < 0:
        parser.error('-n must be greater than or equal to 0')

    d = options.max_density
    if d < 0.0 or d > 1.0:
        parser.error('-d must be between 0 and 1 inclusive')

    extra_args = options.generate_input
    while d >= 0.0:
        if d == 0 and not options.zero:
            break

        e = get_edges_from_density(v, d)
        for _ in range(n):
            args = ('-n %u %s %u' % (e, extra_args, v)).split()
            try:
                ret = generate_input(args)
            except Exception, errstr:
                print >> sys.stderr, 'fan_gen failed: ' + errstr
                return -1
            if ret != 0:
                print >> sys.stderr, 'fan_gen failed'
                return -1
        d -= di
Example #5
0
from generate_input import generate_input

container = [
    (13, 2, 2, 2, 1, 2),  # (6,10)
    (5, 1, 3, 4, 1, 2),  # (1,0)
    (17, 4, 12, 5, 15, 3)  # (-1,-1)
]

container = generate_input(323)


def twoPcalc(pX, pY, p):
    if (pY == 0):
        return 'inf'
    # lambda
    gL = (3 * pow(pX, 2) + A) * pow(2 * pY, p - 2, p)
    # Nue
    gN = pY - (gL * pX)
    # P coordinates
    x3 = pow(gL, 2) - (2 * pX)
    y3 = (-gL * x3) - gN
    return (x3 % p, y3 % p)


def dblAdd(pX, pY, qX, qY, p):
    if pY == (-qY % p):
        return 'inf'
    # lambda
    gL = (qY - pY) * pow(qX - pX, p - 2, p)
    # Nue
    gN = pY - gL * pX
def main(argv=sys.argv[1:]):
    usage = """usage: %prog [options] NUM_VERTICES
Generates input for evaluating performance at different edge densities for a given |V|."""
    parser = OptionParser(usage)
    parser.add_option("-a", "--additive-step-type",
                      action="store_true", default=False,
                      help="use additive stepping between numbers of vertices [default: multiplicative]")
    parser.add_option("-l", "--min",
                      type="float", default=4.0,
                      help="minimum edge:vertex ratio to generate a graph for [default: %default]")
    parser.add_option("-n", "--num-per-step",
                      type="int", default=1, metavar="n",
                      help="number of inputs to generate for each step [default: %default]")
    parser.add_option("-s", "--step",
                      type="float", default=2.0,
                      help="step amount between edge:vertex ratios (see -a) [default: %default]")
    parser.add_option("-u", "--max",
                      type="float", default=1500.0,
                      help="maximum edge:vertex ratio to generate a graph for [default: %default]")
    (options, args) = parser.parse_args(argv)
    if len(args) < 1:
        parser.error("missing NUM_VERTICES")
    elif len(args) > 1:
        parser.error("too many arguments")

    try:
        num_verts = int(args[0])
        inputs_list_file = get_path_to_project_root() + 'input/density-%u.inputs' % num_verts
    except ValueError:
        parser.error('NUM_NUM_VERTSERTICES must be a positive integer')
    if num_verts < 1:
        parser.error('NUM_VERTICES must be at least 1')

    if options.min < 1 or options.min > options.max:
        parser.error('-l must be in the range [1, max]')

    max_edges = edges_in_complete_undirected_graph(num_verts)
    max_ratio = max_edges / num_verts
    if options.max < 1:
        parser.error('-u must be at least 1')
    elif options.max > max_ratio:
        fmt = 'max edge:vertex ratio for %u vertices is %.1f, but -u specified a ratio of %u'
        parser.error(fmt % (num_verts, max_ratio, options.max))

    if options.additive_step_type:
        if options.step < 1.0:
            parser.error('-s must be greater than or equal to 1 when -a is used')
    elif options.step <= 1.0:
        parser.error('-s must be greater than 1 when -a is not used')

    d = options.min
    while True:
        for _ in range(options.num_per_step):
            num_edges = int(d * num_verts)
            # stay within a complete graph, but round up to one if we get very close
            if num_edges > max_edges or (num_edges/float(max_edges)) > 0.995:
                num_edges = max_edges
                d = options.max + 1 # stop after this iteration

            args = '-p1 -l %s -n %u %u' % (inputs_list_file, num_edges, num_verts)
            try:
                print 'generating new input: ' + args
                ret = generate_input(args.split())
            except Exception, errstr:
                print >> sys.stderr, 'generate_density_inputs failed for: ' + args + ': ' + str(errstr)
                return -1
            if ret != 0:
                print >> sys.stderr, 'generate_density_inputs failed for: ' + args
                return -1

        if d >= options.max:
            break
        if options.additive_step_type:
            d += options.step
        else:
            d *= options.step
        if d > options.max:
            d = options.max
Example #7
0
    for p in poms:
        e = int(get_edges_from_percent_of_max(v, p))
        density = e / float(v)
        if density > 55 and density < 135 and v < 500:
            what = 'skipped: '
        else:
            what = 'added: '
            variations.append( (e, v) )
        print '%sv=%u pom=%.2f e=%u => density=%.2f' % (what, v, p, e, e/float(v))

# compute expected size
tot_sz = 0
max_sz = 0
for (e, v) in variations:
    # per edge size cost is chars for two vertices, an edge weight, and spacing
    my_sz = (e * (2 * len(str(v)) + 8 + 3))
    max_sz = max(max_sz, my_sz)
    tot_sz += my_sz

tot_sz /= (1024 * 1024)
max_sz /= (1024 * 1024)
print 'aggregate input size is %uMB (max input file size is %uMB)' % (int(tot_sz), int(max_sz))

# generate the graphs
for i in range(1, num_versions+1):
    ifl = get_path_to_project_root() + 'input/cperf-%u.inputs' % i
    print 'generating inputs for ' + ifl
    for (e, v) in variations:
        argstr = '--dont-generate -q -l %s -n %u %u' % (ifl, e, v)
        generate_input(argstr.split())
def main(argv=sys.argv[1:]):
    usage = """usage: %prog [options]
Generates input for part 2 of the project en masse.

Examples:
    Generate inputs for 2D vertex placement in powers of 2 up to and including
    10000 vertices (10 inputs for each step):
        %prog -d2 -u10000 -n10

    Generate inputs for random edge weights in steps of 10 vertices up to and
    including 100 vertices (1 input for each step):
        %prog -a -s10 -u100"""
    parser = OptionParser(usage)
    parser.add_option("-a", "--additive-step-type",
                      action="store_true", default=False,
                      help="use additive stepping between numbers of vertices [default: multiplicative]")
    parser.add_option("-d", "--dims",
                      type="int", default=0,
                      help="number of dimensions to use; 0 => use random edge weights [default: %default]")
    parser.add_option("-g", "--go",
                      action="store_true", default=False,
                      help="run right away rather than generating inputs")
    parser.add_option("-l", "--min",
                      type="int", default=1,
                      help="minimum number of vertices to generate a graph for [default: %default]")
    parser.add_option("-n", "--num-per-step",
                      type="int", default=1, metavar="n",
                      help="number of inputs to generate for each step [default: %default]")
    parser.add_option("-s", "--step",
                      type="float", default=2.0,
                      help="step amount between vertex sizes (see -a) [default: %default]")
    parser.add_option("-u", "--max",
                      type="int", default=1024,
                      help="maximum number of vertices to generate a graph for [default: %default]")
    (options, args) = parser.parse_args(argv)
    if len(args) > 1:
        parser.error("too many arguments")

    if options.dims == 0:
        what = '-e 0.0,1.0'
    else:
        what = '-v %u,0.0,1.0' % options.dims

    if options.min < 1 or options.min > options.max:
        parser.error('-l must be in the range [1, max]')

    if options.max < 1:
        parser.error('-u must be at least 1')

    if options.additive_step_type:
        if options.step < 1.0:
            parser.error('-s must be greater than or equal to 1 when -a is used')
    elif options.step <= 1.0:
        parser.error('-s must be greater than 1 when -a is not used')

    v = options.min
    while True:
        for _ in range(options.num_per_step):
            if not options.go:
                args = '-p15 %s %u' % (what, int(v))
                try:
                    print 'generating new input: ' + args
                    ret = generate_input(args.split())
                except Exception, errstr:
                    print >> sys.stderr, 'generate_weight_inputs failed for: ' + args + ': ' + str(errstr)
                    return -1
                if ret != 0:
                    print >> sys.stderr, 'generate_weight_inputs failed for: ' + args
                    return -1
            else:
                cmd = get_path_to_tools_root() + 'run_test.py'
                cmd += " -G '-p15 %s %u' -n1" % (what, int(v))
                if os.system(cmd) != 0:
                    print >> sys.stderr, 'generate_weight_inputs GO mode failed for: ' + cmd
                    return -1

        if v >= options.max:
            break
        if options.additive_step_type:
            v += options.step
        else:
            v *= options.step
        if v > options.max:
            v = options.max
Example #9
0
def main(argv=sys.argv[1:]):
    usage = """usage: %prog [options] NUM_VERTICES
Generates input for evaluating performance at different edge densities for a given |V|."""
    parser = OptionParser(usage)
    parser.add_option(
        "-a",
        "--additive-step-type",
        action="store_true",
        default=False,
        help=
        "use additive stepping between numbers of vertices [default: multiplicative]"
    )
    parser.add_option(
        "-l",
        "--min",
        type="float",
        default=4.0,
        help=
        "minimum edge:vertex ratio to generate a graph for [default: %default]"
    )
    parser.add_option(
        "-n",
        "--num-per-step",
        type="int",
        default=1,
        metavar="n",
        help="number of inputs to generate for each step [default: %default]")
    parser.add_option(
        "-s",
        "--step",
        type="float",
        default=2.0,
        help=
        "step amount between edge:vertex ratios (see -a) [default: %default]")
    parser.add_option(
        "-u",
        "--max",
        type="float",
        default=1500.0,
        help=
        "maximum edge:vertex ratio to generate a graph for [default: %default]"
    )
    (options, args) = parser.parse_args(argv)
    if len(args) < 1:
        parser.error("missing NUM_VERTICES")
    elif len(args) > 1:
        parser.error("too many arguments")

    try:
        num_verts = int(args[0])
        inputs_list_file = get_path_to_project_root(
        ) + 'input/density-%u.inputs' % num_verts
    except ValueError:
        parser.error('NUM_NUM_VERTSERTICES must be a positive integer')
    if num_verts < 1:
        parser.error('NUM_VERTICES must be at least 1')

    if options.min < 1 or options.min > options.max:
        parser.error('-l must be in the range [1, max]')

    max_edges = edges_in_complete_undirected_graph(num_verts)
    max_ratio = max_edges / num_verts
    if options.max < 1:
        parser.error('-u must be at least 1')
    elif options.max > max_ratio:
        fmt = 'max edge:vertex ratio for %u vertices is %.1f, but -u specified a ratio of %u'
        parser.error(fmt % (num_verts, max_ratio, options.max))

    if options.additive_step_type:
        if options.step < 1.0:
            parser.error(
                '-s must be greater than or equal to 1 when -a is used')
    elif options.step <= 1.0:
        parser.error('-s must be greater than 1 when -a is not used')

    d = options.min
    while True:
        for _ in range(options.num_per_step):
            num_edges = int(d * num_verts)
            # stay within a complete graph, but round up to one if we get very close
            if num_edges > max_edges or (num_edges / float(max_edges)) > 0.995:
                num_edges = max_edges
                d = options.max + 1  # stop after this iteration

            args = '-p1 -l %s -n %u %u' % (inputs_list_file, num_edges,
                                           num_verts)
            try:
                print 'generating new input: ' + args
                ret = generate_input(args.split())
            except Exception, errstr:
                print >> sys.stderr, 'generate_density_inputs failed for: ' + args + ': ' + str(
                    errstr)
                return -1
            if ret != 0:
                print >> sys.stderr, 'generate_density_inputs failed for: ' + args
                return -1

        if d >= options.max:
            break
        if options.additive_step_type:
            d += options.step
        else:
            d *= options.step
        if d > options.max:
            d = options.max
Example #10
0
from generate_input import main as generate_input
import sys, time

if len(sys.argv) != 2:
    print 'usage: gather_correctness.py LOG_FN'
    sys.exit(-1)

# get the file to read inputs from
logfn = sys.argv[1]
ds = DataSet.read_from_file(InputSolution, logfn)

# compute correctness for each input
inputs = ds.dataset.keys()  # Input objects
inputs.sort()
on = 0
for i in inputs:
    on += 1
    # figure out how to generate the graph and where it will be sotred
    argstr = '-mt ' + i.make_args_for_generate_input()
    input_graph = generate_input(argstr.split(), get_output_name_only=True)
    print time.ctime(time.time()) + ' input # ' + str(
        on) + ' => gathering correctness data for ' + argstr

    # generate the graph
    generate_input(argstr.split())

    # compute the weight for the graph
    get_and_log_mst_weight_from_checker(input_graph,
                                        force_recompute=False,
                                        inputslogfn=logfn)
Example #11
0
from data import DataSet, InputSolution
from check_output import get_and_log_mst_weight_from_checker
from generate_input import main as generate_input
import sys, time

if len(sys.argv) != 2:
    print 'usage: gather_correctness.py LOG_FN'
    sys.exit(-1)

# get the file to read inputs from
logfn = sys.argv[1]
ds = DataSet.read_from_file(InputSolution, logfn)

# compute correctness for each input
inputs = ds.dataset.keys() # Input objects
inputs.sort()
on = 0
for i in inputs:
    on += 1
    # figure out how to generate the graph and where it will be sotred
    argstr = '-mt ' + i.make_args_for_generate_input()
    input_graph = generate_input(argstr.split(), get_output_name_only=True)
    print time.ctime(time.time()) + ' input # ' + str(on) + ' => gathering correctness data for ' + argstr

    # generate the graph
    generate_input(argstr.split())

    # compute the weight for the graph
    get_and_log_mst_weight_from_checker(input_graph, force_recompute=False, inputslogfn=logfn)
Example #12
0
        seq = []

        for i in range(k):
            seq.append(a % n)
            a = pow(a, 2, n)

        for x in seq:
            if gcd(n, x - 1) > 1:
                p = gcd(n, x - 1)
                q = int(n / p)
                if q != 1:
                    found = True
                    break
        i += 1
    return p, q


def gcd(a, b):
    if (b == 0):
        return a
    else:
        return gcd(b, a % b)


l = generate_input("323")
for x in l:
    N, e, d = x[0], x[1], x[2]
    print("input: ", N, e, d)
    print(mr(N, e, d))
Example #13
0
def main(argv=sys.argv[1:]):
    usage = """usage: %prog [options]
Generates input for part 2 of the project en masse.

Examples:
    Generate inputs for 2D vertex placement in powers of 2 up to and including
    10000 vertices (10 inputs for each step):
        %prog -d2 -u10000 -n10

    Generate inputs for random edge weights in steps of 10 vertices up to and
    including 100 vertices (1 input for each step):
        %prog -a -s10 -u100"""
    parser = OptionParser(usage)
    parser.add_option(
        "-a",
        "--additive-step-type",
        action="store_true",
        default=False,
        help=
        "use additive stepping between numbers of vertices [default: multiplicative]"
    )
    parser.add_option(
        "-d",
        "--dims",
        type="int",
        default=0,
        help=
        "number of dimensions to use; 0 => use random edge weights [default: %default]"
    )
    parser.add_option("-g",
                      "--go",
                      action="store_true",
                      default=False,
                      help="run right away rather than generating inputs")
    parser.add_option(
        "-l",
        "--min",
        type="int",
        default=1,
        help=
        "minimum number of vertices to generate a graph for [default: %default]"
    )
    parser.add_option(
        "-n",
        "--num-per-step",
        type="int",
        default=1,
        metavar="n",
        help="number of inputs to generate for each step [default: %default]")
    parser.add_option(
        "-s",
        "--step",
        type="float",
        default=2.0,
        help="step amount between vertex sizes (see -a) [default: %default]")
    parser.add_option(
        "-u",
        "--max",
        type="int",
        default=1024,
        help=
        "maximum number of vertices to generate a graph for [default: %default]"
    )
    (options, args) = parser.parse_args(argv)
    if len(args) > 1:
        parser.error("too many arguments")

    if options.dims == 0:
        what = '-e 0.0,1.0'
    else:
        what = '-v %u,0.0,1.0' % options.dims

    if options.min < 1 or options.min > options.max:
        parser.error('-l must be in the range [1, max]')

    if options.max < 1:
        parser.error('-u must be at least 1')

    if options.additive_step_type:
        if options.step < 1.0:
            parser.error(
                '-s must be greater than or equal to 1 when -a is used')
    elif options.step <= 1.0:
        parser.error('-s must be greater than 1 when -a is not used')

    v = options.min
    while True:
        for _ in range(options.num_per_step):
            if not options.go:
                args = '-p15 %s %u' % (what, int(v))
                try:
                    print 'generating new input: ' + args
                    ret = generate_input(args.split())
                except Exception, errstr:
                    print >> sys.stderr, 'generate_weight_inputs failed for: ' + args + ': ' + str(
                        errstr)
                    return -1
                if ret != 0:
                    print >> sys.stderr, 'generate_weight_inputs failed for: ' + args
                    return -1
            else:
                cmd = get_path_to_tools_root() + 'run_test.py'
                cmd += " -G '-p15 %s %u' -n1" % (what, int(v))
                if os.system(cmd) != 0:
                    print >> sys.stderr, 'generate_weight_inputs GO mode failed for: ' + cmd
                    return -1

        if v >= options.max:
            break
        if options.additive_step_type:
            v += options.step
        else:
            v *= options.step
        if v > options.max:
            v = options.max
Example #14
0
def main(argv=sys.argv[1:]):
    usage = """usage: %prog [options] NUM_VERTICES
Uses generate_input.py to generate a variety of edge densities for a given
number of vertices.  The edge densities used will be the maximum edge density
(-m) down to 0.0 (excluded unless -z is specified) in steps of -d.

Example: Generate 5 inputs and log them to the corr.inputs file with correctness
         values for 10 vertices and for densities 1.0, 0.75, 0.5, and 0.25:
         %prog -n5 -g '-l ../input/corr.inputs -c' 10"""
    parser = OptionParser(usage)
    parser.add_option(
        "-d",
        "--density-interval",
        type="float",
        default=0.25,
        metavar="D",
        help=
        "spacing between inputs in terms of the edge density interval [default: %default]"
    )
    parser.add_option("-g",
                      "--generate-input",
                      metavar="GEN_ARGS",
                      default="",
                      help="extra arguments to pass to generate_input.py")
    parser.add_option("-m",
                      "--max-density",
                      type="float",
                      default=1.0,
                      metavar="D",
                      help="maximum edge density [default: %default]")
    parser.add_option(
        "-n",
        "--num-runs-per-edge-density",
        type="int",
        default=1,
        metavar="n",
        help=
        "number of inputs to generate for each edge density [default: %default]"
    )
    parser.add_option("-z",
                      "--zero",
                      action="store_true",
                      default=False,
                      help="generate zero-density (spanning tree) graphs too")

    (options, args) = parser.parse_args(argv)
    if len(args) < 1:
        parser.error("missing NUM_VERTICES")
    elif len(args) > 1:
        parser.error("too many arguments")
    try:
        v = int(args[0])
        if v <= 0:
            parser.error('NUM_VERTICES must be at least 1')
    except ValueError:
        parser.error('NUM_VERTICES must be an integer')

    di = options.density_interval
    if di < 0.0 or di > 1.0:
        parser.error('-d must be between 0 and 1 inclusive')

    n = options.num_runs_per_edge_density
    if n < 0:
        parser.error('-n must be greater than or equal to 0')

    d = options.max_density
    if d < 0.0 or d > 1.0:
        parser.error('-d must be between 0 and 1 inclusive')

    extra_args = options.generate_input
    while d >= 0.0:
        if d == 0 and not options.zero:
            break

        e = get_edges_from_density(v, d)
        for _ in range(n):
            args = ('-n %u %s %u' % (e, extra_args, v)).split()
            try:
                ret = generate_input(args)
            except Exception, errstr:
                print >> sys.stderr, 'fan_gen failed: ' + errstr
                return -1
            if ret != 0:
                print >> sys.stderr, 'fan_gen failed'
                return -1
        d -= di
Example #15
0
import os
import re
from generate_input import generate_input
from done import solve
import time

MY_NUMS = '323'

if __name__ == '__main__':
    input_lists = generate_input(MY_NUMS)
    correct = 0
    total = 0

    for input_list in input_lists:
        # convert to tuple
        input_tuple = tuple(input_list)

        # get result from solve
        time_start = time.time() * 1000
        local_result = solve(*input_tuple)
        time_end = time.time() * 1000
        time_dur = round(time_end - time_start, 4)

        # print local result
        print(f"solve{input_tuple}")
        print(f"    = {local_result}")
        print(f"        Computation took {time_dur}ms")

        # ask sage what the answer should be
        print('    Checking against Sage....')
        stream = os.popen(