//
// Created by martin on 26. 2. 2021.
//

#include "GenerateCombinations.h"
using arc = std::vector<cv::Point2i>;
// Posterior Arc Search (algorithm 3.)
void PAS(std::vector<arc> & arcs,std::vector<std::vector<int>>& arcIndex,int r,std::set<int> phi_r,std::set<std::set<int>> & PiPlus) {
    phi_r.emplace(r);
    for (int i = r +1 ;i < arcIndex.size();i++) {
        if (arcIndex[r][i] > 0) {
//            phi_r.push_back(i);
            PAS(arcs,arcIndex,i, phi_r ,PiPlus);
        }
    }
    PiPlus.emplace(phi_r);
    phi_r.erase(r);
}

// Anterior Arc Search (modified algorithm 3.)
void AAS(std::vector<arc> & arcs,std::vector<std::vector<int>>& arcIndex,int r,std::set<int> phi_r,std::set<std::set<int>> & PiMinus) {
    phi_r.emplace(r);
    for (int i = r -1 ;i < arcIndex.size();i--) {
        if (arcIndex[r][i] == 1) {
            AAS(arcs,arcIndex,i,phi_r,PiMinus);
        }
    }
    PiMinus.emplace(phi_r);
    phi_r.erase(r);
}

//Biderectional combination verification equation (EQ 8 from the article hence the name verifyGroup)
bool verifyGroup (std::vector<std::vector<int>>& arcIndex, std::set<int> pPlus, std::set<int> pMinus) {
    for (int m : pMinus) {
        for (int p : pPlus) {
            if (arcIndex[m][p] == -1) {
                return false;
            }
        }
    }
    return true;
}



std::set<std::set<int>> BCV(std::vector<arc> & arcs, std::vector<std::vector<int>>& arcIndex) {
    std::vector<std::vector<arc>> arcCombinations;
    std::set<std::set<int>> combinations;

    for (int i = 0; i < arcIndex.size(); i++) {
        std::set<std::set<int>> PiPlus, PiMinus;

        std::set<int> phi_rP, phi_rM,empty;
        PAS(arcs, arcIndex, i, phi_rP, PiPlus);
        AAS(arcs, arcIndex, i, phi_rM, PiMinus);



        //verifying the combination
        for (std::set<int> pPlus : PiPlus) {
            for (std::set<int> pMinus : PiMinus) {
                //if satisfies criterion then push in
                if (verifyGroup(arcIndex, pPlus, pMinus)) {
                    std::set<int> aCombination = pMinus;
                    aCombination.merge(pPlus);
                    combinations.emplace(aCombination);
                }
            }
        }
    }

    return combinations;
}


