summaryrefslogtreecommitdiff
diff options
authorBen Asselstine <[email protected]>2024-02-20 12:48:08 -0500
committerBen Asselstine <[email protected]>2024-02-20 12:48:08 -0500
commitb3063cf84bc545bf2d0d8bd7dcace43d043219ac (patch)
tree4d3d80f2bf128f271453447b564153fc97ac7a54
parent3d0db784d07042fff6eebfa75037eb4d944ce57d (diff)
downloadfituvalu-master.tar.gz
subtype searches for 6:1 squaresHEADmaster
-rw-r--r--src/Makefile.am10
-rw-r--r--src/search-61s1-small.c329
-rw-r--r--src/search-61s2-small.c323
-rw-r--r--src/search-61s7-small.c319
-rw-r--r--src/search-63s1-small.c1
5 files changed, 981 insertions, 1 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index c6ca56e..d58398a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -70,6 +70,7 @@ bin_PROGRAMS = \
3sq-search-61-small cycle-square-63 zerocen 3sq-search-coords-small \
filter-perfect-square count-negatives cycle-square-62 \
search-61-small search-61 gen-61-center-small \
+ search-61s1-small search-61s2-small search-61s7-small \
search-62-small search-62 \
search-63-small search-63 gen-63-center gen-63-center-small \
search-63-medium search-63s1-small \
@@ -538,6 +539,15 @@ search_613_small_LDADD = libmagicsquareutil.la -lm -lpthread
search_61_small_SOURCES = search-61-small.c
search_61_small_LDADD = libmagicsquareutil.la -lm -lpthread
+search_61s1_small_SOURCES = search-61s1-small.c
+search_61s1_small_LDADD = libmagicsquareutil.la -lm -lpthread
+
+search_61s2_small_SOURCES = search-61s2-small.c
+search_61s2_small_LDADD = libmagicsquareutil.la -lm -lpthread
+
+search_61s7_small_SOURCES = search-61s7-small.c
+search_61s7_small_LDADD = libmagicsquareutil.la -lm -lpthread
+
search_616_small_SOURCES = search-616-small.c
search_616_small_LDADD =libmagicsquareutil.la -lm -lpthread
diff --git a/src/search-61s1-small.c b/src/search-61s1-small.c
new file mode 100644
index 0000000..c758f32
--- /dev/null
+++ b/src/search-61s1-small.c
@@ -0,0 +1,329 @@
+/* Copyright (C) 2019, 2020 Ben Asselstine
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <argp.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <error.h>
+#include "magicsquareutil.h"
+
+pthread_mutex_t read_lock = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t display_lock = PTHREAD_MUTEX_INITIALIZER;
+
+struct fv_app_search_61s1
+{
+ int in_binary;
+ int num_args;
+ int threads;
+ FILE *infile;
+ FILE *out;
+ int progress;
+};
+
+struct fv_app_log_t lg;
+struct thread_data_t
+{
+ void *data;
+};
+
+static void
+run_threads (void *data, int num_threads, void* (*func)(void*))
+{
+ int retval;
+ pthread_t threads[num_threads];
+ struct thread_data_t param[num_threads];
+ for (int i = 0; i < num_threads; i++)
+ {
+ param[i].data = data;
+ //run process_perfect_square
+ if ((retval = pthread_create (&threads[i], NULL, func, &param[i])))
+ {
+ fprintf (stderr, "can't create a thread!\n");
+ return;
+ }
+ }
+ for (int i = 0; i < num_threads; i++)
+ pthread_join (threads[i], NULL);
+}
+
+static unsigned long long int
+gcd (unsigned long long int n1, unsigned long long int n2)
+{
+ while (n1 != n2)
+ {
+ if(n1 > n2)
+ n1 -= n2;
+ else
+ n2 -= n1;
+ }
+ return n1;
+}
+static void
+generate_61_type_1 (struct fv_app_search_61s1 *app, unsigned long long lo, unsigned long long hi, unsigned long long distance, unsigned long long sum, unsigned long long sum_minus_middle, long long int (*s)[3][3])
+{
+ unsigned long long i, iroot, j, distance2, limit, twoiroot;
+
+ distance2 = distance * 2;
+
+ limit = sum * 3;
+
+ iroot = sqrtl (hi);
+ iroot++;
+ i = iroot * iroot;
+
+ twoiroot = iroot * 2;
+ i += twoiroot;
+ i++;
+ iroot++;
+
+// +---+---+---+ +---+---+---+
+// | | | X | | 6 | 1 | 8 |
+// +---+---+---+ +---+---+---+
+// | | X | X | | 7 | 5 | 3 |
+// +---+---+---+ +---+---+---+
+// | X | X | X | | 2 | 9 | 4 |
+// +---+---+---+ +---+---+---+
+
+ (*s)[0][2] = hi;
+ (*s)[2][0] = lo;
+
+ while (1)
+ {
+ (*s)[2][1] = i;
+ j = i - distance2;
+
+ (*s)[1][2] = j;
+ (*s)[0][0] = (*s)[1][2] + distance;
+
+ (*s)[0][1] = sum_minus_middle - (*s)[2][1];
+ (*s)[1][0] = sum_minus_middle - (*s)[1][2];
+ (*s)[2][2] = sum_minus_middle - (*s)[0][0];
+
+ {
+ int dup = 0;
+ //check for dups
+ if ((*s)[1][1] == (*s)[1][2] ||
+ (*s)[1][1] == (*s)[2][2])
+ dup = 1;
+ if (!dup &&
+ small_is_square (j) &&
+ small_is_square ((*s)[2][2]))
+ {
+ pthread_mutex_lock (&display_lock);
+ fprintf (app->out,
+ "%llu, %lld, %llu, "
+ "%llu, %llu, %llu, "
+ "%llu, %llu, %llu, \n",
+ (*s)[0][0], (*s)[0][1], (*s)[0][2],
+ (*s)[1][0], (*s)[1][1], (*s)[1][2],
+ (*s)[2][0], (*s)[2][1], (*s)[2][2]);
+ fflush (app->out);
+ pthread_mutex_unlock (&display_lock);
+ }
+
+ }
+ twoiroot = iroot * 2;
+ i += twoiroot;
+ i++;
+ iroot++;
+ if (i > limit)
+ break;
+ }
+}
+
+static void
+handle_progression (struct fv_app_search_61s1 *app, unsigned long long lo, unsigned long long hi, unsigned long long int distance, unsigned long long sum, unsigned long long sum_minus_middle, long long (*s)[3][3])
+{
+ if (app->progress)
+ fv_update_log_ull (&lg, (*s)[1][1]);
+ unsigned long long int n = gcd (lo, hi);
+ if (n % 2 == 1)
+ generate_61_type_1 (app, lo, hi, distance, sum, sum_minus_middle, s);
+}
+
+static void
+generate_progressions (struct fv_app_search_61s1 *app, unsigned long long n, long long (*s)[3][3])
+{
+ unsigned long long i, iroot, diff, limit, nn, mn, twomn, lo, hi, sum, sum_minus_middle, twoiroot;
+
+ sum = n * 3;
+ sum_minus_middle = sum - n;
+ limit = n / 2;
+ i = 1;
+ iroot = 1;
+ while (1)
+ {
+ if (i > limit)
+ break;
+
+ diff = n - i;
+
+ if (small_is_square (diff))
+ {
+ nn = sqrtl (diff);
+ mn = iroot * nn;
+ twomn = mn * 2;
+ lo = n - twomn;
+ hi = n + twomn;
+
+ if (twomn > 0)
+ handle_progression (app, lo, hi, twomn, sum, sum_minus_middle, s);
+ }
+
+ twoiroot = iroot * 2;
+ i += twoiroot;
+ i++;
+ iroot++;
+ }
+ return;
+}
+
+static void*
+process_record (void *arg)
+{
+ char *line = NULL, *end = NULL;
+ size_t len = 0;
+ unsigned long long n, num;
+ struct thread_data_t *param = (struct thread_data_t *) arg;
+ struct fv_app_search_61s1 *app =
+ (struct fv_app_search_61s1 *) param->data;
+
+ long long s[3][3];
+
+ while (1)
+ {
+ //go get the next progression to work on
+ if (app->threads > 1)
+ pthread_mutex_lock (&read_lock);
+
+ if (app->in_binary)
+ {
+ size_t read = fread (&n, sizeof (unsigned long long), 1, app->infile);
+ if (read != 1)
+ {
+ if (app->threads > 1)
+ pthread_mutex_unlock (&read_lock);
+ break;
+ }
+ }
+ else
+ {
+ ssize_t read = fv_getline (&line, &len, app->infile);
+ if (read == -1)
+ {
+ if (app->threads > 1)
+ pthread_mutex_unlock (&read_lock);
+ break;
+ }
+ num = strtoull (line, &end, 10);
+ }
+ n = num;
+
+ if (app->threads > 1)
+ pthread_mutex_unlock (&read_lock);
+
+ //now we work on n
+ {
+ s[1][1] = n;
+ generate_progressions (app, n, &s);
+ }
+ }
+
+ if (line)
+ free (line);
+ return NULL;
+}
+
+int
+fituvalu_search_61 (struct fv_app_search_61s1 *app)
+{
+ run_threads (app, app->threads, process_record);
+ return 0;
+}
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct fv_app_search_61s1 *app = (struct fv_app_search_61s1 *) state->input;
+ switch (key)
+ {
+ case 'i':
+ app->in_binary = 1;
+ break;
+ case ARGP_KEY_ARG:
+ if (app->num_args == 2)
+ argp_error (state, "too many arguments");
+ else
+ {
+ app->infile = fopen (arg, "r");
+ if (!app->infile)
+ argp_error (state, "could not open `%s' for reading");
+ app->num_args++;
+ }
+ break;
+ case 't':
+ app->threads = atoi (arg);
+ break;
+ case 'p':
+ app->progress = 1;
+ break;
+ case ARGP_KEY_INIT:
+ setenv ("ARGP_HELP_FMT", "no-dup-args-note", 1);
+ break;
+ }
+ return 0;
+}
+
+static struct argp_option
+options[] =
+{
+ { "in-binary", 'i', 0, 0, "Input raw unsigned long longs instead of text"},
+ { "threads", 't', "NUM", 0, "Spread the work across NUM threads"},
+ { "progress", 'p', 0, OPTION_HIDDEN, "Show progress information in /tmp"},
+ { 0 }
+};
+
+static struct argp
+argp =
+{
+ options, parse_opt, "[FILE]",
+ "Find 3x3 magic squares of the type 6:1:1 given a FILE containing center values.\vWhen FILE is not provided, it is read from the standard input. This program is limited to 64-bit integers. Magic squares of type 6:1:1 have the following layout of squares vs non-squares:\n"
+" +---+---+---+ +---+---+---+\n"
+" | | | X | | | | 8 | 2,5,8 is a three square progression where\n"
+" +---+---+---+ +---+---+---+ 5 comes from FILE. Start iterating 9\n"
+" | | X | X | | | 5 | 3 | from 8 upwards until 5 * 3. Squares at\n"
+" +---+---+---+ +---+---+---+ 3 and 4 shake out.\n"
+" | X | X | X | | 2 | 9 | 4 |\n"
+" +---+---+---+ +---+---+---+\n"
+"This program finds 6:1:1, 6:1:2, 6:1:3 and 6:1:4.",
+ 0
+};
+
+int
+main (int argc, char **argv)
+{
+ struct fv_app_search_61s1 app;
+ memset (&app, 0, sizeof (app));
+ app.threads = 1;
+ app.infile = stdin;
+ app.out = stdout;
+ argp_parse (&argp, argc, argv, 0, 0, &app);
+ if (app.progress)
+ fv_init_log (&lg, "search-61s1-small");
+ return fituvalu_search_61 (&app);
+}
diff --git a/src/search-61s2-small.c b/src/search-61s2-small.c
new file mode 100644
index 0000000..db17d8d
--- /dev/null
+++ b/src/search-61s2-small.c
@@ -0,0 +1,323 @@
+/* Copyright (C) 2019, 2020 Ben Asselstine
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <argp.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <error.h>
+#include "magicsquareutil.h"
+
+pthread_mutex_t read_lock = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t display_lock = PTHREAD_MUTEX_INITIALIZER;
+
+struct fv_app_search_61s2
+{
+ int in_binary;
+ int num_args;
+ int threads;
+ FILE *infile;
+ FILE *out;
+ int progress;
+};
+
+struct fv_app_log_t lg;
+struct thread_data_t
+{
+ void *data;
+};
+
+static void
+run_threads (void *data, int num_threads, void* (*func)(void*))
+{
+ int retval;
+ pthread_t threads[num_threads];
+ struct thread_data_t param[num_threads];
+ for (int i = 0; i < num_threads; i++)
+ {
+ param[i].data = data;
+ //run process_perfect_square
+ if ((retval = pthread_create (&threads[i], NULL, func, &param[i])))
+ {
+ fprintf (stderr, "can't create a thread!\n");
+ return;
+ }
+ }
+ for (int i = 0; i < num_threads; i++)
+ pthread_join (threads[i], NULL);
+}
+
+static unsigned long long int
+gcd (unsigned long long int n1, unsigned long long int n2)
+{
+ while (n1 != n2)
+ {
+ if(n1 > n2)
+ n1 -= n2;
+ else
+ n2 -= n1;
+ }
+ return n1;
+}
+static void
+generate_61_type_1 (struct fv_app_search_61s2 *app, unsigned long long lo, unsigned long long hi, unsigned long long distance, unsigned long long sum, unsigned long long sum_minus_middle, long long int (*s)[3][3])
+{
+ unsigned long long i, iroot, j, distance2, limit, twoiroot;
+
+ distance2 = distance * 2;
+
+ limit = sum;
+
+ iroot = sqrtl (lo);
+ i = lo;
+
+ twoiroot = iroot * 2;
+ i += twoiroot;
+ i++;
+ iroot++;
+
+// +---+---+---+ +---+---+---+
+// | | | X | | 7 | 1 | 8 |
+// +---+---+---+ +---+---+---+
+// | | X | X | | 6 | 5 | 4 |
+// +---+---+---+ +---+---+---+
+// | X | X | X | | 2 | 9 | 3 |
+// +---+---+---+ +---+---+---+
+ (*s)[0][2] = hi;
+ (*s)[2][0] = lo;
+ while (1)
+ {
+ (*s)[2][2] = i;
+ (*s)[0][0] = sum - (*s)[1][1] - i;
+ (*s)[2][1] = sum - (*s)[2][0] - (*s)[2][2];
+ (*s)[0][1] = sum - (*s)[0][0] - (*s)[0][2];
+ (*s)[1][0] = sum - (*s)[0][0] - (*s)[2][0];
+ (*s)[1][2] = sum - (*s)[1][1] - (*s)[1][0];
+
+ {
+ int dup = 0;
+ //check for dups
+ if ((*s)[1][0] == (*s)[2][1] ||
+ (*s)[1][1] == (*s)[2][2])
+ dup = 1;
+ if (!dup &&
+ small_is_square ((*s)[2][1]) &&
+ small_is_square ((*s)[1][2]))
+ {
+ pthread_mutex_lock (&display_lock);
+ fprintf (app->out,
+ "%llu, %lld, %llu, "
+ "%llu, %llu, %llu, "
+ "%llu, %llu, %llu, \n",
+ (*s)[0][0], (*s)[0][1], (*s)[0][2],
+ (*s)[1][0], (*s)[1][1], (*s)[1][2],
+ (*s)[2][0], (*s)[2][1], (*s)[2][2]);
+ fflush (app->out);
+ pthread_mutex_unlock (&display_lock);
+ }
+
+ }
+ twoiroot = iroot * 2;
+ i += twoiroot;
+ i++;
+ iroot++;
+ if (i > limit)
+ break;
+ }
+}
+
+static void
+handle_progression (struct fv_app_search_61s2 *app, unsigned long long lo, unsigned long long hi, unsigned long long int distance, unsigned long long sum, unsigned long long sum_minus_middle, long long (*s)[3][3])
+{
+ if (app->progress)
+ fv_update_log_ull (&lg, (*s)[1][1]);
+ unsigned long long int n = gcd (lo, hi);
+ if (n % 2 == 1)
+ generate_61_type_1 (app, lo, hi, distance, sum, sum_minus_middle, s);
+}
+
+static void
+generate_progressions (struct fv_app_search_61s2 *app, unsigned long long n, long long (*s)[3][3])
+{
+ unsigned long long i, iroot, diff, limit, nn, mn, twomn, lo, hi, sum, sum_minus_middle, twoiroot;
+
+ sum = n * 3;
+ sum_minus_middle = sum - n;
+ limit = n / 2;
+ i = 1;
+ iroot = 1;
+ while (1)
+ {
+ if (i > limit)
+ break;
+
+ diff = n - i;
+
+ if (small_is_square (diff))
+ {
+ nn = sqrtl (diff);
+ mn = iroot * nn;
+ twomn = mn * 2;
+ lo = n - twomn;
+ hi = n + twomn;
+
+ if (twomn > 0)
+ handle_progression (app, lo, hi, twomn, sum, sum_minus_middle, s);
+ }
+
+ twoiroot = iroot * 2;
+ i += twoiroot;
+ i++;
+ iroot++;
+ }
+ return;
+}
+
+static void*
+process_record (void *arg)
+{
+ char *line = NULL, *end = NULL;
+ size_t len = 0;
+ unsigned long long n, num;
+ struct thread_data_t *param = (struct thread_data_t *) arg;
+ struct fv_app_search_61s2 *app =
+ (struct fv_app_search_61s2 *) param->data;
+
+ long long s[3][3];
+
+ while (1)
+ {
+ //go get the next progression to work on
+ if (app->threads > 1)
+ pthread_mutex_lock (&read_lock);
+
+ if (app->in_binary)
+ {
+ size_t read = fread (&n, sizeof (unsigned long long), 1, app->infile);
+ if (read != 1)
+ {
+ if (app->threads > 1)
+ pthread_mutex_unlock (&read_lock);
+ break;
+ }
+ }
+ else
+ {
+ ssize_t read = fv_getline (&line, &len, app->infile);
+ if (read == -1)
+ {
+ if (app->threads > 1)
+ pthread_mutex_unlock (&read_lock);
+ break;
+ }
+ num = strtoull (line, &end, 10);
+ }
+ n = num;
+
+ if (app->threads > 1)
+ pthread_mutex_unlock (&read_lock);
+
+ //now we work on n
+ {
+ s[1][1] = n;
+ generate_progressions (app, n, &s);
+ }
+ }
+
+ if (line)
+ free (line);
+ return NULL;
+}
+
+int
+fituvalu_search_61 (struct fv_app_search_61s2 *app)
+{
+ run_threads (app, app->threads, process_record);
+ return 0;
+}
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct fv_app_search_61s2 *app = (struct fv_app_search_61s2 *) state->input;
+ switch (key)
+ {
+ case 'i':
+ app->in_binary = 1;
+ break;
+ case ARGP_KEY_ARG:
+ if (app->num_args == 2)
+ argp_error (state, "too many arguments");
+ else
+ {
+ app->infile = fopen (arg, "r");
+ if (!app->infile)
+ argp_error (state, "could not open `%s' for reading");
+ app->num_args++;
+ }
+ break;
+ case 't':
+ app->threads = atoi (arg);
+ break;
+ case 'p':
+ app->progress = 1;
+ break;
+ case ARGP_KEY_INIT:
+ setenv ("ARGP_HELP_FMT", "no-dup-args-note", 1);
+ break;
+ }
+ return 0;
+}
+
+static struct argp_option
+options[] =
+{
+ { "in-binary", 'i', 0, 0, "Input raw unsigned long longs instead of text"},
+ { "threads", 't', "NUM", 0, "Spread the work across NUM threads"},
+ { "progress", 'p', 0, OPTION_HIDDEN, "Show progress information in /tmp"},
+ { 0 }
+};
+
+static struct argp
+argp =
+{
+ options, parse_opt, "[FILE]",
+ "Find 3x3 magic squares of the type 6:1:2 given a FILE containing center values.\vWhen FILE is not provided, it is read from the standard input. This program is limited to 64-bit integers. Magic squares of type 6:1:1 have the following layout of squares vs non-squares:\n"
+" +---+---+---+ +---+---+---+\n"
+" | | | X | | | | 8 | 2,5,8 is a three square progression where\n"
+" +---+---+---+ +---+---+---+ 5 comes from FILE. Start iterating 3\n"
+" | | X | X | | | 5 | 4 | from 2 upwards until 5. Squares at\n"
+" +---+---+---+ +---+---+---+ 9 and 4 shake out.\n"
+" | X | X | X | | 2 | 9 | 3 |\n"
+" +---+---+---+ +---+---+---+\n"
+"This program finds 6:1:1, 6:1:2, 6:1:5, 6:1:6, 6:1:7, and 6:1:8.",
+ 0
+};
+
+int
+main (int argc, char **argv)
+{
+ struct fv_app_search_61s2 app;
+ memset (&app, 0, sizeof (app));
+ app.threads = 1;
+ app.infile = stdin;
+ app.out = stdout;
+ argp_parse (&argp, argc, argv, 0, 0, &app);
+ if (app.progress)
+ fv_init_log (&lg, "search-61s2-small");
+ return fituvalu_search_61 (&app);
+}
diff --git a/src/search-61s7-small.c b/src/search-61s7-small.c
new file mode 100644
index 0000000..cb72da0
--- /dev/null
+++ b/src/search-61s7-small.c
@@ -0,0 +1,319 @@
+/* Copyright (C) 2019, 2020 Ben Asselstine
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <argp.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <error.h>
+#include "magicsquareutil.h"
+
+pthread_mutex_t read_lock = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t display_lock = PTHREAD_MUTEX_INITIALIZER;
+
+struct fv_app_search_61_t
+{
+ int in_binary;
+ int num_args;
+ int threads;
+ FILE *infile;
+ FILE *out;
+ int progress;
+};
+
+struct fv_app_log_t lg;
+struct thread_data_t
+{
+ void *data;
+};
+
+static void
+run_threads (void *data, int num_threads, void* (*func)(void*))
+{
+ int retval;
+ pthread_t threads[num_threads];
+ struct thread_data_t param[num_threads];
+ for (int i = 0; i < num_threads; i++)
+ {
+ param[i].data = data;
+ //run process_perfect_square
+ if ((retval = pthread_create (&threads[i], NULL, func, &param[i])))
+ {
+ fprintf (stderr, "can't create a thread!\n");
+ return;
+ }
+ }
+ for (int i = 0; i < num_threads; i++)
+ pthread_join (threads[i], NULL);
+}
+
+static unsigned long long int
+gcd (unsigned long long int n1, unsigned long long int n2)
+{
+ while (n1 != n2)
+ {
+ if(n1 > n2)
+ n1 -= n2;
+ else
+ n2 -= n1;
+ }
+ return n1;
+}
+static void
+generate_61_type_1 (struct fv_app_search_61_t *app, unsigned long long lo, unsigned long long hi, unsigned long long distance, unsigned long long sum, unsigned long long sum_minus_middle, long long int (*s)[3][3])
+{
+ unsigned long long i, iroot, j, distance2, limit, twoiroot;
+
+ distance2 = distance * 2;
+
+ limit = lo;
+
+ iroot = 1;
+ i = 1;
+
+// +---+---+---+ +---+---+---+
+// | | | X | | 3 | 4 | 8 |
+// +---+---+---+ +---+---+---+
+// | | X | X | | 9 | 5 | 1 |
+// +---+---+---+ +---+---+---+
+// | X | X | X | | 2 | 6 | 7 |
+// +---+---+---+ +---+---+---+
+ (*s)[0][2] = hi;
+ (*s)[2][0] = lo;
+ while (1)
+ {
+ (*s)[1][2] = i;
+ (*s)[2][2] = sum - (*s)[1][2] - (*s)[0][2];
+ (*s)[2][1] = sum - (*s)[2][0] - (*s)[2][2];
+ (*s)[1][0] = sum - (*s)[1][1] - (*s)[1][2];
+ (*s)[0][1] = sum - (*s)[1][1] - (*s)[2][1];
+ (*s)[0][0] = sum - (*s)[0][1] - (*s)[0][2];
+
+
+ {
+ int dup = 0;
+ //check for dups
+ if ((*s)[1][1] == (*s)[1][2] ||
+ (*s)[1][1] == (*s)[2][2])
+ dup = 1;
+ if (!dup &&
+ small_is_square ((*s)[2][1]) &&
+ small_is_square ((*s)[2][2]))
+ {
+ pthread_mutex_lock (&display_lock);
+ fprintf (app->out,
+ "%llu, %lld, %llu, "
+ "%llu, %llu, %llu, "
+ "%llu, %llu, %llu, \n",
+ (*s)[0][0], (*s)[0][1], (*s)[0][2],
+ (*s)[1][0], (*s)[1][1], (*s)[1][2],
+ (*s)[2][0], (*s)[2][1], (*s)[2][2]);
+ fflush (app->out);
+ pthread_mutex_unlock (&display_lock);
+ }
+
+ }
+ twoiroot = iroot * 2;
+ i += twoiroot;
+ i++;
+ iroot++;
+ if (i > limit)
+ break;
+ }
+}
+
+static void
+handle_progression (struct fv_app_search_61_t *app, unsigned long long lo, unsigned long long hi, unsigned long long int distance, unsigned long long sum, unsigned long long sum_minus_middle, long long (*s)[3][3])
+{
+ if (app->progress)
+ fv_update_log_ull (&lg, (*s)[1][1]);
+ unsigned long long int n = gcd (lo, hi);
+ if (n % 2 == 1)
+ generate_61_type_1 (app, lo, hi, distance, sum, sum_minus_middle, s);
+}
+
+static void
+generate_progressions (struct fv_app_search_61_t *app, unsigned long long n, long long (*s)[3][3])
+{
+ unsigned long long i, iroot, diff, limit, nn, mn, twomn, lo, hi, sum, sum_minus_middle, twoiroot;
+
+ sum = n * 3;
+ sum_minus_middle = sum - n;
+ limit = n / 2;
+ i = 1;
+ iroot = 1;
+ while (1)
+ {
+ if (i > limit)
+ break;
+
+ diff = n - i;
+
+ if (small_is_square (diff))
+ {
+ nn = sqrtl (diff);
+ mn = iroot * nn;
+ twomn = mn * 2;
+ lo = n - twomn;
+ hi = n + twomn;
+
+ if (twomn > 0)
+ handle_progression (app, lo, hi, twomn, sum, sum_minus_middle, s);
+ }
+
+ twoiroot = iroot * 2;
+ i += twoiroot;
+ i++;
+ iroot++;
+ }
+ return;
+}
+
+static void*
+process_record (void *arg)
+{
+ char *line = NULL, *end = NULL;
+ size_t len = 0;
+ unsigned long long n, num;
+ struct thread_data_t *param = (struct thread_data_t *) arg;
+ struct fv_app_search_61_t *app =
+ (struct fv_app_search_61_t *) param->data;
+
+ long long s[3][3];
+
+ while (1)
+ {
+ //go get the next progression to work on
+ if (app->threads > 1)
+ pthread_mutex_lock (&read_lock);
+
+ if (app->in_binary)
+ {
+ size_t read = fread (&n, sizeof (unsigned long long), 1, app->infile);
+ if (read != 1)
+ {
+ if (app->threads > 1)
+ pthread_mutex_unlock (&read_lock);
+ break;
+ }
+ }
+ else
+ {
+ ssize_t read = fv_getline (&line, &len, app->infile);
+ if (read == -1)
+ {
+ if (app->threads > 1)
+ pthread_mutex_unlock (&read_lock);
+ break;
+ }
+ num = strtoull (line, &end, 10);
+ }
+ n = num;
+
+ if (app->threads > 1)
+ pthread_mutex_unlock (&read_lock);
+
+ //now we work on n
+ {
+ s[1][1] = n;
+ generate_progressions (app, n, &s);
+ }
+ }
+
+ if (line)
+ free (line);
+ return NULL;
+}
+
+int
+fituvalu_search_61 (struct fv_app_search_61_t *app)
+{
+ run_threads (app, app->threads, process_record);
+ return 0;
+}
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct fv_app_search_61_t *app = (struct fv_app_search_61_t *) state->input;
+ switch (key)
+ {
+ case 'i':
+ app->in_binary = 1;
+ break;
+ case ARGP_KEY_ARG:
+ if (app->num_args == 2)
+ argp_error (state, "too many arguments");
+ else
+ {
+ app->infile = fopen (arg, "r");
+ if (!app->infile)
+ argp_error (state, "could not open `%s' for reading");
+ app->num_args++;
+ }
+ break;
+ case 't':
+ app->threads = atoi (arg);
+ break;
+ case 'p':
+ app->progress = 1;
+ break;
+ case ARGP_KEY_INIT:
+ setenv ("ARGP_HELP_FMT", "no-dup-args-note", 1);
+ break;
+ }
+ return 0;
+}
+
+static struct argp_option
+options[] =
+{
+ { "in-binary", 'i', 0, 0, "Input raw unsigned long longs instead of text"},
+ { "threads", 't', "NUM", 0, "Spread the work across NUM threads"},
+ { "progress", 'p', 0, OPTION_HIDDEN, "Show progress information in /tmp"},
+ { 0 }
+};
+
+static struct argp
+argp =
+{
+ options, parse_opt, "[FILE]",
+ "Find 3x3 magic squares of the type 6:1:7 given a FILE containing center values.\vWhen FILE is not provided, it is read from the standard input. This program is limited to 64-bit integers. Magic squares of type 6:1:7 have the following layout of squares vs non-squares:\n"
+" +---+---+---+ +---+---+---+\n"
+" | | | X | | | | 8 | 2,5,8 is a three square progression where\n"
+" +---+---+---+ +---+---+---+ 5 comes from FILE. Start iterating 1\n"
+" | | X | X | | | 5 | 1 | upwards until 2. Squares at 2 and 6 shake\n"
+" +---+---+---+ +---+---+---+ out.\n"
+" | X | X | X | | 2 | 6 | 7 |\n"
+" +---+---+---+ +---+---+---+\n"
+"This program finds 6:1:5, 6:1:6, 6:1:7 and 6:1:8.",
+ 0
+};
+
+int
+main (int argc, char **argv)
+{
+ struct fv_app_search_61_t app;
+ memset (&app, 0, sizeof (app));
+ app.threads = 1;
+ app.infile = stdin;
+ app.out = stdout;
+ argp_parse (&argp, argc, argv, 0, 0, &app);
+ if (app.progress)
+ fv_init_log (&lg, "search-61s1-small");
+ return fituvalu_search_61 (&app);
+}
diff --git a/src/search-63s1-small.c b/src/search-63s1-small.c
index 191014c..d9d9052 100644
--- a/src/search-63s1-small.c
+++ b/src/search-63s1-small.c
@@ -167,7 +167,6 @@ search_631 (struct fv_app_search_631_t *app, unsigned long long int n)
s[1][2] = sum - s[0][2] - s[2][2];
if (small_is_square (s[1][2]))
{
- s[0][1] = sum - s[0][0] - s[0][2];
s[2][1] = sum - s[2][0] - s[2][2];
pthread_mutex_lock (&display_lock);
fprintf (app->out,