#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 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; version 2
# of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.

from __future__ import print_function
import sys
import os
from math import log, ceil, sqrt
import random
import argparse
import copy
import tempfile

cwd = os.getcwd()+"/WAPS"
sys.path.append(cwd)

from waps import sampler as samp
import weightcount.WeightCount as chainform

SAMPLER_UNIGEN3 = 1
SAMPLER_QUICKSAMPLER = 2
SAMPLER_STS = 3
SAMPLER_CUSTOM = 4

BUCKETWIDTH = 2

class IdealSampleRetriever:
    def __init__(self,inputFile):
        self.sampler = samp(cnfFile=inputFile)
        self.sampler.compile()
        self.sampler.parse()
        self.weight = self.sampler.annotate()

    def getSolutionFromIdeal(self,numSolutions):
        return self.getSolutionFromWAPS(numSolutions)

    def getSolutionFromWAPS(self,numSolutions):
        samples = self.sampler.sample(totalSamples=numSolutions)
        solList = list(samples)
        solList = [i.strip().split() for i in solList]
        solList = [[int(x) for x in i] for i in solList]
        return solList

def hoeffding(p1,p2, delta):
    assert(p1<p2)
    return int(ceil(2*log(1/delta)/(p2-p1)**2))

def parseWeights(inputFile, indVarList):
    f = open(inputFile, "r")
    lines = f.readlines()
    f.close()
    weight_map = {}

    for line in lines:
        if line.startswith("w"):
            variable, weight = line[2:].strip().split()
            variable = int(variable)
            weight = float(weight)
            if (0.0 < weight < 1.0):
                if (variable in indVarList):
                    weight_map[variable] = weight
            else:
                print("Error: weights should only be in (0,1) ")
                exit(-1)
    return weight_map

def weightof(weight_map, sample, UserIndVarList):
    sample_w = copy.deepcopy(sample)
    sample_w.sort(key=abs)

    weight = 1.0

    for i in range(len(sample_w)):
        if sample_w[i] > 0:
            weight *= weight_map.get(abs(sample_w[i]),0.5)
        else:
            weight *= 1-weight_map.get(abs(sample_w[i]),0.5)
    return weight

def bucketof(weight_map, sample, UserIndVarList):
    return int(ceil(log(weightof(weight_map, sample, UserIndVarList), BUCKETWIDTH)))

def parseIndSupport(indSupportFile):  # returns List of Independent Variables
    f = open(indSupportFile, "r")
    lines = f.readlines()
    f.close()
    indList = []
    numVars = 0
    for line in lines:
        if line.startswith("p cnf"):
            fields = line.split()
            numVars = int(fields[2])
        if line.startswith("c ind"):
            indList.extend(
                line.strip()
                .replace("c ind", "")
                .replace(" 0", "")
                .strip()
                .replace("v ", "")
                .split()
            )
    if len(indList) == 0:
        indList = [int(x) for x in range(1, numVars + 1)]
    else:
        indList = [int(x) for x in indList]
    return indList


def getSolutionFromUniGen3(inputFile, numSolutions, indVarList):
    #inputFilePrefix = inputFile.split("/")[-1][:-4]
    tempOutputFile = inputFile + ".txt"
    f = open(tempOutputFile, "w")
    f.close()

    cmd = './samplers/unigen3  -v 0 --samples ' + str(numSolutions) + ' --multisample 1 --kappa 0.635'
    cmd += ' --sampleout ' + str(tempOutputFile)
    cmd += ' ' + inputFile + ' > /dev/null 2>&1'

    print(cmd)
    os.system(cmd)
    f = open(tempOutputFile, "r")
    lines = f.readlines()
    f.close()
    solList = []
    for line in lines:
        line = line.strip("0\n")
        sample = line.split()
        sample = [int(i) for i in sample]
        solList.append(sample)

    solreturnList = solList
    if (len(solList) > numSolutions):
        solreturnList = random.sample(solList, numSolutions)

    os.unlink(str(tempOutputFile))
    return solreturnList


# @CHANGE_HERE : please make changes in the below block of code
""" this is the method where you could run your sampler for testing
Arguments : input file, number of solutions to be returned, list of independent variables
output : list of solutions """


