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

// Find all decompositions in KFGZ - {0} of the form o = p join q.

// 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, **fam, a;
    int         j, k, l, space = 0;
    int      ***decomp;
    char      **set;

// Cardinality 7 suffices.

    int         spacesize = 7;

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

    KFGZ       *kfgz = CreateKFGZ(spacesize);

    set = (char **)malloc(20 * sizeof(char *));
    if (set==0)
    {
        printf("\nCould not allocate space for set.\n");
        exit(0);
    }

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

    decomp = (int ***)malloc(20 * sizeof(int *));
    if (decomp==0)
    {
        printf("\nCould not allocate space for decomp.\n");
        exit(0);
    }

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

        fam[j] = (uint32_t *)malloc((one<<spacesize) * sizeof(uint32_t));
        if (fam[j]==0)
        {
            printf("\nCould not allocate space for fam[%d].\n", j);
            exit(0);
        }
        decomp[j] = (int **)malloc(20 * sizeof(int *));
        if (decomp[j]==0)
        {
            printf("\nCould not allocate space for decomp[%d].\n", j);
            exit(0);
        }
        for (k=0; k<20; k++)
        {
            fam[j][k] = 0;
            decomp[j][k] = (int *)malloc(20 * sizeof(int));
            if (decomp[j][k]==0)
            {
                printf("\nCould not allocate space for decomp[%d][%d].\n", j, k);
                exit(0);
            }
            for (l=0; l<20; l++) decomp[j][k][l] = 1;
        }
    }

    KFGZlabels(set);

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

    input = fopen("7-spaces.txt", "r");
    if (input==0)
    {
        printf("\nCould not open file 7-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 KFGZ(A) for every A in X and store the result in fam.

        ComputeKFGZarray(fam, kfgz, spacesize, point_closures);

// Rule out every operator equation o = p join q in KFGZ - {0} that fails to hold.

        for (a=0; a<(one<<spacesize); a++)
        {
            for (j=0; j<19; j++)
                for (k=0; k<19; k++)
                {

// If fam[j][a]&fam[k][a] != 0 then fam[j][a]|fam[k][a] is not a decomposition.

                    if (fam[j][a]&fam[k][a])
                    {
                        for (l=0; l<19; l++) decomp[l][j][k] = 0;
                    }

// Otherwise it is a candidate, but if it fails to equal fam[l][a] we rule it out.

                    for (l=0; l<19; l++)
                    {
                        if (fam[l][a] != (fam[j][a]|fam[k][a])) decomp[l][j][k] = 0;
                    }
                }
        }

// Advance the while counter.

        space++;
    }

    printf("\n\n");

// Print all nontrivial equations that were not ruled out above.

    for (j=0; j<19; j++)
        for (k=0; k<18; k++)
            for (l=k+1; l<19; l++)
            {
                if (!decomp[j][k][l]) continue;
                if (j == k || j == l) continue;
                printf("%s = %s join %s\n", set[j], set[k], set[l]);
            }

    fclose(input);
    for (j=0; j<20; j++)
    {
        for (k=0; k<20; k++) free(decomp[j][k]);
        free(decomp[j]);
        free(set[j]);
        free(fam[j]);
    }
    free(decomp);
    free(set);
    free(fam);
    free(point_closures);
    FreeKFGZ(kfgz);
    printf("\n");
    return EXIT_SUCCESS;
}
