def test_get_rbf_matrix(self): """Test basic properties of the RBF matrix (e.g. symmetry, size). Verify that the RBF matrix is symmetric and it has the correct size for all types of RBF. """ settings = RbfSettings() for i in range(50): dim = random.randint(1, 20) num_points = random.randint(10, 50) node_pos = np.array( [[random.uniform(-100, 100) for j in range(dim)] for k in range(num_points)]) # Possible shapes of the matrix for rbf_type in self.rbf_types: settings.rbf = rbf_type mat = ru.get_rbf_matrix(settings, dim, num_points, node_pos) self.assertIsInstance(mat, np.matrix) self.assertAlmostEqual(np.max(mat - mat.transpose()), 0.0, msg='RBF matrix is not symmetric') size = num_points + 1 if (ru.get_degree_polynomial(settings) > 0): size += dim**ru.get_degree_polynomial(settings) self.assertEqual(mat.shape, (size, size)) # Check that exception is raised for unknown RBF types settings.rbf = 'unknown' self.assertRaises(ValueError, ru.get_rbf_matrix, settings, dim, num_points, node_pos)
def test_get_degree_polynomial(self): """Verify that the degree is always between 0 and 1.""" settings = RbfSettings() for rbf_type in self.rbf_types: settings.rbf = rbf_type degree = ru.get_degree_polynomial(settings) self.assertTrue(degree == 0 or degree == 1)
def get_model_quality_estimate_clp(settings, n, k, node_pos, node_val, num_iterations): """Compute an estimate of model quality using LPs with Clp. Computes an estimate of model quality, performing cross-validation. This version does not use all interpolation nodes, but rather only the best num_iterations ones, and it uses a sequence of LPs instead of a brute-force calculation. It should be much faster than the brute-force calculation, as each LP in the sequence requires only two pivots. The solver is COIN-OR Clp. Parameters ---------- settings : :class:`rbfopt_settings.RbfSettings` Global and algorithmic settings. n : int Dimension of the problem, i.e. the space where the point lives. k : int Number of nodes, i.e. interpolation points. node_pos : 2D numpy.ndarray[float] Location of current interpolation nodes (one on each row). node_val : 1D numpy.ndarray[float] List of values of the function at the nodes. num_iterations : int Number of nodes on which quality should be tested. Returns ------- float An estimate of the leave-one-out cross-validation error, which can be interpreted as a measure of model quality. Raises ------ RuntimeError If the LPs cannot be solved. ValueError If some settings are not supported. """ assert(isinstance(node_pos, np.ndarray)) assert(isinstance(node_val, np.ndarray)) assert(isinstance(settings, RbfSettings)) assert(len(node_val) == k) assert(len(node_pos) == k) assert(num_iterations <= k) assert(cpx_available) # We cannot find a leave-one-out interpolant if the following # condition is not met. assert(k > n + 1) # Get size of polynomial part of the matrix (p) and sign of obj # function (sign) if (ru.get_degree_polynomial(settings) == 1): p = n + 1 sign = 1 elif (ru.get_degree_polynomial(settings) == 0): p = 1 sign = -1 else: raise ValueError('RBF type ' + settings.rbf + ' not supported') # Sort interpolation nodes by increasing objective function value sorted_idx = node_val.argsort() # Initialize the arrays used for the cross-validation cv_node_pos = node_pos[sorted_idx] cv_node_val = node_val[sorted_idx] # Compute the RBF matrix, and the two submatrices of interest Amat = ru.get_rbf_matrix(settings, n, k, cv_node_pos) Phimat = Amat[:k, :k] Pmat = Amat[:k, k:] identity = np.matrix(np.identity(k)) # Instantiate model model = CyLPModel() # Add variables: lambda, h, slacks rbf_lambda = model.addVariable('rbf_lambda', k) rbf_h = model.addVariable('rbf_h', p) slack = model.addVariable('slack', k) # Add constraints: interpolation conditions, unisolvence F = CyLPArray(cv_node_val) zeros = CyLPArray([0] * p) ones = CyLPArray([1] * p) if (p > 1): # We can use matrix form model += (Phimat * rbf_lambda + Pmat * rbf_h + identity * slack == F) model += (Pmat.transpose() * rbf_lambda == zeros) else: # Workaround for one dimensional variables: one row at a time for i in range(k): model += Phimat[i, :] * rbf_lambda + rbf_h + slack[i] == F[i] model += (Pmat.transpose() * rbf_lambda == zeros) # Add objective obj = CyLPArray([sign*val for val in node_val]) model.objective = obj * rbf_lambda # Create LP, suppress output, and set bounds lp = clp.CyClpSimplex(model) lp.logLevel = 0 infinity = lp.getCoinInfinity() for i in range(k + p): lp.setColumnLower(i, -infinity) lp.setColumnUpper(i, infinity) for i in range(k): lp.setColumnLower(k + p + i, 0.0) lp.setColumnUpper(k + p + i, 0.0) # Estimate of the model error loo_error = 0.0 for i in range(num_iterations): # Fix lambda[i] to zero lp.setColumnLower(i, 0.0) lp.setColumnUpper(i, 0.0) # Set slack[i] to unconstrained lp.setColumnLower(k + p + i, -infinity) lp.setColumnUpper(k + p + i, infinity) lp.dual(startFinishOptions = 'sx') if (not lp.getStatusCode() == 0): raise RuntimeError('Could not solve LP with Clp, status ' + lp.getStatusString()) lambda_sol = lp.primalVariableSolution['rbf_lambda'].tolist() h_sol = lp.primalVariableSolution['rbf_h'].tolist() # Compute value of the interpolant at the removed node predicted_val = ru.evaluate_rbf(settings, cv_node_pos[i], n, k, cv_node_pos, lambda_sol, h_sol) # Update leave-one-out error loo_error += abs(predicted_val - cv_node_val[i]) # Fix lambda[i] to zero lp.setColumnLower(i, -infinity) lp.setColumnUpper(i, infinity) # Set slack[i] to unconstrained lp.setColumnLower(k + p + i, 0.0) lp.setColumnUpper(k + p + i, 0.0) return loo_error/num_iterations
def get_model_quality_estimate_cpx(settings, n, k, node_pos, node_val, num_iterations): """Compute an estimate of model quality using LPs with Cplex. Computes an estimate of model quality, performing cross-validation. This version does not use all interpolation nodes, but rather only the best num_iterations ones, and it uses a sequence of LPs instead of a brute-force calculation. It should be much faster than the brute-force calculation, as each LP in the sequence requires only two pivots. The solver is IBM-ILOG Cplex. Parameters ---------- settings : :class:`rbfopt_settings.RbfSettings` Global and algorithmic settings. n : int Dimension of the problem, i.e. the space where the point lives. k : int Number of nodes, i.e. interpolation points. node_pos : 2D numpy.ndarray[float] Location of current interpolation nodes (one on each row). node_val : 1D numpy.ndarray[float] List of values of the function at the nodes. num_iterations : int Number of nodes on which quality should be tested. Returns ------- float An estimate of the leave-one-out cross-validation error, which can be interpreted as a measure of model quality. Raises ------ RuntimeError If the LPs cannot be solved. ValueError If some settings are not supported. """ assert(isinstance(node_pos, np.ndarray)) assert(isinstance(node_val, np.ndarray)) assert(isinstance(settings, RbfSettings)) assert(len(node_val) == k) assert(len(node_pos) == k) assert(num_iterations <= k) assert(cpx_available) # We cannot find a leave-one-out interpolant if the following # condition is not met. assert(k > n + 1) # Get size of polynomial part of the matrix (p) and sign of obj # function (sign) if (ru.get_degree_polynomial(settings) == 1): p = n + 1 sign = 1 elif (ru.get_degree_polynomial(settings) == 0): p = 1 sign = -1 else: raise ValueError('RBF type ' + settings.rbf + ' not supported') # Sort interpolation nodes by increasing objective function value sorted_idx = node_val.argsort() # Initialize the arrays used for the cross-validation cv_node_pos = node_pos[sorted_idx] cv_node_val = node_val[sorted_idx] # Compute the RBF matrix Amat = ru.get_rbf_matrix(settings, n, k, cv_node_pos) # Instantiate model and suppress output lp = cpx.Cplex() lp.set_log_stream(None) lp.set_error_stream(None) lp.set_warning_stream(None) lp.set_results_stream(None) lp.cleanup(settings.eps_zero) lp.parameters.threads.set(1) # lp.parameters.simplex.display.set(2) # Add variables: lambda, h, slacks lp.variables.add(obj = [sign*val for val in node_val], lb = [-cpx.infinity] * k, ub = [cpx.infinity] * k) lp.variables.add(lb = [-cpx.infinity] * p, ub = [cpx.infinity] * p) lp.variables.add(lb = [0] * k, ub = [0] * k) # Add constraints: interpolation conditions, unisolvence expr = [cpx.SparsePair(ind = [j for j in range(k + p)] + [k + p + i], val = [Amat[i, j] for j in range(k + p)] + [1.0]) for i in range(k)] lp.linear_constraints.add(lin_expr = expr, senses = ['E'] * k, rhs = cv_node_val) expr = [cpx.SparsePair(ind = [j for j in range(k + p)], val = [Amat[i, j] for j in range(k + p)]) for i in range(k, k + p)] lp.linear_constraints.add(lin_expr = expr, senses = ['E'] * p, rhs = [0] * p) # Estimate of the model error loo_error = 0.0 for i in range(num_iterations): # Fix lambda[i] to zero lp.variables.set_lower_bounds(i, 0.0) lp.variables.set_upper_bounds(i, 0.0) # Set slack[i] to unconstrained lp.variables.set_lower_bounds(k + p + i, -cpx.infinity) lp.variables.set_upper_bounds(k + p + i, cpx.infinity) lp.solve() if (not lp.solution.is_primal_feasible()): raise RuntimeError('Could not solve LP with Cplex') rbf_l = np.array(lp.solution.get_values(0, k - 1)) rbf_h = np.array(lp.solution.get_values(k, k + p - 1)) # Compute value of the interpolant at the removed node predicted_val = ru.evaluate_rbf(settings, cv_node_pos[i], n, k, cv_node_pos, rbf_l, rbf_h) # Update leave-one-out error loo_error += abs(predicted_val - cv_node_val[i]) # Fix lambda[i] to zero lp.variables.set_lower_bounds(i, -cpx.infinity) lp.variables.set_upper_bounds(i, cpx.infinity) # Set slack[i] to unconstrained lp.variables.set_lower_bounds(k + p + i, 0.0) lp.variables.set_upper_bounds(k + p + i, 0.0) return loo_error/num_iterations
def create_min_msrsm_model(settings, n, k, var_lower, var_upper, integer_vars, node_pos, rbf_lambda, rbf_h, dist_weight, dist_min, dist_max, fmin, fmax): """Create the concrete model to optimize the MSRSM objective. Create the concreate model to minimize a weighted combination of the value of the RBF interpolant and the (negative of the) distance from the closes interpolation node. This is the Global Search Step of the MSRSM method. Parameters ---------- settings : :class:`rbfopt_settings.RbfSettings` Global and algorithmic settings. n : int The dimension of the problem, i.e. size of the space. k : int Number of nodes, i.e. interpolation points. var_lower : 1D numpy.ndarray[float] Vector of variable lower bounds. var_upper : 1D numpy.ndarray[float] Vector of variable upper bounds. integer_vars : 1D numpy.ndarray[int] List of indices of integer variables. node_pos : 2D numpy.ndarray[float] List of coordinates of the nodes (one on each row). rbf_lambda : 1D numpy.ndarray[float] The lambda coefficients of the RBF interpolant, corresponding to the radial basis functions. List of dimension k. rbf_h : 1D numpy.ndarray[float] The h coefficients of the RBF interpolant, corresponding to the polynomial. List of dimension n+1. dist_weight : float The weight paramater for distance and RBF interpolant value. Must be between 0 and 1. A weight of 1.0 corresponds to using solely distance, 0.0 to objective function. dist_min : float The minimum distance between two interpolation nodes. dist_max : float The maximum distance between two interpolation nodes. fmin : float The minimum value of an interpolation node. fmax : float The maximum value of an interpolation node. Returns ------- pyomo.ConcreteModel The concrete model describing the problem. """ assert (isinstance(var_lower, np.ndarray)) assert (isinstance(var_upper, np.ndarray)) assert (isinstance(integer_vars, np.ndarray)) assert (isinstance(node_pos, np.ndarray)) assert (isinstance(rbf_lambda, np.ndarray)) assert (isinstance(rbf_h, np.ndarray)) assert (len(var_lower) == n) assert (len(var_upper) == n) assert (len(rbf_lambda) == k) assert (len(rbf_h) == 1) assert (len(node_pos) == k) assert (isinstance(settings, RbfSettings)) assert (ru.get_degree_polynomial(settings) == 0) assert (0 <= dist_weight <= 1) assert (dist_max >= dist_min >= 0) model = ConcreteModel() # Dimension of the space model.n = Param(initialize=n) model.N = RangeSet(0, model.n - 1) # Number of interpolation nodes model.k = Param(initialize=k) model.K = RangeSet(0, model.k - 1) # Dimension of u_pi model.q = Param(initialize=(k + 1)) model.Q = RangeSet(0, model.q - 1) model.Qlast = RangeSet(model.q - 1, model.q - 1) # Coefficients of the RBF lambda_h_param = {} for i in range(k): lambda_h_param[i] = float(rbf_lambda[i]) for i in range(1): lambda_h_param[k + i] = float(rbf_h[i]) model.lambda_h = Param(model.Q, initialize=lambda_h_param) # Coordinates of the nodes node_param = {} for i in range(k): for j in range(n): node_param[i, j] = float(node_pos[i][j]) model.node = Param(model.K, model.N, initialize=node_param) # Variable bounds var_lower_param = {} var_upper_param = {} for i in range(n): var_lower_param[i] = float(var_lower[i]) var_upper_param[i] = float(var_upper[i]) model.var_lower = Param(model.N, initialize=var_lower_param) model.var_upper = Param(model.N, initialize=var_upper_param) # Adjust parameters to avoid zero denominators in expressions if (fmax <= fmin + settings.eps_zero): fmax = fmin + 1 if (dist_max <= dist_min + settings.eps_zero): dist_min = dist_max - 1 # Minimum and maximum distance model.dist_min = Param(initialize=dist_min) model.dist_max = Param(initialize=dist_max) # Minimum and maximum of function values interpolation nodes model.fmin = Param(initialize=fmin) model.fmax = Param(initialize=fmax) # Weight of the distance and objective criteria model.dist_weight = Param(initialize=dist_weight) model.obj_weight = Param( initialize=(1.0 if settings.modified_msrsm_score else 1 - dist_weight)) # Value of phi at zero, necessary for shift if (settings.rbf == 'linear'): model.phi_0 = Param(initialize=0.0) elif (settings.rbf == 'multiquadric'): model.phi_0 = Param(initialize=GAMMA) # Variable: the point in the space model.x = Var(model.N, domain=Reals, bounds=_x_bounds) # Auxiliary variables: the vectors (u, \pi), # see equations (6) and (7) in the paper by Costa and Nannicini model.u_pi = Var(model.Q, domain=Reals) # Auxiliary variable: value of the rbf at a given point model.rbfval = Var(domain=Reals) # Auxiliary variable: value of the inverse of \mu_k at a given point model.mindistsq = Var(domain=NonNegativeReals) # Objective function. model.OBJ = Objective(rule=_min_msrsm_obj_expression, sense=minimize) # Constraints. See definitions below. # Constraints. See definitions below. if (settings.rbf == 'linear'): model.UdefConstraint = Constraint(model.K, rule=_udef_linear_constraint_rule) elif (settings.rbf == 'multiquadric'): model.UdefConstraint = Constraint(model.K, rule=_udef_multiquad_constraint_rule) model.NonhomoConstraint = Constraint(model.Qlast, rule=_nonhomo_constraint_rule) model.RbfdefConstraint = Constraint(rule=_rbfdef_constraint_rule) model.MdistdefConstraint = Constraint(model.K, rule=_mdistdef_constraint_rule) # Add integer variables if necessary if (len(integer_vars) > 0): add_integrality_constraints(model, integer_vars) return model
def create_min_bump_model(settings, n, k, Phimat, Pmat, node_val, fast_node_index, fast_node_err_bounds): """Create a model to find RBF coefficients with min bumpiness. Create a quadratic problem to compute the coefficients of the RBF interpolant that minimizes bumpiness and lets all points with index in fast_node_index deviate by a specified percentage from their value. Parameters ---------- settings : :class:`rbfopt_settings.RbfSettings` Global and algorithmic settings. n : int The dimension of the problem, i.e. size of the space. k : int Number of nodes, i.e. interpolation points. Phimat : numpy.matrix Matrix Phi, i.e. top left part of the standard RBF matrix. Pmat : numpy.matrix Matrix P, i.e. top right part of the standard RBF matrix. node_val : 1D numpy.ndarray[float] List of values of the function at the nodes. fast_node_index : 1D numpy.ndarray[float] List of indices of nodes whose function value should be considered variable withing the allowed range. fast_node_err_bounds : List[(float, float)] Allowed deviation from node values for nodes affected by error. This is a list of pairs (lower, upper) of the same length as fast_node_index. Returns ------- pyomo.ConcreteModel The concrete model describing the problem. """ assert (isinstance(node_val, np.ndarray)) assert (isinstance(fast_node_index, np.ndarray)) assert (isinstance(settings, RbfSettings)) assert (len(node_val) == k) assert (isinstance(Phimat, np.matrix)) assert (isinstance(Pmat, np.matrix)) assert (Phimat.shape == (k, k)) assert (Pmat.shape == (k, 1)) assert (len(fast_node_index) == len(fast_node_err_bounds)) assert (ru.get_degree_polynomial(settings) == 0) model = ConcreteModel() # Dimension of the space model.n = Param(initialize=n) model.N = RangeSet(0, model.n - 1) # Dimension of P matrix model.p = Param(initialize=1) model.P = RangeSet(0, 0) # Number of interpolation nodes model.k = Param(initialize=k) model.K = RangeSet(0, model.k - 1) # Node values, i.e. right hand sides of the first set of equations # in the constraints node_val_param = {} for i in range(k): node_val_param[i] = node_val[i] model.node_val = Param(model.K, initialize=node_val_param) # Variable bounds slack_lower_param = {} slack_upper_param = {} for (pos, var_index) in enumerate(fast_node_index): slack_lower_param[var_index] = float(fast_node_err_bounds[pos][0]) slack_upper_param[var_index] = float(fast_node_err_bounds[pos][1]) model.slack_lower = Param(model.K, initialize=slack_lower_param, default=0.0) model.slack_upper = Param(model.K, initialize=slack_upper_param, default=0.0) # Phi matrix. Phi_param = {} for i in range(k): for j in range(k): if (abs(Phimat[i, j]) != 0.0): Phi_param[i, j] = float(Phimat[i, j]) model.Phi = Param(model.K, model.K, initialize=Phi_param, default=0.0) # P matrix. Pm_param = {} for i in range(k): for j in range(1): if (abs(Pmat[i, j]) != 0.0): Pm_param[i, j] = float(Pmat[i, j]) model.Pm = Param(model.K, model.P, initialize=Pm_param, default=0.0) # Variable: the lambda coefficients of the RBF model.rbf_lambda = Var(model.K, domain=Reals) # Variable: the h coefficients of the RBF model.rbf_h = Var(model.P, domain=Reals) # Variable: the slacks for the equality constraints model.slack = Var(model.K, domain=Reals, bounds=_slack_bounds) # Objective function. model.OBJ = Objective(rule=_min_bump_obj_expression, sense=minimize) # Constraints. See definitions below. model.IntrConstraint = Constraint(model.K, rule=_intr_constraint_rule) model.UnisConstraint = Constraint(model.P, rule=_unis_constraint_rule) return model
def create_max_h_k_model(settings, n, k, var_lower, var_upper, integer_vars, node_pos, rbf_lambda, rbf_h, mat, target_val): """Create the abstract model to maximize h_k. Create the abstract model to maximize h_k, also known as the Global Search Step of the RBF method. Parameters ---------- settings : :class:`rbfopt_settings.RbfSettings` Global and algorithmic settings. n : int The dimension of the problem, i.e. size of the space. k : int Number of nodes, i.e. interpolation points. var_lower : 1D numpy.ndarray[float] Vector of variable lower bounds. var_upper : 1D numpy.ndarray[float] Vector of variable upper bounds. integer_vars : 1D numpy.ndarray[int] List of indices of integer variables. node_pos : 2D numpy.ndarray[float] List of coordinates of the nodes (one on each row). rbf_lambda : 1D numpy.ndarray[float] The lambda coefficients of the RBF interpolant, corresponding to the radial basis functions. List of dimension k. rbf_h : 1D numpy.ndarray[float] The h coefficients of the RBF interpolant, corresponding to the polynomial. List of dimension n+1. mat: numpy.matrix The matrix necessary for the computation. This is the inverse of the matrix [Phi P; P^T 0], see paper as cited above. Must be a numpy.matrix of dimension ((k+1) x (k+1)) target_val : float Value f* that we want to find in the unknown objective function. Returns ------- pyomo.ConcreteModel The concrete model describing the problem. """ assert (isinstance(var_lower, np.ndarray)) assert (isinstance(var_upper, np.ndarray)) assert (isinstance(integer_vars, np.ndarray)) assert (isinstance(node_pos, np.ndarray)) assert (isinstance(rbf_lambda, np.ndarray)) assert (isinstance(rbf_h, np.ndarray)) assert (len(var_lower) == n) assert (len(var_upper) == n) assert (len(rbf_lambda) == k) assert (len(rbf_h) == 1) assert (len(node_pos) == k) assert (isinstance(mat, np.matrix)) assert (mat.shape == (k + 1, k + 1)) assert (isinstance(settings, RbfSettings)) assert (ru.get_degree_polynomial(settings) == 0) model = ConcreteModel() # Dimension of the space model.n = Param(initialize=n) model.N = RangeSet(0, model.n - 1) # Number of interpolation nodes model.k = Param(initialize=k) model.K = RangeSet(0, model.k - 1) # Dimension of the matrix model.q = Param(initialize=(k + 1)) model.Q = RangeSet(0, model.q - 1) model.Qlast = RangeSet(model.q - 1, model.q - 1) # Coefficients of the RBF lambda_h_param = {} for i in range(k): lambda_h_param[i] = float(rbf_lambda[i]) for i in range(1): lambda_h_param[k + i] = float(rbf_h[i]) model.lambda_h = Param(model.Q, initialize=lambda_h_param) # Coordinates of the nodes node_param = {} for i in range(k): for j in range(n): node_param[i, j] = float(node_pos[i][j]) model.node = Param(model.K, model.N, initialize=node_param) # Variable bounds var_lower_param = {} var_upper_param = {} for i in range(n): var_lower_param[i] = float(var_lower[i]) var_upper_param[i] = float(var_upper[i]) model.var_lower = Param(model.N, initialize=var_lower_param) model.var_upper = Param(model.N, initialize=var_upper_param) # Inverse of the matrix [Phi P; P^T 0]. Because the matrix is # symmetric, we only save the upper right part, while doubling the # off-diagonal elements. Ainv_param = {} for i in range(k + 1): for j in range(i, k + 1): if (abs(mat[i, j]) != 0.0): if (i == j): Ainv_param[i, j] = float(mat[i, j]) else: Ainv_param[i, j] = float(2 * mat[i, j]) model.Ainv = Param(model.Q, model.Q, initialize=Ainv_param, default=0.0) # Target value model.fstar = Param(initialize=target_val) # Value of phi at zero, necessary for shift if (settings.rbf == 'linear'): model.phi_0 = Param(initialize=0.0) elif (settings.rbf == 'multiquadric'): model.phi_0 = Param(initialize=GAMMA) # Variable: the point in the space model.x = Var(model.N, domain=Reals, bounds=_x_bounds) # Auxiliary variables: the vectors (u, \pi), # see equations (6) and (7) in the paper by Costa and Nannicini model.u_pi = Var(model.Q, domain=Reals) # Auxiliary variable: value of the rbf at a given point model.rbfval = Var(domain=Reals) # Auxiliary variable: value of the inverse of \mu_k at a given point model.mu_k_inv = Var(domain=Reals) # Objective function. model.OBJ = Objective(rule=_max_h_k_obj_expression, sense=maximize) # Constraints. See definitions below. if (settings.rbf == 'linear'): model.UdefConstraint = Constraint(model.K, rule=_udef_linear_constraint_rule) elif (settings.rbf == 'multiquadric'): model.UdefConstraint = Constraint(model.K, rule=_udef_multiquad_constraint_rule) model.NonhomoConstraint = Constraint(model.Qlast, rule=_nonhomo_constraint_rule) model.RbfdefConstraint = Constraint(rule=_rbfdef_constraint_rule) model.MukdefConstraint = Constraint(rule=_mukdef_constraint_rule) # Add integer variables if necessary if (len(integer_vars) > 0): add_integrality_constraints(model, integer_vars) return model
def create_min_rbf_model(settings, n, k, var_lower, var_upper, integer_vars, node_pos, rbf_lambda, rbf_h): """Create the concrete model to minimize the RBF. Create the concrete model to minimize the RBF. Parameters ---------- settings : :class:`rbfopt_settings.RbfSettings` Global and algorithmic settings. n : int The dimension of the problem, i.e. size of the space. k : int Number of nodes, i.e. interpolation points. var_lower : 1D numpy.ndarray[float] Vector of variable lower bounds. var_upper : 1D numpy.ndarray[float] Vector of variable upper bounds. integer_vars : 1D numpy.ndarray[int] List of indices of integer variables. node_pos : 2D numpy.ndarray[float] List of coordinates of the nodes. rbf_lambda : 1D numpy.ndarray[float] The lambda coefficients of the RBF interpolant, corresponding to the radial basis functions. List of dimension k. rbf_h : 1D numpy.ndarray[float] The h coefficients of the RBF interpolant, corresponding to the polynomial. List of dimension n+1. Returns ------- pyomo.ConcreteModel The concrete model describing the problem. """ assert (isinstance(var_lower, np.ndarray)) assert (isinstance(var_upper, np.ndarray)) assert (isinstance(integer_vars, np.ndarray)) assert (isinstance(node_pos, np.ndarray)) assert (isinstance(rbf_lambda, np.ndarray)) assert (isinstance(rbf_h, np.ndarray)) assert (len(var_lower) == n) assert (len(var_upper) == n) assert (len(rbf_lambda) == k) assert (len(rbf_h) == 1) assert (len(node_pos) == k) assert (isinstance(settings, RbfSettings)) assert (ru.get_degree_polynomial(settings) == 0) model = ConcreteModel() # Dimension of the space model.n = Param(initialize=n) model.N = RangeSet(0, model.n - 1) # Number of interpolation nodes model.k = Param(initialize=k) model.K = RangeSet(0, model.k - 1) # Dimension of u_pi model.q = Param(initialize=(k + 1)) model.Q = RangeSet(0, model.q - 1) model.Qlast = RangeSet(model.q - 1, model.q - 1) # Coefficients of the RBF lambda_h_param = {} for i in range(k): lambda_h_param[i] = float(rbf_lambda[i]) for i in range(1): lambda_h_param[k + i] = float(rbf_h[i]) model.lambda_h = Param(model.Q, initialize=lambda_h_param) # Coordinates of the nodes node_param = {} for i in range(k): for j in range(n): node_param[i, j] = float(node_pos[i][j]) model.node = Param(model.K, model.N, initialize=node_param) # Variable bounds var_lower_param = {} var_upper_param = {} for i in range(n): var_lower_param[i] = float(var_lower[i]) var_upper_param[i] = float(var_upper[i]) model.var_lower = Param(model.N, initialize=var_lower_param) model.var_upper = Param(model.N, initialize=var_upper_param) # Variable: the point in the space model.x = Var(model.N, domain=Reals, bounds=_x_bounds) # Auxiliary variables: the vectors (u, \pi), # see equations (6) and (7) in the paper by Costa and Nannicini model.u_pi = Var(model.Q, domain=Reals) model.OBJ = Objective(rule=_min_rbf_obj_expression, sense=minimize) # Constraints. See definitions below. if (settings.rbf == 'linear'): model.UdefConstraint = Constraint(model.K, rule=_udef_linear_constraint_rule) elif (settings.rbf == 'multiquadric'): model.UdefConstraint = Constraint(model.K, rule=_udef_multiquad_constraint_rule) model.NonhomoConstraint = Constraint(model.Qlast, rule=_nonhomo_constraint_rule) # Add integer variables if necessary if (len(integer_vars) > 0): add_integrality_constraints(model, integer_vars) return model
def create_max_one_over_mu_model(settings, n, k, var_lower, var_upper, integer_vars, node_pos, mat): """Create the concrete model to maximize 1/\mu. Create the concrete model to maximize :math: `1/\mu`, also known as the InfStep of the RBF method. See paper by Costa and Nannicini, equation (7) pag 4, and the references therein. Parameters ---------- settings : :class:`rbfopt_settings.RbfSettings` Global and algorithmic settings. n : int The dimension of the problem, i.e. size of the space. k : int Number of nodes, i.e. interpolation points. var_lower : 1D numpy.ndarray[float] Vector of variable lower bounds. var_upper : 1D numpy.ndarray[float] Vector of variable upper bounds. integer_vars : 1D numpy.ndarray[int] List of indices of integer variables. node_pos : 2D numpy.ndarray[float] List of coordinates of the nodes (one on each row). mat: numpy.matrix The matrix necessary for the computation. This is the inverse of the matrix [Phi P; P^T 0], see paper as cited above. Must be a numpy.matrix of dimension ((k+1) x (k+1)) Returns ------- pyomo.ConcreteModel The concrete model describing the problem. """ assert (isinstance(var_lower, np.ndarray)) assert (isinstance(var_upper, np.ndarray)) assert (isinstance(integer_vars, np.ndarray)) assert (isinstance(node_pos, np.ndarray)) assert (len(var_lower) == n) assert (len(var_upper) == n) assert (len(node_pos) == k) assert (isinstance(mat, np.matrix)) assert (mat.shape == (k + 1, k + 1)) assert (isinstance(settings, RbfSettings)) assert (ru.get_degree_polynomial(settings) == 0) model = ConcreteModel() # Dimension of the space model.n = Param(initialize=n) model.N = RangeSet(0, model.n - 1) # Number of interpolation nodes model.k = Param(initialize=k) model.K = RangeSet(0, model.k - 1) # Dimension of the matrix model.q = Param(initialize=(k + 1)) model.Q = RangeSet(0, model.q - 1) model.Qlast = RangeSet(model.q - 1, model.q - 1) # Coordinates of the nodes node_param = {} for i in range(k): for j in range(n): node_param[i, j] = float(node_pos[i][j]) model.node = Param(model.K, model.N, initialize=node_param) # Variable bounds var_lower_param = {} var_upper_param = {} for i in range(n): var_lower_param[i] = float(var_lower[i]) var_upper_param[i] = float(var_upper[i]) model.var_lower = Param(model.N, initialize=var_lower_param) model.var_upper = Param(model.N, initialize=var_upper_param) # Inverse of the matrix [Phi P; P^T 0]. Because the matrix is # symmetric, we only save the upper right part, while doubling the # off-diagonal elements. Ainv_param = {} for i in range(k + 1): for j in range(i, k + 1): if (abs(mat[i, j]) != 0.0): if (i == j): Ainv_param[i, j] = float(mat[i, j]) else: Ainv_param[i, j] = float(2 * mat[i, j]) model.Ainv = Param(model.Q, model.Q, initialize=Ainv_param, default=0.0) # Value of phi at zero, necessary for shift if (settings.rbf == 'linear'): model.phi_0 = Param(initialize=0.0) elif (settings.rbf == 'multiquadric'): model.phi_0 = Param(initialize=GAMMA) # Variable: the point in the space model.x = Var(model.N, domain=Reals, bounds=_x_bounds) # Auxiliary variables: the vectors (u, \pi), # see equations (6) and (7) in the paper by Costa and Nannicini model.u_pi = Var(model.Q, domain=Reals) # Objective function. Remember that there should be a constant # term \phi(0) at the beginning, but because this is zero in this # case we take it out. model.OBJ = Objective(rule=_max_one_over_mu_obj_expression, sense=maximize) # Constraints. See definitions below. if (settings.rbf == 'linear'): model.UdefConstraint = Constraint(model.K, rule=_udef_linear_constraint_rule) elif (settings.rbf == 'multiquadric'): model.UdefConstraint = Constraint(model.K, rule=_udef_multiquad_constraint_rule) model.NonhomoConstraint = Constraint(model.Qlast, rule=_nonhomo_constraint_rule) # Add integer variables if necessary if (len(integer_vars) > 0): add_integrality_constraints(model, integer_vars) return model