def getSolutionFromCustomSampler(inputFile, numSolutions, indVarList):
    solreturnList = []
    """ write your code here """

    return solreturnList


def getSolutionFromSampler(seed, inputFile, numSolutions, samplerType, indVarList):
    if samplerType == SAMPLER_UNIGEN3:
        return getSolutionFromUniGen3(inputFile, numSolutions, indVarList)
    if samplerType == SAMPLER_QUICKSAMPLER:
        return getSolutionFromQuickSampler(inputFile, numSolutions, indVarList)
    if samplerType == SAMPLER_STS:
        return getSolutionFromSTS(seed, inputFile, numSolutions, indVarList)
    if samplerType == SAMPLER_CUSTOM:
        return getSolutionFromCustomSampler(inputFile, numSolutions, indVarList)
    else:
        print("Error")
        return None


def getSolutionFromSTS(seed, inputFile, numSolutions, indVarList):
    kValue = 50
    samplingRounds = numSolutions/kValue + 1
    inputFileSuffix = inputFile.split('/')[-1][:-4]
    outputFile = tempfile.gettempdir()+'/'+inputFileSuffix+"sts.out"

    cmd = './samplers/STS -k=' +str(kValue)
    cmd +=' -nsamples='+ str(samplingRounds) + ' ' + str(inputFile)
    cmd += ' > '+str(outputFile)

    print(cmd)
    #os.system(cmd)

    solList = []

    while(len(solList) < numSolutions):
        os.system(cmd)
        with open(outputFile, 'r') as f:
            lines = f.readlines()

        shouldStart = False
        for j in range(len(lines)):
            if(lines[j].strip() == 'Outputting samples:' or lines[j].strip() == 'start'):
                shouldStart = True
                continue
            if (lines[j].strip().startswith('Log') or lines[j].strip() == 'end'):
                shouldStart = False
            if (shouldStart):
                i = 0
                sol = []
                # valutions are 0 and 1 and in the same order as c ind.
                for x in list(lines[j].strip()):
                    if (x == '0'):
                        sol.append(-1*indVarList[i])
                    else:
                        sol.append(indVarList[i])
                    i += 1
                solList.append(sol)

    solreturnList = solList
    if len(solList) > numSolutions:
        solreturnList = random.sample(solList, numSolutions)
    elif len(solList) < numSolutions:
        print(len(solList))
        print("Error: STS Did not find required number of solutions")
        sys.exit(1)

    os.unlink(outputFile)
    return solreturnList


def getSolutionFromQuickSampler(inputFile, numSolutions, indVarList):
    cmd = "./samplers/quicksampler -n " + str(numSolutions * 5) + " " + str(inputFile)
    cmd += " > /dev/null 2>&1"

    cmd_z3 = "./samplers/z3 " + str(inputFile) + " > /dev/null 2>&1"

    print(cmd)

    solList = []
    while(len(solList) < numSolutions):
        os.system(cmd)
        os.system(cmd_z3)

        f = open(inputFile + ".samples", "r")
        lines = f.readlines()
        f.close()
        f = open(inputFile + ".samples.valid", "r")
        validLines = f.readlines()
        f.close()
        for j in range(len(lines)):
            if validLines[j].strip() == "0":
                continue
            fields = lines[j].strip().split(":")
            sol = []
            i = 0
            for x in list(fields[1].strip()):
                if x == "0":
                    sol.append(-1*indVarList[i])
                else:
                    sol.append(indVarList[i])
                i += 1
            solList.append(sol)

    solreturnList = solList
    if len(solList) > numSolutions:
        solreturnList = random.sample(solList, numSolutions)
    elif len(solList) < numSolutions:
        print(len(solList))
        print("Error: Quicksampler did not find required number of solutions")
        exit(1)

    os.unlink(inputFile+'.samples')
    os.unlink(inputFile+'.samples.valid')

    return solreturnList





