// collapses.h
// Copyright (C) 2023 Mark Bowron

// Compute Kuratowski/GE monoids and phi- and psi-numbers.

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

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

int     Kur(KZ *fam, int spacesize);
// compute the Kuratowski monoid K given KZ(A) for all A in X.

// Kur()    space type
// -----    ----------
// 1        D
// 2        P
// 3        EO
// 4        ED
// 5        OU
// 6        Kuratowski

int     GE(KZ *fam, int spacesize, uint32_t *point_closures);
// If Kur() returns 6 (Kuratowski) then check whether fif = 0.
// point_closures is needed for Bdry().

// GE()     space type
// ----     ----------
// 1-5      see Kur()
// 6        GE
// 7        KD

int     Phi(uint32_t set, KZ *fam);
// compute phi(set) given KZ(A) for all A in X.

int     PhiArray(int **equals, KZenum *fam);
// compute phi(set) given all equations in KZ(set).

int     Psi(uint32_t set, int spacesize, KFZ *fam);
// compute psi(set) given KFZ(A) for all A in X.

int     PsiArray(int **equals, KFenum *fam);
// compute psi-number given all equations in KF(set).

int     PsiArrayKFZ(int **equals, KFZenum *fam);
// compute non-dense psi-number given all equations in KFZ(set).


int Kur(KZ *fam, int spacesize)
{
    if (OpEquals(fam->_b,fam->_bib,spacesize))
    {
        if (OpEquals(fam->_bi,fam->_bib,spacesize)) return 1;
        else                                        return 2;
    }
    if (OpEquals(fam->_ib,fam->_bib,spacesize))
    {
        if (OpEquals(fam->_bi,fam->_bib,spacesize)) return 3;
        else                                        return 4;
    }
    if (OpEquals(fam->_bi,fam->_bib,spacesize))     return 5;
    else                                            return 6;
}


int GE(KZ *fam, int spacesize, uint32_t *point_closures)
{
    uint32_t    fif, j;
    int         kur = Kur(fam,spacesize);
    if (kur < 6) return kur;
    for (j=0; j<(one<<spacesize); j++)
    {
        fif = Bdry(j,spacesize,point_closures);
        fif = fam->_i[fif];
        if (Bdry(fif,spacesize,point_closures))     return 6;
    }
                                                    return 7;
}


int Phi(uint32_t set, KZ *fam)
{
    if (fam->_i[set] == fam->_b[set])           return 30;
    if (fam->_ibi[set] == fam->_b[set])
    {
        if (set == fam->_i[set])                return 28;
                                                return 22;
    }
    if (fam->_bib[set] == fam->_i[set])
    {
        if (set == fam->_b[set])                return 29;
                                                return 23;
    }
    if (fam->_ib[set] == fam->_i[set])
    {
        if (set == fam->_i[set])                return 27;
        if (set == fam->_b[set])
        {
            if (set == fam->_bi[set])           return 26;
                                                return 21;
        }
        if (fam->_bi[set] == fam->_b[set])      return 24;
                                                return 19;
    }                                                                           
    if (fam->_bi[set] == fam->_i[set])
    {
        if (fam->_ib[set] == fam->_b[set])      return 25;
        if (fam->_bib[set] == fam->_b[set])     return 15;
        if (fam->_bib[set] == fam->_ib[set])    return 17;
                                                return 10;
    }
    if (fam->_bi[set] == fam->_b[set])
    {
        if (set == fam->_i[set])                return 20;
                                                return 18;
    }
    if (fam->_ib[set] == fam->_b[set])
    {
        if (fam->_ibi[set] == fam->_i[set])     return 14;
        if (fam->_ibi[set] == fam->_bi[set])    return 16;
                                                return 9;
    }
    if (fam->_ib[set] == fam->_bi[set])         return 13;
    if (fam->_ibi[set] == fam->_i[set])
    {
        if (fam->_bib[set] == fam->_b[set])     return 6;
        if (fam->_bib[set] == fam->_ib[set])    return 7;
                                                return 3;
    }
    if (fam->_ibi[set] == fam->_bi[set])
    {
        if (fam->_bib[set] == fam->_b[set])     return 8;
        if (fam->_bib[set] == fam->_ib[set])    return 11;
                                                return 5;
    }
    if (fam->_ibi[set] == fam->_ib[set])        return 12;
    if (fam->_bib[set] == fam->_b[set])         return 2;
    if (fam->_bib[set] == fam->_ib[set])        return 4;
                                                return 1;
}


