diff --git a/lang/fr/gklearn/ged/util/lsape_solver.py b/lang/fr/gklearn/ged/util/lsape_solver.py new file mode 100644 index 0000000..72c2776 --- /dev/null +++ b/lang/fr/gklearn/ged/util/lsape_solver.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Mon Jun 22 15:37:36 2020 + +@author: ljia +""" +import numpy as np +from scipy.optimize import linear_sum_assignment + + +class LSAPESolver(object): + + + def __init__(self, cost_matrix=None): + """ + /*! + * @brief Constructs solver for LSAPE problem instance. + * @param[in] cost_matrix Pointer to the LSAPE problem instance that should be solved. + */ + """ + self.__cost_matrix = cost_matrix + self.__model = 'ECBP' + self.__greedy_method = 'BASIC' + self.__solve_optimally = True + self.__minimal_cost = 0 + self.__row_to_col_assignments = [] + self.__col_to_row_assignments = [] + self.__dual_var_rows = [] # @todo + self.__dual_var_cols = [] # @todo + + + def clear_solution(self): + """Clears a previously computed solution. + """ + self.__minimal_cost = 0 + self.__row_to_col_assignments.clear() + self.__col_to_row_assignments.clear() + self.__row_to_col_assignments.append([]) # @todo + self.__col_to_row_assignments.append([]) + self.__dual_var_rows = [] # @todo + self.__dual_var_cols = [] # @todo + + + def set_model(self, model): + """ + /*! + * @brief Makes the solver use a specific model for optimal solving. + * @param[in] model The model that should be used. + */ + """ + self.__solve_optimally = True + self.__model = model + + + def solve(self, num_solutions=1): + """ + /*! + * @brief Solves the LSAPE problem instance. + * @param[in] num_solutions The maximal number of solutions that should be computed. + */ + """ + self.clear_solution() + if self.__solve_optimally: + row_ind, col_ind = linear_sum_assignment(self.__cost_matrix) # @todo: only hungarianLSAPE ('ECBP') can be used. + self.__row_to_col_assignments[0] = col_ind + self.__col_to_row_assignments[0] = np.argsort(col_ind) # @todo: might be slow, can use row_ind + self.__compute_cost_from_assignments() + if num_solutions > 1: + pass # @todo: + else: + print('here is non op.') + pass # @todo: greedy. +# self.__ + + + def minimal_cost(self): + """ + /*! + * @brief Returns the cost of the computed solutions. + * @return Cost of computed solutions. + */ + """ + return self.__minimal_cost + + + def get_assigned_col(self, row, solution_id=0): + """ + /*! + * @brief Returns the assigned column. + * @param[in] row Row whose assigned column should be returned. + * @param[in] solution_id ID of the solution where the assignment should be looked up. + * @returns Column to which @p row is assigned to in solution with ID @p solution_id or ged::undefined() if @p row is not assigned to any column. + */ + """ + return self.__row_to_col_assignments[solution_id][row] + + + def get_assigned_row(self, col, solution_id=0): + """ + /*! + * @brief Returns the assigned row. + * @param[in] col Column whose assigned row should be returned. + * @param[in] solution_id ID of the solution where the assignment should be looked up. + * @returns Row to which @p col is assigned to in solution with ID @p solution_id or ged::undefined() if @p col is not assigned to any row. + */ + """ + return self.__col_to_row_assignments[solution_id][col] + + + def num_solutions(self): + """ + /*! + * @brief Returns the number of solutions. + * @returns Actual number of solutions computed by solve(). Might be smaller than @p num_solutions. + */ + """ + return len(self.__row_to_col_assignments) + + + def __compute_cost_from_assignments(self): # @todo + self.__minimal_cost = np.sum(self.__cost_matrix[range(0, len(self.__row_to_col_assignments[0])), self.__row_to_col_assignments[0]]) \ No newline at end of file