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

// Count local orderings of KFGZ.

// 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  **kfgz_array, *point_closures, set;
    int      ***inequalities, space, spacesize, max_spacesize = 10;
    int         flag = 0, j, k, m;
    int         count[10] = {0};
    KFGZ      **kfgz;

    kfgz_array = (uint32_t **)malloc(20 * sizeof(uint32_t *));
    if (kfgz_array==0)
    {
        printf("\nCould not allocate space for kfgz_array.\n");
        exit(0);
    }
    for (j=0; j<20; j++)
    {
        kfgz_array[j] = (uint32_t *)malloc((one<<max_spacesize) * sizeof(uint32_t));
        if (kfgz_array[j]==0)
        {
            printf("\nCould not allocate space for kfgz_array[%d].\n", j);
            exit(0);
        }
        for (k=0; k<(one<<max_spacesize); k++) kfgz_array[j][k] = 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(max_spacesize * sizeof(uint32_t));
    if (point_closures==0)
    {
        printf("\nCould not allocate space for point_closures.\n");
        exit(0);
    }

    inequalities = (int ***)malloc(700 * sizeof(int **));
    if (inequalities==0)
    {
        printf("\nCould not allocate space for inequalities.\n");
        exit(0);
    }
    for (j=0; j<700; j++)
    {
        inequalities[j] = (int **)malloc(20 * sizeof(int *));
        if (inequalities[j]==0)
        {
            printf("\nCould not allocate space for inequalities[%d].\n", j);
            exit(0);
        }
        for (k=0; k<20; k++)
        {
            inequalities[j][k] = (int *)malloc(20 * sizeof(int));
            if (inequalities[j][k]==0)
            {
                printf("\nCould not allocate space for inequalities[%d][%d].\n", j, k);
                exit(0);
            }
            for (m=0; m<20; m++) inequalities[j][k][m] = 0;
        }
    }

    kfgz = (KFGZ **)malloc(max_spacesize * sizeof(KFGZ *));
    if (kfgz==0)
    {
        printf("\nCould not allocate space for kfgz.\n");
        exit(0);
    }

    for (spacesize = 0; spacesize < max_spacesize; spacesize++)
    {
        if (spacesize < 2)
        {
            kfgz[spacesize] = NULL;
            continue;
        }
        kfgz[spacesize] = CreateKFGZ(spacesize);
    }

// The input file contains all nonhomeomorphic spaces.

    for (spacesize = 2; spacesize < max_spacesize; 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);
                }
                break;
            case 9:
                input = fopen("9-spaces.txt", "r");
                if (input==0)
                {
                    printf("\nCould not open file 9-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]);

// Need KFZ(A) for all A in X to get the k- and k_f-numbers of X.

            ComputeKFGZ(kfgz[spacesize],spacesize,point_closures);
            CopyKFGZarray(kfgz_array,kfgz[spacesize],spacesize);

// Use the local ordering on the empty set to initialize inequalities[count].

            if (!space)
            {
                for (j=0; j<20; j++)
                    for (k=0; k<20; k++)
                        if (Subset(kfgz_array[j][0],kfgz_array[k][0])) inequalities[count[spacesize]][j][k] = 1;
                count[spacesize]++;
            }

            for (set=1; set<(one<<spacesize); set++)
            {
                for (j=0; j<20; j++)
                    for (k=0; k<20; k++)
                        inequalities[count[spacesize]][j][k] = 0;
                for (j=0; j<20; j++)
                    for (k=0; k<20; k++)
                        if (Subset(kfgz_array[j][set],kfgz_array[k][set])) inequalities[count[spacesize]][j][k] = 1;
                for (m=0; m<count[spacesize]; m++)
                {
                    for (j=0; j<20; j++)
                    {
                        k = 0;
                        while (k < 20)
                        {
                            if (inequalities[count[spacesize]][j][k] != inequalities[m][j][k]) break;
                            k++;
                        }
                        if (k < 20)
                        {
                            flag = 1;
                            break;
                        }
                    }
                    if (flag)
                    {
                        flag = 0;
                        continue;
                    }
                    break;  // if we get to here it means the local ordering is not new
                }
                if (m == count[spacesize]) count[spacesize]++;
            }
            space++;
        }
        fclose(input);
    }

    printf("\nNumber of local orderings of KFGZ admitted by spaces of cardinality n for n=2,...,9:\n\n");
    for (spacesize = 2; spacesize < max_spacesize; spacesize++) printf("%d ", count[spacesize]);

    free(point_closures);
    for (j=0; j<700; j++)
    {
        for (k=0; k<20; k++) free(inequalities[j][k]);
        free(inequalities[j]);
    }
    free(inequalities);
    for (j=0; j<20; j++) free(kfgz_array[j]);
    free(kfgz_array);
    for (j=2; j<max_spacesize; j++) FreeKFGZ(kfgz[j]);
    free(kfgz);
    printf("\n\n");
    return EXIT_SUCCESS;
}