int PhiArray(int **equals, KZenum *fam)
{
    if (equals[fam->_i][fam->_b])           return 30;
    if (equals[fam->_ibi][fam->_b])
    {
        if (equals[fam->_id][fam->_i])      return 28;
                                            return 22;
    }
    if (equals[fam->_bib][fam->_i])
    {
        if (equals[fam->_id][fam->_b])      return 29;
                                            return 23;
    }
    if (equals[fam->_ib][fam->_i])
    {
        if (equals[fam->_id][fam->_i])      return 27;
        if (equals[fam->_id][fam->_b])
        {
            if (equals[fam->_id][fam->_bi]) return 26;
                                            return 21;
        }
        if (equals[fam->_bi][fam->_b])      return 24;
                                            return 19;
    }                                                                           
    if (equals[fam->_bi][fam->_i])
    {
        if (equals[fam->_ib][fam->_b])      return 25;
        if (equals[fam->_bib][fam->_b])     return 15;
        if (equals[fam->_bib][fam->_ib])    return 17;
                                            return 10;
    }
    if (equals[fam->_bi][fam->_b])
    {
        if (equals[fam->_id][fam->_i])      return 20;
                                            return 18;
    }
    if (equals[fam->_ib][fam->_b])
    {
        if (equals[fam->_ibi][fam->_i])     return 14;
        if (equals[fam->_ibi][fam->_bi])    return 16;
                                            return 9;
    }
    if (equals[fam->_ib][fam->_bi])         return 13;
    if (equals[fam->_ibi][fam->_i])
    {
        if (equals[fam->_bib][fam->_b])     return 6;
        if (equals[fam->_bib][fam->_ib])    return 7;
                                            return 3;
    }
    if (equals[fam->_ibi][fam->_bi])
    {
        if (equals[fam->_bib][fam->_b])     return 8;
        if (equals[fam->_bib][fam->_ib])    return 11;
                                            return 5;
    }
    if (equals[fam->_ibi][fam->_ib])        return 12;
    if (equals[fam->_bib][fam->_b])         return 2;
    if (equals[fam->_bib][fam->_ib])        return 4;
                                            return 1;
}


