Depth-first search for multiplicative sequences

From Polymath Wiki
Revision as of 04:16, 6 February 2010 by Alec (talk | contribs) (New page: This C program performs depth-first search for multiplicative sequences. In the source code, define N to be the limit of your search and C to be the limit on discrepancy. You also need to...)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

This C program performs depth-first search for multiplicative sequences.

In the source code, define N to be the limit of your search and C to be the limit on discrepancy. You also need to set MAX_N_PRIMES and MAX_N_DIVISORS (but you'll be prompted to do so if they aren't high enough).

The initial mapping of primes (f) is set within the main program: edit to taste! f[i] = true means that f maps the ith prime to -1, where the 0th prime is 2.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifndef _WIN32
# include <stdbool.h>
#else
# define bool char
# define true 1
# define false 0
#endif

#define N 3000 // limit of search
#define MAX_N_PRIMES 600
#define MAX_N_DIVISORS 600
#define C 3 // limit on sums

static unsigned int primes[MAX_N_PRIMES];
static unsigned int n_primes;
static bool is_prime[N+1];
static bool a[N+1][MAX_N_PRIMES]; // table of factorizations
static unsigned int s[N+1][MAX_N_DIVISORS]; // s[n] = list of divisors of n
static unsigned int l[N+1]; // l[n] = number of divisors of n

static bool f[MAX_N_PRIMES], g[MAX_N_PRIMES]; // f = initital values, g = values under test, true = sends to -1
static char x[N+1]; // sequence under test
static tot[N+1]; // totals table

static void seq(unsigned int M) { // calculate x corresponding to g, up to and including M
    unsigned int n, i;
    bool *fact;
    char v = 1;
    for (n = 1; n <= M; n++) {
        fact = a[n];
        for (i = 0; i < n_primes; i++) if (fact[i] && g[i]) v = -v;
        x[n] = v;
    }
}

static bool update_x(unsigned int i) { // update x from primes[i] to primes[i+1]-1, if discrep OK, return false if not
    bool ok = true;
    bool *fact;
    char v;
    unsigned int p1 = primes[i+1];
    unsigned int n = primes[i];
    unsigned int j;
    char tt;
    while ((n < p1) && ok) {
        fact = a[n];
        v = 1;
        for (j = 0; j <= i; j++) if (fact[j] && g[j]) v = -v;
        x[n] = v;
        tt = tot[n-1] + x[n];
        if (abs(tt) <= C) tot[n] = tt;
        else ok = false;
        n++;
    }
    return ok;
}

static void print_seq(FILE *fp, char *seq, unsigned int n) {
    unsigned int j;
    fprintf(fp, "\n ");
    for (j = 1; j<=n; j++) {
        fprintf(fp, "%s", (seq[j] == 1) ? "+" : "-");
        if (j%81==0) fprintf(fp, "\n ");
    }
    fprintf(fp, "\n");
}

static bool check(char *seq, unsigned int n) {
    bool ok = true;
    unsigned int d = 1;
    while ((d <= n) && ok) {
        unsigned int i = d;
        char tot = 0;
        while ((i <= n) && ok) {
            tot += seq[i];
            if (abs(tot) > C) ok = false;
            i += d;
        }
        d++;
    }
    return ok;
}

int main(int argc, char *argv[]) {
    unsigned int i, max_i, min_back, max_fwd, next_g_i, n1, i0;
    bool hope, ok, more;
    { // use Eratosthenes to find primes up to N
        unsigned int p = 2;
        bool ok = true;
        unsigned int i, index;

        is_prime[0] = false;
        is_prime[1] = false;
        for (i = 2; i<=N; i++) is_prime[i] = true;
        while (ok) {
            unsigned int i, q;
            bool found;
            for (i = 2*p; i <= N; i += p) is_prime[i] = false;
            q = p+1;
            found = false;
            while ((q <= N) && !found) {
                if (is_prime[q]) {
                    found = true;
                    p = q;
                    n_primes++;
                }
                q++;
            }
            if (!found) ok = false;
        }
        if (n_primes > MAX_N_PRIMES) {
            fprintf(stderr, "Aborting. Increase MAX_N_PRIMES to at least %d.\n", n_primes);
            return -1;
        }
        index = 0;
        for (i = 2; i <= N; i++) {
            if (is_prime[i]) {
                primes[index] = i;
                index++;
            }
        }
    }

    { // initialize divisors table
        unsigned int n, d;
        for (n = 1; n <= N; n++) {
            unsigned int d_count = 0;
            for (d = 1; d <= N; d++) {
                if ((n%d) == 0) {
                    if (d_count > MAX_N_DIVISORS) {
                        fprintf(stderr, "Aborting. Increase MAX_N_DIVISORS to at least %d (n = %d).\n", d_count, n);
                        return -1;
                    }
                    s[n][d_count] = d;
                    d_count++;
                }
            }
            l[n] = d_count;
        }
    }

    { // make table of factorizations
        unsigned int n;
        for (n = 1; n <= N; n++) {
            unsigned int i, k = n;
            for (i = 0; i < n_primes; i++) {
                unsigned int p = primes[i];
                bool v = false;
                while (k % p == 0) {
                    v = !v;
                    k /= p;
                }
                a[n][i] = v;
            }
        }
    }
    { // set initial values of f, g, x
        unsigned int i, p;
        for (i = 0; i < n_primes; i++) {
            p = primes[i];
            if (p==3) f[i] = true;
            else f[i] = (p%3==2);
            if ((p==709) || (p==881) || (p==1201) || (p==1697) || (p==1999) || (p==2837) || (p==3323) || (p==3457)) f[i] = !f[i];
        }
        for (i = 0; i < n_primes; i++) g[i] = f[i];
        seq(N);
    }

    { // initialize totals table, t[n] = x[1]+x[2]+...+x[n]
        unsigned int n;
        for (n = 0; n <= N; n++) tot[n] = 0;
        tot[1] = x[1];
    }
    i = 0;
    max_i = 0;
    min_back = 0;
    max_fwd = 0;
    hope = true;
    while ((i < n_primes) && hope) {
        if (i < min_back) {
            min_back = i;
            max_fwd = min_back;
            printf("%d ", primes[min_back]);
            fflush(stdout);
        }
        ok = update_x(i);
        if (!ok) {
            if (g[i] == f[i]) {
                g[i] = !f[i];
                ok = update_x(i);
            }
        }
        if (ok) {
            //if (i > max_fwd) {
            //    max_fwd = i;
            //    printf(" %d", i);
            //}
            if (i > max_i) {
                max_i = i;
                min_back = max_i;
                n1 = primes[i+1]-1;
                printf("\n\nmax_i = %d\n", max_i);
                printf("max_n = %d\n", n1);
                printf("verify: %s\n", check(x, n1) ? "pass" : "fail");
                print_seq(stdout, x, n1);
                printf("primes sent to -1:\n");
                for (i0 = 0; i0 <= i; i0++) if (g[i0]) printf("%d, ", primes[i0]);
                printf("\n\nbacktracking...\n");
            }
            i++;
        }
        else /* backtrack */{
            while (g[i] == !f[i]) {
                g[i] = f[i];
                i--;
            }
            g[i] = !f[i];
            if ((i == 0) && (g[i] == f[i])) hope = false;
        }
    }
    printf("\n\nEND\n");
    return 0;
 }