Permalink
Browse files

first commit

  • Loading branch information...
0 parents commit ecf5959a0a78cb5551b3825993116636bc897b89 @juzna committed Jun 4, 2010
6 README
@@ -0,0 +1,6 @@
+Project for PA184 - Heuristic Search Methods
+
+In this directory:
+ c/ - constructive heuristics written in C
+ python/ - great deluge written in Python
+ sets/ - data sets (problem definitions)
1 c/.gitignore
@@ -0,0 +1 @@
+/main
40 c/README
@@ -0,0 +1,40 @@
+1/ COMPILE
+ for release: g++ -O2 -pthread -o main main.c
+ for debugging: g++ -ggdb3 -pthread -o main main.c
+
+
+
+2/ USAGE
+Usage: ./main jobs workers job-randomizer worker-randomizer dataset [set-index]
+ Job order funcions: constant order order-r price-diff
+ Worker order funcions: constant order order-r free-capacity price
+ Randomizers: rand linear add
+
+Sample: ./main order order - - sets/gap1.txt 0 # priorize jobs and workers by it's order, no randomize, dataset gap1.txt, first problem
+Sample: ./main price-diff free-capacity linear linear sets/gap1.txt 0 # heuristics for jobs and workers, peckish
+Sample: ./main - - rand rand sets/gap1.txt 0 # no heuristics for jobs and workers, totally random
+
+Environment variables:
+ DEBUG=1 - print debug informations
+ SIMPLE=1 - print just problem number, price, used space and time in miliseconds
+ Sample: SIMPLE=1 ./main order order - - sets/gap1.txt 0
+
+
+
+3/ ALGORITHM
+There is universal greedy solver with several hooks, which has to be implemented to solve problems.
+This hooks are:
+ - getJobsPriority - computes priority for jobs
+ - getWorkersPriority - computes priority for workers
+ - randomizeJobs, randomizeWorkers - add some random component to priorities
+The higher priority, the sooner is job (resp. worker) assigned.
+
+Algorithm then works as follows:
+ call getJobsPriority and order jobs
+ solveGreedy(problem of size n):
+ findNextJob
+ order workers
+ foreach worker:
+ assign worker to job
+ recursion of problem os size (n-1)
+ (if recursion failed, continue by trying another worker)
25 c/all.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+clear
+g++ -O2 -pthread -o main main.c || exit
+
+for ds in 1 2 3 4 5 6 7 8 9 10 11 12; do
+ for job in constant order order-r price-diff; do
+ for worker in constant order order-r free-capacity price; do
+ for jr in - linear; do
+ for wr in - linear; do
+ echo "$ds $job $worker $jr $wr"
+ ./main $job $worker $jr $wr sets/gap$ds.txt
+ echo "------------"
+ done
+ done
+ done
+ done
+
+ # random
+ #for i in `seq 10`; do
+ echo "$ds - - rand rand"
+ ./main - - rand rand sets/gap$ds.txt
+ echo "------------"
+ # sleep 2
+ #done
+done
199 c/main.c
@@ -0,0 +1,199 @@
+/*
+* Very simple Greedy GAP solver
+* - findNextJob returns first not assigned job
+* - findWorkersForJob orders workers by free capacity (max free capacity goes first)
+*/
+#include "main.h"
+
+
+/**
+* Worker order functions
+*/
+
+// Give all workers same priority
+char _gw_constant(Problem *p, int j, int workers[]) {
+ for(int w = 0; w < p->wc; w++) workers[w] = 1;
+}
+
+// Worker priority as it's number
+char _gw_order(Problem *p, int j, int workers[]) {
+ for(int w = 0; w < p->wc; w++) workers[w] = p->wc - w;
+}
+
+// Worker priority as reverse order number
+char _gw_orderr(Problem *p, int j, int workers[]) {
+ for(int w = 0; w < p->wc; w++) workers[w] = w;
+}
+
+// Workers have priority same as free capacity
+char _gw_freeCapacity(Problem *p, int j, int workers[]) {
+ for(int w = 0; w < p->wc; w++) workers[w] = p->capacityFree[w];
+}
+
+// Workers priority by price of assigning job
+char _gw_price(Problem *p, int j, int workers[]) {
+ int priceMax = 0;
+
+ for(int w = 0; w < p->wc; w++) {
+ int space = getSpace(p, w, j); // Space required
+ if(p->capacityFree[w] < space) {
+ workers[w] = -1; // Worker is full
+ }
+ else {
+ int price = getPrice(p, w, j);
+ if(price > priceMax) priceMax = price; // Store maximal price
+ workers[w] = price;
+ }
+ }
+
+ // Revert high prices to small priorities
+ for(int w = 0; w < p->wc; w++) {
+ if(workers[w] > 0) workers[w] = priceMax - workers[w];
+ }
+}
+
+
+
+
+/**
+* Job order functions
+*/
+
+// Job priority is constant
+char _gj_constant(struct Problem *p, int jobs[]) {
+ for(int j = 0; j < p->jc; j++) jobs[j] = 1;
+}
+
+// Job priority by order
+char _gj_order(struct Problem *p, int jobs[]) {
+ for(int j = 0; j < p->jc; j++) jobs[j] = p->jc - j;
+}
+
+// Job priority reverse order
+char _gj_orderr(struct Problem *p, int jobs[]) {
+ for(int j = 0; j < p->jc; j++) jobs[j] = j;
+}
+
+// Job priority highest with biggest difference between max- and min-price
+char _gj_pricediff(struct Problem *p, int jobs[]) {
+ int diff, min = -1, max = -1;
+
+ for(int j = 0; j < p->jc; j++) {
+ // Find min and max price
+ for(int w = 0; w < p->wc; w++) {
+ int c = getPrice(p, w, j);
+ if(c > max) max = c;
+ if(c < min || min == -1) min = c;
+ }
+
+ // Difference
+ diff = max - min;
+ jobs[j] = diff;
+ }
+}
+
+
+
+
+
+
+
+// Callback list: Get worker priority
+const GetWorkersPriorityEntry getWorkersPriorityCallbacks[] = {
+ { "constant", _gw_constant },
+ { "order", _gw_order },
+ { "order-r", _gw_orderr },
+ { "free-capacity", _gw_freeCapacity },
+ { "price", _gw_price },
+ { NULL, NULL },
+};
+
+// Callback list: Get jobs priority
+const GetJobsPriorityEntry getJobPriorityCallbacks[] = {
+ { "constant", _gj_constant },
+ { "order", _gj_order },
+ { "order-r", _gj_orderr },
+ { "price-diff", _gj_pricediff },
+ { NULL, NULL },
+};
+
+// Callback list: Randomizers
+const RandomizerEntry randomizerCallbacks[] = {
+ { "rand", randomizeTotal},
+ { "linear", randomizeLinear },
+ { "add", randomizeAdd},
+ { NULL, NULL },
+};
+
+GetJobsPriority getJobsPriorityCallback(char *name) {
+ // Find callbacks
+ const GetJobsPriorityEntry *cb = getJobPriorityCallbacks;
+
+ for(; cb && cb->name; ++cb) if(!strcmp(cb->name, name)) return cb->cb;
+ return NULL;
+}
+
+GetWorkersPriority getWorkersPriorityCallback(char *name) {
+ // Find callbacks
+ const GetWorkersPriorityEntry *cb = getWorkersPriorityCallbacks;
+
+ for(; cb && cb->name; ++cb) if(!strcmp(cb->name, name)) return cb->cb;
+ return NULL;
+}
+
+Randomizer getRandomizerCallback(char *name) {
+ // Find callbacks
+ const RandomizerEntry *cb = randomizerCallbacks;
+
+ for(; cb && cb->name; ++cb) if(!strcmp(cb->name, name)) return cb->cb;
+ return NULL;
+}
+
+#define DUMP_LIST(TEntry, List) {\
+ const TEntry *cb = List;\
+ for(; cb && cb->name; ++cb) printf("%s ", cb->name);\
+ printf("\n");\
+}
+
+void usage(char *file) {
+ printf("Usage: %s jobs workers job-randomizer worker-randomizer dataset [set-index]\n", file);
+
+ // Dump Job order cb's
+ printf(" Job order funcions: "); DUMP_LIST(GetJobsPriorityEntry, getJobPriorityCallbacks);
+ printf(" Worker order funcions: "); DUMP_LIST(GetWorkersPriorityEntry, getWorkersPriorityCallbacks);
+ printf(" Randomizers: "); DUMP_LIST(RandomizerEntry, randomizerCallbacks);
+ printf("\n");
+
+ printf("Sample: %s order order - - sets/gap1.txt 0 # priorize jobs and workers by it's order, no randomize, dataset gap1.txt, first problem\n", file);
+ printf("Sample: %s price-diff free-capacity linear linear sets/gap1.txt 0 # heuristics for jobs and workers, peckish\n", file);
+ printf("Sample: %s - - rand rand sets/gap1.txt 0 # no heuristics for jobs and workers, totally random\n", file);
+ printf("\n");
+
+ printf("Environment variables:\n DEBUG=1 - print debug informations\n SIMPLE=1 - print just problem number, price, used space and time in miliseconds\n");
+ printf(" Sample: SIMPLE=1 %s order order - - sets/gap1.txt 0\n", file);
+
+ printf("\n");
+ exit(1);
+}
+
+
+// Main function
+int main(int argc, char**argv) {
+ // Find callbacks
+ const GetJobsPriorityEntry *cb = getJobPriorityCallbacks;
+
+ if(argc < 5) usage(argv[0]);
+
+ // Create solver
+ Solver solver;
+ solver.findJobMethod = Priority;
+ solver.getJobsPriority = getJobsPriorityCallback(argv[1]);
+ solver.getWorkersPriority = getWorkersPriorityCallback(argv[2]);
+ solver.randomizeJobs = getRandomizerCallback(argv[3]);
+ solver.randomizeWorkers = getRandomizerCallback(argv[4]);
+
+ //printf("%u %u %u %u\n", solver.getJobsPriority, solver.getWorkersPriority, solver.randomizeJobs, solver.randomizeWorkers);
+
+ // Run program
+ return main_(&solver, argc - 4, argv + 4);
+}
537 c/main.h
@@ -0,0 +1,537 @@
+/*
+* Greedy GAP solver
+*
+* This file is not much like C++ header file look like, but it's made for simplicity.
+* Here are defines basic functions for several Greedy GAP solvers invoked from other files
+*
+* You can use functions:
+* - loadData(char* file) - loads set of problems from text file defined in PA184
+* - dumpProblem(Problem *p) - dump problem definition for users
+* - dumpProblem2(Problem *p) - dump problem definition in loadData() format
+* - dumpResult(Problem *p) - dump results of solved problem
+* - solveGreedy(Problem *p) - tries to solve the problem
+* - solveGreedyAndDump(...) - try to solve problem and dump results
+* - main_(...) - run program with given solver
+*
+* Check main.c for example solver solution.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#define DIE(x) { printf("%s\n", x); exit(1); }
+#define ROTATE(x) (x) = (x)
+#define microtime ((int)((clock())*1E3/CLOCKS_PER_SEC))
+
+char debug = 0; // Show debug info
+char simple = 0; // Simple output
+char quit = 0; // Quitting
+
+struct Problem;
+struct Solver;
+struct WorkerWithProblem;
+struct JobWithProblem;
+
+enum FindJobMethod {
+ Callback = 1,
+ Priority = 2,
+};
+
+typedef char (* GetJobsPriority)(struct Problem *p, int jobs[]);
+typedef char (* GetWorkersPriority)(struct Problem *p, int job, int workers[]); // Callback to order jobs
+typedef char (* Randomizer)(struct Problem *p, int num, int items[]);
+typedef int (* FindNextJob)(struct Problem *p);
+
+// Solver info -> defines solver callbacks
+struct Solver {
+ enum FindJobMethod findJobMethod; // What method is used to find job
+ FindNextJob findNextJob;
+ GetJobsPriority getJobsPriority; // Callback to order jobs
+ GetWorkersPriority getWorkersPriority;
+ Randomizer randomizeJobs;
+ Randomizer randomizeWorkers;
+};
+
+struct GetJobsPriorityEntry {
+ char *name;
+ GetJobsPriority cb;
+};
+
+struct GetWorkersPriorityEntry {
+ char *name;
+ GetWorkersPriority cb;
+};
+
+struct RandomizerEntry {
+ char *name;
+ Randomizer cb;
+};
+
+struct Problem {
+ // Settings
+ int index;
+ int wc;
+ int jc;
+ int *price;
+ int *space;
+ int *capacity;
+
+ // Calculations
+ int *assignments; // Assignment job to worker
+ int *capacityFree; // Free capacity for each worker
+
+ // Solver
+ struct Solver *solver;
+ int actualJob;
+ void *solverData; // Any kind of data solver would like to associate with this problem
+ JobWithProblem *jobList;
+ char solved;
+
+};
+
+// Touple of worker and associated problem (used for sorting, because qsort not accepts scope parameter)
+struct WorkerWithProblem{
+ Problem *problem;
+ int worker;
+ long int priority;
+};
+
+// Touple of job and associated problem (used for sorting, because qsort not accepts scope parameter)
+struct JobWithProblem{
+ Problem *problem;
+ int job;
+ long int priority;
+};
+
+
+// Get price for worker and job
+inline int getPrice(Problem *problem, int w, int j) {
+ return (w >= problem->wc || j >= problem->jc) ? -1 : problem->price[w * problem->jc + j];
+}
+
+// Get space for worker and job
+inline int getSpace(Problem *problem, int w, int j) {
+ return (w >= problem->wc || j >= problem->jc) ? -1 : problem->space[w * problem->jc + j];
+}
+
+// Get capacity for worker
+inline int getCapacity(Problem *problem, int w) {
+ return (w >= problem->wc) ? -1 : problem->capacity[w];
+}
+
+// Create new problem data space
+Problem *createProblem(int wc, int jc) {
+ Problem *problem = (Problem *) malloc(sizeof(Problem));
+ problem->wc = wc;
+ problem->jc = jc;
+
+ problem->price = (int *) malloc(sizeof(int) * wc * jc);
+ problem->space = (int *) malloc(sizeof(int) * wc * jc);
+ problem->capacity = (int *) malloc(sizeof(int) * wc);
+ problem->assignments = (int *) malloc(sizeof(int) * jc);
+ problem->capacityFree = (int *) malloc(sizeof(int) * wc);
+ memset(problem->assignments, -1, sizeof(int) * jc); // Clear assignments
+
+ problem->solved = 0;
+
+ return problem;
+}
+
+// Deallocate
+void removeProblem(Problem *problem) {
+ free(problem->price);
+ free(problem->space);
+ free(problem->capacity);
+ free(problem->assignments);
+ free(problem->capacityFree);
+ free(problem);
+}
+
+// Load data from file
+Problem** loadData(char *file) {
+ FILE *fp = fopen(file, "r");
+ if(!fp) DIE("Unable to open file");
+
+ int numSets = 0;
+ if(fscanf(fp, "%d", &numSets) != 1 || numSets < 1) DIE("Wrong data set number");
+
+ // Allocate problem list
+ Problem **problems = (Problem**) malloc(sizeof(Problem *) * (numSets + 1)); // List of pointers to Problem
+ problems[numSets] = 0;
+
+ for(int i = 0; i < numSets; i++) {
+ int wc, jc, *p;
+ if(fscanf(fp, "%d %d", &wc, &jc) != 2) DIE("Wrong data: wc/jc");
+
+ if(debug) printf("Loading data set %d\n", i);
+
+ // Allocate space
+ problems[i] = createProblem(wc, jc);
+ problems[i]->index = i;
+
+ // Load prices
+ p = problems[i]->price;
+ for(int w = 0; w < wc; w++) {
+ for(int j = 0; j < jc; j++) {
+ fscanf(fp, "%d", p);
+ ROTATE(*p);
+ p++;
+ }
+ }
+
+ // Load spaces
+ p = problems[i]->space;
+ for(int w = 0; w < wc; w++) {
+ for(int j = 0; j < jc; j++) {
+ fscanf(fp, "%d", p);
+ p++;
+ }
+ }
+
+ // Load capacities
+ p = problems[i]->capacity;
+ for(int w = 0; w < wc; w++) {
+ fscanf(fp, "%d", p);
+ p++;
+ }
+ }
+
+ return problems;
+}
+
+// Dump problem
+void dumpProblem(Problem *problem) {
+ printf("Workers: %d, jobs: %d\n", problem->wc, problem->jc);
+
+ printf("Prices:\n");
+ for(int w = 0; w < problem->wc; w++) {
+ printf("W%3d: ", w + 1);
+ for(int j = 0; j < problem->jc; j++) printf("%4d", getPrice(problem, w, j));
+ printf("\n");
+ }
+
+ printf("Spaces:\n");
+ for(int w = 0; w < problem->wc; w++) {
+ printf("W%3d: ", w + 1);
+ for(int j = 0; j < problem->jc; j++) printf("%4d", getSpace(problem, w, j));
+ printf("\n");
+ }
+
+ printf("Capacities:\n");
+ for(int w = 0; w < problem->wc; w++) {
+ printf("W%3d: %d\n", w + 1, problem->capacity[w]);
+ }
+}
+
+// Dump problem
+void dumpProblem2(Problem *problem) {
+ printf("%d %d\n", problem->wc, problem->jc);
+ for(int w = 0; w < problem->wc; w++) {
+ for(int j = 0; j < problem->jc; j++) printf("%4d", getPrice(problem, w, j));
+ printf("\n");
+ }
+
+ for(int w = 0; w < problem->wc; w++) {
+ for(int j = 0; j < problem->jc; j++) printf("%4d", getSpace(problem, w, j));
+ printf("\n");
+ }
+
+ for(int w = 0; w < problem->wc; w++) {
+ printf("%4d", problem->capacity[w]);
+ }
+
+ printf("\n\n");
+}
+
+// Dump result of a problem
+void dumpResult(Problem *problem) {
+ int w, j, p, s;
+ int price = 0, space = 0; // Used price and space
+
+ printf("Assignments:\n");
+ for(j = 0; j < problem->jc; j++) {
+ w = problem->assignments[j];
+ printf("Job %3d: worker %3d (price %4d, space %3d)\n", j + 1, w + 1, p = getPrice(problem, w, j), s = getSpace(problem, w, j));
+ price += p; space += s;
+ }
+
+ printf("Capacities:\n");
+ for(int w = 0; w < problem->wc; w++) {
+ printf("W%3d: total %4d, free %4d\n", w + 1, problem->capacity[w], problem->capacityFree[w]);
+ }
+
+ printf("Price: %d, used space: %d\n", price, space);
+}
+
+// Get price of solution
+int getProblemPrice(Problem *problem, int *retSpace) {
+ int w, j, p, s;
+ int price = 0, space = 0; // Used price and space
+
+ for(j = 0; j < problem->jc; j++) {
+ w = problem->assignments[j];
+ price += getPrice(problem, w, j); space += getSpace(problem, w, j);
+ }
+
+ if(retSpace) *retSpace = space;
+ return price;
+}
+
+// Find next job by priority
+int findNextJobByPriority(Problem *p) {
+ for(int ji = 0; ji < p->jc; ji++) {
+ int j = p->jobList[ji].job;
+ if(p->assignments[j] == -1) return j;
+ }
+
+ return -1;
+}
+
+// Compare two workers
+int compareWorkersByPriority(const void *a, const void *b) {
+ WorkerWithProblem *A = (WorkerWithProblem*) a, *B = (WorkerWithProblem *) b;
+ return (B->priority - A->priority);
+}
+
+// Compare two jobs
+int compareJobsByPriority(const void *a, const void *b) {
+ JobWithProblem *A = (JobWithProblem*) a, *B = (JobWithProblem *) b;
+ return (B->priority - A->priority);
+}
+
+
+// Greedy solver
+// return negative value if failed, positive if sucessful
+char solveGreedy_(Problem *p, int jr) {
+ if(quit) return 0;
+
+ // Find what job we would solve
+ int j = p->solver->findNextJob(p);
+ if(j < 0 || j >= p->jc) throw "INVALID JOB ID";
+ if(debug) printf("[%d] will assign job %d\n", p->jc - jr, j);
+
+ // Get workers priority
+ int workerList_[p->wc];
+ if(p->solver->getWorkersPriority) {
+ if(!p->solver->getWorkersPriority(p, j, workerList_)) {
+ if(debug) printf("[%d] no workers available\n", p->jc - jr);
+ return -1;
+ }
+ }
+
+ // Randomizer
+ if(p->solver->randomizeWorkers) p->solver->randomizeWorkers(p, p->wc, workerList_);
+
+ // Order workers
+ int wc = 0;
+ WorkerWithProblem workerList[p->wc];
+ for(int i = 0; i < p->wc; i++) {
+ if(workerList_[i] <= 0) continue;
+
+ workerList[wc].problem = p;
+ workerList[wc].worker = i;
+ workerList[wc].priority = workerList_[i];
+ wc++;
+ }
+
+ // Sort workers
+ qsort(workerList, wc, sizeof(WorkerWithProblem), compareWorkersByPriority);
+
+ if(debug) {
+ printf("[%d] workers ordered: ", p->jc - jr);
+ for(int wi = 0; wi < wc; wi++) {
+ int w = workerList[wi].worker; // Get worker ID
+ printf("%d (%d)\t", w, workerList[wi].priority);
+ }
+ printf("\n");
+ }
+
+ // Try workers
+ for(int wi = 0; wi < wc; wi++) {
+ int w = workerList[wi].worker; // Get worker ID
+ int s = getSpace(p, w, j); // Space required
+
+ if(p->capacityFree[w] < s) continue; // Not possible -> continue with another worker
+
+ // Try to assign this job
+ if(debug) printf("[%d] assigning %d to %d with price %d and space %d\n", p->jc - jr, j, w, s, getPrice(p, w, j));
+ p->assignments[j] = w;
+ p->capacityFree[w] -= s;
+
+ // Recursion
+ if(jr <= 1 || solveGreedy_(p, jr - 1) > 0) return 1;
+
+ // Deassign
+ p->assignments[j] = -1;
+ p->capacityFree[w] += s;
+ }
+
+ if(debug) printf("bt \n");
+ return -1;
+}
+
+// Slove problem using greedy algorithm, return price
+// returns 1 is OK, 0 if notfound
+int solveGreedy(Problem *p) {
+ // Clear assignments
+ memset(p->assignments, -1, sizeof(int) * p->jc);
+ memcpy(p->capacityFree, p->capacity, sizeof(int) * p->wc);
+
+ // Prepare priority queue of jobs
+ if(p->solver->findJobMethod == Priority) {
+ int jobList[p->jc];
+ if(p->solver->getJobsPriority) p->solver->getJobsPriority(p, jobList);
+
+ // Randomizer
+ if(p->solver->randomizeJobs) p->solver->randomizeJobs(p, p->jc, jobList);
+
+ // Generate touple list
+ JobWithProblem jobList2[p->jc];
+ for(int i = 0; i < p->jc; i++) {
+ jobList2[i].problem = p;
+ jobList2[i].job = i;
+ jobList2[i].priority = jobList[i];
+ }
+
+ // Order jobs
+ qsort(jobList2, p->jc, sizeof(JobWithProblem), compareJobsByPriority);
+
+ p->jobList = jobList2;
+ p->solver->findNextJob = &findNextJobByPriority;
+
+ return (solveGreedy_(p, p->jc) > 0) ? 1 : 0;
+ }
+
+ // Get next job using callback
+ else {
+ return (solveGreedy_(p, p->jc) > 0) ? 1 : 0;
+ }
+}
+
+// Solve problem and dump result
+// return nonzero if successful
+char solveGreedyAndDump(Solver *s, Problem *p) {
+ if(!simple) dumpProblem(p);
+
+ // Assign solver
+ p->solver = s;
+
+ // Solve first problem
+ try {
+ int tstart = microtime;
+ char found = solveGreedy(p);
+ int tend = microtime, tduration = tend - tstart;
+ if(found) {
+ if(simple) {
+ int space, price = getProblemPrice(p, &space);
+ printf("%d\t%d\t%d\t%d\n", p->index, price, space, tduration);
+ }
+ else {
+ printf("Solution found\n");
+ dumpResult(p);
+ }
+ }
+ else {
+ if(simple) printf("-\n");
+ else printf("Solution not found\n");
+ }
+ p->solved = 1;
+ return found;
+ }
+ catch(char *err) {
+ printf("Exception: %s\n", err);
+ p->solved = 2;
+ return 0;
+ }
+}
+
+void *solveGreedyAndDump_(void *p_) {
+ Problem *p = (Problem *) p_;
+ if(!simple) printf("Solving problem %d\n", p->index);
+ solveGreedyAndDump(p->solver, p);
+}
+
+
+// Usual main function with given solver
+int main_(Solver *solver, int argc, char**argv) {
+ if(argc < 2) DIE("Enter input file name");
+ char *file = argv[1];
+ srand(time(NULL));
+
+ // Load data
+ Problem **problems = loadData(file);
+ Problem *p = problems[0];
+
+ char *deb = getenv("DEBUG");
+ char *simple_ = getenv("SIMPLE");
+ if(deb) debug = atol(deb);
+ if(simple_) simple = atol(simple_);
+
+
+ // Print out the source
+ //dumpProblem2(p);
+
+ // Print out source info
+ //dumpProblem(p);
+
+ // Just one problem
+ if(argc == 3) {
+ int pi = atol(argv[2]);
+ solveGreedyAndDump(solver, problems[pi]);
+ }
+
+ // All problems
+ else {
+ int cnt = 0; // Count problems
+ for(; problems[cnt] != NULL; cnt++);
+
+ pthread_t threads[cnt];
+ for(int i = 0; i < cnt; i++) {
+ problems[i]->solver = solver;
+ pthread_create(&threads[i], NULL, solveGreedyAndDump_, problems[i]);
+ }
+
+ // Wait for all threads
+ int tlimit = time(NULL) + 600;
+ while(time(NULL) < tlimit) {
+ int numSolved = 0;
+ for(int i = 0; i < cnt; i++) if(problems[i]->solved) numSolved++;
+
+ if(numSolved == cnt) break;
+ else {
+ //printf("sleeping\n");
+ usleep(10000);
+ }
+ }
+
+ printf("# all solved\n");
+
+ // Join threads
+ quit = 1;
+ for(int i = 0; i < cnt; i++) {
+ pthread_join(threads[i], NULL);
+ }
+ }
+
+ // Deallocate data sets
+ for(int i = 0; problems[i] != NULL; i++) removeProblem(problems[i]);
+ free(problems);
+
+ return 0;
+}
+
+// Linear randomize
+char randomizeLinear(struct Problem *p, int num, int items[]) {
+ for(int i = 0; i < num; i++) items[i] *= (rand() % 100);
+}
+
+char randomizeTotal(struct Problem *p, int num, int items[]) {
+ for(int i = 0; i < num; i++) items[i] = (rand() % 100);
+}
+
+char randomizeAdd(struct Problem *p, int num, int items[]) {
+ for(int i = 0; i < num; i++) items[i] += (rand() % 100);
+}
2 c/run.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+clear;g++ -ggdb3 -o $1 $1.c && ./$1 sets/gap1.txt $2
1 c/sets
2 c/test.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+clear;g++ -pthread -ggdb3 -o $1 $1.c && valgrind --leak-check=full ./$1 constant constant - - sets/gap8.txt
188 python/constructive_heuristics.py
@@ -0,0 +1,188 @@
+#!/usr/bin/env python
+
+import random
+from heapq import heappush, heappop
+
+# Select random job, select first fitting worker
+# Instead of backtracking, release random job
+def constructive_random_heuristic( w_price, w_space, w_capacity ):
+ available_jobs = set( range(len(w_price[0])))
+ wc = len(w_capacity)
+ available_capacity = w_capacity[:] # copy list
+ solution = {}
+
+ safe_count = 0
+ # until all jobs are assigned
+ while len(available_jobs)>0:
+ safe_count += 1
+ if safe_count>10000:
+ print "no solution avaible in 10000 steps."
+ break
+ """ select job """
+ jc = len(available_jobs)
+ # random selection
+ select_job = list(available_jobs)[ random.randint(0, jc-1) ]
+ # job isnt avaible anymore
+ available_jobs.remove( select_job )
+ """ select worker """
+ # feasable workers
+ candidates = []
+ for worker in range(wc):
+ if available_capacity[ worker ] >= w_space[ worker ][ select_job ]:
+ candidates.append(worker)
+ # select random worker if available
+ if len(candidates)>0:
+ select_worker = candidates[random.randint(0, len(candidates)-1 )]
+ # udpate available capacity
+ available_capacity[ select_worker ] -= w_space[ select_worker ][ select_job ]
+ # save solution
+ solution[ select_job ] = select_worker
+ else:
+ # otherwise clear selection
+ available_jobs.add( select_job )
+ # because the job cant be assigned, we release another job from the worker
+ # select random assigned job
+ remove = solution.keys()[ random.randint(
+ 0, len( solution.keys() )-1
+ )]
+ # free worker capacity
+ worker_inc = solution[remove]
+ available_capacity[worker_inc] += w_space[ worker_inc ][ remove ]
+ del solution[remove]
+ # make job available
+ available_jobs.add( remove )
+
+
+
+ return solution
+
+
+" NOT IMPLEMENTED "
+def constructive_peckish_heuristic_r( w_price, w_space, w_capacity, criteria ):
+ available_jobs = set( range(len(w_price[0])))
+ w_id = range( len(w_capacity) )
+ available_capacity = w_capacity[:] # copy list
+ solution = {}
+ return count_greedy(
+ w_price, w_space, available_jobs, available_capacity, solution, w_id,
+ criteria, True
+ )
+
+"""
+while we have unassigned jobs:
+ Select job by criteria
+ (for example biggest difference between min and max available assertion).
+ Assign job to the cheapest available worker.
+ If there is no available worker nor job, backtrack to the last assigment and
+ select next optimal assignment.
+
+style:
+ if criteria == "maxdif":
+ criteria_val = -(max-min)
+ if criteria == "mindif":
+ criteria_val = -(min-max)
+ if criteria == "maxmax":
+ criteria_val = -(max)
+ if criteria == "minmax":
+ criteria_val = (max)
+ if criteria == "minmin":
+ criteria_val = (min)
+ if criteria == "maxmin":
+ criteria_val = -(min)
+ if criteria == "minavg":
+ criteria_val = -(max+min)/2
+"""
+def constructive_greedy_heuristic_r( w_price, w_space, w_capacity, criteria ):
+ available_jobs = set( range(len(w_price[0])))
+ w_id = range( len(w_capacity) )
+ available_capacity = w_capacity[:] # copy list
+ solution = {}
+ return count_greedy(
+ w_price, w_space, available_jobs, available_capacity, solution, w_id, criteria
+ )
+
+# recursive function
+# select best job
+# assign worker
+# call recursively
+# backtrack if call return None
+# ++ peckish: give some randomness
+def count_greedy(
+ w_price, w_space, available_jobs, available_capacity, solution, w_id,
+ criteria, peckish=False
+ ):
+
+ if len(available_jobs) == 0:
+ return solution
+
+ # job to be processed
+ selected_job = None
+ if peckish and len(available_jobs)>0:
+ # peckish select random job
+ selected_job = list(available_jobs)[ random.randint(0, len(available_jobs)-1) ]
+ else:
+ # greedy, select best job
+ selected_job = select_best_job(
+ w_price, w_space, available_jobs, available_capacity, w_id, criteria
+ )
+
+ if selected_job == None:
+ return None
+
+ w_order = []
+
+ for worker_id in w_id:
+ if available_capacity[worker_id] >= w_space[worker_id][selected_job]:
+ heappush( w_order, (w_price[worker_id][selected_job], worker_id))
+ while len(w_order) > 0:
+ worker_id = heappop( w_order )[1]
+
+ solution[selected_job] = worker_id
+ available_capacity[worker_id] -= w_space[worker_id][selected_job]
+ available_jobs.remove(selected_job)
+ new_solution = count_greedy(
+ w_price, w_space, available_jobs, available_capacity,
+ solution, w_id, criteria, peckish
+ )
+
+ if new_solution != None:
+ return new_solution
+ else:
+ del solution[selected_job]
+ available_jobs.add(selected_job)
+ available_capacity[worker_id] += w_space[worker_id][selected_job]
+ return None
+
+def select_best_job( w_price, w_space, available_jobs, available_capacity, w_id, criteria ):
+ jobs = []
+ for job_id in available_jobs:
+ min = 32000
+ max = -1
+ for worker_id in w_id:
+ if available_capacity[worker_id] > w_space[worker_id][job_id]:
+ price = w_price[worker_id][job_id]
+ if price < min:
+ min = price
+ if price > max:
+ max = price
+
+ if max > -1:
+ if criteria == "maxdif":
+ criteria_val = -(max-min)
+ if criteria == "mindif":
+ criteria_val = -(min-max)
+ if criteria == "maxmax":
+ criteria_val = -(max)
+ if criteria == "minmax":
+ criteria_val = (max)
+ if criteria == "minmin":
+ criteria_val = (min)
+ if criteria == "maxmin":
+ criteria_val = -(min)
+ if criteria == "minavg":
+ criteria_val = -(max+min)/2
+ heappush( jobs, (criteria_val, job_id) )
+ if len( jobs ) == 0:
+ return None
+ # maximum difference
+ return heappop( jobs )[1]
8 python/doc/doc.aux
@@ -0,0 +1,8 @@
+\relax
+\select@language{english}
+\@writefile{toc}{\select@language{english}}
+\@writefile{lof}{\select@language{english}}
+\@writefile{lot}{\select@language{english}}
+\@writefile{toc}{\contentsline {section}{\numberline {1}Requirements}{1}}
+\@writefile{toc}{\contentsline {section}{\numberline {2}Usage}{1}}
+\@writefile{toc}{\contentsline {section}{\numberline {3}Structure}{3}}
104 python/doc/doc.log
@@ -0,0 +1,104 @@
+This is pdfTeXk, Version 3.1415926-1.40.9 (Web2C 7.5.7) (format=pdflatex 2009.8.1) 4 JUN 2010 14:18
+entering extended mode
+ %&-line parsing enabled.
+**doc
+(./doc.tex
+LaTeX2e <2005/12/01>
+Babel <v3.8l> and hyphenation patterns for english, usenglishmax, dumylang, noh
+yphenation, german-x-2008-06-18, ngerman-x-2008-06-18, ancientgreek, ibycus, ar
+abic, basque, bulgarian, catalan, pinyin, coptic, croatian, czech, danish, dutc
+h, esperanto, estonian, farsi, finnish, french, galician, german, ngerman, mono
+greek, greek, hungarian, icelandic, indonesian, interlingua, irish, italian, la
+tin, lithuanian, mongolian, mongolian2a, bokmal, nynorsk, polish, portuguese, r
+omanian, russian, sanskrit, serbian, slovak, slovenian, spanish, swedish, turki
+sh, ukenglish, ukrainian, uppersorbian, welsh, loaded.
+(c:/Programy/texlive/2008/texmf-dist/tex/latex/base/article.cls
+Document Class: article 2005/09/16 v1.4f Standard LaTeX document class
+(c:/Programy/texlive/2008/texmf-dist/tex/latex/base/size10.clo
+File: size10.clo 2005/09/16 v1.4f Standard LaTeX file (size option)
+)
+\c@part=\count79
+\c@section=\count80
+\c@subsection=\count81
+\c@subsubsection=\count82
+\c@paragraph=\count83
+\c@subparagraph=\count84
+\c@figure=\count85
+\c@table=\count86
+\abovecaptionskip=\skip41
+\belowcaptionskip=\skip42
+\bibindent=\dimen102
+)
+(c:/Programy/texlive/2008/texmf-dist/tex/generic/babel/babel.sty
+Package: babel 2008/07/06 v3.8l The Babel package
+
+(c:/Programy/texlive/2008/texmf-dist/tex/generic/babel/english.ldf
+Language: english 2005/03/30 v3.3o English support from the babel system
+
+(c:/Programy/texlive/2008/texmf-dist/tex/generic/babel/babel.def
+File: babel.def 2008/07/06 v3.8l Babel common definitions
+\babel@savecnt=\count87
+\U@D=\dimen103
+)
+\l@canadian = a dialect from \language\l@american
+\l@australian = a dialect from \language\l@british
+\l@newzealand = a dialect from \language\l@british
+)) (./doc.aux)
+\openout1 = `doc.aux'.
+
+LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 5.
+LaTeX Font Info: ... okay on input line 5.
+LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 5.
+LaTeX Font Info: ... okay on input line 5.
+LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 5.
+LaTeX Font Info: ... okay on input line 5.
+LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 5.
+LaTeX Font Info: ... okay on input line 5.
+LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 5.
+LaTeX Font Info: ... okay on input line 5.
+LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 5.
+LaTeX Font Info: ... okay on input line 5.
+LaTeX Font Info: External font `cmex10' loaded for size
+(Font) <12> on input line 6.
+LaTeX Font Info: External font `cmex10' loaded for size
+(Font) <8> on input line 6.
+LaTeX Font Info: External font `cmex10' loaded for size
+(Font) <6> on input line 6.
+
+LaTeX Warning: No \author given.
+
+LaTeX Font Info: Try loading font information for OMS+cmr on input line 20.
+(c:/Programy/texlive/2008/texmf-dist/tex/latex/base/omscmr.fd
+File: omscmr.fd 1999/05/25 v2.5h Standard LaTeX font definitions
+)
+LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available
+(Font) Font shape `OMS/cmsy/m/n' tried instead on input line 20.
+ [1
+
+{c:/Programy/texlive/2008/texmf-var/fonts/map/pdftex/updmap/pdftex.map}]
+LaTeX Font Info: External font `cmex10' loaded for size
+(Font) <7> on input line 76.
+LaTeX Font Info: External font `cmex10' loaded for size
+(Font) <5> on input line 76.
+ [2] [3] (./doc.aux) )
+Here is how much of TeX's memory you used:
+ 558 strings out of 493876
+ 6476 string characters out of 1150232
+ 61071 words of memory out of 3000000
+ 3892 multiletter control sequences out of 10000+50000
+ 7756 words of font info for 28 fonts, out of 3000000 for 5000
+ 714 hyphenation exceptions out of 8191
+ 24i,6n,19p,181b,211s stack positions out of 5000i,500n,10000p,200000b,50000s
+<c:/Programy/texlive/2008/texmf-dist/fonts/type1/bluesky/
+cm/cmbx10.pfb><c:/Programy/texlive/2008/texmf-dist/fonts/type1/bluesky/cm/cmbx1
+2.pfb><c:/Programy/texlive/2008/texmf-dist/fonts/type1/bluesky/cm/cmr10.pfb><c:
+/Programy/texlive/2008/texmf-dist/fonts/type1/bluesky/cm/cmr12.pfb><c:/Programy
+/texlive/2008/texmf-dist/fonts/type1/bluesky/cm/cmr17.pfb><c:/Programy/texlive/
+2008/texmf-dist/fonts/type1/bluesky/cm/cmsy10.pfb><c:/Programy/texlive/2008/tex
+mf-dist/fonts/type1/bluesky/cm/cmtt10.pfb>
+Output written on doc.pdf (3 pages, 41519 bytes).
+PDF statistics:
+ 40 PDF objects out of 1000 (max. 8388607)
+ 0 named destinations out of 1000 (max. 131072)
+ 1 words of extra memory for PDF output out of 10000 (max. 10000000)
+
BIN python/doc/doc.pdf
Binary file not shown.
82 python/doc/doc.tex
@@ -0,0 +1,82 @@
+\documentclass{article}
+\usepackage[english]{babel}
+\title{Great deluge algorithm}
+
+\begin{document}
+\maketitle
+\section{Requirements}
+The program was written and tested in Python2.5.\\
+To visualize solution you need to install {\tt{}matplotlib} and {\tt{}numpy} module.
+
+\section{Usage}
+
+To call a program type:
+\begin{verbatim}python main.py [options]\end{verbatim}
+
+Available options:
+
+\begin{itemize}
+
+\item{--action=}
+\begin{verbatim}python main.py -a=action\end{verbatim}
+Select the goal of run:
+ \begin{itemize}
+ \item{\tt{}c} All constructive heuristics.
+ \item{\tt{}cgreedy} Greedy constructive heuristic.
+ \item{\tt{}cpeckish} Peckish constructive heuristic.
+ \item{\tt{}crandom} Random constructive heuristic.
+ \item{\tt{}iterative} Iterative local search with random initialisation.
+ \item{\tt{}deluge} Great deluge with default initialisation.
+ \item{\tt{}delugeall} Run great deluge with peckish, random and greedy initialisation.
+ \item{\tt{}delugerandom} Run great deluge with random initialisation.
+ \item{\tt{}delugegreedy} Run great deluge with greedy initialisation.
+ \item{\tt{}delugepeckish} Run great deluge with peckish initialisation.
+ \end{itemize}
+
+\item{--dataset=}
+\begin{verbatim}python main.py -d=number\end{verbatim}
+Select the set from input file to be used. If you type {\tt{}-d=*}, all sets are used instead.
+
+\item{--help}
+\begin{verbatim}python main.py -h\end{verbatim}
+Print list of commands.
+
+\item{--input=}
+\begin{verbatim}python main.py -i=path\end{verbatim}
+Path to input file. Default path is 'sets/gap1.txt'.
+
+\item{--solution}
+\begin{verbatim}python main.py -s\end{verbatim}
+Print solution as table job:worker.
+
+\item{--visualize}
+\begin{verbatim}python main.py -v\end{verbatim}
+Visualize solution.\\
+Required modules: numpy, matplotlib
+
+\item{--time}
+\begin{verbatim}python main.py -t\end{verbatim}
+Print time marks (start and end of run).
+
+\item{--beautyoff}
+\begin{verbatim}python main.py -b\end{verbatim}
+Strip some decorative texts.
+
+\end{itemize}
+
+Examples:
+\begin{verbatim}
+python main.py -i="sets/gap9.txt" -s -t -d=* -a=delugerandom
+python main.py -i="sets/gap9.txt" -t -v -a=delugerandom
+\end{verbatim}
+
+\section{Structure}
+\begin{itemize}
+ \item{main.py} Call other programmes and mark time.
+ \item{local$\_{}$search.py} Implement great deluge and iterative search.
+ \item{constructive$\_{}$heuristics.py} Implement constructive heuristics.
+ \item{visualisation.py} Implement generating of 3d image using matplotlib and numpy.
+ \item{process$\_{}$data.py} Load and process input.
+ \item{img} Examples of visualization. Green color means good solution, more red in RGB means worse solution.
+\end{itemize}
+\end{document}
BIN python/img/c-set1a.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN python/img/c-set1b.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN python/img/c-set1c.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN python/img/c-set1d.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN python/img/deluge-set12.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN python/img/deluge-set1a.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN python/img/deluge-set1b.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
383 python/local_search.py
@@ -0,0 +1,383 @@
+#!/usr/bin/env python
+import random
+from copy import deepcopy, copy
+from math import pow as power
+from math import exp
+
+from heapq import heappush, heappop, nlargest
+
+class Frame:
+
+ PENALTY_EXP = 0
+ PENALTY_LIN = 20
+ DELTA = 0.0005
+ START_LEVEL_MULTIPLY_BEST = 2
+ AVERAGE_ERRORS = 4
+
+ # + raw solution: dictionary job:worker
+ # + w_price, w_space, w_capacity: output of load function
+ def __init__( self, raw_solution, w_price, w_space, w_capacity ):
+ self.init_solution = self.solution_format( raw_solution )
+ self.w_price = w_price
+ self.w_space = w_space
+ self.w_capacity = w_capacity
+ self.wc = len(w_capacity)
+
+
+
+ # + raw solution: dictionary job:worker
+ # @return dictionary worker:list(jobs)
+ def solution_format( self, raw_solution ):
+ solution = {}
+ for job_key in raw_solution:
+ worker_id = raw_solution[job_key]
+ if solution.has_key(worker_id):
+ solution[worker_id].append(job_key)
+ else:
+ solution[worker_id] = [job_key]
+ return solution
+
+ # + counted solution: dictionary worker:list of jobs
+ # @return dictionary job:worker
+ # Inverse to solution format function
+ def output_format( self, counted_solution ):
+ output = {}
+ for worker_id in counted_solution.keys():
+ for job_id in counted_solution[worker_id]:
+ output[job_id] = worker_id
+ return output
+
+ # level of decay
+ # + current_level float
+ # @return new level
+ # The function is based on the article
+ """
+ Non-Linear Great Deluge with Learning Mechanism for Solving
+ the Course Timetabling Problem
+ Joe H. Obit Dario Landa-Silva Djamilah Ouelhadj Marc Sevauxy
+ """
+ def _decay( self, current_level ):
+ level = current_level
+ level = level * (
+ exp(-self.DELTA * (2 + random.random()))
+ )
+ return level
+
+ # ITERATIVE SEARCH
+ # ++ max. number of iterations
+ # ++ debug True to view intern information about progress
+ def great_deluge( self, number=1600, debug = False ):
+ # init solution generated by some constructive feasable h.
+ solution = self.init_solution
+ # best_solution = deepcopy( solution )
+ # best feasable solution
+ best_solution_w_e = deepcopy( solution )
+ # best feasable/unfeasable price
+ best_price = price = self.count( solution )
+ # best only feasable price
+ best_price_w_e = price
+ # debug statistics
+ stats1 = {
+ "switch two jobs":0,
+ "switch max and random jobs":0,
+ "switch two workers":0,
+ "rearange 2-5 workers":0,
+ "rearange greedy 2-5 workers":0
+ }
+ if debug:
+ print "Begin parameters:"
+ print self.count(solution, True)
+ # level of decay
+ level = best_price *\
+ self.START_LEVEL_MULTIPLY_BEST +\
+ self.AVERAGE_ERRORS * self.PENALTY_LIN +\
+ power(self.AVERAGE_ERRORS, self.PENALTY_EXP)
+ # for number of interations or too low decay
+ for i in range(number):
+ level = self._decay( level )
+ new_price, (new_solution, source) = self.select_step(
+ self.available_steps( solution )
+ )
+ # if step is acceptable
+ if new_price < price + level:
+ price = new_price
+ solution = new_solution
+ # if step is optimal
+ if new_price < best_price:
+ # if new price doesnt have any error
+ if self.count(new_solution, True)[2] == 0:
+ best_price_w_e = min(new_price, best_price_w_e)
+ best_solution_w_e = deepcopy( solution )
+ if debug:
+ print self.count(new_solution, True), " l:", round(level), source
+ # best infeasable or feasable solution
+ stats1[source] += 1
+ best_price = min(new_price, best_price)
+ # best_solution = deepcopy( solution )
+ # finish condition
+ if level <= max(self.PENALTY_LIN, 1):
+ if debug:
+ print "level", level
+ break
+ return self.output_format( best_solution_w_e )
+
+ # ITERATIVE SEARCH
+ # ++ max. number of iterations
+ # ++ debug True to view intern information about progress
+ # ++ stop_condition_max = 10. if 10 iterations in row are worse than
+ # actual solution, break
+ def run_iteration( self, number=2000, debug = False, stop_condition_max = 10 ):
+ solution = self.init_solution
+ price = new_price = self.count( solution )
+
+ stop_condition = stop_condition_max
+
+ stats1 = {
+ "switch two jobs":0,
+ "switch max and random jobs":0,
+ "switch two workers":0,
+ "rearange 2-5 workers":0,
+ "rearange greedy 2-5 workers":0
+ }
+ if debug:
+ print self.count(solution, True), "begin"
+ min_p = price
+ for i in range(number):
+ if stop_condition < 0:
+ break
+
+ old_price = new_price
+ new_price, (new_solution, source) = self.select_step(
+ self.available_steps( solution )
+ )
+ if old_price < new_price:
+ stop_condition -= 1
+ else:
+ stop_condition = stop_condition_max
+
+ if new_price < min_p:
+ price = new_price
+ solution = new_solution
+ if new_price < min_p:
+ if debug:
+ print self.count(new_solution, True)
+ stats1[source] += 1
+ min_p = min(price, min_p)
+ store = min_p
+
+ min_p = self.count(solution)
+ if debug:
+ for key in stats1.keys():
+ print key
+ print "1:",stats1[key]
+ print "2:",stats2[key]
+ return self.output_format( new_solution )
+
+ """
+ Generate local
+ """
+ # + current solution
+ # @return list of prices and local steps [price,solution]
+ # local steps are generated randomly, because there are too many possibilities
+ def available_steps( self, solution ):
+ priced_solutions = []
+
+ # switch two workers
+ """
+ for i in range(5):
+ w1, w2 = self._select_n_workers( 2 )
+ temp = w1
+ w1 = w2
+ w2 = w1
+ new_solution = self._switch_all_jobs(w1, w2, solution)
+ price = self.count( new_solution )
+ heappush( priced_solutions, (price, (new_solution, "switch two workers") ) )
+ """
+
+ # switch two jobs
+ for i in range(5):
+ w1, w2 = self._select_n_workers( 2 )
+ j1_v = self._select_n_jobs( solution[w1], 1)
+ j2_v = self._select_n_jobs( solution[w2], 1)
+ # selected worker doesnt have any job
+ if len(j1_v)==0 or len(j2_v)==0:
+ continue
+ j1 = j1_v[0]
+ j2 = j2_v[0]
+ new_solution = self._switch_2_jobs(w1, j1, w2, j2, solution)
+ price = self.count( new_solution )
+ heappush( priced_solutions, (price, (new_solution, "switch two jobs") ) )
+
+
+ # rearange randomly x worker's jobs, x in <2,5>
+ for i in range(2):
+ k = random.randint(2, 5)
+ w_vector = self._select_n_workers( k )
+ new_solution = deepcopy( solution )
+
+ released_jobs = []
+ # release
+ for worker_id in w_vector:
+ released_jobs += new_solution[worker_id]
+ new_solution[worker_id] = []
+
+ for job_id in released_jobs:
+ new_solution[w_vector[random.randint(0, k-1)]].append(job_id)
+
+ price = self.count( new_solution )
+ heappush( priced_solutions, (price, (new_solution, "rearange 2-5 workers") ) )
+
+ # rearange x jobs -- greedy, x in <2,5>
+ for i in range(2):
+ k = random.randint(2, 5)
+ w_vector = self._select_n_workers( k )
+ new_solution = deepcopy( solution )
+
+ released_jobs = []
+ # release
+ for worker_id in w_vector:
+ released_jobs += new_solution[worker_id]
+ new_solution[worker_id] = []
+
+ for job_id in released_jobs:
+ # find cheapest job for available workers
+ min_price = 32000
+ min_sel = None
+ for worker_id in w_vector:
+ if self.w_price[worker_id][job_id] < min_price:
+ min_price = self.w_price[worker_id][job_id]
+ min_sel = worker_id
+ new_solution[min_sel].append(job_id)
+
+ price = self.count( new_solution )
+ heappush( priced_solutions, (price, (new_solution, "rearange greedy 2-5 workers") ) )
+
+ # move the most expensive
+ most_exp_w = None
+ most_exp_id = None
+ most_exp_price = -1
+
+ for worker_id in solution.keys():
+ for job_id in solution[worker_id]:
+ if self.w_price[worker_id][job_id]>most_exp_price:
+ most_exp_price = self.w_price[worker_id][job_id]
+ most_exp_id = job_id
+ most_exp_w = worker_id
+ for i in range(5):
+ w = self._select_n_workers( 1 )[0]
+ while (w == most_exp_w):
+ w = self._select_n_workers( 1 )[0]
+
+ j_v = self._select_n_jobs( solution[w], 1 )
+ if len(j_v)==0:
+ # worker doesnt have any job
+ continue
+ j = j_v[0]
+
+ new_solution = self._switch_2_jobs(most_exp_w, most_exp_id, w, j, solution)
+ price = self.count( new_solution )
+ heappush( priced_solutions, (price, (new_solution, "switch max and random jobs") ) )
+
+ return priced_solutions
+
+ # + list of (price, step)
+ # @return some solution
+ def select_step( self, priced_solutions ):
+ return heappop( priced_solutions )
+
+ # + w1 worker 1 id
+ # + w2 worker 2 id
+ # + solution_old... old solution, remains intact
+ # @return switched copy of solution
+ def _switch_all_jobs( self, w1, w2, solution_old ):
+ solution = deepcopy(solution_old)
+ temp = solution[w1]
+ solution[w1] = solution[w2]
+ solution[w2] = temp
+ return solution
+
+ # + w1 worker 1 id,
+ # + j1 switched job of worker 1
+ # + w2 worker 2 id
+ # + j2 switched job of worker 2
+ # + solution_old... old solution, remains intact
+ # if selected worker doesnt have any job, this fucntion is identity
+ # @return switched copy of solution
+ def _switch_2_jobs( self, w1, j1, w2, j2, solution_old ):
+ if len(solution_old[w1])==0 or len(solution_old[w2])==0:
+ return solution_old
+ solution = deepcopy(solution_old)
+ solution[w1].remove(j1)
+ solution[w1].append(j2)
+ solution[w2].remove(j2)
+ solution[w2].append(j1)
+ return solution
+
+ # + w_list list of jobs available to worker
+ # + number n less or equal to number of jobs
+ # @return random distinct ids of jobs
+ def _select_n_jobs( self, w_list, n ):
+ ws = copy(w_list)
+ w_len = len(ws)
+ if n > w_len:
+ n = w_len
+ jobs = []
+ for demand in range(n):
+ get = ws[random.randint(0, w_len-1)]
+ while get in jobs:
+ get = ws[random.randint(0, w_len-1)]
+ jobs.append(get)
+ return jobs
+
+ # + number n less or equal to number of workers
+ # @return random distinct ids of workers
+ def _select_n_workers( self, n ):
+ if n > self.wc:
+ n = self.wc
+ workers = []
+ for demand in range(n):
+ get = random.randint(0, self.wc-1)
+ while get in workers:
+ get = random.randint(0, self.wc-1)
+ workers.append(get)
+ return workers
+
+ # + solution
+ # ++ parts True/False, return total price or vector of cost and penalty
+ # @return price of solution, tak in consideration the penalty
+ def count( self, solution, parts=False ):
+ cost = 0
+ weight_penalty = copy(self.w_capacity)
+ penalty_cost = 0
+ for worker_id in solution.keys():
+ for job_id in solution[worker_id]:
+ cost += self.w_price[worker_id][job_id]
+ weight_penalty[worker_id] -= self.w_space[worker_id][job_id]
+ for item in weight_penalty:
+ if item<0:
+ penalty_cost += self.PENALTY_LIN + power( -1 * item, self.PENALTY_EXP)
+ if parts==True:
+ return round(cost + penalty_cost), cost, round(penalty_cost)
+ else:
+ return float(cost + penalty_cost)
+
+
+if __name__ == u"__main__":
+ from main import *
+ load = load_data()
+ #from visualisation import visualize
+ w_price, w_space, w_capacity = select_problem( load, 0)
+ if trivial_conditions( w_price, w_space, w_capacity ):
+ #solution = constructive_greedy_heuristic_r( w_price, w_space, w_capacity, "maxmax" )
+ solution = constructive_random_heuristic( w_price, w_space, w_capacity )
+ print calculate_price(solution, w_price)
+ f = Frame(solution, w_price, w_space, w_capacity)
+
+ """
+ for i in range(1,100):
+ print i*10, f._decay(i*10)
+ """
+ result = f.great_deluge()
+ print result
+ #visualize( w_price, w_space, w_capacity, f.output_format( result ) )
+ #f.run_iteration()
280 python/main.py
@@ -0,0 +1,280 @@
+#!/usr/bin/python
+# coding=utf-8
+
+import time
+import getopt
+import os
+import sys
+
+from constructive_heuristics import constructive_greedy_heuristic_r
+from constructive_heuristics import constructive_peckish_heuristic_r
+from constructive_heuristics import constructive_random_heuristic
+
+from process_data import calculate_price
+from process_data import get_number_of_problems
+from process_data import load_data
+from process_data import select_problem
+from process_data import solution_table
+from process_data import trivial_conditions
+
+from local_search import Frame as local_search
+
+# Class to measure speed.
+class Stops:
+ # Start counting (sec)
+ def start_time( self ):
+ self.time = time.time()
+ return "0.000 sec"
+ # Get elapsed time (sec)
+ def current_time( self ):
+ return str(round((time.time()-self.time), 3)) + " sec"
+stops = Stops()
+
+if __name__ == u"__main__":
+ input_file_name = "./sets/gap1.txt"
+ output_file = None
+ task = "deluge"
+ visualise = False
+ decoration = True
+ m_time = False # print start and end time
+
+ stats = False # print statistics
+ set_demand = [0]
+ greedy_goals = ("maxdif","mindif","maxmax","minmax","minmin","maxmin","minavg")
+
+
+ opts, args = getopt.getopt(
+ sys.argv[1:],
+ "hi:a:g:d:tvsb",
+ ["help","input=","action=","greedygoal=","dataset=","time","visualize","solutions","beautyoff"]
+ )
+
+ for option in opts:
+ if len(option)>0:
+ option = (option[0], option[1].replace("=",""))
+ if option[0] in ["-i","--input"]:
+ # inputFile
+ if os.path.exists(option[1]):
+ input_file_name = option[1]
+ if option[0] in ["-b","--beautyoff"]:
+ decoration = False
+ if option[0] in ["-a","--action"]:
+ # inputFile
+ task = option[1]
+ if task not in (
+ "c",
+ "cgreedy",
+ "cpeckish",
+ "crandom",
+ "iterative",
+ "deluge",
+ "delugeall",
+ "delugerandom",
+ "delugegreedy",
+ "delugepeckish"):
+ task = "default"
+ if option[0] in ["-g","--greedygoal"]:
+ if option[1] in greedy_goals:
+ greedy_goals = [ option[1] ]
+ # default greedy_goals =
+ # = ("maxdif","mindif","maxmax","minmax","minmin","maxmin","minavg")
+ if option[0] in ["-d","--dataset"]:
+ # which test set to select
+ if option[1].isdigit():
+ set_demand = [ int(option[1]) ]
+ else:
+ set_demand = "*" # select all
+ if option[0] in ["-v","--visualise"]:
+ visualise = True
+ try:
+ from visualisation import visualize as visualise_sol
+ except (Exception), e:
+ print e.message()
+ visualise = False
+ if option[0] in ["-t","--time"]:
+ m_time = True
+ if option[0] in ["-s","--solutions"]:
+ stats = True
+ if option[0] in ["-h","--help"]:
+ print """
+ Python 2.5 or 2.6 is required.
+
+ Call python main.py to run a program.
+
+ "help"
+ "input=" main.py -i=opt (--input=opt) path to gap.txt
+ "action=" main.py -a=opt (--action=opt)
+ Specify the goal.
+ "c", all constructive heuristics
+ "cgreedy", constructive greedy heuristic
+ "cpeckish", constructive peckish heuristic
+ "crandom", constructive random heuristic
+ "iterative", iterative local search with random initialisation
+ "deluge", great deluge algorithm with random initialisation
+ "delugegreedy", great deluge algorithm with greedy initialisation
+ "delugepeckish", great deluge algorithm with peckish initialisation
+ "delugerandom", great deluge algorithm with random initialisation
+ "delugeall", great deluge algorithm with all initialisation
+ "greedygoal=" main.py -g=default (--greedygoal=default)
+ Use selected greedy criteria:
+ "maxdif","mindif","maxmax","minmax","minmin","maxmin","minavg"
+ "dataset=" main.py -d=number (--dataset=0) to use selected test set in a file
+ main.py -d=* (--dataset=*) to use all test sets in a file
+ "time" main.py -t (--time) to view start and end time
+ "beautyoff" main.py -b (--beautyoff) strip some text blocks
+ "visualise" main.py -v (--visualise) to run 3D visualization
+ Modules matplotlib, numpy and scipy are required!
+ "solutions" main.py -s (--solutions) to view assigment table
+ """
+
+ loaded_data = load_data( input_file_name )
+ if set_demand == "*":
+ set_demand = range( get_number_of_problems(loaded_data) )
+
+ # for each set independently
+ for set_id in set_demand:
+ w_price, w_space, w_capacity = select_problem( loaded_data, set_id)
+ best_sol = 32000
+ best_type = None
+ if decoration:
+ print "\n Processing...\n Filename: %s\n Set: %s" % (input_file_name, set_id)
+ print " -------------------------"
+ if trivial_conditions( w_price, w_space, w_capacity ):
+ # if trivial conditions succed, continue
+
+ # test all constructvie heuristics
+ if task in ("c", "crandom", "cpeckish", "cgreedy"):
+ if task == "c" or task == "crandom":
+ for i in range(8):
+ if m_time:
+ print "@ Start constructive %s h.: %s" % (
+ "random", stops.start_time()
+ )
+ solution = constructive_random_heuristic( w_price, w_space, w_capacity )
+ if m_time:
+ print "@ End constructive %s h.: %s" % (
+ "random", stops.current_time()
+ )
+ temp_price = calculate_price( solution, w_price )
+ if temp_price < best_sol:
+ best_sol = temp_price
+ best_type = "random"
+ print "\t\trandom %s: %s." % (str(i+1), str(temp_price) )
+ if task == "c" or task == "cgreedy":
+ for crit in greedy_goals:
+ if m_time:
+ print "@ Start constructive %s h.: %s" % (
+ "greedy", stops.start_time()
+ )
+ solution = constructive_greedy_heuristic_r( w_price, w_space, w_capacity, crit )
+ if m_time:
+ print "@ End constructive %s h.: %s" % (
+ "greedy", stops.current_time()
+ )
+ temp_price = calculate_price( solution, w_price )
+ if temp_price < best_sol:
+ best_sol = temp_price
+ best_type = "greedy: %s" % (crit)
+ print "\t\tgreedy %s: %s" % (crit, str(temp_price))
+ if task == "c" or task == "cpeckish":
+ for crit in greedy_goals:
+ if m_time:
+ print "@ Start constructive %s h.: %s" % (
+ "peckish", stops.start_time()
+ )
+ solution = constructive_peckish_heuristic_r( w_price, w_space, w_capacity, crit )
+ if m_time:
+ print "@ End constructive %s h.: %s" % (
+ "peckish", stops.current_time()
+ )
+ temp_price = calculate_price( solution, w_price )
+ if temp_price < best_sol:
+ best_sol = temp_price
+ best_type = "peckish: %s" % (crit)
+ print "\t\tpeckish %s: %s" % (crit, str(temp_price))
+ if stats:
+ print solution_table( solution )
+ if visualise:
+ visualise_sol( w_price, w_space, w_capacity, solution )
+ # ITERATIVE
+ if task == "iterative":
+ for i in range(8):
+ if m_time:
+ print "@ Start constructive h.: %s" % (
+ stops.start_time()
+ )
+ init_solution = constructive_random_heuristic(
+ w_price, w_space, w_capacity
+ )
+ if m_time:
+ print "@ Start iterative ls.: %s" % (
+ stops.current_time()
+ )
+ frame = local_search( init_solution, w_price, w_space, w_capacity )
+ solution = frame.run_iteration()
+ temp_price = calculate_price( solution, w_price )
+ if temp_price < best_sol:
+ best_sol = temp_price
+ best_type = "iterative"
+ if m_time:
+ print "@ Finish: %s" % ( stops.current_time() )
+ print "\t\tIterative: %s" % (str(temp_price))
+ if stats:
+ print solution_table( solution )
+ if visualise:
+ visualise_sol( w_price, w_space, w_capacity, solution )
+ # GREAT DELUGE
+ if task in ("deluge", "delugeall", \
+ "delugerandom", "delugegreedy", "delugepeckish"):
+ if task == "deluge":
+ todo = ["delugepeckish"]
+ if task == "delugeall":
+ todo = ["delugerandom", "delugegreedy", "delugepeckish"]
+ if task in ("delugerandom", "delugegreedy", "delugepeckish"):
+ todo = [task]
+ for type in todo:
+ if m_time:
+ print "@ Start constructive %s h.: %s" % (
+ type, stops.start_time()
+ )
+ init_solution = None
+ if type == "delugerandom":
+ init_solution = constructive_random_heuristic(
+ w_price, w_space, w_capacity
+ )
+ if type == "delugegreedy":
+ init_solution = constructive_greedy_heuristic_r(
+ w_price, w_space, w_capacity, greedy_goals[0]
+ )
+ if type == "delugepeckish":
+ init_solution = constructive_peckish_heuristic_r(
+ w_price, w_space, w_capacity, greedy_goals[0]
+ )
+ if m_time:
+ print "@ Start deluge ls.: %s" % ( stops.current_time() )
+ frame = local_search( init_solution, w_price, w_space, w_capacity )
+
+ solution = frame.great_deluge()
+
+ temp_price = calculate_price( solution, w_price )
+ if temp_price < best_sol:
+ best_sol = temp_price
+ best_type = "deluge: %s" % (type)
+ if m_time:
+ print "@ Finish: %s" % ( stops.current_time() )
+ print "\t\tDeluge %s: %s" % (type, str(temp_price))
+ if stats:
+ print solution_table( solution )
+ if visualise:
+ visualise_sol( w_price, w_space, w_capacity, solution )
+ else:
+ print "Set violates trivial constrains!"
+
+ if decoration:
+ print """
+ Statistics...
+ Best: %s
+ Heuristic: %s
+ -------------------------""" % (str(best_sol), best_type)
+
+
109 python/process_data.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python
+
+def load_data( filename = "./sets/gap1.txt" ):
+ input = open( filename, "r" )
+ lines = [ line.replace( "\n", "" ) for line in input.readlines() ]
+ input.close()
+
+ number_of_sets = int( lines[0] )
+
+ cur_line = 1
+ while(lines[cur_line] == ""):
+ cur_line += 1
+
+ out_w_price = [[] for i in range( number_of_sets) ]
+ out_w_space = [[] for i in range( number_of_sets) ]
+ out_w_capacity = [[] for i in range( number_of_sets) ]
+
+ for set_id in range( number_of_sets ):
+ # wc: worker_count number of workers
+ # jc: job_count number of jobs
+ wc, jc = [ int( number ) for number in lines[ cur_line ].split() ]
+ cur_line += 1
+ for worker in range( wc ):
+ out_w_price[ set_id ].append(
+ [ int( number ) for number in lines[cur_line + worker].split() ]
+ )
+ out_w_space[ set_id ].append(
+ [ int( number ) for number in lines[ wc + cur_line + worker].split() ]
+ )
+ out_w_capacity[ set_id ] = [ int( number ) for number in lines[ 2*wc + cur_line].split() ]
+ cur_line += 1 + 2*wc + 1
+
+ while len(lines)-1 > cur_line and lines[cur_line] == "":
+ cur_line += 1
+ return ( out_w_price, out_w_space, out_w_capacity )
+
+# + loaded_data:
+# output of load_data
+# @return number of data sets
+def get_number_of_problems( loaded_data ):
+ return len(loaded_data[0])
+
+# + loaded_data:
+# output of load_data
+# ++ index:
+# select which set to use
+def select_problem( loaded_data, index = 0 ):
+ if index >= len(loaded_data[0]):
+ # out of range
+ index = 0
+
+ w_price = loaded_data[0][index]
+ w_space = loaded_data[1][index]
+ w_capacity = loaded_data[2][index]
+ return w_price, w_space, w_capacity
+
+# if sum of minimal demands of each jobs exceeds maximum capacity of workers
+# or
+# if demand of one job exceeds all capacities of workers
+# @return False and write error code
+# otherwise:
+# @return True
+def trivial_conditions( w_price, w_space, w_capacity ):
+ # 1:
+ used_cap = 0
+ for job_id in range( len ( w_space[0] ) ):
+ used_cap += min( [jv[job_id] for jv in w_space] )
+ max_cap = sum( w_capacity )
+
+ if max_cap < used_cap:
+ print "the capacity of workers %s is exceeded by demand of jobs %s." % (
+ max_cap, used_cap
+ )
+ return False
+
+ # 2:
+ for job_id in range( len( w_space[0] ) ):
+ fit = False
+ for work_id in range( len ( w_capacity ) ):
+ if w_space[work_id][job_id] <= w_capacity[work_id]:
+ fit = True
+ if not fit:
+ print "the demand of job %s exceeds all workers capacities." % (
+ str(job_id)
+ )
+ return False
+ return True
+
+# + solution in dictionary
+# + price vector
+# @return number
+def calculate_price( result, w_price ):
+ total = 0
+ for key in result.keys():
+ total += w_price[ result[key] ][ key ]
+ return total
+
+
+# + solution if format dictionary job:worker
+# @return string with beautified output
+def solution_table( solution ):
+ output = "\n"
+ output += "\t******************\n"
+ output += "\t| Job\t| Worker\n"
+ output += "\t******************\n"
+ for key in solution.keys():
+ output += "\t| %s\t| %s\n" % ( str(key), str(solution[key]) )
+ output += "\t******************\n"
+ return output
15 python/sets/format-gap.txt
@@ -0,0 +1,15 @@
+These data sets for the GAP have been taken from the data sets
+available at the OR Library:
+
+http://people.brunel.ac.uk/~mastjjb/jeb/orlib/gapinfo.html
+
+The format for each of these data files is:
+
+- number of different problem sets
+- for each problem set in turn:
+ number of workers (m), number of tasks (n)
+- for each worker j (j=1,...,m) in turn:
+ cost of allocating task i to worker j
+- for each worker j (j=1,...,m) in turn:
+ resource consumed (tij) in allocating task i to worker j
+- resource capacity (Tj) of agent j (j=1,...,m)
15 python/sets/gap0.txt
@@ -0,0 +1,15 @@
+1
+
+5 5
+17 21 22 18 24
+23 16 21 16 17
+16 20 16 25 24
+19 19 22 22 20
+18 19 15 15 21
+16 15 14 23 8
+15 7 23 22 11
+21 20 6 22 24
+20 11 8 14 9
+8 13 13 13 10
+15 14 15 17 12
+
71 python/sets/gap1.txt
@@ -0,0 +1,71 @@
+5
+
+5 15
+17 21 22 18 24 15 20 18 19 18 16 22 24 24 16
+23 16 21 16 17 16 19 25 18 21 17 15 25 17 24
+16 20 16 25 24 16 17 19 19 18 20 16 17 21 24
+19 19 22 22 20 16 19 17 21 19 25 23 25 25 25
+18 19 15 15 21 25 16 16 23 15 22 17 19 22 24
+8 15 14 23 8 16 8 25 9 17 25 15 10 8 24
+15 7 23 22 11 11 12 10 17 16 7 16 10 18 22
+21 20 6 22 24 10 24 9 21 14 11 14 11 19 16
+20 11 8 14 9 5 6 19 19 7 6 6 13 9 18
+8 13 13 13 10 20 25 16 16 17 10 10 5 12 23
+36 34 38 27 33
+
+
+5 15
+19 23 24 20 20 25 16 21 24 15 17 17 20 20 20
+25 24 16 21 19 17 17 19 23 21 21 23 20 15 16
+16 21 25 22 24 24 16 17 15 18 15 17 18 24 18
+25 24 18 19 15 18 20 22 23 18 16 19 17 15 22
+25 19 21 22 20 15 20 19 18 18 17 23 17 25 25
+16 12 8 20 18 10 12 8 14 23 19 14 15 15 24
+16 18 19 22 13 20 9 7 25 10 20 13 11 15 16
+6 20 20 5 14 12 6 15 22 18 13 23 23 18 25
+18 23 25 17 25 13 23 23 13 20 20 23 17 19 24
+12 17 15 25 22 5 24 19 12 25 23 21 23 19 18
+36 37 38 48 44
+
+
+5 15
+22 21 16 17 21 15 17 22 22 25 18 20 24 15 22
+23 24 19 15 16 21 15 25 16 21 20 19 16 23 20
+21 20 21 25 21 20 21 19 17 16 25 19 15 15 15
+17 21 25 25 23 22 20 19 20 25 15 20 21 25 23
+15 25 23 19 17 17 25 24 24 17 24 19 18 19 16
+23 10 15 13 17 10 13 6 9 21 20 7 9 25 8
+17 13 8 23 11 18 7 22 13 5 24 24 15 10 22
+22 17 22 23 20 11 17 25 23 9 22 20 15 9 25
+5 19 25 16 15 10 18 9 11 20 7 21 15 8 25
+22 9 10 23 19 21 17 15 15 17 25 19 10 9 21
+32 37 44 35 40
+
+
+5 15
+15 25 20 18 19 21 18 22 24 15 25 17 17 15 22
+20 18 25 25 16 24 22 24 17 18 23 25 21 25 24
+25 19 18 18 23 18 15 22 23 16 25 22 22 15 16
+19 19 23 17 19 19 22 19 23 22 24 22 25 19 16
+25 24 17 19 25 19 23 19 25 15 19 21 18 19 22
+20 20 18 9 18 5 16 18 13 24 21 23 15 19 9
+5 12 18 8 22 19 19 11 7 19 20 17 21 25 5
+18 8 8 9 20 20 23 13 15 12 6 12 25 25 23
+17 19 24 9 16 22 10 17 12 17 15 21 16 18 6
+14 6 20 6 21 5 11 23 20 21 20 18 13 13 21
+39 36 37 38 37
+
+
+5 15
+25 25 18 24 20 19 25 24 23 15 18 18 25 15 22
+25 18 17 22 21 23 20 23 16 19 15 18 16 23 16
+18 16 19 15 15 18 15 20 19 24 22 20 25 16 21
+18 21 16 18 17 24 18 23 22 16 17 22 22 18 16
+17 18 15 21 23 21 24 23 20 22 19 15 22 22 25
+16 20 9 22 17 19 20 22 20 13 6 20 23 19 7
+12 22 18 18 6 13 17 17 17 14 20 12 17 14 22
+5 19 19 14 24 16 7 8 9 22 13 23 24 15 20
+20 8 6 9 5 17 23 18 14 12 14 17 15 23 21
+6 6 24 24 8 7 5 25 21 18 12 20 20 7 12
+40 38 38 35 34
+
120 python/sets/gap12.txt
@@ -0,0 +1,120 @@
+5
+
+10 60
+25 18 15 16 18 25 19 18 25 23 19 25 19 21 24 16 18 23 18 17 25 20 24 21 17 19 24 25 17 19 19 25 20 17 21 20 20 17 19 25 25 19 23 24 20 16 21 24 17 15 17 19 15 21 25 16 21 20 24 22
+21 21 15 23 23 22 20 22 21 24 20 19 23 24 23 23 22 22 15 18 20 19 20 24 22 20 20 20 20 17 20 24 18 19 22 17 21 17 19 17 22 22 18 22 20 17 19 15 15 19 23 22 24 23 17 21 25 23 20 19
+21 17 24 17 24 15 22 24 20 18 21 23 19 24 23 22 22 21 16 18 21 22 25 22 17 25 22 22 24 22 25 20 16 19 23 20 18 23 23 19 19 21 17 22 15 16 23 24 17 22 23 18 24 16 20 25 19 17 22 21
+21 20 22 15 23 24 25 22 18 16 23 24 20 21 15 21 17 20 24 22 24 25 16 17 18 20 25 18 24 24 24 22 19 20 15 20 17 19 16 23 15 22 22 24 15 16 20 17 21 24 24 24 24 25 19 24 25 16 22 19
+24 23 22 19 18 16 23 18 22 24 25 16 23 21 17 18 19 17 25 17 18 23 24 18 24 23 23 15 19 18 24 19 19 24 24 24 15 21 21 24 24 19 23 24 21 23 24 22 18 19 24 15 17 17 25 17 24 16 19 21
+16 21 19 22 16 16 17 23 25 16 18 22 15 25 20 15 18 23 22 16 17 17 16 24 24 16 17 23 19 23 15 17 24 19 24 24 24 16 22 16 18 23 23 20 16 25 23 17 18 23 24 19 22 19 19 18 21 21 22 17
+23 23 19 18 19 19 21 24 22 16 17 25 24 17 23 17 20 25 25 22 17 24 17 17 23 23 16 17 19 19 23 24 17 25 18 19 18 16 17 17 24 23 17 19 15 23 22 17 23 21 15 19 18 22 23 16 16 22 16 21
+24 16 15 25 16 15 20 20 22 18 21 19 21 19 17 17 17 22 25 17 20 25 15 17 20 16 23 20 23 22 23 15 21 24 21 23 19 24 17 24 25 18 24 21 20 18 22 15 16 18 23 24 25 20 20 21 17 15 24 21
+18 18 18 19 18 24 22 19 25 15 16 23 17 16 18 22 21 18 21 18 20 18 16 24 17 22 24 18 22 18 24 23 23 25 20 23 18 22 21 18 24 17 15 25 23 16 22 24 18 21 16 24 22 18 25 23 23 18 16 22
+16 18 19 18 18 24 24 23 25 16 20 22 25 16 20 18 19 24 24 25 22 23 23 24 18 24 16 21 17 22 22 16 15 17 19 23 15 19 22 22 23 23 16 20 22 24 20 20 23 16 24 17 22 17 19 25 16 16 19 16
+17 25 6 14 16 12 19 19 5 16 23 16 15 22 19 10 25 7 24 9 724 22 23 10 25 21 16 13 17 9 6 16 23 11 22 14 22 5 14 9 19 24 16 6 21 19 11 22 22 19 24 12 20 15 17 21 17 25 19 10
+6 24 12 24 14 22 11 10 25 12 20 17 18 22 11 15 20 20 21 12 5 5 25 15 24 17 7 21 11 12 24 16 12 5 9 11 14 7 14 9 13 7 25 12 6 10 7 15 13 22 6 10 5 21 5 16 16 13 5 23 10
+21 21 7 5 20 16 9 14 22 12 9 8 14 17 22 9 17 8 12 15 24 19 6 8 16 14 14 23 14 23 5 21 17 25 13 23 23 12 20 19 16 15 22 19 18 7 5 20 19 9 23 14 14 11 20 15 25 17 12 13 10
+22 14 19 7 5 20 19 5 20 7 12 8 13 18 16 9 23 16 16 9 25 8 13 16 6 8 5 18 12 5 12 16 12 25 5 24 23 23 25 22 17 17 21 24 16 7 17 9 13 24 22 25 25 23 12 12 8 24 14 8 10
+17 10 18 13 14 18 6 6 11 9 12 20 15 12 18 18 11 7 9 25 13 9 10 9 15 10 19 15 15 14 25 6 12 21 9 10 18 20 13 17 17 21 15 9 22 11 14 14 13 16 12 5 14 18 24 9 19 14 9 24 10
+24 23 6 13 9 17 18 21 10 15 15 18 14 15 11 24 20 24 16 20 23 25 9 21 21 13 9 24 12 8 14 21 16 25 20 23 8 16 20 10 5 16 11 20 10 11 21 15 12 12 21 10 19 18 10 25 23 16 8 25 10
+5 21 24 13 21 11 18 12 24 22 20 21 16 18 8 25 7 19 11 12 18 5 15 7 12 5 23 16 12 5 8 24 25 10 13 24 22 20 12 16 18 9 21 17 19 6 21 12 6 9 24 10 8 13 13 13 23 25 8 22 10
+9 19 23 7 5 8 16 17 21 15 15 12 21 24 15 6 7 11 5 13 10 16 19 9 22 8 21 17 7 8 25 23 20 8 14 16 5 16 5 10 17 6 18 9 19 9 11 18 23 14 24 13 20 10 22 19 6 15 18 15 10
+23 15 16 20 19 23 8 15 24 25 25 5 13 14 12 25 5 11 23 24 18 7 17 10 25 21 13 19 18 6 8 9 21 18 5 12 8 7 19 24 7 9 22 7 9 10 14 24 22 24 15 16 11 19 18 18 16 8 6 8 10
+10 14 24 13 18 11 13 24 22 7 12 17 23 12 15 5 5 16 20 22 18 12 20 12 9 5 7 6 25 6 7 13 7 23 21 21 18 8 23 7 11 9 15 19 9 13 22 24 18 14 11 15 15 18 22 13 17 14 11 11 10
+79 67 74 73 67 78 73 68 73 69
+
+
+10 60
+16 25 25 19 16 20 16 16 18 16 18 16 21 18 17 20 16 18 19 15 19 17 15 25 22 24 19 22 15 25 19 20 18 25 24 20 23 21 24 19 18 25 21 18 22 15 15 24 17 24 21 19 18 24 18 17 23 24 16 21
+20 20 21 18 23 15 20 25 17 15 23 15 18 24 18 22 20 24 15 24 24 18 18 21 19 16 25 16 21 21 17 25 15 24 25 21 23 19 23 19 25 23 25 23 16 18 21 23 21 15 24 21 20 21 22 16 23 21 24 22
+25 19 17 21 20 23 22 22 20 15 17 25 19 24 19 15 18 15 25 23 15 15 23 20 18 22 24 19 24 15 18 15 15 23 25 19 19 19 20 24 22 25 21 15 16 22 23 15 15 24 24 15 18 24 20 25 18 16 17 15
+18 25 20 19 16 20 16 19 16 17 23 23 16 17 16 24 21 23 24 17 23 16 15 23 21 17 23 23 17 24 24 21 19 24 23 25 18 17 19 17 17 20 21 24 15 24 25 24 23 15 23 18 22 16 23 16 21 17 21 25
+16 20 24 17 17 23 17 17 17 18 22 24 23 23 20 23 15 21 25 17 15 18 19 21 23 18 21 21 24 18 21 15 20 23 23 23 23 19 16 24 22 20 22 19 24 24 18 25 23 15 18 23 22 17 23 17 25 19 25 18
+19 15 22 21 21 17 15 24 15 24 25 21 25 19 17 23 21 20 16 24 24 23 24 23 16 23 20 20 17 17 19 19 15 19 23 19 19 22 20 15 23 19 24 19 25 23 18 15 15 15 15 19 16 19 24 17 17 22 17 15
+23 24 16 18 24 23 16 21 21 19 15 22 24 18 17 17 16 22 18 16 17 20 19 16 19 18 17 16 20 18 18 18 19 18 17 16 16 18 25 25 19 25 24 21 25 22 22 18 18 16 15 21 15 17 22 23 15 19 19 18
+17 23 23 23 16 17 23 19 17 25 16 20 24 22 17 19 25 17 24 18 18 20 23 20 18 24 18 18 18 17 21 22 23 24 17 20 21 19 16 19 15 21 19 24 18 22 24 15 16 21 24 25 17 22 17 22 15 18 19 16
+16 25 24 17 15 25 16 15 16 25 25 20 19 20 15 18 17 23 22 15 25 19 22 22 16 17 18 24 21 19 22 23 25 15 25 24 25 15 15 24 20 24 25 20 15 25 22 17 21 23 25 17 16 23 20 19 23 24 20 20
+19 20 15 18 23 21 20 23 15 24 25 24 21 20 21 25 19 15 20 21 22 15 25 24 18 16 16 22 23 20 21 22 15 21 18 19 22 18 23 25 18 16 20 20 15 25 18 23 17 22 24 23 22 20 21 18 19 20 22 24
+5 5 6 14 22 22 18 5 6 15 18 23 17 8 8 25 13 24 18 14 6 13 11 13 14 7 11 9 20 8 6 8 15 9 9 19 22 21 8 12 6 11 7 20 11 23 14 19 23 20 10 6 16 13 24 24 10 20 14 16
+11 11 14 11 8 15 17 18 19 5 10 23 15 10 12 6 11 22 19 12 22 12 7 7 21 9 7 20 11 19 6 20 22 5 14 21 15 17 17 19 5 22 5 5 17 24 12 16 19 11 6 12 24 18 24 23 13 11 20 19
+6 21 24 14 12 18 23 25 10 10 7 7 25 17 24 8 17 5 8 24 6 13 15 17 14 5 25 5 19 20 15 18 16 9 7 18 6 7 10 6 25 24 6 7 15 18 13 13 22 20 19 7 17 5 18 18 9 16 20 17
+24 15 16 25 21 16 5 15 21 23 15 23 13 19 18 13 16 7 11 20 5 17 21 14 14 7 10 17 22 6 21 18 7 19 8 16 21 24 20 8 16 14 10 24 14 9 24 12 23 15 8 25 6 13 25 6 15 21 5 17
+20 16 20 6 25 16 19 20 12 7 24 13 14 18 22 20 17 21 6 13 13 25 19 25 19 7 24 5 24 17 25 15 14 10 8 13 5 20 17 22 18 7 5 24 23 10 13 22 16 15 9 13 11 24 7 14 18 11 17 6
+13 23 15 5 21 17 16 16 18 18 19 5 19 21 24 7 16 6 19 14 15 15 8 25 6 24 8 18 10 17 13 19 20 8 8 16 11 18 17 15 18 8 6 21 12 15 12 21 22 17 20 20 20 16 6 11 17 12 19 11
+18 21 16 19 21 11 21 22 12 14 20 19 19 7 7 8 19 21 22 11 8 8 12 12 7 5 5 23 8 11 15 11 24 9 21 18 25 10 19 19 10 13 21 5 15 16 5 22 12 24 24 18 24 14 6 9 10 15 25 20
+8 13 20 9 19 15 12 25 8 18 20 12 25 17 15 7 15 9 23 25 6 20 5 9 21 16 21 10 22 10 17 25 7 21 18 5 25 14 25 13 17 11 8 17 18 13 9 20 5 12 19 16 14 15 8 22 22 11 14 16
+18 24 15 20 8 12 11 23 24 8 23 15 24 22 17 17 8 13 18 6 21 13 9 18 8 16 16 12 25 20 24 9 21 18 17 9 25 17 20 12 18 17 15 10 19 11 8 9 18 5 17 23 14 17 6 13 20 23 12 23
+13 10 21 6 18 23 9 24 9 10 5 12 19 11 24 6 21 14 10 22 18 22 12 6 15 25 21 15 13 17 24 12 13 12 20 13 18 24 11 6 9 17 21 18 24 15 16 14 24 10 11 16 5 25 21 16 24 12 24 13
+66 69 69 74 75 72 72 72 76 75
+
+
+10 60
+20 22 15 15 25 20 18 17 17 22 16 19 24 22 25 17 15 16 22 19 21 16 17 17 15 24 25 23 23 17 25 19 23 17 21 17 24 24 16 15 18 18 23 23 15 18 23 22 18 17 19 24 25 16 18 18 15 21 23 17
+17 22 15 18 17 17 24 21 21 16 19 22 21 19 18 19 23 19 15 20 16 20 18 19 18 16 19 23 20 24 18 15 15 17 18 17 18 25 21 22 18 22 24 22 16 17 23 17 22 22 23 23 19 15 22 15 24 22 18 20
+18 15 24 22 20 15 19 15 23 17 15 17 23 21 20 15 18 20 25 23 21 23 17 22 15 21 16 25 24 18 25 18 16 19 19 17 15 16 17 19 22 24 24 21 20 20 22 17 19 18 16 16 25 17 15 24 15 17 24 23
+18 22 24 23 18 22 24 17 20 22 23 24 18 21 16 16 22 21 17 19 17 15 20 15 19 20 18 16 23 23 20 19 20 18 23 16 18 16 24 25 20 20 22 15 21 23 21 19 16 22 20 15 18 23 15 23 19 17 24 16
+22 19 20 24 25 15 17 25 17 15 24 16 17 23 24 23 20 20 18 18 23 19 17 24 18 15 22 17 24 25 23 19 21 15 24 19 24 20 17 25 20 22 25 24 19 23 21 20 17 17 16 18 16 17 15 24 23 21 19 21
+15 21 16 22 21 15 18 17 17 16 24 20 15 15 21 23 19 17 15 22 25 25 16 16 16 20 17 15 19 21 16 25 24 23 22 24 20 19 24 21 19 18 23 20 15 21 20 15 22 23 15 24 23 23 17 25 21 23 18 18
+24 16 16 23 16 19 25 20 20 19 21 23 24 18 24 24 21 18 25 22 15 15 16 23 17 21 23 21 19 24 16 15 19 25 21 17 15 23 16 25 23 25 25 19 22 22 22 25 23 20 23 25 16 24 18 20 23 22 20 24
+23 20 24 16 17 18 16 16 24 25 23 25 15 17 23 16 21 18 17 23 16 22 15 21 16 25 24 19 15 18 19 17 16 19 16 22 22 18 24 24 21 25 15 21 16 20 16 17 24 16 25 23 21 19 16 17 19 17 15 21
+19 21 22 17 15 20 25 24 16 20 19 25 24 25 19 19 21 19 25 20 23 15 22 21 16 16 21 23 25 22 22 23 19 15 25 18 15 19 19 21 15 17 16 21 19 18 24 24 24 22 20 18 19 25 16 25 18 17 22 23
+19 19 22 19 17 17 23 25 22 17 19 18 19 16 23 22 24 17 18 20 24 24 23 25 17 23 16 22 16 17 25 18 21 19 22 25 22 17 18 16 21 23 23 25 18 19 15 21 19 22 18 19 23 17 16 17 19 16 23 21
+23 17 23 17 10 23 21 14 11 17 16 16 21 20 9 24 15 6 23 15 22 7 14 5 7 20 10 22 8 9 23 24 6 11 25 20 22 5 9 13 25 5 18 8 10 15 23 21 18 23 11 6 8 11 12 12 8 14 10 19
+12 15 10 24 25 16 21 25 9 10 18 14 17 22 7 15 15 18 18 24 25 19 13 22 15 7 23 12 8 5 16 8 24 23 19 7 13 9 23 5 10 8 8 25 19 10 11 16 16 20 22 25 17 23 15 9 18 13 11 8
+18 10 24 25 13 10 24 12 25 21 17 13 5 18 25 8 16 12 7 23 8 24 15 14 22 7 20 21 16 17 15 23 22 16 11 12 20 21 14 8 21 10 5 7 21 14 8 9 21 25 8 14 7 17 13 12 16 7 21 6
+20 25 21 7 5 25 7 19 12 15 25 11 8 6 25 12 9 22 5 13 18 25 19 6 15 7 14 18 8 22 8 10 9 8 19 16 7 13 10 7 11 8 5 11 23 6 10 24 15 22 8 12 11 16 16 11 12 16 16 6
+12 11 21 21 15 10 11 10 24 20 20 9 11 21 14 12 17 12 5 17 22 20 23 17 10 5 19 5 17 22 17 12 19 14 21 17 18 21 6 16 14 13 10 11 15 8 7 21 18 12 11 21 15 6 14 25 6 12 24 20
+21 7 11 6 14 8 5 5 9 24 20 25 17 8 7 5 19 5 8 21 7 8 11 24 19 17 16 16 7 17 23 8 20 13 14 16 25 19 19 15 21 13 19 12 9 20 24 5 9 10 7 18 10 24 17 11 5 25 12 25
+18 20 23 17 16 23 24 21 6 22 7 21 24 10 24 12 9 9 21 21 14 5 7 23 25 23 14 6 5 8 13 25 13 11 23 17 17 9 20 21 21 15 7 14 18 5 20 20 23 21 12 18 7 20 10 24 16 15 9 19
+20 12 20 21 6 5 25 19 12 5 25 8 25 15 5 7 21 14 10 13 5 5 8 5 15 8 24 15 8 5 10 21 10 16 23 17 19 19 9 18 8 5 23 20 13 16 6 5 21 8 22 18 9 21 19 18 14 7 25 5
+19 10 23 5 8 15 21 17 16 6 16 6 19 10 7 11 14 20 24 18 2222 14 6 10 9 11 17 7 14 23 6 16 16 13 18 15 13 9 23 16 18 18 7 21 20 24 25 16 18 21 12 20 21 13 16 22 15 18 24
+21 22 5 14 23 8 21 9 25 23 7 23 5 25 18 18 24 23 20 16 21 21 12 17 12 19 22 22 14 19 17 19 15 22 17 9 18 12 8 21 14 17 6 12 13 6 25 23 19 13 25 25 5 17 7 25 25 23 7 19
+72 74 73 64 71 68 76 66 74 81
+
+
+10 60
+18 20 17 17 22 24 25 24 18 24 20 21 22 17 20 21 23 21 19 25 19 21 21 25 23 21 23 18 19 20 25 23 18 22 20 20 15 17 22 15 15 18 16 17 20 23 23 24 21 16 22 15 24 23 23 25 17 18 17 19
+17 19 16 19 25 21 24 23 23 22 15 20 25 24 19 21 20 19 15 22 20 20 22 18 16 25 25 18 17 25 16 18 16 17 20 25 21 17 22 15 20 18 17 19 15 21 16 16 23 19 25 22 20 17 23 25 20 18 22 20
+20 17 16 24 25 24 16 20 25 20 16 22 20 25 15 17 21 16 22 24 17 16 16 17 18 17 17 18 19 23 25 15 19 20 17 16 20 19 21 17 18 24 20 15 23 23 19 25 22 25 24 25 16 23 25 16 18 18 22 25
+22 17 22 23 19 16 22 19 21 24 17 25 15 15 18 17 24 19 21 15 17 23 21 15 22 21 23 18 15 15 21 20 21 21 19 22 23 20 18 17 24 17 15 19 16 15 23 20 15 18 25 15 20 22 21 15 24 25 21 24
+23 24 25 25 15 20 20 25 21 17 21 20 20 24 23 22 23 16 21 25 25 21 17 19 21 24 22 25 16 25 19 24 21 22 22 20 20 22 16 24 15 21 21 22 21 18 20 16 15 20 22 19 17 16 25 25 21 17 23 18
+15 24 16 16 15 22 18 20 24 19 22 18 24 22 22 16 22 16 21 16 21 24 17 23 22 20 17 23 19 23 20 21 18 22 16 15 22 15 22 16 21 25 17 18 19 23 22 22 25 19 21 25 23 16 21 15 19 15 21 22
+18 16 19 22 20 15 18 21 22 19 20 22 17 25 18 20 16 24 21 23 23 15 16 23 20 22 17 21 23 17 20 23 25 16 17 22 25 24 24 24 19 15 23 19 17 18 18 24 18 19 19 21 21 18 19 17 23 20 15 18
+18 22 18 24 23 16 21 23 20 20 16 24 24 18 19 15 22 22 15 23 21 23 25 24 18 16 17 19 15 19 18 19 22 21 22 16 15 16 15 21 16 20 19 18 24 24 16 23 16 15 19 20 19 17 17 24 20 23 18 18
+15 15 23 15 19 23 22 18 22 17 24 24 20 23 19 16 16 25 25 21 24 22 18 16 25 23 16 25 22 15 24 17 15 17 22 21 15 23 22 20 16 21 22 23 16 19 22 17 24 22 25 23 24 22 23 21 19 15 23 24
+21 22 17 21 25 22 20 22 23 21 15 23 20 15 22 15 24 22 21 16 21 16 21 16 17 19 23 25 17 17 24 21 15 15 20 19 19 22 21 20 22 25 24 15 19 17 23 22 21 22 17 24 16 21 25 25 16 17 21 25
+25 24 16 25 5 14 10 14 23 21 20 22 22 12 22 9 15 17 23 7 14 10 6 6 8 22 14 14 21 25 23 20 17 5 17 13 7 25 21 21 25 16 14 7 9 7 7 15 22 14 25 17 9 19 20 6 7 6 22 6
+12 19 20 18 22 10 6 18 20 22 19 24 17 7 7 11 8 13 17 11 24 10 25 18 6 25 9 16 15 9 17 15 8 5 13 16 12 20 18 23 6 10 24 25 19 14 13 24 16 13 6 19 10 16 12 5 8 13 13 7
+14 25 19 5 13 7 24 20 8 6 13 7 19 15 18 21 20 9 7 14 19 14 25 13 7 5 18 14 12 10 20 8 21 21 19 13 25 8 9 7 14 14 11 16 7 11 21 21 25 13 13 5 5 20 23 23 25 13 19 7
+20 15 11 16 20 21 20 17 7 8 10 13 5 6 24 22 6 5 9 25 5 9 7 9 20 5 13 25 5 12 12 23 16 21 13 6 8 5 21 20 8 20 15 7 11 25 20 10 11 9 13 24 18 6 11 19 6 23 22 7
+18 8 23 16 20 22 23 13 6 24 5 25 23 8 21 12 19 8 8 13 17 5 9 7 23 18 8 10 12 17 22 23 25 14 25 5 15 20 23 21 15 16 13 18 21 18 5 24 22 17 7 10 14 7 24 14 9 8 13 16
+13 25 24 22 5 10 22 22 9 18 10 21 23 21 8 22 9 25 24 19 21 8 8 18 17 5 13 11 13 9 22 8 12 23 7 22 15 16 10 7 9 8 17 7 5 21 8 17 9 16 5 21 13 5 17 7 19 8 24 10
+20 24 21 17 20 21 25 16 6 25 12 25 21 16 22 21 6 25 13 14 13 11 11 22 7 8 9 14 14 20 12 5 14 6 16 11 18 17 10 19 7 9 13 22 24 15 22 7 5 16 10 21 24 17 15 19 14 8 25 6
+10 15 16 25 15 12 14 20 24 22 19 8 9 7 23 22 25 14 23 22 23 21 11 21 6 24 11 25 18 8 25 23 22 25 9 18 16 17 12 24 25 16 8 11 13 9 13 20 6 21 14 17 24 21 15 17 17 15 17 5
+20 5 15 10 6 24 6 10 25 10 20 21 13 25 22 14 19 12 22 13 18 15 17 6 16 12 19 14 20 6 22 18 7 11 14 12 20 6 5 11 14 18 6 7 12 17 24 17 8 5 19 23 6 15 10 21 18 23 15 12
+5 19 18 25 25 14 23 21 22 11 15 21 19 11 6 5 21 14 17 10 19 13 5 20 23 19 21 9 12 20 23 14 21 12 24 25 16 6 25 12 5 6 18 25 19 17 12 24 12 12 11 18 17 5 22 8 20 13 17 6
+74 70 70 65 74 69 74 80 69 75
+
+
+10 60
+25 18 23 22 24 16 17 21 22 23 23 25 20 17 25 24 23 23 15 25 20 24 18 21 19 15 20 17 20 17 22 24 15 17 16 20 19 24 20 20 25 17 23 19 18 16 16 20 19 20 16 19 20 22 16 24 19 22 15 21
+16 17 22 15 18 22 17 15 23 18 25 21 21 23 17 21 17 25 21 21 15 18 24 25 19 21 19 22 21 18 16 21 21 25 15 25 18 18 19 17 22 15 19 16 17 18 20 16 16 16 17 24 18 22 18 16 23 21 18 15
+21 16 21 17 15 19 25 22 25 18 18 23 24 22 19 20 21 25 16 17 24 16 19 17 17 16 16 24 16 17 23 24 20 23 17 17 25 22 19 24 24 18 21 20 16 20 25 23 21 18 17 23 24 23 15 21 25 24 22 16
+22 15 25 24 25 20 16 17 15 20 19 23 17 20 24 25 24 23 22 20 23 24 23 24 25 19 15 25 19 15 19 18 19 18 25 17 22 15 25 17 15 20 22 23 17 21 16 22 21 20 23 23 23 23 22 18 22 18 18 24
+21 20 25 23 23 23 18 22 24 20 23 15 20 19 21 18 24 17 15 17 21 21 19 24 24 15 24 21 24 23 25 17 23 17 18 19 20 25 25 21 20 23 16 25 24 24 22 24 22 23 20 19 19 16 17 15 19 23 22 25
+15 16 15 15 24 25 19 22 15 23 21 19 16 21 16 15 21 17 23 20 25 23 25 16 15 20 15 18 25 19 20 18 16 22 21 23 22 21 25 19 18 19 16 22 15 15 22 21 16 21 23 19 20 24 18 17 18 17 19 16
+15 17 15 21 21 17 15 21 25 25 17 16 15 19 18 25 18 16 21 21 21 20 24 21 15 15 21 25 24 22 20 15 21 25 22 18 15 21 15 22 15 23 23 17 16 16 18 21 17 25 19 20 25 25 25 17 23 25 16 23
+22 16 25 22 20 18 23 18 22 25 17 15 15 23 20 22 19 15 20 23 16 21 21 25 17 18 18 15 24 17 21 22 23 15 16 23 20 17 16 15 21 16 21 23 16 24 15 21 22 18 20 19 18 22 20 20 19 16 18 22
+18 16 16 24 21 19 25 19 23 22 16 22 20 17 23 23 15 19 23 15 21 17 22 20 21 15 23 15 21 15 22 25 18 19 21 25 15 15 15 24 22 19 17 22 25 16 25 19 24 24 16 15 21 24 18 18 25 18 20 25
+21 15 19 24 21 16 23 19 22 24 20 19 20 20 21 23 19 15 23 15 17 22 20 16 23 17 20 24 21 16 17 19 16 24 17 21 16 20 23 22 20 20 20 18 15 19 25 22 21 19 18 23 15 16 24 20 19 25 15 17
+16 25 23 24 19 17 17 16 18 17 12 10 24 25 6 18 17 6 10 10 6 11 8 25 22 18 18 12 17 5 16 8 17 15 22 13 13 15 10 25 15 18 20 25 6 18 15 24 9 16 7 15 24 9 18 12 9 19 22 16
+10 7 20 18 19 7 8 8 18 7 8 16 14 11 20 17 5 6 17 19 21 20 10 5 25 15 5 16 19 11 14 13 12 22 18 13 6 8 17 5 5 23 23 11 12 17 17 19 21 24 15 11 23 11 18 6 21 8 24 14
+5 5 13 22 5 25 9 9 14 8 11 8 13 10 16 12 5 20 19 16 13 19 18 8 18 6 23 9 12 12 21 11 13 8 17 16 12 14 22 13 12 16 24 7 18 17 8 17 17 25 22 16 20 13 12 22 12 14 8 18
+25 19 15 7 21 16 23 10 24 14 19 17 10 14 25 21 13 6 8 8 15 13 20 19 11 7 18 6 13 9 13 7 16 23 9 7 6 7 13 7 16 8 21 14 16 25 22 7 10 13 17 23 6 19 22 15 14 10 23 25
+25 20 25 13 7 6 11 7 12 17 18 23 16 25 21 9 19 20 13 24 24 9 17 20 19 13 6 18 11 8 5 6 17 11 9 8 16 16 24 12 5 12 15 14 10 8 21 13 17 16 18 7 15 22 5 9 22 12 25 11
+23 8 15 7 15 7 12 10 17 13 13 11 21 23 21 8 10 17 15 25 10 13 10 18 18 9 11 22 18 24 24 18 21 22 19 17 23 25 16 5 11 7 10 18 5 7 19 12 9 23 25 17 13 11 10 6 5 19 22 24
+25 19 24 20 18 6 8 16 22 14 22 8 15 13 15 12 21 20 13 16 12 20 7 18 19 24 9 7 10 11 17 17 11 21 25 5 18 9 22 22 11 9 14 7 13 13 22 20 15 17 20 8 21 8 5 25 21 19 10 8
+18 24 20 8 19 21 23 6 20 23 23 9 7 23 20 7 6 11 23 16 17 24 23 19 14 13 15 22 13 16 6 14 20 11 13 19 17 12 6 23 13 25 23 12 17 5 24 25 11 10 25 25 22 12 12 10 8 8 18 14
+18 10 9 23 17 13 15 13 8 5 15 6 15 12 8 23 7 22 10 9 14 24 8 11 7 20 24 6 22 20 6 18 8 10 6 22 18 18 5 7 13 25 7 15 18 15 19 7 23 11 7 6 9 15 7 12 9 20 11 23
+22 20 10 16 24 22 15 5 25 24 11 8 7 20 24 6 19 13 14 8 18 6 16 21 6 16 14 21 18 5 15 21 7 10 20 18 22 14 12 18 17 9 14 12 17 22 8 16 13 12 6 20 20 6 9 22 13 20 24 19
+75 68 67 70 70 72 73 77 64 72
70 python/sets/gap4.txt
@@ -0,0 +1,70 @@
+5
+
+5 30
+15 16 12 17 12 15 19 15 19 17 25 17 19 15 20 16 12 16 13 22 16 16 14 21 21 24 13 25 21 22
+12 20 11 13 22 15 14 22 21 10 24 22 23 14 14 22 22 17 14 19 21 11 20 21 14 23 10 17 24 22
+19 19 16 11 18 20 18 22 21 15 22 23 16 23 18 18 18 22 21 12 20 18 13 25 10 23 21 24 22 18
+23 12 13 12 24 23 11 20 14 20 19 14 19 22 24 13 10 16 12 23 18 24 24 18 25 10 18 18 19 15
+15 13 16 23 19 21 15 12 18 21 12 18 21 16 17 14 13 14 19 18 21 12 14 17 15 24 21 13 11 24
+7 13 21 19 10 23 14 16 13 16 17 11 23 20 9 24 24 19 18 21 18 18 18 17 24 19 9 9 7 13
+12 12 23 23 6 24 13 24 16 17 9 15 5 20 19 17 16 13 8 13 24 5 6 25 10 16 23 8 6 13
+11 17 17 21 12 13 16 17 15 11 16 20 23 18 14 24 23 21 6 20 13 10 20 15 20 10 8 23 24 18
+18 23 13 8 15 12 16 13 9 6 12 13 13 14 18 6 6 7 12 10 22 10 8 8 9 18 5 7 21 22
+22 7 7 13 12 15 13 12 23 16 21 9 15 16 6 18 11 16 22 6 9 7 15 9 6 16 17 23 5 10
+79 72 79 61 64
+
+
+5 30
+16 16 13 20 22 24 15 25 18 25 11 19 20 21 17 16 16 21 17 13 13 17 14 12 24 20 15 22 15 12
+14 15 19 16 22 18 13 11 21 24 14 23 21 20 13 11 25 19 21 14 18 19 15 25 23 17 19 15 13 25
+25 23 19 17 11 19 16 25 11 23 15 17 21 13 18 18 22 13 20 23 24 16 24 16 23 15 10 23 23 14
+11 16 12 16 13 11 18 14 21 15 11 10 20 13 13 17 17 13 17 19 20 17 14 21 23 17 19 18 22 12
+18 11 24 18 13 14 14 14 21 19 20 25 22 18 24 23 21 17 23 23 17 20 23 24 19 15 15 14 24 15
+7 10 9 13 22 18 19 17 18 15 5 9 11 18 21 20 19 21 21 7 23 24 15 14 18 10 19 5 22 13
+24 25 12 24 15 21 20 14 25 13 14 6 16 21 7 24 7 14 7 18 13 24 22 20 10 21 20 11 10 24
+12 13 7 13 16 7 14 25 23 18 10 14 16 24 24 16 15 12 13 7 18 16 19 12 13 22 24 17 12 19
+19 5 7 15 16 9 18 6 7 22 8 10 14 5 9 20 6 11 9 5 6 20 25 17 19 11 15 18 24 7
+10 15 13 24 11 13 17 6 9 19 21 21 12 14 18 8 17 24 8 20 15 18 25 19 7 16 15 15 6 11
+76 80 75 62 72
+
+
+5 30
+19 23 11 24 19 18 24 19 25 21 17 22 25 16 19 21 17 14 13 22 11 16 23 14 24 11 22 17 21 11
+11 18 19 19 13 15 12 21 13 19 16 19 21 21 21 19 17 20 13 18 13 15 14 19 18 12 24 13 19 21
+13 21 22 22 25 17 14 18 16 17 18 20 23 14 21 17 18 24 19 11 12 24 25 23 22 24 12 19 13 23
+17 15 16 14 19 20 15 16 18 23 20 24 12 19 13 19 20 20 24 23 21 13 14 16 14 18 16 13 21 15
+22 21 11 11 22 24 24 15 23 19 23 12 20 16 22 22 21 19 18 18 12 10 12 11 19 17 13 23 22 19
+14 18 6 11 14 7 24 19 8 16 22 9 12 16 14 14 17 22 6 13 14 14 24 18 18 12 24 23 10 7
+21 13 18 10 16 24 18 11 17 24 16 22 9 10 24 12 24 9 5 24 16 19 11 15 10 12 25 18 8 11
+13 22 20 24 19 20 17 6 23 10 6 16 24 6 5 12 16 7 11 8 21 9 17 13 23 15 20 9 14 14
+7 15 11 21 18 12 7 22 9 23 21 8 18 23 20 12 5 12 5 10 12 20 18 17 11 11 18 20 24 24
+10 15 17 20 17 11 22 19 24 24 17 20 16 10 6 11 9 14 14 22 17 16 19 21 24 22 18 8 5 14
+72 75 70 72 78
+
+
+5 30
+16 14 16 21 13 14 14 21 20 19 25 12 22 17 12 21 11 10 24 15 23 14 14 20 15 23 14 23 13 22
+24 18 23 18 12 20 12 15 14 22 22 18 18 21 12 19 18 13 16 16 16 10 18 15 14 13 23 15 12 10
+20 16 15 18 24 16 21 21 24 15 14 23 11 12 15 14 18 15 14 12 25 20 23 13 16 23 18 20 22 16
+20 14 20 16 17 24 15 23 13 11 18 22 10 15 19 10 21 10 21 11 13 16 18 22 20 16 21 22 19 20
+19 15 12 11 23 24 15 17 17 11 23 14 20 21 22 16 16 23 10 22 12 25 24 20 13 20 16 11 23 18
+15 16 24 17 9 18 5 8 25 21 22 22 11 7 23 15 16 19 22 21 6 14 13 19 21 14 21 15 17 10
+22 13 7 14 23 10 6 11 21 14 15 9 13 18 15 14 7 7 17 8 16 19 16 15 10 7 12 10 21 13
+9 16 13 20 10 17 16 15 24 12 16 8 6 6 21 23 6 16 9 18 20 10 12 15 20 21 11 9 18 25
+14 22 23 8 25 24 23 12 8 15 13 23 7 11 10 10 21 19 23 24 7 8 18 11 18 10 19 25 16 10
+10 15 20 21 12 23 19 11 9 20 9 13 11 10 11 8 18 10 8 6 19 15 7 16 5 17 24 12 20 21
+78 64 71 76 67
+
+
+5 30
+15 20 23 10 16 20 20 24 13 13 11 11 15 16 18 17 17 19 20 10 15 17 12 17 15 23 22 23 25 16
+18 23 19 11 14 20 20 13 20 11 13 24 14 16 18 19 19 14 16 12 11 16 12 23 12 19 10 10 22 20
+15 23 11 19 11 13 16 21 23 24 13 15 18 24 21 23 21 20 25 19 15 18 17 21 23 10 11 20 15 17
+18 24 11 21 22 11 23 11 16 12 20 21 15 10 16 24 20 19 22 19 24 25 15 24 19 18 21 20 15 23
+25 16 21 13 12 12 16 17 11 21 22 12 21 13 20 22 12 21 14 20 23 13 25 10 10 20 12 19 23 14
+25 9 15 24 12 14 23 13 17 15 17 15 21 23 16 23 15 18 7 16 18 10 6 24 21 8 10 16 7 7
+8 20 11 9 13 6 13 13 12 24 17 9 13 17 11 15 10 24 6 20 16 14 23 12 11 11 22 8 9 12
+21 7 14 8 6 18 11 18 18 10 21 9 20 20 15 20 7 17 14 8 14 12 21 19 24 21 16 5 19 17
+14 20 9 14 17 8 8 9 20 17 9 19 7 15 12 12 16 22 20 5 15 16 18 8 22 24 21 22 12 7
+20 7 5 10 13 7 8 21 19 16 12 20 16 8 18 17 23 6 12 10 22 24 6 20 8 9 17 8 24 22
+74 65 72 70 68
116 python/sets/gap9.txt
@@ -0,0 +1,116 @@
+5
+
+10 30
+25 16 17 24 15 24 24 17 23 16 21 18 18 18 18 20 16 15 25 15 16 23 22 18 23 18 19 20 21 19
+16 17 19 18 17 23 15 25 25 16 16 23 21 23 25 19 16 18 16 21 24 15 21 19 20 16 18 25 20 22
+19 19 15 25 24 25 16 23 15 20 16 19 18 20 15 17 16 17 21 20 18 19 22 20 19 21 18 20 25 17
+17 21 21 21 19 20 24 15 21 15 18 23 18 16 16 18 24 16 22 16 22 19 17 17 22 19 21 16 24 17
+18 23 23 17 25 21 22 17 20 24 18 25 16 15 16 18 23 17 25 17 17 23 24 23 19 16 16 22 22 19
+24 18 20 18 19 16 22 18 19 23 18 23 21 24 22 25 21 18 21 16 21 22 18 22 15 19 16 22 16 17
+20 21 15 24 20 19 16 24 23 24 22 20 24 18 24 20 17 23 17 22 18 21 25 17 21 18 24 21 15 25
+15 23 19 21 17 16 22 23 16 15 19 21 15 18 18 21 25 15 15 15 20 21 18 19 18 21 25 23 25 21
+17 25 16 24 16 22 16 15 15 17 25 17 20 21 16 16 17 17 25 21 18 17 20 19 23 18 17 20 17 17
+17 21 23 22 23 25 25 22 24 18 24 22 15 24 15 16 19 22 25 19 24 17 16 17 17 25 19 16 23 22
+5 25 21 11 25 10 15 17 10 9 10 23 13 13 23 14 24 17 16 21 22 23 7 25 17 17 24 24 7 8
+25 14 19 21 22 11 19 14 12 22 9 10 7 12 6 9 5 23 24 16 8 15 17 22 20 6 18 15 7 7
+12 14 15 25 18 25 6 7 10 17 12 10 12 19 10 12 12 10 7 21 5 5 19 21 12 6 14 6 19 24
+24 11 18 14 9 13 18 14 11 12 9 14 12 18 8 19 24 13 7 17 22 20 24 15 12 12 20 21 6 22
+15 9 19 9 13 19 25 16 14 17 6 9 15 12 20 21 9 17 19 14 23 19 25 22 13 14 14 23 15 23
+25 22 12 6 11 25 15 13 13 9 9 13 19 10 18 23 14 8 9 19 15 21 10 5 23 17 22 11 17 5
+20 10 18 7 12 14 12 18 8 25 25 14 16 25 23 5 22 22 7 24 12 13 5 8 12 25 24 19 15 14
+15 18 21 17 7 5 10 10 25 13 23 10 7 7 20 18 21 12 24 10 7 25 20 13 19 18 16 7 9 6