diff options
| author | Ben Asselstine <[email protected]> | 2024-02-20 12:48:08 -0500 |
|---|---|---|
| committer | Ben Asselstine <[email protected]> | 2024-02-20 12:48:08 -0500 |
| commit | b3063cf84bc545bf2d0d8bd7dcace43d043219ac (patch) | |
| tree | 4d3d80f2bf128f271453447b564153fc97ac7a54 | |
| parent | 3d0db784d07042fff6eebfa75037eb4d944ce57d (diff) | |
| download | fituvalu-master.tar.gz | |
| -rw-r--r-- | src/Makefile.am | 10 | ||||
| -rw-r--r-- | src/search-61s1-small.c | 329 | ||||
| -rw-r--r-- | src/search-61s2-small.c | 323 | ||||
| -rw-r--r-- | src/search-61s7-small.c | 319 | ||||
| -rw-r--r-- | src/search-63s1-small.c | 1 |
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, ¶m[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, ¶m[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, ¶m[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, |