def findWeightsForVariables(sampleSol, idealSol, numSolutions):
    """
    Finds rExtList
    """
    countList = []
    newVarList = []
    lenSol = len(sampleSol)
    tau = min(3,lenSol)

    for _ in range(tau):
        countList.append(5)
        newVarList.append(4)
    rExtList = []
    oldVarList = []

    indexes = random.sample(range(len(sampleSol)), len(countList))

    idealVarList = [idealSol[i] for i in indexes]
    sampleVarList = [sampleSol[i] for i in indexes]

    assert len(idealVarList) == len(sampleVarList)
    for a, b in zip(idealVarList, sampleVarList):
        assert abs(int(a)) == abs(int(b))

    oldVarList.append(sampleVarList)
    oldVarList.append(idealVarList)
    rExtList.append(countList)
    rExtList.append(newVarList)
    rExtList.append(oldVarList)

    return rExtList


def pushVar(variable, cnfClauses):
    cnfLen = len(cnfClauses)
    for i in range(cnfLen):
        cnfClauses[i].append(variable)
    return cnfClauses


def getCNF(variable, binStr, sign, origTotalVars):
    cnfClauses = []
    binLen = len(binStr)
    if sign:
        cnfClauses.append([binLen + 1 + origTotalVars])
    else:
        cnfClauses.append([-(binLen + 1 + origTotalVars)])
    for i in range(binLen):
        newVar = int(binLen - i + origTotalVars)
        if sign == False:
            newVar = -1 * (binLen - i + origTotalVars)
        if binStr[binLen - i - 1] == "0":
            cnfClauses.append([newVar])
        else:
            cnfClauses = pushVar(newVar, cnfClauses)
    pushVar(variable, cnfClauses)
    return cnfClauses


def constructChainFormula(originalVar, solCount, newVars, origTotalVars, invert):

    binStr = str(bin(int(solCount)))[2:-1]
    binLen = len(binStr)
    for _ in range(newVars - binLen - 1):
        binStr = "0" + binStr

    firstCNFClauses = getCNF(-int(originalVar), binStr, invert, origTotalVars)
    addedClauseNum = 0
    writeLines = ""
    for cl in firstCNFClauses:
        addedClauseNum += 1
        for lit in cl:
            writeLines += "%d " % lit
        writeLines += "0\n"

    return writeLines, addedClauseNum


# @returns whether new file was created and the list of independent variables
def constructNewFile(inputFile, tempFile, sampleSol, unifSol, rExtList, origIndVarList):
    sampleMap = {}
    unifMap = {}
    diffIndex = -1   #ensures that sampleSol != unifSol when projected on indVarList
    for i in sampleSol:
        if not (abs(int(i)) in origIndVarList):
            continue
        if int(i) != 0:
            sampleMap[abs(int(i))] = int(int(i) / abs(int(i)))
    for j in unifSol:
        if int(j) != 0:
            if not (abs(int(j)) in origIndVarList):
                continue

            if sampleMap[abs(int(j))] != int(j) / abs(int(j)):
                diffIndex = abs(int(j))
            unifMap[abs(int(j))] = int(int(j) / abs(int(j)))

    if diffIndex == -1:
        print("Error: both samples are the same")
        print(sampleSol, unifSol)
        exit(-1)

    solClause = ""
    f = open(inputFile, "r")
    lines = f.readlines()
    f.close()
    countList = rExtList[0]
    newVarList = rExtList[1]
    sumNewVar = int(sum(newVarList))
    oldClauseStr = ""
    numVar = 0
    for line in lines:
        if line.strip().startswith("p cnf"):
            numVar = int(line.strip().split()[2])
            numClause = int(line.strip().split()[3])
        else:
            if line.strip().startswith("w"):
                oldClauseStr += line.strip()+"\n"
            elif not (line.strip().startswith("c")):
                oldClauseStr += line.strip()+"\n"
    #Adding constraints to ensure only two clauses
    for i in origIndVarList:
        if int(i) != diffIndex:
            numClause += 2
            solClause += (
                str(-(diffIndex ) * sampleMap[diffIndex])
                + " "
                + str(sampleMap[int(i)] * int(i))
                + " 0\n"
            )
            solClause += (
                str(-(diffIndex ) * unifMap[diffIndex])
                + " "
                + str(unifMap[int(i)] * int(i))
                + " 0\n"
            )

    invert = True
    seenVars = []
    currentNumVar = numVar

    for oldVarList in rExtList[2]:
        for i in range(len(oldVarList)):
            addedClause = ""
            addedClauseNum = 0

            if True or not (int(oldVarList[i]) in seenVars):
                sign = int(oldVarList[i]) / abs(int(oldVarList[i]))
                addedClause, addedClauseNum = constructChainFormula(
                    sign * (abs(int(oldVarList[i]))),
                    int(countList[i]),
                    int(newVarList[i]),
                    currentNumVar,
                    invert,
                )
            seenVars.append(int(oldVarList[i]))
            currentNumVar += int(newVarList[i])
            numClause += addedClauseNum
            solClause += addedClause
        invert = True #not (invert)

    tempIndVarList =[]
    indStr = "c ind "
    indIter = 1
    for i in origIndVarList:
        if indIter % 10 == 0:
            indStr += " 0\nc ind "
        indStr += str(i) + " "
        indIter += 1
        tempIndVarList.append(i)
    for i in range(numVar+1, currentNumVar + 1):
        if indIter % 10 == 0:
            indStr += " 0\nc ind "
        indStr += str(i) + " "
        indIter += 1
        tempIndVarList.append(i)


    indStr += " 0\n"
    headStr = "p cnf " + str(currentNumVar) + " " + str(numClause) + "\n"
    writeStr = headStr + indStr
    writeStr += solClause
    writeStr += oldClauseStr

    f = open(tempFile, "w")
    f.write(writeStr)
    f.close()
    return tempIndVarList


