1# Copyright 2018 The TensorFlow Authors. All Rights Reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# ============================================================================== 15"""Defines abstract class for `ConstrainedMinimizationProblem`s. 16 17A ConstrainedMinimizationProblem consists of an objective function to minimize, 18and a set of constraint functions that are constrained to be nonpositive. 19""" 20 21from __future__ import absolute_import 22from __future__ import division 23from __future__ import print_function 24 25import abc 26 27import six 28 29 30@six.add_metaclass(abc.ABCMeta) 31class ConstrainedMinimizationProblem(object): 32 """Abstract class representing a `ConstrainedMinimizationProblem`. 33 34 A ConstrainedMinimizationProblem consists of an objective function to 35 minimize, and a set of constraint functions that are constrained to be 36 nonpositive. 37 38 In addition to the constraint functions, there may (optionally) be proxy 39 constraint functions: a ConstrainedOptimizer will attempt to penalize these 40 proxy constraint functions so as to satisfy the (non-proxy) constraints. Proxy 41 constraints could be used if the constraints functions are difficult or 42 impossible to optimize (e.g. if they're piecewise constant), in which case the 43 proxy constraints should be some approximation of the original constraints 44 that is well-enough behaved to permit successful optimization. 45 """ 46 47 @abc.abstractproperty 48 def objective(self): 49 """Returns the objective function. 50 51 Returns: 52 A 0d tensor that should be minimized. 53 """ 54 pass 55 56 @property 57 def num_constraints(self): 58 """Returns the number of constraints. 59 60 Returns: 61 An int containing the number of constraints. 62 63 Raises: 64 ValueError: If the constraints (or proxy_constraints, if present) do not 65 have fully-known shapes, OR if proxy_constraints are present, and the 66 shapes of constraints and proxy_constraints are fully-known, but they're 67 different. 68 """ 69 constraints_shape = self.constraints.get_shape() 70 if self.proxy_constraints is None: 71 proxy_constraints_shape = constraints_shape 72 else: 73 proxy_constraints_shape = self.proxy_constraints.get_shape() 74 75 if (constraints_shape.ndims is None or 76 proxy_constraints_shape.ndims is None or 77 any(ii is None for ii in constraints_shape.as_list()) or 78 any(ii is None for ii in proxy_constraints_shape.as_list())): 79 raise ValueError( 80 "constraints and proxy_constraints must have fully-known shapes") 81 if constraints_shape != proxy_constraints_shape: 82 raise ValueError( 83 "constraints and proxy_constraints must have the same shape") 84 85 size = 1 86 for ii in constraints_shape.as_list(): 87 size *= ii 88 return int(size) 89 90 @abc.abstractproperty 91 def constraints(self): 92 """Returns the vector of constraint functions. 93 94 Letting g_i be the ith element of the constraints vector, the ith constraint 95 will be g_i <= 0. 96 97 Returns: 98 A tensor of constraint functions. 99 """ 100 pass 101 102 # This is a property, instead of an abstract property, since it doesn't need 103 # to be overridden: if proxy_constraints returns None, then there are no 104 # proxy constraints. 105 @property 106 def proxy_constraints(self): 107 """Returns the optional vector of proxy constraint functions. 108 109 The difference between `constraints` and `proxy_constraints` is that, when 110 proxy constraints are present, the `constraints` are merely EVALUATED during 111 optimization, whereas the `proxy_constraints` are DIFFERENTIATED. If there 112 are no proxy constraints, then the `constraints` are both evaluated and 113 differentiated. 114 115 For example, if we want to impose constraints on step functions, then we 116 could use these functions for `constraints`. However, because a step 117 function has zero gradient almost everywhere, we can't differentiate these 118 functions, so we would take `proxy_constraints` to be some differentiable 119 approximation of `constraints`. 120 121 Returns: 122 A tensor of proxy constraint functions. 123 """ 124 return None 125 126 # This is a property, instead of an abstract property, since it doesn't need 127 # to be overridden: if pre_train_ops returns None, then there are no ops to 128 # run before train_op. 129 @property 130 def pre_train_ops(self): 131 """Returns a list of `Operation`s to run before the train_op. 132 133 When a `ConstrainedOptimizer` creates a train_op (in `minimize` 134 `minimize_unconstrained`, or `minimize_constrained`), it will include these 135 ops before the main training step. 136 137 Returns: 138 A list of `Operation`s. 139 """ 140 return None 141