int Psi(uint32_t set, int spacesize, KFZ *fam)
{

    if (fam->_f[set] == (one<<spacesize)-1)         return 61;
    if (fam->_i[set] == fam->_b[set])
    {
        if (fam->_b[set] == 0)                      return 70;
        if (fam->_b[set] == (one<<spacesize)-1)     return 69;
                                                    return 68;
    }

    if (fam->_ibi[set] == fam->_b[set])
    {
        if (fam->_i[set] == set)
        {
            if (fam->_b[set] == (one<<spacesize)-1) return 65;
                                                    return 64;
        }
        if (fam->_b[set] == (one<<spacesize)-1)     return 54;
                                                    return 53;
    }

    if (fam->_i[set] == fam->_bib[set])
    {
        if (fam->_b[set] == set)
        {
            if (fam->_b[set] == fam->_f[set])       return 67;
                                                    return 66;
        }
        if (fam->_b[set] == fam->_f[set])           return 56;
                                                    return 55;
    }

    if (fam->_i[set] == set)
    {
        if (fam->_i[set] == fam->_ib[set])          return 63;
        return 51;
    }

    if (fam->_b[set] == set)
    {
        if (fam->_b[set] == fam->_bi[set])          return 62;
                                                    return 52;
    }

    if (fam->_b[set] == fam->_ib[set])
    {
        if (fam->_i[set] == fam->_bi[set])
        {
            if (fam->_b[set] == (one<<spacesize)-1) return 59;
            if (fam->_i[set] == 0)                  return 60;
                                                    return 58;
        }
        if (fam->_ibi[set] == fam->_bi[set])
        {
            if (fam->_b[set] == (one<<spacesize)-1) return 46;
                                                    return 45;
        }
        if (fam->_ibi[set] == fam->_i[set])
        {
            if (fam->_b[set] == (one<<spacesize)-1) return 42;
                                                    return 41;
        }
        if (fam->_b[set] == (one<<spacesize)-1)     return 35;
                                                    return 34;
    }

    if (fam->_i[set] == fam->_bi[set])
    {
        if (fam->_bib[set] == fam->_ib[set])
        {
            if (fam->_b[set] == fam->_f[set])       return 48;
                                                    return 47;
        }
        if (fam->_bib[set] == fam->_b[set])
        {
            if (fam->_b[set] == fam->_f[set])       return 44;
                                                    return 43;
        }
        if (fam->_b[set] == fam->_f[set])           return 37;
                                                    return 36;
    }

    if (fam->_b[set] == fam->_bi[set])
    {
        if (fam->_i[set] == fam->_ib[set])          return 57;
                                                    return 49;
    }

    if (fam->_i[set] == fam->_ib[set])              return 50;

    if (fam->_bib[set] == fam->_ibi[set])           return 40;

    if (fam->_bib[set] == fam->_bi[set])            return 39;

    if (fam->_bib[set] == fam->_ib[set])
    {
        if (fam->_ibi[set] == fam->_bi[set])        return 38;
        if (fam->_ibi[set] == fam->_i[set])         return 32;
                                                    return 21;
    }

    if (fam->_ibi[set] == fam->_bi[set])
    {
        if (fam->_bib[set] == fam->_b[set])         return 33;
                                                    return 22;
    }

    if (fam->_b[set] == fam->_bib[set])
    {
        if (fam->_i[set] == fam->_ibi[set])
        {
            if (fam->_fif[set] == 0)                return 31;
            if (fam->_fb[set] == fam->_fbi[set])
            {
                if (fam->_f[set] == fam->_bif[set]) return 30;
                                                    return 26;
            }
            if (fam->_ff[set] == fam->_fi[set])
            {
                if (fam->_f[set] == fam->_bif[set]) return 29;
                                                    return 25;
            }
            if (fam->_ff[set] == fam->_fb[set])
            {
                if (fam->_f[set] == fam->_bif[set]) return 28;
                                                    return 24;
            }
            if (fam->_f[set] == fam->_bif[set])     return 27;
                                                    return 23;
        }

        if (fam->_fif[set] == 0)                    return 13;
        if (fam->_fib[set] == fam->_fif[set])
        {
            if (fam->_ff[set] == fam->_fi[set])     return 12;
                                                    return 8;
        }
        if (fam->_fib[set] == fam->_fbi[set])       return 11;
        if (fam->_fbi[set] == fam->_fif[set])       return 10;
        if (fam->_ff[set] == fam->_fi[set])         return 9;
                                                    return 7;
    }

    if (fam->_i[set] == fam->_ibi[set])
    {
        if (fam->_fif[set] == 0)                    return 20;
        if (fam->_fib[set] == fam->_fif[set])
        {
            if (fam->_fbi[set] == fam->_fif[set])   return 19;
                                                    return 17;
        }
        if (fam->_fib[set] == fam->_fbi[set])       return 18;
        if (fam->_fbi[set] == fam->_fif[set])       return 15;
        if (fam->_ff[set] == fam->_fb[set])         return 16;
                                                    return 14;
    }

    if (fam->_fif[set] == 0)                        return 6;
    if (fam->_fib[set] == fam->_fif[set])
    {
        if (fam->_fbi[set] == fam->_fif[set])       return 5;
                                                    return 3;
    }
    if (fam->_fbi[set] == fam->_fif[set])           return 4;
    if (fam->_fib[set] == fam->_fbi[set])           return 2;
                                                    return 1;
}


