// main.c
// Copyright (C) 2023 Mark Bowron

// Find 34-sets that prove the sharpness of Proposition 3.

// 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.


#include    <stdio.h>
#include    <stdlib.h>
#include    <inttypes.h>
#include    <stdbool.h>
#include    <string.h>
#include    "set_operators.h"
#include    "set_families.h"
#include    "set_relations.h"
#include    "collapses.h"


int main(int argc, const char * argv[])
{
    FILE       *input;
    uint32_t   *point_closures, set;
    int         inequality[10] = {0};           
    int         j, product, psi, space = 0;

// The smallest cardinality that works is 9 (the program takes a few minutes to run).

    int         spacesize = 9;

// This struct stores KFZ(A) for all A in X.

    KFZ        *kfz = CreateKFZ(spacesize);

// The input file contains all nonhomeomorphic spaces on 9 points.

    input = fopen("9-spaces.txt", "r");
    if (input==0)
    {
        printf("\nCould not open file 9-spaces.txt.\n");
        exit(0);
    }

// Sets are represented by unsigned 32-bit binary integers with leading zeros.
// Assuming X = {0,1,...,n-1} the element k is in A iff the coefficient of 2^k in the
// binary integer representing A is 1 (i.e., the bits of the binary integer representing
// A are in reverse order compared to X).

    point_closures = (uint32_t *)malloc(spacesize * sizeof(uint32_t));
    if (point_closures==0)
    {
        printf("\nCould not allocate space for point_closures.\n");
        exit(0);
    }

    while (space < spaces[spacesize])
    {

// Each line of input lists the closure of every singleton.  (These integers can
// alternatively be interpreted as smallest open neighborhoods.  Either interpretation
// yields all nonhomeomorphic spaces of cardinality = spacesize at the file level, but a
// given line does not in general yield the same space.)

// Read the current line of input into the point_closures array.

        for (j=0; j<spacesize; j++) fscanf(input, "%" PRIu32, &point_closures[j]);

// Compute KFZ(A) for every A in X and store the result in kfz.

        ComputeKFZ(kfz,spacesize,point_closures);

        for (set=0; set<(one<<spacesize); set++)
        {
            psi = Psi(set,spacesize,kfz);
            if (psi > 1) continue;

// We now have a GE 34-set.  Does it satisfy exactly one of the following inequalities?

// 1 fib < fif
// 2 fif < fbi
// 3 fbi < fib
// 4 fib < id
// 5 fif < id
// 6 fbi < id
// 7 fib < a
// 8 fif < a
// 9 fbi < a

            product = 1;

// OEIS sequence A026477 is used below to ensure that no product of two or more terms can
// equal any of the nine original ones (the first nine primes would also suffice).

            if (Subset(kfz->_fib[set],kfz->_fif[set])) product = 2;
            if (Subset(kfz->_fif[set],kfz->_fbi[set])) product = product * 3;
            if (Subset(kfz->_fbi[set],kfz->_fib[set])) product = product * 4;
            if (Subset(kfz->_fib[set],set)) product = product * 5;
            if (Subset(kfz->_fif[set],set)) product = product * 7;
            if (Subset(kfz->_fbi[set],set)) product = product * 9;
            if (Subset(kfz->_fib[set],Comp(set, spacesize))) product = product * 11;
            if (Subset(kfz->_fif[set],Comp(set, spacesize))) product = product * 13;
            if (Subset(kfz->_fbi[set],Comp(set, spacesize))) product = product * 16;

            switch (product)
            {
                case 2:
                    inequality[1] = 1;
                    break;
                case 3:
                    inequality[2] = 1;
                    break;
                case 4:
                    inequality[3] = 1;
                    break;
                case 5:
                    inequality[4] = 1;
                    break;
                case 7:
                    inequality[5] = 1;
                    break;
                case 9:
                    inequality[6] = 1;
                    break;
                case 11:
                    inequality[7] = 1;
                    break;
                case 13:
                    inequality[8] = 1;
                    break;
                case 16:
                    inequality[9] = 1;
                    break;
            }
        }

// Advance the while counter.

        space++;
    }

    printf("\n");

// If inequality[j] = 1 for j = 1 to 9 then Proposition 3 is sharp.

    for (j=1; j<10; j++)
    {
        if (!inequality[j])
        {
            printf("Failure: execution aborted.\n\n");
            exit(0);
        }
    }
    printf("\nProposition 3 is sharp since for each inequality a 34-set\n");
    printf("exists that satisfies it and only it among the nine.\n");

    fclose(input);
    free(point_closures);
    FreeKFZ(kfz);
    printf("\n");
    return EXIT_SUCCESS;
}