def constructKernel(inputFile, tempFile, samplerSample, idealSample, numSolutions, origIndVarList):
    rExtList = findWeightsForVariables(samplerSample, idealSample, numSolutions)
    tempIndVarList = constructNewFile(inputFile, tempFile, samplerSample, idealSample, rExtList, origIndVarList)
    return tempIndVarList

# Returns 1 if Ideal and 0 otherwise
def biasFind(sample, solList, indVarList):
    solMap = {}
    numSolutions = len(solList)
    for sol in solList:
        solution = ""
        solFields = sol
        solFields.sort(key=abs)
        for entry in solFields:
            if (abs(entry)) in indVarList:
                solution += str(entry) + " "
        if solution in solMap.keys():
            solMap[solution] += 1
        else:
            solMap[solution] = 1

    if not (bool(solMap)):
        print("Error: no Solutions were given to the test")
        exit(1)
    print("c Printing solMap")
    print(solMap)

    solution = ""

    for i in solList[0]:
        if abs(i) in indVarList:
            solution += str(i) + " "

    print("solList[0]", solList[0])
    print("sample", sample)

    if(len(set(solList[0]).intersection(set(sample))) == len(sample)):
        return solMap.get(solution, 0)*1.0/numSolutions
    else:
        return 1.0-(solMap.get(solution, 0)*1.0/numSolutions)