int PsiArray(int **equals, KFenum *fam)
{
    if (equals[fam->_f][fam->_one])             return 61;
    if (equals[fam->_i][fam->_b])
    {
        if (equals[fam->_b][fam->_zero])        return 70;
        if (equals[fam->_b][fam->_one])         return 69;
                                                return 68;
    }

    if (equals[fam->_ibi][fam->_b])
    {
        if (equals[fam->_i][fam->_id])
        {
            if (equals[fam->_b][fam->_one])     return 65;
                                                return 64;
        }
        if (equals[fam->_b][fam->_one])         return 54;
                                                return 53;
    }

    if (equals[fam->_i][fam->_bib])
    {
        if (equals[fam->_b][fam->_id])
        {
            if (equals[fam->_b][fam->_f])       return 67;
                                                return 66;
        }
        if (equals[fam->_b][fam->_f])           return 56;
                                                return 55;
    }

    if (equals[fam->_i][fam->_id])
    {
        if (equals[fam->_i][fam->_ib])          return 63;
                                                return 51;
    }

    if (equals[fam->_b][fam->_id])
    {
        if (equals[fam->_b][fam->_bi])          return 62;
                                                return 52;
    }

    if (equals[fam->_b][fam->_ib])
    {
        if (equals[fam->_i][fam->_bi])
        {
            if (equals[fam->_b][fam->_one])     return 59;
            if (equals[fam->_i][fam->_zero])    return 60;
                                                return 58;
        }
        if (equals[fam->_ibi][fam->_bi])
        {
            if (equals[fam->_b][fam->_one])     return 46;
                                                return 45;
        }
        if (equals[fam->_ibi][fam->_i])
        {
            if (equals[fam->_b][fam->_one])     return 42;
                                                return 41;
        }
        if (equals[fam->_b][fam->_one])         return 35;
                                                return 34;
    }

    if (equals[fam->_i][fam->_bi])
    {
        if (equals[fam->_bib][fam->_ib])
        {
            if (equals[fam->_b][fam->_f])       return 48;
                                                return 47;
        }
        if (equals[fam->_bib][fam->_b])
        {
            if (equals[fam->_b][fam->_f])       return 44;
                                                return 43;
        }
        if (equals[fam->_b][fam->_f])           return 37;
                                                return 36;
    }

    if (equals[fam->_b][fam->_bi])
    {
        if (equals[fam->_i][fam->_ib])          return 57;
                                                return 49;
    }

    if (equals[fam->_i][fam->_ib])              return 50;

    if (equals[fam->_bib][fam->_ibi])           return 40;

    if (equals[fam->_bib][fam->_bi])            return 39;

    if (equals[fam->_bib][fam->_ib])
    {
        if (equals[fam->_ibi][fam->_bi])        return 38;
        if (equals[fam->_ibi][fam->_i])         return 32;
                                                return 21;
    }

    if (equals[fam->_ibi][fam->_bi])
    {
        if (equals[fam->_bib][fam->_b])         return 33;
                                                return 22;
    }

    if (equals[fam->_b][fam->_bib])
    {
        if (equals[fam->_i][fam->_ibi])
        {
            if (equals[fam->_fif][fam->_zero])  return 31;
            if (equals[fam->_fb][fam->_fbi])
            {
                if (equals[fam->_f][fam->_bif]) return 30;
                                                return 26;
            }
            if (equals[fam->_ff][fam->_fi])
            {
                if (equals[fam->_f][fam->_bif]) return 29;
                                                return 25;
            }
            if (equals[fam->_ff][fam->_fb])
            {
                if (equals[fam->_f][fam->_bif]) return 28;
                                                return 24;
            }
            if (equals[fam->_f][fam->_bif])     return 27;
                                                return 23;
        }

        if (equals[fam->_fif][fam->_zero])      return 13;
        if (equals[fam->_fib][fam->_fif])
        {
            if (equals[fam->_ff][fam->_fi])     return 12;
                                                return 8;
        }
        if (equals[fam->_fib][fam->_fbi])       return 11;
        if (equals[fam->_fbi][fam->_fif])       return 10;
        if (equals[fam->_ff][fam->_fi])         return 9;
                                                return 7;
    }

    if (equals[fam->_i][fam->_ibi])
    {
        if (equals[fam->_fif][fam->_zero])      return 20;
        if (equals[fam->_fib][fam->_fif])
        {
            if (equals[fam->_fbi][fam->_fif])   return 19;
                                                return 17;
        }
        if (equals[fam->_fib][fam->_fbi])       return 18;
        if (equals[fam->_fbi][fam->_fif])       return 15;
        if (equals[fam->_ff][fam->_fb])         return 16;
                                                return 14;
    }

    if (equals[fam->_fif][fam->_zero])          return 6;
    if (equals[fam->_fib][fam->_fif])
    {
        if (equals[fam->_fbi][fam->_fif])       return 5;
                                                return 3;
    }
    if (equals[fam->_fbi][fam->_fif])           return 4;
    if (equals[fam->_fib][fam->_fbi])           return 2;
                                                return 1;
}


