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

// Find connected space (when possible) and minimal cardinality for each psi-number.

// 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 = NULL;
    uint32_t   *point_closures, set;
    int         j, spacesize, space, connected, con[71] = {0};
    int         psi_min[71] = {0}, psi[256] = {0};
    KFZ       **kfz;

// Allocate memory for the struct that stores KFZ(A) for all A in X.

    kfz = (KFZ **)malloc(9 * sizeof(KFZ *));
    if (kfz==0)
    {
        printf("\nCould not allocate space for kfz.\n");
        exit(0);
    }
    for (spacesize = 0; spacesize < 9; spacesize++)
    {
        if (spacesize < 2)
        {
            kfz[spacesize] = NULL;
            continue;
        }
        kfz[spacesize] = CreateKFZ(spacesize);
    }

// 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);
    }

// The input file contains all nonhomeomorphic spaces.

    for (spacesize = 2; spacesize < 9; spacesize++)
    {
        switch (spacesize)
        {
            case 2:
                input = fopen("2-spaces.txt", "r");
                if (input==0)
                {
                    printf("\nCould not open file 2-spaces.txt for input.\n");
                    exit(0);
                }
                break;
            case 3:
                input = fopen("3-spaces.txt", "r");
                if (input==0)
                {
                    printf("\nCould not open file 3-spaces.txt for input.\n");
                    exit(0);
                }
                break;
            case 4:
                input = fopen("4-spaces.txt", "r");
                if (input==0)
                {
                    printf("\nCould not open file 4-spaces.txt for input.\n");
                    exit(0);
                }
                break;
            case 5:
                input = fopen("5-spaces.txt", "r");
                if (input==0)
                {
                    printf("\nCould not open file 5-spaces.txt for input.\n");
                    exit(0);
                }
                break;
            case 6:
                input = fopen("6-spaces.txt", "r");
                if (input==0)
                {
                    printf("\nCould not open file 6-spaces.txt for input.\n");
                    exit(0);
                }
                break;
            case 7:
                input = fopen("7-spaces.txt", "r");
                if (input==0)
                {
                    printf("\nCould not open file 7-spaces.txt for input.\n");
                    exit(0);
                }
                break;
            case 8:
                input = fopen("8-spaces.txt", "r");
                if (input==0)
                {
                    printf("\nCould not open file 8-spaces.txt for input.\n");
                    exit(0);
                }
        }

        space = 0;
        while (space < spaces[spacesize])
        {

// Each line of input has the closure of every singleton.  These can alternatively be
// regarded as smallest open neighborhoods.  Either interpretation yields all
// nonhomeomorphic spaces of cardinality = spacesize, but any given line does not
// in general produce the same space under the two.

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

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

// We need KFZ(A) to get psi(A), so we compute it for every A in X.

            ComputeKFZ(kfz[spacesize],spacesize,point_closures);

// We find the psi-number of every subset in X and set psi_min[psi] = spacesize if new.

            connected = 1;
            for (set=0; set<(one<<spacesize); set++)
            {
                psi[set] = Psi(set,spacesize,kfz[spacesize]);
                if (psi[set] == 68) connected = 0;
                if (psi_min[psi[set]]) continue;
                psi_min[psi[set]] = spacesize;
            }
            if (connected)
            {
                for (set=0; set<(one<<spacesize); set++) con[psi[set]] = 1;
            }
            space++;
        }
        fclose(input);
    }

// Print the results.

    printf("\nMinimal cardinalities for each psi-number appear below up to duality.");
    printf("\nThose that failed to appear in any connected space have an asterisk.\n\n1: 69");

    for (spacesize = 2; spacesize < 9; spacesize++)
    {
        printf("\n%d: ", spacesize);
        for (j=0; j<42; j++)
        {
            if (psi_min[canonical_psi_number[j]] == spacesize)
            {
                printf("%d", canonical_psi_number[j]);
                if (con[canonical_psi_number[j]]) printf(" ");
                else printf("* ");
            }
        }
    }
    printf("\n\n");

    free(point_closures);
    for (spacesize = 2; spacesize < 9; spacesize++) FreeKFZ(kfz[spacesize]);
    free(kfz);
}
