def optimize(self):
        start = time.time()
        clock = Clock()
        clock.setStart(start)
        if (self.DEBUG_MESSAGES):
            print("=============================")
            print("LNS Optimize Method Started...")

        customerSubset = copy.deepcopy(self.customers)
        facilitySubet = copy.deepcopy(self.facilities)
        self.__InitializeProblem(facilitySubet, customerSubset)
        self.__getQuantiles()
        self.currentObjectiveFunction = self.subproblemSolutionForest.getTotalCost(
        )
        self.currentSolutionAssignment = self.subproblemSolutionForest.getAssignmentsArray(
        )
        initialQuantiles = copy.deepcopy(self.quantiles)
        quantileSize = len(initialQuantiles)
        quantilesCount = 0
        customerCount = len(self.customers)
        noImprovementIterations = 0
        while True:
            if (clock.isTimeOver(time.time(),
                                 self.params["executionTimeLimit"])):
                break

            iterationsCount = len(self.clusterAreas)
            for iteration in range(0, iterationsCount):
                self.currentIteration = iteration
                clustersCount = 0
                clustersSize = len(self.clusterAreas.get(iteration))
                for cluster in self.clusterAreas.get(iteration).values():
                    clustersCount = clustersCount + 1
                    print("Iteration: %s/%s || Instance: %s_%s" %
                          (quantilesCount + 1, quantileSize,
                           self.facilitiesCount, customerCount))
                    print("Subproblem: %s/%s" %
                          (self.currentIteration + 1, iterationsCount))
                    candidateForest = self.__destroy(cluster)
                    if (candidateForest.getTreesCount() *
                            candidateForest.getTotalNodes() >
                            self.MAX_PROBLEM_SIZE):
                        print(
                            "Problem instance is larger than limit. Skipping..."
                        )
                        candidateFacilities = [
                            tree.getRoot()
                            for tree in candidateForest.getTrees().values()
                        ]
                        self.__updateFrequency(
                            dict([(facility.index, facility)
                                  for facility in candidateFacilities]),
                            self.NO_ASSIGNMENT_REWARD)
                        continue

                    cFacilities, cCustomers = candidateForest.getData()

                    print(
                        "Current Cluster: %s/%s || Facilities: %s || Customers Assigned: %s"
                        % (clustersCount, clustersSize,
                           candidateForest.getTreesCount(),
                           candidateForest.getTotalNodes()))
                    if (candidateForest.getTotalNodes() == 0):
                        if (self.DEBUG_MESSAGES):
                            print("No Customers Assigned... Continue")
                        continue

                    obj, assignment, status = self.__repair(
                        cFacilities, cCustomers)

                    if (status == 'optimal'):
                        self.__evaluate(obj, assignment, candidateForest,
                                        cluster)
                    else:
                        print("No Optimal Solution Found for this instance")
                        candidateFacilities = [
                            tree.getRoot()
                            for tree in candidateForest.getTrees().values()
                        ]
                        self.__updateFrequency(
                            dict([(facility.index, facility)
                                  for facility in candidateFacilities]),
                            self.ASSIGNMENT_REWARD)

                    print("Subproblem Forest: %s/%s" %
                          (self.subproblemSolutionForest.getTreesCount(),
                           self.subproblemSolutionForest.getTotalNodes()))
                    print("Subproblem Objective Funciton: %s" %
                          self.subproblemSolutionForest.getTotalCost())
                    print("Current Objective Function: %s" %
                          self.currentObjectiveFunction)

                if (self.DEBUG_MESSAGES):
                    print("Partial Solution")
                    partial = ""
                    partial = '%.2f' % self.subproblemSolutionForest.getTotalCost(
                    ) + ' ' + str(0) + '\n'
                    partial += ' '.join(
                        map(
                            str,
                            self.subproblemSolutionForest.getAssignmentsArray(
                            )))
                    print(partial)

            if (self.currentObjectiveFunction >=
                    self.subproblemSolutionForest.getTotalCost()):
                self.currentObjectiveFunction = self.subproblemSolutionForest.getTotalCost(
                )
                self.currentSolutionAssignment = self.subproblemSolutionForest.getAssignmentsArray(
                )
            else:
                noImprovementIterations = noImprovementIterations + 1

            print("====================================================")
            print("CURRENT OBJECTIVE FUNCTION: %s" %
                  self.currentObjectiveFunction)
            print("====================================================")
            if (quantilesCount >= quantileSize):
                print("Maximum Iteration Count Reached! Stopping...")
                break

            if (noImprovementIterations >
                    self.params["noImprovementIterationLimit"]):
                print("No improvement limit reached! Stopping the search...")
                break

            ##filtrar as facilities mais interessantes e jogar no facility subset
            candidates = [
                facility.index for facility in facilitySubet.values()
            ]
            lastCandidateCount = len(candidates)
            while quantilesCount < quantileSize and len(
                    candidates) == lastCandidateCount:
                candidates = self.__getCandidateFacilities(
                    candidates, self.totalDemand,
                    Util.truncate(initialQuantiles[quantilesCount], 5), False)
                quantilesCount = quantilesCount + 1

            if (candidates is None or len(candidates) == 0
                    or len(candidates) == lastCandidateCount):
                break

            facilitySubet = dict(
                zip([index for index in candidates],
                    [facilitySubet[index] for index in candidates]))
            self.facilities = facilitySubet
            self.__InitializeProblem(facilitySubet, customerSubset)
            self.__getQuantiles()

        return self.currentObjectiveFunction, self.currentSolutionAssignment