int PsiArrayKFZ(int **equals, KFZenum *fam)
{
//  if (equals[fam->_f][fam->_one])             return 61;
    if (equals[fam->_i][fam->_b])
    {
        if (equals[fam->_b][fam->_zero])        return 70;
//      if (equals[fam->_b][fam->_one])         return 69;
                                                return 68;
    }

    if (equals[fam->_ibi][fam->_b])
    {
        if (equals[fam->_i][fam->_id])
        {
//          if (equals[fam->_b][fam->_one])     return 65;
                                                return 64;
        }
//      if (equals[fam->_b][fam->_one])         return 54;
                                                return 53;
    }

    if (equals[fam->_i][fam->_bib])
    {
        if (equals[fam->_b][fam->_id])
        {
            if (equals[fam->_b][fam->_f])       return 67;
                                                return 66;
        }
        if (equals[fam->_b][fam->_f])           return 56;
                                                return 55;
    }

    if (equals[fam->_i][fam->_id])
    {
        if (equals[fam->_i][fam->_ib])          return 63;
                                                return 51;
    }

    if (equals[fam->_b][fam->_id])
    {
        if (equals[fam->_b][fam->_bi])          return 62;
                                                return 52;
    }

    if (equals[fam->_b][fam->_ib])
    {
        if (equals[fam->_i][fam->_bi])
        {
//          if (equals[fam->_b][fam->_one])     return 59;
            if (equals[fam->_i][fam->_zero])    return 60;
                                                return 58;
        }
        if (equals[fam->_ibi][fam->_bi])
        {
//          if (equals[fam->_b][fam->_one])     return 46;
                                                return 45;
        }
        if (equals[fam->_ibi][fam->_i])
        {
//          if (equals[fam->_b][fam->_one])     return 42;
                                                return 41;
        }
//      if (equals[fam->_b][fam->_one])         return 35;
                                                return 34;
    }

    if (equals[fam->_i][fam->_bi])
    {
        if (equals[fam->_bib][fam->_ib])
        {
            if (equals[fam->_b][fam->_f])       return 48;
                                                return 47;
        }
        if (equals[fam->_bib][fam->_b])
        {
            if (equals[fam->_b][fam->_f])       return 44;
                                                return 43;
        }
        if (equals[fam->_b][fam->_f])           return 37;
                                                return 36;
    }

    if (equals[fam->_b][fam->_bi])
    {
        if (equals[fam->_i][fam->_ib])          return 57;
                                                return 49;
    }

    if (equals[fam->_i][fam->_ib])              return 50;

    if (equals[fam->_bib][fam->_ibi])           return 40;

    if (equals[fam->_bib][fam->_bi])            return 39;

    if (equals[fam->_bib][fam->_ib])
    {
        if (equals[fam->_ibi][fam->_bi])        return 38;
        if (equals[fam->_ibi][fam->_i])         return 32;
                                                return 21;
    }

    if (equals[fam->_ibi][fam->_bi])
    {
        if (equals[fam->_bib][fam->_b])         return 33;
                                                return 22;
    }

    if (equals[fam->_b][fam->_bib])
    {
        if (equals[fam->_i][fam->_ibi])
        {
            if (equals[fam->_fif][fam->_zero])  return 31;
            if (equals[fam->_fb][fam->_fbi])
            {
                if (equals[fam->_f][fam->_bif]) return 30;
                                                return 26;
            }
            if (equals[fam->_ff][fam->_fi])
            {
                if (equals[fam->_f][fam->_bif]) return 29;
                                                return 25;
            }
            if (equals[fam->_ff][fam->_fb])
            {
                if (equals[fam->_f][fam->_bif]) return 28;
                                                return 24;
            }
            if (equals[fam->_f][fam->_bif])     return 27;
                                                return 23;
        }

        if (equals[fam->_fif][fam->_zero])      return 13;
        if (equals[fam->_fib][fam->_fif])
        {
            if (equals[fam->_ff][fam->_fi])     return 12;
                                                return 8;
        }
        if (equals[fam->_fib][fam->_fbi])       return 11;
        if (equals[fam->_fbi][fam->_fif])       return 10;
        if (equals[fam->_ff][fam->_fi])         return 9;
                                                return 7;
    }

    if (equals[fam->_i][fam->_ibi])
    {
        if (equals[fam->_fif][fam->_zero])      return 20;
        if (equals[fam->_fib][fam->_fif])
        {
            if (equals[fam->_fbi][fam->_fif])   return 19;
                                                return 17;
        }
        if (equals[fam->_fib][fam->_fbi])       return 18;
        if (equals[fam->_fbi][fam->_fif])       return 15;
        if (equals[fam->_ff][fam->_fb])         return 16;
                                                return 14;
    }

    if (equals[fam->_fif][fam->_zero])          return 6;
    if (equals[fam->_fib][fam->_fif])
    {
        if (equals[fam->_fbi][fam->_fif])       return 5;
                                                return 3;
    }
    if (equals[fam->_fbi][fam->_fif])           return 4;
    if (equals[fam->_fib][fam->_fbi])           return 2;
                                                return 1;
}