def insideBucket(K,eps,eps2,eta,delta,UserInputFile,inputFile,samplerType,indVarList,UserIndVarList,weight_map,ideal,totalSolsGenerated,seed):

    print("eta", eta)
    print("eps2",eps2)

    if(0.99*eta - 3.25*eps2 - 2*eps/(1-eps) < 0):
        print("Error: cannot test for these params")
        exit(1)

    tempFile = inputFile[:-6] + "_t.cnf"

    eps1 = (0.99*eta - 3.25*eps2 - 2*eps/(1-eps))/1.05 + 2*eps/(1-eps)
    alpha = (eps1+2*eps/(1-eps))/2

    M = int(ceil(sqrt(K)/(0.99*eta - 3.25*eps2 - eps1)))
    print("M #of samples in each round of InBucket = ", M)

    print("denom", (0.99*eta - 3.25*eps2 -eps1))

    T = int(ceil(log(2/delta)/log(10/(10 - eps1 + alpha))))
    print("T #of iteration = " + str(T))

    assert(M>0)
    assert(T>0)

    print("indVarList", indVarList)

    print("Getting "+str(M*T)+" samples from Ideal")
    total_weight = ideal.weight
    AllPsamples  = ideal.getSolutionFromIdeal(M*T)

    lower_threshold_probability = -int(log(total_weight, BUCKETWIDTH))

    for i in range(T):
        seed += 1

        Psamples = AllPsamples[i*M:(i+1)*M]
        Qsamples = getSolutionFromSampler(seed, inputFile, M, samplerType, indVarList)

        projectedQsamples = []
        for sample in Qsamples:
            projectedQsample = []
            for s in sample:
                if abs(s) in UserIndVarList:
                    projectedQsample.append(s)
            projectedQsamples.append(projectedQsample)

        BucketedQsamples = {}
        bucketsofQ = []
        for sample in projectedQsamples:
            bucketID = -bucketof(weight_map, sample,UserIndVarList) - lower_threshold_probability
            assert(bucketID >= 0)
            if bucketID <= K:
                BucketedQsamples[bucketID] = sample
                bucketsofQ.append(bucketID)

        BucketedPsamples = {}
        bucketsofP = []
        for sample in Psamples:
            bucketID = -bucketof(weight_map, sample,UserIndVarList) - lower_threshold_probability
            assert(bucketID >= 0)
            if bucketID <= K:
                BucketedPsamples[bucketID] = sample
                bucketsofP.append(bucketID)

        commonBuckets = list(set(bucketsofP).intersection(set(bucketsofQ)))

        collisions = len(commonBuckets)
        print("# of collisions ", collisions)

        if collisions == 0:
            print("No collisions in round", i)
            continue

        #R = hoeffding(L,H,delta/(2*collisions*T))

        for bucketID in commonBuckets:

            Psample = BucketedPsamples[bucketID]
            Qsample = BucketedQsamples[bucketID]

            if Psample==Qsample:
                continue

            # the weight of Psample in P
            P_p = weightof(weight_map,Psample,UserIndVarList)
            # the weightof of Qsample in P
            P_q = weightof(weight_map,Qsample,UserIndVarList)

            H = P_p/(P_p+P_q*(1+2*eps/(1-eps)))
            L = P_p/(P_p+P_q*(1+alpha))

            R = hoeffding(L,H,delta/(4*collisions*T))
            print("R #of PAIRCOND queries "+str(R))

            if(totalSolsGenerated + R > 10**8):
                print("Looking for more than 10**8 solutions", R)
                print("too many to ask ,so quitting here")
                print("Totalnumsol: ", totalSolsGenerated)
                exit(1)

            tempIndVarList = constructKernel(UserInputFile, tempFile, Qsample,
                                                    Psample, R, UserIndVarList)
            samplinglist = list(chainform.Transform(tempFile, tempFile, 4))  # precision set to 4
            #print("file was constructed with these", Qsample, Psample)
            #print("samplingList:", samplinglist)
            solList = getSolutionFromSampler(seed, tempFile, R, samplerType, samplinglist)
            totalSolsGenerated += R

            seed += 1
            c_hat = biasFind(Psample, solList, UserIndVarList)

            cmd = "rm " + tempFile
            os.system(cmd)
            print("chat", c_hat)
            print("thresh", (H+L)/2)
            if c_hat < (H+L)/2:
                breakExperiment = True
                print("Rejected at iteration: ", i)
                print("Toalnumsol: ", totalSolsGenerated)
                return 0

        print("Accept on round: ", i)

    print("All rounds passed")
    print("Totalnumsol: ", totalSolsGenerated)

    return 1

