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

// Investigate Kleiner's OU example in the footnote on page 12.

// 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"
#include    "topologies.h"


int main(int argc, const char * argv[])
{
    uint32_t   *point_closures;
    int       **closures, **base, *psi_number;
    int         j, k, max_spacesize = 11;
    char      **spacetype;

// These structs store KZ(A) and KFZ(A) for all A in X.

    KFZ        *kfz = CreateKFZ(max_spacesize);
    KZ         *kz = CreateKZ(max_spacesize);

// Sets are represented by unsigned 32-bit integers with leading zeros.

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

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

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

    psi_number = (int *)malloc(71 * sizeof(int));
    if (psi_number==0)
    {
        printf("\nCould not allocate space for psi_number.\n");
        exit(0);
    }
    for (j=0; j<71; j++) psi_number[j] = 0;

    for (j=0; j<max_spacesize; j++)
    {
        base[j] = (int *)malloc(max_spacesize * sizeof(int));
        if (base[j]==0)
        {
            printf("\nCould not allocate space for base[%d].\n", j);
            exit(0);
        }
        closures[j] = (int *)malloc(max_spacesize * sizeof(int));
        if (closures[j]==0)
        {
            printf("\nCould not allocate space for closures[%d].\n", j);
            exit(0);
        }
        for (k=0; k<max_spacesize; k++)
        {
            base[j][k] = 1;
            closures[j][k] = 1;
        }
        point_closures[j] = 0;
    }

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

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

// Kleiner's OU example X = {a,a',b,b',c} only works if his "topological basis"
// {{c},{b,c},{b',c},{a,b,c},{a',b',c}} is assumed to be the set of closures of
// singletons instead.  Under this assumption the set {a,b',c} generates 20 sets under
// closure, complement, and boundary.  When the set above is taken as a basis instead,
// an EO space results, the k_f-number of which is necessarily less than 20.

    static const int kleiner[5][5] = {
                                {1,0,1,0,1},
                                {0,1,0,1,1},
                                {0,0,1,0,1},
                                {0,0,0,1,1},
                                {0,0,0,0,1}};

    for (j=0; j<5; j++) memcpy(base[j],kleiner[j],sizeof(kleiner[j]));

// First we interpret the rows of kleiner[][] as base sets.

    BaseToPointClosures(base, closures, point_closures, 5);
    ComputeKZ(kz, 5, point_closures);
    k = Kur(kz, 5);

    strcpy(spacetype[1],"D");
    strcpy(spacetype[2],"P");
    strcpy(spacetype[3],"EO");
    strcpy(spacetype[4],"ED");
    strcpy(spacetype[5],"OU");
    strcpy(spacetype[6],"Kuratowski");

    printf("\nIf we assume Kleiner's set is a base we get an %s space.\n", spacetype[k]);

// Now interpret the rows as closures of singletons instead.

    MatrixToPointClosures(base, point_closures, 5);
    ComputeKZ(kz, 5, point_closures);
    k = Kur(kz, 5);

    printf("\nAn %s space results if it has the closures of singletons instead.\n", spacetype[k]);

// The set {a,b',c} is represented by the binary integer 11001 (25 in decimal).
// We now verify it has psi-number 39. 

    ComputeKFZ(kfz, 5, point_closures);
    k = Psi(25, 5, kfz);

    printf("\nThe set {a,b',c} has psi-number %d, giving it a k_f-number of 20.\n", k);

    for (j=0; j<max_spacesize; j++)
    {
        free(base[j]);
        free(closures[j]);
    }
    free(base);
    free(closures);
    free(point_closures);
    free(psi_number);
    for (j=0; j<7; j++) free(spacetype[j]);
    free(spacetype);
    FreeKFZ(kfz);
    FreeKZ(kz);
    printf("\n");
    return EXIT_SUCCESS;
}