def outsideBucket(K,theta,delta,UserInputFile,inputFile,samplerType,indVarList,UserIndVarList,weight_map,ideal,seed):

    numSamp = int(ceil(max(4*(K+1), 8*log(4/delta))/(theta)**2))

    print(4*(K+1)/theta**2, 8*log(4/delta)/theta**2)
    print("Number of samples required for OutBucket ", numSamp)

    total_weight = ideal.weight
    lower_threshold_probability = int(log(total_weight, BUCKETWIDTH))

    empirical_bucketQ = [0]*(K+2)
    numSolTillNow = 0
    while(numSolTillNow < numSamp):
        Qsamples = getSolutionFromSampler(seed, inputFile, 1000, samplerType, indVarList)
        numSolTillNow += 1000

        projectedQsamples = []
        for sample in Qsamples:
            projectedQsample = []
            for s in sample:
                if abs(s) in UserIndVarList:
                    projectedQsample.append(s)
            projectedQsamples.append(projectedQsample)

        for i in projectedQsamples:
            bucketID = -bucketof(weight_map, i,UserIndVarList) +  lower_threshold_probability
            assert(bucketID >= 0)
            if bucketID <=K:
                empirical_bucketQ[bucketID] += 1
            else:
                empirical_bucketQ[K+1] += 1

    Psamples = ideal.getSolutionFromIdeal(numSolTillNow)

    empirical_bucketP = [0]*(K+2)
    for i in Psamples:
        bucketID = -bucketof(weight_map, i,UserIndVarList) +  lower_threshold_probability
        assert(bucketID >= 0)
        if bucketID <=K:
            empirical_bucketP[bucketID] += 1
        else:
            empirical_bucketP[K+1] += 1

    print("Bucket of P", empirical_bucketP)
    print("Bucket of Q", empirical_bucketQ)

    if(sum(empirical_bucketP) != sum(empirical_bucketP)):
        print("Error: The length of two sample sets is not equal")
        print(len(projectedQsamples), len(Psamples))
        exit(0)

    dhat = 0.0
    for i in range(K+2):
        dhat += 0.5*abs(empirical_bucketP[i]-empirical_bucketQ[i])/numSolTillNow
    print("dhat: ", dhat)
    print("NumSol Outside", numSolTillNow)

    return dhat, numSolTillNow



def closeness():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--eta", type=float, help="default = 0.9", default=0.9, dest="eta"
    )
    parser.add_argument(
        "--epsilon", type=float, help="default = 0.1", default=0.1, dest="epsilon"
    )
    parser.add_argument(
        "--delta", type=float, help="default = 0.2", default=0.2, dest="delta"
    )
    parser.add_argument(
        "--sampler",
        type=int,
        help=str(SAMPLER_UNIGEN3)
        + " for UniGen3;\n"
        + str(SAMPLER_QUICKSAMPLER)
        + " for QuickSampler;\n"
        + str(SAMPLER_STS)
        + " for STS;\n",
        default=SAMPLER_STS,
        dest="samplertype",
    )
    parser.add_argument("--seed", type=int, dest="seed", default=420)
    parser.add_argument("input", help="input file")

    args = parser.parse_args()

    eta = args.eta
    eps = args.epsilon
    delta = args.delta
    samplerType = args.samplertype
    seed = args.seed
    random.seed(seed)

    UserInputFile = args.input
    print("This is the user input:--", UserInputFile)

    inputFilePrefix = UserInputFile.split("/")[-1][:-4]
    inputFile = inputFilePrefix + "."+str(samplerType)+".cnf"

    print("This is the output file after weighted to unweighted:", inputFile)

    UserIndVarList = parseIndSupport(UserInputFile)
    indVarList = list(chainform.Transform(UserInputFile, inputFile, 4))  # precision set to 4

    samplerString = ""

    if samplerType == SAMPLER_UNIGEN3:
        samplerString = "UniGen3"
    if samplerType == SAMPLER_QUICKSAMPLER:
        samplerString = "QuickSampler"
    if samplerType == SAMPLER_STS:
        samplerString = "STS"
    if samplerType == SAMPLER_CUSTOM:
        samplerString = "CustomSampler"

    weight_map = parseWeights(UserInputFile, UserIndVarList)

    breakExperiment = False
    totalSolsGenerated = 0
    totalIdealSamples = 0

    numVars = len(UserIndVarList)
    print("Dimensions: ", numVars)
    K =  int(ceil(numVars*log(2,BUCKETWIDTH)+log(100/eta,BUCKETWIDTH)))

    theta = eta/20
    print("K", K)

    ideal = IdealSampleRetriever(inputFile = UserInputFile)

    dhat, totalSolsGenerated = outsideBucket(K,theta,delta/2,UserInputFile,inputFile,samplerType,indVarList,UserIndVarList,weight_map,ideal,seed)

    if dhat - theta  > eps/2:
        print("Rejected as dhat("+str(dhat)+") > eps/2 ("+str(eps/2)+") " )
    else:
        eps2 = dhat + theta
        insideBucket(K,eps,eps2,eta,delta/2,UserInputFile,inputFile,samplerType,indVarList,UserIndVarList,weight_map,ideal,totalSolsGenerated,seed)

if __name__ == "__main__":
    closeness()
