diff --git a/.github/workflows/execute_notebook.yaml b/.github/workflows/execute_notebook.yaml index a3d4f842..75773a0c 100644 --- a/.github/workflows/execute_notebook.yaml +++ b/.github/workflows/execute_notebook.yaml @@ -11,46 +11,48 @@ on: branches: - 'master' - 'develop' + create: branches: - 'master' tags: - '**' + jobs: linux: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 if: "!contains(github.event.head_commit.message, 'no ci')" strategy: max-parallel: 5 matrix: - os: [ubuntu-latest] python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} + cache: 'pip' - name: Install dependencies run: | python -m pip install --upgrade pip - pip install lxml_html_clean - pip install -r requirements.txt - pip install mosek + python -m pip install lxml_html_clean + python -m pip install -r requirements.txt + python -m pip install mosek - name: Update version in setup.py run: sed -i "s/{{VERSION_PLACEHOLDER}}/0.0.0/g" setup.py - name: Install PEPit - run: pip install -e . + run: python -m pip install -e . - name: Install notebook runner deps (papermill etc.) run: | - pip install papermill ipykernel nbformat nbconvert + python -m pip install papermill ipykernel nbformat nbconvert - name: Run demo notebook with papermill env: diff --git a/.github/workflows/pypi_release.yaml b/.github/workflows/pypi_release.yaml index 922f7c8a..e73f7aee 100644 --- a/.github/workflows/pypi_release.yaml +++ b/.github/workflows/pypi_release.yaml @@ -3,32 +3,40 @@ name: Publish Python 🐍 distributions 📦 to PyPI on: push: tags: - - '*' + - '*' jobs: build-n-publish: name: Build and publish Python 🐍 distributions 📦 to PyPI - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 + steps: - - uses: actions/checkout@master - - name: Set up Python 3.10 - uses: actions/setup-python@v3 - with: - python-version: '3.10' - - name: Install pypa/setuptools - run: >- - python -m - pip install wheel - - name: Extract tag name - id: tag - run: echo ::set-output name=TAG_NAME::$(echo $GITHUB_REF | cut -d / -f 3) - - name: Update version in setup.py - run: >- - sed -i "s/{{VERSION_PLACEHOLDER}}/${{ steps.tag.outputs.TAG_NAME }}/g" setup.py - - name: Build a binary wheel - run: >- - python setup.py sdist bdist_wheel - - name: Publish distribution 📦 to PyPI - uses: pypa/gh-action-pypi-publish@master - with: - password: ${{ secrets.PYPI_API_TOKEN }} + - uses: actions/checkout@v4 + + - name: Set up Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Install build tooling + run: | + python -m pip install --upgrade pip + python -m pip install build + + - name: Extract tag name + id: tag + run: | + echo "TAG_NAME=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + + - name: Update version in setup.py + run: | + sed -i "s/{{VERSION_PLACEHOLDER}}/${{ steps.tag.outputs.TAG_NAME }}/g" setup.py + + - name: Build distributions + run: | + python -m build + + - name: Publish distribution 📦 to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 1376c02d..d6b68017 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -21,8 +21,7 @@ on: jobs: linux: - - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 if: "!contains(github.event.head_commit.message, 'no ci')" strategy: max-parallel: 5 @@ -30,37 +29,41 @@ jobs: python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] steps: - - uses: actions/checkout@v1 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - pip install coverage - - name: Update version in setup.py - run: >- - sed -i "s/{{VERSION_PLACEHOLDER}}/0.0.0/g" setup.py - - name: Install PEPit - run: | - pip install -e . - - name: Install MOSEK - run: | - pip install mosek - - name: Setup MOSEK license, run tests and generate report - env: - MOSEKLM_LICENSE_FILE: ${{ secrets.MSK_LICENSE }} - run: | - coverage run -m unittest tests/test_* - - name: Upload Coverage to Codecov - uses: codecov/codecov-action@v3 + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' - linux_no_mosek: + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install -r requirements.txt + python -m pip install coverage + + - name: Update version in setup.py + run: sed -i "s/{{VERSION_PLACEHOLDER}}/0.0.0/g" setup.py + + - name: Install PEPit + run: python -m pip install -e . + + - name: Install MOSEK + run: python -m pip install mosek + + - name: Setup MOSEK license, run tests and generate report + env: + MOSEKLM_LICENSE_FILE: ${{ secrets.MSK_LICENSE }} + run: | + coverage run -m unittest tests/test_* - runs-on: ubuntu-latest + - name: Upload Coverage to Codecov + uses: codecov/codecov-action@v3 + + + linux_no_mosek: + runs-on: ubuntu-22.04 if: "!contains(github.event.head_commit.message, 'no ci')" strategy: max-parallel: 5 @@ -68,32 +71,36 @@ jobs: python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] steps: - - uses: actions/checkout@v1 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - pip install coverage - - name: Update version in setup.py - run: >- - sed -i "s/{{VERSION_PLACEHOLDER}}/0.0.0/g" setup.py - - name: Install PEPit - run: | - pip install -e . - - name: Run tests and generate report - run: | - coverage run -m unittest tests/test_* - - name: Upload Coverage to Codecov - uses: codecov/codecov-action@v3 + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' - linux_no_mosek_license: + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install -r requirements.txt + python -m pip install coverage + + - name: Update version in setup.py + run: sed -i "s/{{VERSION_PLACEHOLDER}}/0.0.0/g" setup.py + + - name: Install PEPit + run: python -m pip install -e . - runs-on: ubuntu-latest + - name: Run tests and generate report + run: | + coverage run -m unittest tests/test_* + + - name: Upload Coverage to Codecov + uses: codecov/codecov-action@v3 + + + linux_no_mosek_license: + runs-on: ubuntu-22.04 if: "!contains(github.event.head_commit.message, 'no ci')" strategy: max-parallel: 5 @@ -101,27 +108,32 @@ jobs: python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] steps: - - uses: actions/checkout@v1 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - pip install coverage - - name: Update version in setup.py - run: >- - sed -i "s/{{VERSION_PLACEHOLDER}}/0.0.0/g" setup.py - - name: Install PEPit - run: | - pip install -e . - - name: Setup MOSEK - run: | - pip install mosek - - name: Run tests and generate report - run: | - coverage run -m unittest tests/test_* - - name: Upload Coverage to Codecov - uses: codecov/codecov-action@v3 + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install -r requirements.txt + python -m pip install coverage + + - name: Update version in setup.py + run: sed -i "s/{{VERSION_PLACEHOLDER}}/0.0.0/g" setup.py + + - name: Install PEPit + run: python -m pip install -e . + + - name: Setup MOSEK + run: python -m pip install mosek + + - name: Run tests and generate report + run: | + coverage run -m unittest tests/test_* + + - name: Upload Coverage to Codecov + uses: codecov/codecov-action@v3 diff --git a/PEPit/constraint.py b/PEPit/constraint.py index fd28e74e..7aa64ce3 100644 --- a/PEPit/constraint.py +++ b/PEPit/constraint.py @@ -8,6 +8,7 @@ class Constraint(object): Attributes: name (str): A name set through the set_name method. None is no name is given. + activated (bool): A boolean flag used to activate/deactivate the Constraint in the PEP. expression (Expression): The :class:`Expression` that is compared to 0. equality_or_inequality (str): "equality" or "inequality". Encodes the type of constraint. _value (float): numerical value of `self.expression` obtained after solving the PEP via SDP solver. @@ -56,13 +57,16 @@ def __init__(self, AssertionError: if provided `equality_or_inequality` argument is neither "equality" nor "inequality". """ - # Initialize name of the constraint - self.name = None + # Initialize the activated attribute to True + self.activated = True # Update the counter self.counter = Constraint.counter Constraint.counter += 1 + # Initialize name of the constraint + self.name = "Constraint {}".format(self.counter) + # Store the underlying expression self.expression = expression @@ -92,6 +96,20 @@ def get_name(self): """ return self.name + def activate(self): + """ + Activate the use of the Constraint. + + """ + self.activated = True + + def deactivate(self): + """ + Deactivate the use of the Constraint. + + """ + self.activated = False + def eval(self): """ Compute, store and return the value of the underlying :class:`Expression` of this :class:`Constraint`. diff --git a/PEPit/function.py b/PEPit/function.py index fd555b70..24445fb8 100644 --- a/PEPit/function.py +++ b/PEPit/function.py @@ -418,7 +418,7 @@ def add_constraints_from_two_lists_of_points(self, list_of_points_1, list_of_poi if xj_id is None: xj_id = "Point_{}".format(j) - if i == j or (i > j and symmetry): + if point_i == point_j or (i > j and symmetry): row_of_constraints.append(0) else: diff --git a/PEPit/pep.py b/PEPit/pep.py index 82653f09..8fd32905 100644 --- a/PEPit/pep.py +++ b/PEPit/pep.py @@ -37,8 +37,11 @@ class PEP(object): wrapper_name (str): name of the used wrapper. wrapper (Wrapper): :class:`Wrapper` object that interfaces between the :class:`PEP` and the solver. - _list_of_constraints_sent_to_wrapper (list): list of :class:`Constraint` objects sent to the wrapper. - _list_of_psd_sent_to_wrapper (list): list of :class:`PSDMatrix` objects sent to the wrapper. + _list_of_prepared_constraints (list): list of :class:`Constraint` objects ready to be sent to the wrapper. + _list_of_prepared_psd (list): list of :class:`PSDMatrix` objects ready to be sent to the wrapper. + + _list_of_constraints_sent_to_wrapper (list): list of :class:`Constraint` objects actually sent to the wrapper. + _list_of_psd_sent_to_wrapper (list): list of :class:`PSDMatrix` objects actually sent to the wrapper. objective (Expression): the expression to be maximized by the solver. It is set by the method `solve`. And should not be updated otherwise. @@ -87,6 +90,8 @@ def __init__(self): # Initialize lists of constraints that will be sent to the wrapper to solve the SDP. # Those lists should not be updated by hand, only the solve method does update them. + self._list_of_prepared_constraints = list() + self._list_of_prepared_psd = list() self._list_of_constraints_sent_to_wrapper = list() self._list_of_psd_sent_to_wrapper = list() @@ -330,6 +335,13 @@ def solve(self, wrapper="cvxpy", return_primal_or_dual="dual", safe_mode=True, v float: Worst case guarantee of the PEP. """ + # Prepare the list of constraints to be given to the wrapper + # This runs only once! + # Then the method solve directly interacts with the solvers without browsing all PEPit's data. + if self.objective is None: + self._prepare_constraints(verbose=verbose) + + # Prepare wrapper and solver wrapper_name = wrapper.lower() # Check that the solver is installed, if it is not, switch to CVXPY. @@ -356,53 +368,24 @@ def solve(self, wrapper="cvxpy", return_primal_or_dual="dual", safe_mode=True, v self.wrapper_name = wrapper_name self.wrapper = wrapper - # Call the internal solve methods, which formulates and solves the PEP via the SDP solver. + # Call the internal solving methods, which formulates and solves the PEP via the SDP solver. out = self._solve_with_wrapper(wrapper, verbose, return_primal_or_dual, dimension_reduction_heuristic, eig_regularization, tol_dimension_reduction, **kwargs) return out - def _solve_with_wrapper(self, wrapper, verbose=1, return_primal_or_dual="dual", - dimension_reduction_heuristic=None, eig_regularization=1e-3, tol_dimension_reduction=1e-4, - **kwargs): + def _prepare_constraints(self, verbose=1): """ - Internal solve method. Translate the :class:`PEP` to an SDP, and solve it via the wrapper. + Prepare the lists of scalar and lmi constraints that can be used. + Those are stored in the attributes `_list_of_prepared_constraints` and `_list_of_prepared_psd`. Args: - wrapper (Wrapper): Interface to the solver. verbose (int, optional): Level of information details to print - (Override the CVXPY solver verbose parameter). - - - 0: No verbose at all - - 1: PEPit information is printed but not CVXPY's - - 2: Both PEPit and solver details are printed - return_primal_or_dual (str, optional): If "dual", it returns a worst-case upper bound of the PEP - (dual value of the objective). - If "primal", it returns a worst-case lower bound of the PEP - (primal value of the objective). - Default is "dual". - Note both value should be almost the same by strong duality. - dimension_reduction_heuristic (str, optional): An heuristic to reduce the dimension of the solution - (rank of the Gram matrix). Set to None to deactivate - it (default value). Available heuristics are: - - - "trace": minimize :math:`Tr(G)` - - "logdet{an integer n}": minimize - :math:`\\log\\left(\\mathrm{Det}(G)\\right)` - using n iterations of local approximation problems. - - eig_regularization (float, optional): The regularization we use to make - :math:`G + \\mathrm{eig_regularization}I_d \succ 0`. - (only used when "dimension_reduction_heuristic" is not None) - The default value is 1e-5. - tol_dimension_reduction (float, optional): The error tolerance in the heuristic minimization problem. - Precisely, the second problem minimizes "optimal_value - tol" - (only used when "dimension_reduction_heuristic" is not None) - The default value is 1e-5. - kwargs (keywords, optional): Additional solver-specific arguments. + (Override the solver verbose parameter). - Returns: - float: Worst-case guarantee of the PEP. + - 0: No verbose at all + - 1: PEPit information is printed but not solver's + - 2: Both PEPit and solver details are printed """ @@ -423,15 +406,9 @@ def _solve_with_wrapper(self, wrapper, verbose=1, return_primal_or_dual="dual", # Create an expression that serve for the objective (min of the performance measures) self.objective = Expression(is_leaf=True) - # Report the creation of variables (G, F) - if verbose: - print('(PEPit) Setting up the problem:' - ' size of the Gram matrix: {}x{}'.format(Point.counter, Point.counter)) - wrapper.set_main_variables() - # Initialize the lists of constraints sent to wrapper - self._list_of_constraints_sent_to_wrapper = list() - self._list_of_psd_sent_to_wrapper = list() + self._list_of_prepared_constraints = list() + self._list_of_prepared_psd = list() # Defining performance metrics # Note maximizing the minimum of all the performance metrics @@ -440,8 +417,7 @@ def _solve_with_wrapper(self, wrapper, verbose=1, return_primal_or_dual="dual", for performance_metric in self.list_of_performance_metrics: assert isinstance(performance_metric, Expression) performance_metric_constraint = (self.objective <= performance_metric) - wrapper.send_constraint_to_solver(performance_metric_constraint) - self._list_of_constraints_sent_to_wrapper.append(performance_metric_constraint) + self._list_of_prepared_constraints.append(performance_metric_constraint) if verbose: print('(PEPit) Setting up the problem:' @@ -451,8 +427,7 @@ def _solve_with_wrapper(self, wrapper, verbose=1, return_primal_or_dual="dual", if verbose: print('(PEPit) Setting up the problem: Adding initial conditions and general constraints ...') for condition in self.list_of_constraints: - wrapper.send_constraint_to_solver(condition) - self._list_of_constraints_sent_to_wrapper.append(condition) + self._list_of_prepared_constraints.append(condition) if verbose: print('(PEPit) Setting up the problem:' ' initial conditions and general constraints ({} constraint(s) added)'.format( @@ -463,8 +438,11 @@ def _solve_with_wrapper(self, wrapper, verbose=1, return_primal_or_dual="dual", if verbose: print('(PEPit) Setting up the problem: {} lmi constraint(s) added'.format(len(self.list_of_psd))) for psd_counter, psd_matrix in enumerate(self.list_of_psd): - wrapper.send_lmi_constraint_to_solver(psd_counter, psd_matrix) - self._list_of_psd_sent_to_wrapper.append(psd_matrix) + # Print a message if verbose mode activated + if verbose > 0: + print('\t\t Size of PSD matrix {}: {}x{}'.format(psd_counter + 1, *psd_matrix.shape)) + # Add the PSD matrix to the list of prepared PSDs + self._list_of_prepared_psd.append(psd_matrix) # Defining class constraints if verbose: @@ -479,8 +457,7 @@ def _solve_with_wrapper(self, wrapper, verbose=1, return_primal_or_dual="dual", 'scalar constraint(s) ...') for constraint in function.list_of_class_constraints: - wrapper.send_constraint_to_solver(constraint) - self._list_of_constraints_sent_to_wrapper.append(constraint) + self._list_of_prepared_constraints.append(constraint) if verbose: print('\t\t\tFunction', function_counter, ':', len(function.list_of_class_constraints), @@ -492,8 +469,11 @@ def _solve_with_wrapper(self, wrapper, verbose=1, return_primal_or_dual="dual", 'lmi constraint(s) ...') for psd_counter, psd_matrix in enumerate(function.list_of_class_psd): - wrapper.send_lmi_constraint_to_solver(psd_counter, psd_matrix) - self._list_of_psd_sent_to_wrapper.append(psd_matrix) + # Print a message if verbose mode activated + if verbose > 0: + print('\t\t Size of PSD matrix {}: {}x{}'.format(psd_counter + 1, *psd_matrix.shape)) + # Add the PSD matrix to the list of prepared PSDs + self._list_of_prepared_psd.append(psd_matrix) if verbose: print('\t\t\tFunction', function_counter, ':', len(function.list_of_class_psd), @@ -513,8 +493,7 @@ def _solve_with_wrapper(self, wrapper, verbose=1, return_primal_or_dual="dual", 'scalar constraint(s) ...') for constraint in function.list_of_constraints: - wrapper.send_constraint_to_solver(constraint) - self._list_of_constraints_sent_to_wrapper.append(constraint) + self._list_of_prepared_constraints.append(constraint) if verbose: print('\t\t\tFunction', function_counter, ':', len(function.list_of_constraints), @@ -526,8 +505,11 @@ def _solve_with_wrapper(self, wrapper, verbose=1, return_primal_or_dual="dual", 'lmi constraint(s) ...') for psd_counter, psd_matrix in enumerate(function.list_of_psd): - wrapper.send_lmi_constraint_to_solver(psd_counter, psd_matrix) - self._list_of_psd_sent_to_wrapper.append(psd_matrix) + # Print a message if verbose mode activated + if verbose > 0: + print('\t\t Size of PSD matrix {}: {}x{}'.format(psd_counter + 1, *psd_matrix.shape)) + # Add the PSD matrix to the list of prepared PSDs + self._list_of_prepared_psd.append(psd_matrix) if verbose: print('\t\t\tFunction', function_counter, ':', len(function.list_of_psd), @@ -545,12 +527,77 @@ def _solve_with_wrapper(self, wrapper, verbose=1, return_primal_or_dual="dual", print('\t\t\tPartition', partition_counter, 'with', partition.get_nb_blocks(), 'blocks: Adding', len(partition.list_of_constraints), 'scalar constraint(s)...') for constraint in partition.list_of_constraints: - wrapper.send_constraint_to_solver(constraint) - self._list_of_constraints_sent_to_wrapper.append(constraint) + self._list_of_prepared_constraints.append(constraint) if verbose: print('\t\t\tPartition', partition_counter, 'with', partition.get_nb_blocks(), 'blocks:', len(partition.list_of_constraints), 'scalar constraint(s) added') + def _solve_with_wrapper(self, wrapper, verbose=1, return_primal_or_dual="dual", + dimension_reduction_heuristic=None, eig_regularization=1e-3, tol_dimension_reduction=1e-4, + **kwargs): + """ + Internal solve method. Translate the :class:`PEP` to an SDP, and solve it via the wrapper. + + Args: + wrapper (Wrapper): Interface to the solver. + verbose (int, optional): Level of information details to print + (Override the CVXPY solver verbose parameter). + + - 0: No verbose at all + - 1: PEPit information is printed but not CVXPY's + - 2: Both PEPit and solver details are printed + return_primal_or_dual (str, optional): If "dual", it returns a worst-case upper bound of the PEP + (dual value of the objective). + If "primal", it returns a worst-case lower bound of the PEP + (primal value of the objective). + Default is "dual". + Note both value should be almost the same by strong duality. + dimension_reduction_heuristic (str, optional): An heuristic to reduce the dimension of the solution + (rank of the Gram matrix). Set to None to deactivate + it (default value). Available heuristics are: + + - "trace": minimize :math:`Tr(G)` + - "logdet{an integer n}": minimize + :math:`\\log\\left(\\mathrm{Det}(G)\\right)` + using n iterations of local approximation problems. + + eig_regularization (float, optional): The regularization we use to make + :math:`G + \\mathrm{eig_regularization}I_d \succ 0`. + (only used when "dimension_reduction_heuristic" is not None) + The default value is 1e-5. + tol_dimension_reduction (float, optional): The error tolerance in the heuristic minimization problem. + Precisely, the second problem minimizes "optimal_value - tol" + (only used when "dimension_reduction_heuristic" is not None) + The default value is 1e-5. + kwargs (keywords, optional): Additional solver-specific arguments. + + Returns: + float: Worst-case guarantee of the PEP. + + """ + + # Report the creation of variables (G, F) + if verbose: + print('(PEPit) Setting up the problem:' + ' size of the Gram matrix: {}x{}'.format(Point.counter, Point.counter)) + wrapper.set_main_variables() + + # Determine the lists of constraints and LMIs sent to wrapper + self._list_of_constraints_sent_to_wrapper = [constraint for constraint in self._list_of_prepared_constraints if constraint.activated] + self._list_of_psd_sent_to_wrapper = [psd for psd in self._list_of_prepared_psd if psd.activated] + + # Clean dual variables before solving + for constraint in self._list_of_prepared_constraints: + constraint._dual_variable_value = 0. + for psd in self._list_of_prepared_psd: + psd._dual_variable_value = np.zeros_like(psd.matrix_of_expressions) + + # Send constraints to the wrapper + for constraint in self._list_of_constraints_sent_to_wrapper: + wrapper.send_constraint_to_solver(constraint) + for psd in self._list_of_psd_sent_to_wrapper: + wrapper.send_lmi_constraint_to_solver(psd) + # Instantiate the problem if verbose: print('(PEPit) Compiling SDP') @@ -704,13 +751,13 @@ def check_feasibility(self, wc_value, verbose=1): print(message) # Get the max value of all transgression of the constraints - if self._list_of_constraints_sent_to_wrapper: + if self._list_of_prepared_constraints: max_constraint_error = np.max( [constraint.eval() - for constraint in self._list_of_constraints_sent_to_wrapper + for constraint in self._list_of_prepared_constraints if constraint.equality_or_inequality == "inequality"] + [np.abs(constraint.eval()) - for constraint in self._list_of_constraints_sent_to_wrapper + for constraint in self._list_of_prepared_constraints if constraint.equality_or_inequality == "equality"] ) if verbose: @@ -755,7 +802,7 @@ def check_feasibility(self, wc_value, verbose=1): # Scalar constraints # Dual of inequality constraints >= 0 inequality_constraint_dual_values = [constraint.eval_dual() - for constraint in self._list_of_constraints_sent_to_wrapper + for constraint in self._list_of_prepared_constraints if constraint.equality_or_inequality == "inequality"] if inequality_constraint_dual_values: inequality_constraint_dual_min_value = np.min(inequality_constraint_dual_values) @@ -765,7 +812,7 @@ def check_feasibility(self, wc_value, verbose=1): message += " up to an error of {}".format(-inequality_constraint_dual_min_value) print(message) # + <= 0 - for constraint in self._list_of_constraints_sent_to_wrapper: + for constraint in self._list_of_prepared_constraints: constraints_combination += constraint.eval_dual() * constraint.expression # Proof reconstruction diff --git a/PEPit/psd_matrix.py b/PEPit/psd_matrix.py index e3314a84..c319b372 100644 --- a/PEPit/psd_matrix.py +++ b/PEPit/psd_matrix.py @@ -9,6 +9,7 @@ class PSDMatrix(object): Attributes: name (str): A name set through the set_name method. None is no name is given. + activated (bool): A boolean flag used to activate/deactivate the LMI constraint in the PEP. matrix_of_expressions (Iterable of Iterable of Expression): a square matrix of :class:`Expression` objects. shape (tuple of ints): the shape of the underlying matrix of :class:`Expression` objects. _value (2D ndarray of floats): numerical values of :class:`Expression` objects @@ -61,6 +62,9 @@ def __init__(self, TypeError: if provided matrix does not contain only Expressions and / or scalar values. """ + # Initialize the activated attribute to True + self.activated = True + # Initialize name of the psd matrix self.name = name @@ -95,6 +99,20 @@ def get_name(self): """ return self.name + def activate(self): + """ + Activate the use of the LMI constraint. + + """ + self.activated = True + + def deactivate(self): + """ + Deactivate the use of the LMI constraint. + + """ + self.activated = False + @staticmethod def _store(matrix_of_expressions): """ diff --git a/PEPit/wrapper.py b/PEPit/wrapper.py index 7e224e4d..27697aa2 100644 --- a/PEPit/wrapper.py +++ b/PEPit/wrapper.py @@ -89,13 +89,12 @@ def send_constraint_to_solver(self, constraint): """ raise NotImplementedError("This method must be overwritten in children classes") - def send_lmi_constraint_to_solver(self, psd_counter, psd_matrix): + def send_lmi_constraint_to_solver(self, psd_matrix): """ Transfer a PEPit :class:`PSDMatrix` (LMI constraint) to the solver and add it the tracking lists. Args: - psd_counter (int): a counter useful for the verbose mode. psd_matrix (PSDMatrix): a matrix of expressions that is constrained to be PSD. """ diff --git a/PEPit/wrappers/cvxpy_wrapper.py b/PEPit/wrappers/cvxpy_wrapper.py index 2605e1ff..5e248265 100644 --- a/PEPit/wrappers/cvxpy_wrapper.py +++ b/PEPit/wrappers/cvxpy_wrapper.py @@ -135,18 +135,17 @@ def send_constraint_to_solver(self, constraint): # Raise an exception otherwise raise ValueError('The attribute \'equality_or_inequality\' of a constraint object' ' must either be \'equality\' or \'inequality\'.' - 'Got {}'.format(constraint.equality_or_inequality)) + '{} got {}'.format(constraint.get_name(), constraint.equality_or_inequality)) # Add the corresponding CVXPY constraint to the list of constraints to be sent to CVXPY self._list_of_solver_constraints.append(cvxpy_constraint) - def send_lmi_constraint_to_solver(self, psd_counter, psd_matrix): + def send_lmi_constraint_to_solver(self, psd_matrix): """ Transform a PEPit :class:`PSDMatrix` into a CVXPY symmetric PSD matrix and add the 2 formats of the constraints into the tracking lists. Args: - psd_counter (int): a counter useful for the verbose mode. psd_matrix (PSDMatrix): a matrix of expressions that is constrained to be PSD. """ @@ -170,10 +169,6 @@ def send_lmi_constraint_to_solver(self, psd_counter, psd_matrix): for j in range(psd_matrix.shape[1]): cvxpy_constraints_list.append(M[i, j] == self._expression_to_solver(psd_matrix[i, j])) - # Print a message if verbose mode activated - if self.verbose > 0: - print('\t\t Size of PSD matrix {}: {}x{}'.format(psd_counter + 1, *psd_matrix.shape)) - # Add the corresponding CVXPY constraints to the list of constraints to be sent to CVXPY self._list_of_solver_constraints += cvxpy_constraints_list diff --git a/PEPit/wrappers/mosek_wrapper.py b/PEPit/wrappers/mosek_wrapper.py index 1cc2427d..36c495a6 100644 --- a/PEPit/wrappers/mosek_wrapper.py +++ b/PEPit/wrappers/mosek_wrapper.py @@ -159,14 +159,13 @@ def send_constraint_to_solver(self, constraint, track=True): # Raise an exception otherwise raise ValueError('The attribute \'equality_or_inequality\' of a constraint object' ' must either be \'equality\' or \'inequality\'.' - 'Got {}'.format(constraint.equality_or_inequality)) + '{} got {}'.format(constraint.get_name(), constraint.equality_or_inequality)) - def send_lmi_constraint_to_solver(self, psd_counter, psd_matrix): + def send_lmi_constraint_to_solver(self, psd_matrix): """ Transfer a PEPit :class:`PSDMatrix` (LMI constraint) to MOSEK and add it the tracking lists. Args: - psd_counter (int): a counter useful for the verbose mode. psd_matrix (PSDMatrix): a matrix of expressions that is constrained to be PSD. """ @@ -204,10 +203,6 @@ def send_lmi_constraint_to_solver(self, psd_counter, psd_matrix): self.task.putaijlist(np.full(a_i.shape, nb_cons), a_i, a_val) self.task.putconbound(nb_cons, mosek.boundkey.fx, -alpha_val, -alpha_val) - # Print a message if verbose mode activated - if self.verbose > 0: - print('\t\t Size of PSD matrix {}: {}x{}'.format(psd_counter + 1, *psd_matrix.shape)) - def _recover_dual_values(self): """ Recover all dual variables from solver. diff --git a/docs/source/whatsnew/0.4.1.rst b/docs/source/whatsnew/0.4.1.rst index 26e58856..717a0941 100644 --- a/docs/source/whatsnew/0.4.1.rst +++ b/docs/source/whatsnew/0.4.1.rst @@ -1,10 +1,23 @@ What's new in PEPit 0.4.1 ========================= -- Improvement: The :class:`SmoothQuadraticLojasiewiczFunctionExpensive` has been improved with slightly cheaper formulations. +New features: +------------- -- Added uselessly complexified tests to verify numerically that the formulations are in line. +- One can now disable some software verification tools (licensing, installation, etc) to allow for fast processing time (via boolean option safe_mode). -- Fix: An integer overflow (due to previously specified dtype=int8) in :class:`MosekWrapper` has been fixed. +- Constraints (scalar and LMI) can now be deactivated using the `deactivate` method and activated back using the `activated` method. Note the PEP can be solved several times with different activated constraints. The method `solve` only creates the interpolation constraints once for all. -- New: one can disable some software verification tools (licensing, installation, etc) to allow for fast processing time (via boolean option safe_mode). +New demo: +--------- + +- The file `ressources/demo/PEPit_demo_extracting_a_proof.ipynb` contains an example usage of the new :class:`Constraint` feature. + +Fixes: +------ + +- The :class:`SmoothQuadraticLojasiewiczFunctionExpensive` has been improved with slightly cheaper formulations. + +- An integer overflow (due to previously specified dtype=int8) in :class:`MosekWrapper` has been fixed. + +- The method `add_constraints_from_two_lists_of_points` of the class :class:`Function` has been fixed. So far, it was assumed that the two lists were identical. diff --git a/ressources/demo/PEPit_demo_extracting_a_proof.ipynb b/ressources/demo/PEPit_demo_extracting_a_proof.ipynb new file mode 100644 index 00000000..ac241f4a --- /dev/null +++ b/ressources/demo/PEPit_demo_extracting_a_proof.ipynb @@ -0,0 +1,1783 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b626da1d-95a1-4176-a342-eb66d647b602", + "metadata": { + "tags": [] + }, + "source": [ + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/bgoujaud/PEPit/blob/master/ressources/demo/PEPit_demo_extracting_a_proof.ipynb)" + ] + }, + { + "cell_type": "markdown", + "id": "318ecadc-e8fa-4cb1-a23b-56c932c79e19", + "metadata": {}, + "source": [ + "# PEPit : numerical examples of worst-case analyses" + ] + }, + { + "cell_type": "markdown", + "id": "79ac4037-2324-4b0e-b64b-f85038445479", + "metadata": {}, + "source": [ + "This notebook provides:\n", + "- two simple examples illustrating how to extract numerical values for the dual variables to analyse **gradient descent** in the smooth and strongly convex setting.\n", + "- We show how to search for simplified versions of the proofs, if possible, by explicitly removing certain constraints from the performance estimation problem and by observing they play no role in certain performance guarantees.\n", + "- Finally, we show how to leverage those numerical findings to find a convergence proof with SymPy. More details about such strategies can be found in the repository [learning performance estimation](https://github.com/PerformanceEstimation/Learning-Performance-Estimation), from which those examples were taken.\n", + "\n", + "The examples below are taken from [this blog post](https://francisbach.com/computer-aided-analyses/) and in the [habilitation thesis](https://hal.science/tel-04794552v2/file/HDR_ATaylor_V_HAL2.pdf) that contain a more mathematical introduction to performance estimation problems." + ] + }, + { + "cell_type": "markdown", + "id": "e5cf3c75-9a56-48ef-85b9-e6f77b3a972f", + "metadata": {}, + "source": [ + "This notebook is organized as follows:\n", + "* [1. Gradient descent, distance to a solution](#example1) : numerical study of **gradient descent** for smooth strongly convex minimization, convergence in terms of $\\frac{\\|x_{k+1}-x_\\star\\|^2}{\\|x_k-x_\\star\\|^2}$ (basic example).\n", + "* [2. Gradient descent, function value accuracy](#example2) : numerical study of **gradient descent** for smooth strongly convex minimization, convergence in terms of $\\frac{f(x_{k+1})-f_\\star}{f(x_{k})-f_\\star}$ (more complicated example).\n", + "* [3. Function values: numerical proof simplification](#example3) : a base (greedy) approach to search for which inequalities are needed for a proof of convergence in terms of $\\frac{f(x_{k+1})-f_\\star}{f(x_{k})-f_\\star}$.\n", + "* [4. Using SymPy for the distance analysis](#example4) : leverage the SymPy package to get a closed form solution (and proof) for the analysis of gradient descent in terms of $\\frac{\\|x_{k+1}-x_\\star\\|^2}{\\|x_k-x_\\star\\|^2}$ (basic example).\n", + "* [5. Using SymPy for the function value accuracy analysis](#example5) : leverage the SymPy package to get a closed form solution (and proof) for the analysis of gradient descent in terms of $\\frac{f(x_{k+1})-f_\\star}{f(x_{k})-f_\\star}$ (more technical and illustrates why step [3.](#example3) is useful/needed.\n", + "* [6. Using symbolic regression (PySR package) for guessing closed-forms](#example6)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "6ae4cd3b-b120-47b0-a37c-7d5a124bc0a6", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# import PEPit and the required function class\n", + "from PEPit import PEP\n", + "from PEPit.functions import SmoothStronglyConvexFunction\n", + "# import numpy and matplotlib\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "89818bda-47bd-4929-831d-e05706b2a27c", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# set up the smoothness and strong convexity constant for the whole notebook\n", + "L, mu = 1, .1" + ] + }, + { + "cell_type": "markdown", + "id": "f8a4ca21-ced4-4621-a5e4-852648ba1e17", + "metadata": {}, + "source": [ + "## 1. Gradient descent, distance to a solution " + ] + }, + { + "cell_type": "markdown", + "id": "7f4b3c2b-83ec-494d-8a28-cda5f12338be", + "metadata": {}, + "source": [ + "We start by a direct attempt: fix class parameters $L,\\mu$ (chosen above) and experiment with different step size values $\\gamma$. Verify that the obtained convergence rate is indeed smaller than one only when $\\gamma\\in\\left(0,\\frac{2}{L}\\right)$. Further verify that it matches the very well-known $\\max\\{(1-\\gamma L)^2,(1-\\gamma\\mu)^2\\}$." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "26925393-8cef-46d8-b1a9-291aade9e3dd", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def wc_gradient_descent_distance(mu,L,gamma, verbose):\n", + " # Instantiate PEP\n", + " problem = PEP()\n", + "\n", + " # Declare a smooth convex function\n", + " f = problem.declare_function(SmoothStronglyConvexFunction, L=L, mu=mu)\n", + " \n", + " # Start by defining its unique optimal point xs = x_* and corresponding function value fs = f_*\n", + " xs = f.stationary_point()\n", + " fs = f(xs)\n", + " \n", + " # Then define the starting point x0 of the algorithm\n", + " x0 = problem.set_initial_point()\n", + " \n", + " # Set the initial constraint that is the distance between x0 and x^*\n", + " problem.set_initial_condition((x0 - xs) ** 2 <= 1)\n", + " \n", + " # Run n steps of the GD method\n", + " x1 = x0 - gamma * f.gradient(x0)\n", + " \n", + " # Set the performance metric to the function values accuracy\n", + " problem.set_performance_metric( (x1 - xs) ** 2 )\n", + " \n", + " # Solve the PEP\n", + " pepit_verbose = max(verbose, 0)\n", + " pepit_tau = problem.solve(verbose=pepit_verbose)\n", + " \n", + " return pepit_tau, problem._list_of_prepared_constraints # outputs optimal value and list of constraints (with their associated dual variables)" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "id": "c75fc2b0-e4ba-474f-ab43-2df06335f21e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "verbose = 0\n", + "\n", + "gamma_min, gamma_max = -1, 3\n", + "nb_gammas = 50\n", + "gamma_list = np.linspace(gamma_min,gamma_max,nb_gammas)\n", + "\n", + "pepit_worst_case_value = list()\n", + "known_worst_case_value = list()\n", + "\n", + "for gamma in gamma_list:\n", + " pepit_tau, _ = wc_gradient_descent_distance(mu,L,gamma, verbose)\n", + " pepit_worst_case_value.append(pepit_tau)\n", + " known_worst_case_value.append(max((1-gamma*L)**2,(1-gamma*mu)**2))" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "id": "7a219f3b-ed75-4420-8292-60ded8f09c9f", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(gamma_list, pepit_worst_case_value, color='red', linestyle='-', linewidth=3, label='PEPit')\n", + "\n", + "plt.plot(gamma_list, known_worst_case_value, color='blue', linestyle='--', linewidth=2, label='Known')\n", + "\n", + "plt.legend()\n", + "plt.xlabel(r'$\\gamma$')\n", + "plt.ylabel(r'$\\frac{\\|x_1 - x_\\star\\|^2}{\\|x_0 - x_\\star\\|^2}$')\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "6287eeba-2a4a-4837-b568-96d93876e594", + "metadata": {}, + "source": [ + "One can admit that the match between PEPit's results and the known convergence rate is pretty good. For completeness, let us also extract the dual variables. The next lines examplify how to do this extraction for given values of the parameters, and we integrate it in a loop for plotting below." + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "id": "0c2f805d-dd80-4f65-94fb-95e4b2d3e213", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Constraint \"Constraint 3\" value: 1.0\n", + "Constraint \"Constraint 0\" value: 0.8100000006611664\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_0, Point_1)\" value: 1.800009898700675\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_1, Point_0)\" value: 1.800009898700675\n" + ] + } + ], + "source": [ + "verbose = 0\n", + "gamma = 1/L\n", + "\n", + "pepit_tau, list_of_constraints = wc_gradient_descent_distance(mu,L,gamma, verbose)\n", + "\n", + "nb_cons = len(list_of_constraints)\n", + "\n", + "for i in range(nb_cons):\n", + " print('Constraint \\\"{}\\\" value: {}'.format(list_of_constraints[i].get_name(),\n", + " list_of_constraints[i]._dual_variable_value))" + ] + }, + { + "cell_type": "markdown", + "id": "6e8721b0-982f-4d87-9de2-2f3520d343c6", + "metadata": {}, + "source": [ + "One can observe that the performance estimation problem is actually involving 4 constraints, 2 of which are of interest for us: the 3rd and 4th ones (that encode the fact the function is smooth and strongly convex). We can therefore extract their values in a loop, plot them, and expect their closed-forms to be nice. Perhaps one could even guess their values." + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "id": "bed29990-e7b3-4ab8-809c-aa5b864bb251", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "verbose = 0\n", + "\n", + "gamma_min, gamma_max = -1, 3\n", + "nb_gammas = 50\n", + "gamma_list = np.linspace(gamma_min,gamma_max,nb_gammas)\n", + "\n", + "pepit_worst_case_value = list()\n", + "pepit_dual_value1 = list()\n", + "pepit_dual_value2 = list()\n", + "known_worst_case_value = list()\n", + "\n", + "for gamma in gamma_list:\n", + " pepit_tau, list_of_constraints = wc_gradient_descent_distance(mu,L,gamma, verbose)\n", + " pepit_worst_case_value.append(pepit_tau)\n", + " known_worst_case_value.append(max((1-gamma*L)**2,(1-gamma*mu)**2))\n", + " pepit_dual_value1.append(list_of_constraints[2]._dual_variable_value)\n", + " pepit_dual_value2.append(list_of_constraints[3]._dual_variable_value)" + ] + }, + { + "cell_type": "markdown", + "id": "25b693b7-e7dc-46d8-ad85-1f4c448c72fd", + "metadata": {}, + "source": [ + "Playing a bit with candidate expressions, one can guess a closed-form for the multipliers (which happen to be always equal): $\\lambda=2|\\gamma| \\rho(\\gamma)$ with $\\rho(\\gamma)=\\max\\{|1-\\gamma L|,|1-\\gamma\\mu|\\}$." + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "id": "fd795ad6-d8c1-454e-b1be-ae4ff67167be", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/png": "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jBkzrM9DQ0ONvn37GilTpjTc3NyMEiVKGEePHo358BF0584do379+kaCBAmMBAkSGPXr13/hksV/7+Pjx4+N8uXLG8mSJTNcXFyMtGnTGo0bNzYuX74c8+FfYty4cUa6dOkMV1dXI1++fOEu0WzcuLFRsmTJcP23bt1q5M2b13B1dTXSp09vTJgwIYYTR05k9m/IkCHGBx98YLi7uxuJEyc2ihUrZqxZs8aE1BH3/LLZ/z4aN25sGIb9H8PI7p+9HcOX7dt//0ba8zF8m/2zp2PYtGlT69+XZMmSGWXLlrUWNoZhW8fOYhh/z+4RERERcQC6FFxEREQcioobERERcSgqbkRERMShqLgRERERh6LiRkRERByKihsRERFxKCpuRERExKGouBERERGHouJGREREHIqKGxEREXEoKm5ExO5lzpyZwoUL8+TJE2ubYRgUKlSILl26mJhMRMyg4kZE7N6iRYs4dOgQu3btsrbNmzePCxcu0KtXLxOTiYgZVNyIiN3LmzcvuXPn5tSpUwA8fvyY7t2788MPP5AwYUKT04lITFNxIyIOIXPmzPj5+QHw008/kSRJEpo1a2ZyKhExQxyzA4iIRIUsWbKwfft2/vzzT37++WdWrVqFs7Oz2bFExAQauRERh/B85KZbt2588sknlClTxuxIImISi2EYhtkhRETe1eHDh8mXLx+urq4cO3aMjBkzmh1JREyikRsRcQiZM2cGoG3btipsRGI5FTci4hCePn2KYRg0atTI7CgiYjIVNyLiEP744w9cXV3Jli2b2VFExGQqbkTEIfzxxx9kz54dFxcXs6OIiMk0oVhEREQcikZuRERExKGouBERERGHouJGREREHIqKGxEREXEoKm5ERETEoai4EREREYei4kZEREQcioobERERcSgqbkRERMShqLgRERERh/J/1/dtzFuZ8AIAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "candidate_lambda = [ max(abs(1-gamma*L),abs(1-gamma*mu))*2*abs(gamma) for gamma in gamma_list ]\n", + "\n", + "plt.plot(gamma_list, pepit_dual_value1, color='red', linestyle='-', linewidth=3, label='PEPit')\n", + "plt.plot(gamma_list, candidate_lambda, color='blue', linestyle='--', linewidth=2, label='Educated guess')\n", + "\n", + "plt.legend()\n", + "plt.xlabel(r'$\\gamma$')\n", + "plt.ylabel(r'$\\lambda(\\gamma)$')\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "20b45983-2f73-4af7-8bed-95bfff0f7145", + "metadata": {}, + "source": [ + "Section [4](#example4) below explores how to transform that into a formal mathematical proof (that include replacing the actual guessing game by formal mathematical steps). In the meantime, we explore a case where things are directly less convenient, that of function values. In fact, this slightly more complicated problem already show a typical feature appearing in computer-aided analyses: non-uniqueness of the proofs. This might seem like a good thing (in fact, it is, in many aspects), but it actually renders the formal translation and search more painful, as the numerical solvers actually generally do not provide the simplest proofs possible, but rather combinations of them and fail providing the *sparse* (and likely simpler) ones." + ] + }, + { + "cell_type": "markdown", + "id": "a9ef34d5-d122-43b7-b0ee-267fa4dcaf26", + "metadata": {}, + "source": [ + "## 2. Gradient descent, function value accuracy " + ] + }, + { + "cell_type": "markdown", + "id": "91bbca45-c600-423f-a3c5-192d785187e6", + "metadata": {}, + "source": [ + "Let us start with the exact same exercise, but now by changing the specific quantity under our radar to function values. Practically speaking, this means changing both the performance metric and the initial condition in the previous code. Executing the code in the same fashion as before, we observe the exact same worst-case ratios." + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "id": "1cdc2dd8-502d-4826-90b9-1b235c4e6a62", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def wc_gradient_descent_function_values(mu,L,gamma, verbose):\n", + " # Instantiate PEP\n", + " problem = PEP()\n", + "\n", + " # Declare a smooth convex function\n", + " f = problem.declare_function(SmoothStronglyConvexFunction, L=L, mu=mu)\n", + " \n", + " # Start by defining its unique optimal point xs = x_* and corresponding function value fs = f_*\n", + " xs = f.stationary_point()\n", + " fs = f(xs)\n", + " \n", + " # Then define the starting point x0 of the algorithm\n", + " x0 = problem.set_initial_point()\n", + " \n", + " # Set the initial constraint that is the distance between x0 and x^*\n", + " problem.set_initial_condition( f(x0) - fs <= 1)\n", + " \n", + " # Run n steps of the GD method\n", + " x1 = x0 - gamma * f.gradient(x0)\n", + " \n", + " # Set the performance metric to the function values accuracy\n", + " problem.set_performance_metric( f(x1) - fs )\n", + " \n", + " # Solve the PEP\n", + " pepit_verbose = max(verbose, 0)\n", + " pepit_tau = problem.solve(verbose=pepit_verbose)\n", + " \n", + " return pepit_tau, problem._list_of_prepared_constraints # outputs optimal value and list of constraints (with their associated dual variables)" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "id": "67257b5a-9ef3-486f-a502-dbcaa9ce2095", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "verbose = 0\n", + "\n", + "gamma_min, gamma_max = -1, 3\n", + "nb_gammas = 50\n", + "gamma_list = np.linspace(gamma_min,gamma_max,nb_gammas)\n", + "\n", + "pepit_worst_case_value = list()\n", + "known_worst_case_value = list()\n", + "\n", + "for gamma in gamma_list:\n", + " pepit_tau, _ = wc_gradient_descent_function_values(mu,L,gamma, verbose)\n", + " pepit_worst_case_value.append(pepit_tau)\n", + " known_worst_case_value.append(max((1-gamma*L)**2,(1-gamma*mu)**2))\n", + " \n", + "plt.plot(gamma_list, pepit_worst_case_value, color='red', linestyle='-', linewidth=3, label='PEPit')\n", + "\n", + "plt.plot(gamma_list, known_worst_case_value, color='blue', linestyle='--', linewidth=2, label='Known')\n", + "\n", + "plt.legend()\n", + "plt.xlabel(r'$\\gamma$')\n", + "plt.ylabel(r'$\\frac{f(x_1) - f_\\star}{f(x_0) - f_\\star}$')\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "82530092-bd44-4d95-bc34-8fb54e072a24", + "metadata": {}, + "source": [ + "However, a bad surprise appears when inspecting the problem: there are actually more constraints, and hence possibly more dual multipliers to be identified. We do not describe here the reason for this difference (more constraints, explained at length, e.g., in [this blog post](https://francisbach.com/computer-aided-analyses/) or this [habilitation thesis](https://hal.science/tel-04794552v2/file/HDR_ATaylor_V_HAL2.pdf)) and instead focus on the consequences." + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "id": "5504126a-0d28-490c-8dd1-ae0094129ce1", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Constraint \"Constraint 7\" value: 1.0\n", + "Constraint \"Constraint 0\" value: 0.8099999034654997\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_0, Point_1)\" value: 0.04318494581205349\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_0, Point_2)\" value: 0.14690493317815176\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_1, Point_0)\" value: 3.7068368407529674e-05\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_1, Point_2)\" value: 1.3215023299277147\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_2, Point_0)\" value: 5.272685701848342e-05\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_2, Point_1)\" value: 0.46835454902147894\n" + ] + } + ], + "source": [ + "verbose = 0\n", + "gamma = 1/L\n", + "\n", + "pepit_tau, list_of_constraints = wc_gradient_descent_function_values(mu,L,gamma, verbose)\n", + "\n", + "nb_cons = len(list_of_constraints)\n", + "\n", + "for i in range(nb_cons):\n", + " print('Constraint \\\"{}\\\" value: {}'.format(list_of_constraints[i].get_name(),\n", + " list_of_constraints[i]._dual_variable_value))" + ] + }, + { + "cell_type": "markdown", + "id": "18c9181e-fcc8-4f1f-b328-779c215f418d", + "metadata": {}, + "source": [ + "To get a clearer picture, let us plot all those values as a function of $\\gamma$ again." + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "id": "dc980cbb-6b58-4584-8dd4-be686b280d39", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "verbose = 0\n", + "\n", + "gamma_min, gamma_max = -1, 3\n", + "nb_gammas = 50\n", + "gamma_list = np.linspace(gamma_min,gamma_max,nb_gammas)\n", + "\n", + "pepit_worst_case_value = list()\n", + "pepit_dual_value1 = list()\n", + "pepit_dual_value2 = list()\n", + "pepit_dual_value3 = list()\n", + "pepit_dual_value4 = list()\n", + "pepit_dual_value5 = list()\n", + "pepit_dual_value6 = list()\n", + "known_worst_case_value = list()\n", + "\n", + "for gamma in gamma_list:\n", + " pepit_tau, list_of_constraints = wc_gradient_descent_function_values(mu,L,gamma, verbose)\n", + " pepit_worst_case_value.append(pepit_tau)\n", + " known_worst_case_value.append(max((1-gamma*L)**2,(1-gamma*mu)**2))\n", + " pepit_dual_value1.append(list_of_constraints[2]._dual_variable_value)\n", + " pepit_dual_value2.append(list_of_constraints[3]._dual_variable_value)\n", + " pepit_dual_value3.append(list_of_constraints[4]._dual_variable_value)\n", + " pepit_dual_value4.append(list_of_constraints[5]._dual_variable_value)\n", + " pepit_dual_value5.append(list_of_constraints[6]._dual_variable_value)\n", + " pepit_dual_value6.append(list_of_constraints[7]._dual_variable_value)\n", + " \n", + " \n", + "plt.plot(gamma_list, pepit_dual_value1, color='red', linestyle='-', linewidth=3, label=r'$\\lambda_1$')\n", + "plt.plot(gamma_list, pepit_dual_value2, color='blue', linestyle='-', linewidth=3, label=r'$\\lambda_2$')\n", + "plt.plot(gamma_list, pepit_dual_value3, color='green', linestyle='-', linewidth=3, label=r'$\\lambda_3$')\n", + "plt.plot(gamma_list, pepit_dual_value4, color='gold', linestyle='-', linewidth=3, label=r'$\\lambda_4$')\n", + "plt.plot(gamma_list, pepit_dual_value5, color='orange', linestyle='-', linewidth=3, label=r'$\\lambda_5$')\n", + "plt.plot(gamma_list, pepit_dual_value6, color='brown', linestyle='-', linewidth=3, label=r'$\\lambda_6$')\n", + "\n", + "plt.legend()\n", + "plt.xlabel(r'$\\gamma$')\n", + "plt.ylabel(r'$\\lambda_i(\\gamma)$')\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "b5d251da-e8f0-424d-8fc9-6bd14b6c4d0b", + "metadata": {}, + "source": [ + "Well, guessing closed-forms appears like a much more challenging game now. The next section illustrates that one can actually simplify this picture simply by removing certain of the constraints (or equivalently by forcing their multipliers to be zero)." + ] + }, + { + "cell_type": "markdown", + "id": "5cb7f440-0d34-4b6f-a140-1536ba4a11b0", + "metadata": {}, + "source": [ + "## 3. Function values: numerical proof simplification " + ] + }, + { + "cell_type": "markdown", + "id": "71459a17-1cd4-4ecf-9ae1-1198cd592dd6", + "metadata": {}, + "source": [ + "The game for this section consists in forcing certain multipliers to be zero (deactivating constraints) while keeping the same optimal value. In other words, we search for possibly *sparse* proofs. For doing that, we must experiment with solve/resolve the PEP with different constraints patterns. In PEPit, this can be done through the *prepare_problem* command (instead of solve) as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "id": "075773e8-1fc9-4a45-ade8-a4c68b387649", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(PEPit) Setting up the problem: performance measure is the minimum of 1 element(s)\n", + "(PEPit) Setting up the problem: Adding initial conditions and general constraints ...\n", + "(PEPit) Setting up the problem: initial conditions and general constraints (1 constraint(s) added)\n", + "(PEPit) Setting up the problem: interpolation conditions for 1 function(s)\n", + "\t\t\tFunction 1 : Adding 6 scalar constraint(s) ...\n", + "\t\t\tFunction 1 : 6 scalar constraint(s) added\n", + "(PEPit) Setting up the problem: additional constraints for 0 function(s)\n" + ] + } + ], + "source": [ + "def wc_gradient_descent_function_values_prepare(mu,L,gamma, verbose):\n", + " # Instantiate PEP\n", + " problem = PEP()\n", + "\n", + " # Declare a smooth convex function\n", + " f = problem.declare_function(SmoothStronglyConvexFunction, L=L, mu=mu)\n", + " \n", + " # Start by defining its unique optimal point xs = x_* and corresponding function value fs = f_*\n", + " xs = f.stationary_point()\n", + " fs = f(xs)\n", + " \n", + " # Then define the starting point x0 of the algorithm\n", + " x0 = problem.set_initial_point()\n", + " \n", + " # Set the initial constraint that is the distance between x0 and x^*\n", + " problem.set_initial_condition( f(x0) - fs <= 1)\n", + " \n", + " # Run n steps of the GD method\n", + " x1 = x0 - gamma * f.gradient(x0)\n", + " \n", + " # Set the performance metric to the function values accuracy\n", + " problem.set_performance_metric( f(x1) - fs )\n", + " \n", + " # Output prepared problem\n", + " pepit_verbose = max(verbose, 0)\n", + " problem._prepare_constraints(verbose=pepit_verbose)\n", + " \n", + " return problem\n", + "\n", + "PEP_GD = wc_gradient_descent_function_values_prepare(mu,L,gamma=1/L, verbose=1)" + ] + }, + { + "cell_type": "markdown", + "id": "9beb6ee2-0153-4e48-ad45-106189dd8000", + "metadata": {}, + "source": [ + "We can now interactively iterate between solving the problem and activating/deactivating constraints, and the goal is to identify a minimal number of constraints that allows recovering the same optimal problem value. Let us start by solving the original problem." + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "id": "df117c5b-664a-4f11-a98c-8c9b16dcbffc", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(PEPit) Setting up the problem: size of the Gram matrix: 4x4\n", + "(PEPit) Compiling SDP\n", + "(PEPit) Calling SDP solver\n", + "(PEPit) Solver status: optimal (wrapper:cvxpy, solver: MOSEK); optimal value: 0.809999909317056\n", + "\u001b[96m(PEPit) Postprocessing: solver's output is not entirely feasible (smallest eigenvalue of the Gram matrix is: -6.17e-09 < 0).\n", + " Small deviation from 0 may simply be due to numerical error. Big ones should be deeply investigated.\n", + " In any case, from now the provided values of parameters are based on the projection of the Gram matrix onto the cone of symmetric semi-definite matrix.\u001b[0m\n", + "(PEPit) Primal feasibility check:\n", + "\t\tThe solver found a Gram matrix that is positive semi-definite up to an error of 6.172665013326517e-09\n", + "\t\tAll the primal scalar constraints are verified up to an error of 2.0330860467376866e-09\n", + "(PEPit) Dual feasibility check:\n", + "\t\tThe solver found a residual matrix that is positive semi-definite\n", + "\t\tAll the dual scalar values associated with inequality constraints are nonnegative\n", + "(PEPit) The worst-case guarantee proof is perfectly reconstituted up to an error of 5.109620224846845e-08\n", + "(PEPit) Final upper bound (dual): 0.8099999034654997 and lower bound (primal example): 0.809999909317056 \n", + "(PEPit) Duality gap: absolute: -5.85155635057788e-09 and relative: -7.224144451462428e-09\n", + "Constraint \"Constraint 7\" value: 1.0\n", + "Constraint \"Constraint 0\" value: 0.8099999034654997\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_0, Point_1)\" value: 0.04318494581205349\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_0, Point_2)\" value: 0.14690493317815176\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_1, Point_0)\" value: 3.7068368407529674e-05\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_1, Point_2)\" value: 1.3215023299277147\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_2, Point_0)\" value: 5.272685701848342e-05\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_2, Point_1)\" value: 0.46835454902147894\n" + ] + } + ], + "source": [ + "# Solve the original problem and output the dual variable values\n", + "\n", + "PEP_GD.solve(verbose = 1)\n", + "list_of_constraints = PEP_GD._list_of_prepared_constraints\n", + "nb_cons = len(list_of_constraints)\n", + "\n", + "for i in range(nb_cons):\n", + " print('Constraint \\\"{}\\\" value: {}'.format(list_of_constraints[i].get_name(),\n", + " list_of_constraints[i]._dual_variable_value))\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "5d66e74d-c59d-4c22-a9bd-360f2287c468", + "metadata": {}, + "source": [ + "The corresponding optimal value matches what we would expect. Let us now deactivate some constraints and observe the result. We start with the first interpolation constraint (third constraint in the list) as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "id": "94a9548e-3451-4087-b186-0fd5d8283ccf", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(PEPit) Setting up the problem: size of the Gram matrix: 4x4\n", + "(PEPit) Compiling SDP\n", + "(PEPit) Calling SDP solver\n", + "(PEPit) Solver status: optimal (wrapper:cvxpy, solver: MOSEK); optimal value: 0.809999956944149\n", + "\u001b[96m(PEPit) Postprocessing: solver's output is not entirely feasible (smallest eigenvalue of the Gram matrix is: -4.02e-09 < 0).\n", + " Small deviation from 0 may simply be due to numerical error. Big ones should be deeply investigated.\n", + " In any case, from now the provided values of parameters are based on the projection of the Gram matrix onto the cone of symmetric semi-definite matrix.\u001b[0m\n", + "(PEPit) Primal feasibility check:\n", + "\t\tThe solver found a Gram matrix that is positive semi-definite up to an error of 4.022897991237727e-09\n", + "\t\tAll the primal scalar constraints are verified up to an error of 2.0330860467376866e-09\n", + "(PEPit) Dual feasibility check:\n", + "\t\tThe solver found a residual matrix that is positive semi-definite\n", + "\t\tAll the dual scalar values associated with inequality constraints are nonnegative\n", + "(PEPit) The worst-case guarantee proof is perfectly reconstituted up to an error of 2.8795806151076664e-08\n", + "(PEPit) Final upper bound (dual): 0.8099999517743242 and lower bound (primal example): 0.809999956944149 \n", + "(PEPit) Duality gap: absolute: -5.169824790485222e-09 and relative: -6.382500080603945e-09\n", + "Constraint \"Constraint 7\" dual value: 1.0 [activated? True]\n", + "Constraint \"Constraint 0\" dual value: 0.8099999517743242 [activated? True]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_0, Point_1)\" dual value: 0.0 [activated? False]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_0, Point_2)\" dual value: 0.1900739137692873 [activated? True]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_1, Point_0)\" dual value: 3.0943424661018764e-05 [activated? True]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_1, Point_2)\" dual value: 1.7099721331569564 [activated? True]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_2, Point_0)\" dual value: 4.292931902870809e-05 [activated? True]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_2, Point_1)\" dual value: 0.9000031248051895 [activated? True]\n" + ] + } + ], + "source": [ + "# Solve the problem with the first interpolation constraint deactivated\n", + "\n", + "list_of_constraints[2].deactivate()\n", + "\n", + "PEP_GD.solve(verbose = 1)\n", + "for i in range(nb_cons):\n", + " print('Constraint \\\"{}\\\" dual value: {} [activated? {}]'.format(list_of_constraints[i].get_name(),\n", + " list_of_constraints[i]._dual_variable_value,\n", + " list_of_constraints[i].activated))\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "d4e026bb-e7b6-4e20-9877-fc6084c4f726", + "metadata": {}, + "source": [ + "Good surprise: the same numerical bound can be achieved without using the first interpolation constraint... let's try to be more aggressive and deactivate more constraints." + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "id": "b494a370-ef9e-43da-992a-bc23bea97106", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(PEPit) Setting up the problem: size of the Gram matrix: 4x4\n", + "(PEPit) Compiling SDP\n", + "(PEPit) Calling SDP solver\n", + "(PEPit) Solver status: unbounded (wrapper:cvxpy, solver: MOSEK); optimal value: None\n", + "\u001b[96m(PEPit) Problem issue: PEPit didn't find any nontrivial worst-case guarantee. It seems that the optimal value of your problem is unbounded.\u001b[0m\n", + "Constraint \"Constraint 7\" dual value: 0.0 [activated? True]\n", + "Constraint \"Constraint 0\" dual value: 0.0 [activated? True]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_0, Point_1)\" dual value: 0.0 [activated? False]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_0, Point_2)\" dual value: 0.0 [activated? False]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_1, Point_0)\" dual value: 0.0 [activated? False]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_1, Point_2)\" dual value: 0.0 [activated? False]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_2, Point_0)\" dual value: 0.0 [activated? True]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_2, Point_1)\" dual value: 0.0 [activated? True]\n" + ] + } + ], + "source": [ + "# Solve the problem with the first interpolation constraint deactivated\n", + "\n", + "list_of_constraints[3].deactivate()\n", + "list_of_constraints[4].deactivate()\n", + "list_of_constraints[5].deactivate()\n", + "\n", + "PEP_GD.solve(verbose = 1)\n", + "for i in range(nb_cons):\n", + " print('Constraint \\\"{}\\\" dual value: {} [activated? {}]'.format(list_of_constraints[i].get_name(),\n", + " list_of_constraints[i]._dual_variable_value,\n", + " list_of_constraints[i].activated))\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "0575db5a-c37b-495f-a606-c85295267797", + "metadata": {}, + "source": [ + "This was too much. We need to reactivate some." + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "id": "ef737d1e-00e2-4619-8868-70814933e342", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(PEPit) Setting up the problem: size of the Gram matrix: 4x4\n", + "(PEPit) Compiling SDP\n", + "(PEPit) Calling SDP solver\n", + "(PEPit) Solver status: optimal (wrapper:cvxpy, solver: MOSEK); optimal value: 0.8099999473346992\n", + "\u001b[96m(PEPit) Postprocessing: solver's output is not entirely feasible (smallest eigenvalue of the Gram matrix is: -2.02e-09 < 0).\n", + " Small deviation from 0 may simply be due to numerical error. Big ones should be deeply investigated.\n", + " In any case, from now the provided values of parameters are based on the projection of the Gram matrix onto the cone of symmetric semi-definite matrix.\u001b[0m\n", + "(PEPit) Primal feasibility check:\n", + "\t\tThe solver found a Gram matrix that is positive semi-definite up to an error of 2.0161722580930193e-09\n", + "\t\tAll the primal scalar constraints are verified up to an error of 2.0330860467376866e-09\n", + "(PEPit) Dual feasibility check:\n", + "\t\tThe solver found a residual matrix that is positive semi-definite\n", + "\t\tAll the dual scalar values associated with inequality constraints are nonnegative\n", + "(PEPit) The worst-case guarantee proof is perfectly reconstituted up to an error of 2.5852069649931475e-08\n", + "(PEPit) Final upper bound (dual): 0.809999941112574 and lower bound (primal example): 0.8099999473346992 \n", + "(PEPit) Duality gap: absolute: -6.222125148447333e-09 and relative: -7.681636485188925e-09\n", + "Constraint \"Constraint 7\" dual value: 1.0 [activated? True]\n", + "Constraint \"Constraint 0\" dual value: 0.809999941112574 [activated? True]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_0, Point_1)\" dual value: 0.0 [activated? False]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_0, Point_2)\" dual value: 0.19005372641333823 [activated? True]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_1, Point_0)\" dual value: 0.0 [activated? False]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_1, Point_2)\" dual value: 1.7099956087838943 [activated? True]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_2, Point_0)\" dual value: 5.3673990181861823e-05 [activated? True]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_2, Point_1)\" dual value: 0.8999956676713203 [activated? True]\n" + ] + } + ], + "source": [ + "# Solve the problem with the first interpolation constraint deactivated\n", + "\n", + "list_of_constraints[3].activate()\n", + "list_of_constraints[5].activate()\n", + "\n", + "PEP_GD.solve(verbose = 1)\n", + "for i in range(nb_cons):\n", + " print('Constraint \\\"{}\\\" dual value: {} [activated? {}]'.format(list_of_constraints[i].get_name(),\n", + " list_of_constraints[i]._dual_variable_value,\n", + " list_of_constraints[i].activated))\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "57aa820f-9320-4593-a9a1-ed51ee40a7c1", + "metadata": { + "tags": [] + }, + "source": [ + "After a bit of experiment, one can arrive to the following pattern" + ] + }, + { + "cell_type": "code", + "execution_count": 97, + "id": "23a08913-26cd-4468-9b45-6ce855e1dc32", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(PEPit) Setting up the problem: size of the Gram matrix: 4x4\n", + "(PEPit) Compiling SDP\n", + "(PEPit) Calling SDP solver\n", + "(PEPit) Solver status: optimal (wrapper:cvxpy, solver: MOSEK); optimal value: 0.8099999848815963\n", + "\u001b[96m(PEPit) Postprocessing: solver's output is not entirely feasible (smallest eigenvalue of the Gram matrix is: -1.29e-09 < 0).\n", + " Small deviation from 0 may simply be due to numerical error. Big ones should be deeply investigated.\n", + " In any case, from now the provided values of parameters are based on the projection of the Gram matrix onto the cone of symmetric semi-definite matrix.\u001b[0m\n", + "(PEPit) Primal feasibility check:\n", + "\t\tThe solver found a Gram matrix that is positive semi-definite up to an error of 1.2887427659820522e-09\n", + "\t\tAll the primal scalar constraints are verified up to an error of 2.0330860467376866e-09\n", + "(PEPit) Dual feasibility check:\n", + "\t\tThe solver found a residual matrix that is positive semi-definite\n", + "\t\tAll the dual scalar values associated with inequality constraints are nonnegative\n", + "(PEPit) The worst-case guarantee proof is perfectly reconstituted up to an error of 6.333316023113211\n", + "(PEPit) Final upper bound (dual): 0.8099999812120227 and lower bound (primal example): 0.8099999848815963 \n", + "(PEPit) Duality gap: absolute: -3.669573644948798e-09 and relative: -4.530337917827501e-09\n", + "Constraint \"Constraint 7\" dual value: 0.0 [activated? True]\n", + "Constraint \"Constraint 0\" dual value: 0.0 [activated? True]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_0, Point_1)\" dual value: 0.0 [activated? True]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_0, Point_2)\" dual value: 0.0 [activated? True]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_1, Point_0)\" dual value: 0.0 [activated? False]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_1, Point_2)\" dual value: 0.0 [activated? True]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_2, Point_0)\" dual value: 0.0 [activated? False]\n", + "Constraint \"IC_Function_0_smoothness_strong_convexity(Point_2, Point_1)\" dual value: 0.0 [activated? False]\n" + ] + } + ], + "source": [ + "# Solve the problem with the first interpolation constraint deactivated\n", + "\n", + "list_of_constraints[2].activate()\n", + "list_of_constraints[3].activate()\n", + "list_of_constraints[5].activate()\n", + "list_of_constraints[4].deactivate()\n", + "list_of_constraints[6].deactivate()\n", + "list_of_constraints[7].deactivate()\n", + "\n", + "PEP_GD.solve(verbose = 1)\n", + "for i in range(nb_cons):\n", + " print('Constraint \\\"{}\\\" dual value: {} [activated? {}]'.format(list_of_constraints[i].get_name(),\n", + " list_of_constraints[i]._dual_variable_value,\n", + " list_of_constraints[i].activated))\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "a9baba97-8b1f-44b8-b166-9e69d94b3c23", + "metadata": {}, + "source": [ + "Let us verify that this pattern of inequalities works throughout the whole range of step sizes $\\gamma$." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "8c4fa25f-ee3e-4ad9-ad7c-9753296287a5", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def wc_gradient_descent_function_values_sparse_proof(mu,L,gamma, verbose):\n", + " # Instantiate PEP\n", + " problem = PEP()\n", + "\n", + " # Declare a smooth convex function\n", + " f = problem.declare_function(SmoothStronglyConvexFunction, L=L, mu=mu)\n", + " \n", + " # Start by defining its unique optimal point xs = x_* and corresponding function value fs = f_*\n", + " xs = f.stationary_point()\n", + " fs = f(xs)\n", + " \n", + " # Then define the starting point x0 of the algorithm\n", + " x0 = problem.set_initial_point()\n", + " \n", + " # Set the initial constraint that is the distance between x0 and x^*\n", + " problem.set_initial_condition( f(x0) - fs <= 1)\n", + " \n", + " # Run n steps of the GD method\n", + " x1 = x0 - gamma * f.gradient(x0)\n", + " \n", + " # Set the performance metric to the function values accuracy\n", + " problem.set_performance_metric( f(x1) - fs )\n", + " \n", + " # Output prepared problem\n", + " pepit_verbose = max(verbose, 0)\n", + " problem._prepare_constraints(verbose=pepit_verbose)\n", + " problem._list_of_prepared_constraints[4].deactivate()\n", + " problem._list_of_prepared_constraints[6].deactivate()\n", + " problem._list_of_prepared_constraints[7].deactivate()\n", + " \n", + " pepit_tau = problem.solve(verbose=pepit_verbose)\n", + " \n", + " return pepit_tau, problem._list_of_prepared_constraints\n" + ] + }, + { + "cell_type": "code", + "execution_count": 121, + "id": "7a6b2196-9e54-42f1-8754-55b99fd57f05", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/png": "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L8KsDrPgq69MCkxERBxCQgJxaSVsm45UDRycNGmaPXs2AwcO5I033iAiIoL69evTsmVLYmJirtt/woQJDB06lHfeeYc//viDd999l+eff54lS5bY9fP29iY+Pt7u4+XllR2XlHsULw5r10LLlgCcxIeWrOBxYwYfPhuD8cabquUkIpJbxcYSy5UkqbTbUShWzMSA7Dll0jR69Gj69OnDU089RYUKFfj888/x9/dnwoQJ1+3/3Xff0bdvX0JDQylXrhxdu3alT58+jBw50q6fxWLBz8/P7nMzFy5cIDk52e4jGZA/PyxaBL17M51u/M5DALzBhzz/YUlSez4JKSkmBykiItkuLs4uafL3SwGLxcSA7Dld0nTx4kV27dpFSEiIXXtISAjh4eHXPebChQvpRozy5MnD9u3bSbnql/Pp06cJCAigdOnStGnThoiIiJvGMmLECHx8fGwffwcaQnR47u4waRLPvVmEj3jN1jyB5+j4XQfOtuioWk4iIrlNbCxxXJnD5B/gWGmKY0WTAYmJiaSmpuLr62vX7uvrS8IN6v40b96ciRMnsmvXLgzDYOfOnUyePJmUlBQSExMBKF++PFOnTmXx4sXMnDkTLy8v6taty8GDB28Yy9ChQ0lKSrJ9Yq8tyCU3Z7FgeW84r319D99ZethqOS2mvbWWU3A7iI83OUgREck2Vz2e8yaJAmUd5805cMKk6TLLNcN1hmGka7vsrbfeomXLltSuXRt3d3fat29Pr169AHB1dQWgdu3adO/encqVK1O/fn1++OEH7r//fsaOHXvDGDw9PfH29rb7yG145hm6L+7CCg/7Wk7Bv3/NX9VDYf9+kwMUEZHsYMTG2UaaHO3NOXDCpKlo0aK4urqmG1U6duxYutGny/LkycPkyZM5e/YsUVFRxMTEEBgYSIECBSha9PpZrIuLCzVq1LjpSJNkoTZteGTjO2ws2I4SHAHgIPcTfGQOO2r1h82bTQ5QRETutsTIU1zAOp3G0d6cAydMmjw8PAgKCmL16tV27atXryY4OPimx7q7u1O6dGlcXV2ZNWsWbdq0weUGKycbhsHu3bspUaLEdffLXfBfLaetZUKpwF4AjuHLouRG8MgjMH++ufGJiMhddfHvf+jIPGqwnYf51eGSJqesCD548GDCwsKoXr06derU4ZtvviEmJoZ+/foB1rlGf//9t60W04EDB9i+fTu1atXixIkTjB49mt9//51vv/3Wds53332X2rVrc99995GcnMwXX3zB7t27GTdunCnXmGvdey9ldsxjc4vHaR8xjNLEMZy34YIBnTrBmDHwwgtmRykiIlktJYVSxyKYR6crbaV/MS+e63DKpCk0NJTjx48zfPhw4uPjqVSpEsuXLycgIACA+Ph4u5pNqampfPrpp/z555+4u7vTuHFjwsPDCQwMtPU5efIkzzzzDAkJCfj4+FC1alU2bNhAzZo1s/vypHhxCm1czKpO3bGsXI4L/9VtMgwYMMC6AvZHH8ENRglFRMQJxcenr9PnYCNNFsNQJcGskpycjI+PD0lJSZoUnhUuXYLnnoP//c/WFE4dvqc7Y7qE4z5tEnh6mhigiIhkmc2boV69K9teXnD2bLbUacro72+nHGmSXMLNDb7+2vovjbff5k/upy1L+JciRP5QljlHOpB/yUwoWNDsSEVE5E5dW7andGmHKmwJTjgRXHIZiwXeegumTOFPl4qcJj8AK2lJw03vk1CrPdxg+RwREXEicXG0ZDn3cYAm/ERKqUCzI0pHSZM4h169aLe8H6vztKcgJwD4hSDqHJjKnzW6w549JgcoIiJ3JDaWA9zPIe5jN1VwDyhpdkTpKGkS59G8OQ02j2Bz0Q6UIRqAKMoSfGwBm+u8DD/9ZHKAIiJyu9JiHLuwJShpEmdTtSoVd05jyz1hVGY3AP9ShEfOLWFeyNfw3XfmxiciIrfln6gzXMT6ck9p4hzuzTlQ0iTOKCCAktsXsqH2azRjFQAX8KJz2iy+7LENPvww/WurIiLi0K6eB+6I1cBBSZM4q8KF8V67iKUdp9ADa5FSAxcK8y+88QY8+6y1ZIGIiDi+ixeJO57Htumoj+dUckCcl5cXHnOmM/Wllynz+XsU4BRPMNO67+uv4e+/YdYsyJfP3DhFROTmjhwhlitJkh7PidwNLi5YPhvNe6Pz86rlE/t9S5dyoUEzOHrUnNhERCRjYmOJ5UqS5O/5DxQqZGJA16ekSXKGQYPghx/sKoRPoRdVfplEVPVO8OefJgYnIiI3FRtre3MOwL/EJYcrbAlKmiQn6dQJ1qyBwoVZTVOe5n/spwK14+awq+az1hL9IiLieOLi7EaaSgW6mxjMjSlpkpylXj0ID+feUue5l0MAHMWPhsmLWd5oFMybZ3KAIiKSTmwsHzGEKfRiJK+SN7C42RFdl5ImyXkeeICyO+ewufLz1GUTAGfIT7tL8/hfpx/h88/NjU9EROzFxlKXcHrxLa/ysUO+OQdKmiSn8vOjyKZFrGn+CZ2YA0AqbjzDN7w16BTGwEGQlmZykCIiAkBcnP22A745B0qaJCfLnx+vpXOZ/fRPDGK0rfl93qLnmKpc7PQEnDtnYoAiIgLYV7YEJU0ipnBzw+XrCYz+8AKf8yIWrKNL39GDXgvaQdOmkJhocpAiIrnYhQtEHcvDGh7hT+7nPJ56PCdiGosFhg7lxe9qMNe1K16cIy9nGMxoCA+H4GD46y+zoxQRyZ3+/ptFtKcZayjPn8yhs8OONKkiuOQe3bvTsWRJfm7blpNn3anOLmv7wYNQuzYsXQq1apkbo4hIbnNtYUuvRPDxMTGgG9NIk+QuTZpQZ9vntPT/w645NfFfdjUcDAsXmhOXiEhudU3SVLpkmkMWtgQlTZIbVaoEW7dClSoAGMBgRlPrwnomP7oExo41NTwRkVwlLs6uGnjpQMd9CKakSXKnkiVhwwZo3pzFtOMLXiQVN/owiWED/sUY/JJKEoiIZIerRpqKcQyvQD+TA7oxJU2SexUoAEuW0KZ3cQYwxtY8nGH0/uwhLnbuppIEIiJ3WWrM3xyhJAD+xDrsJHBQ0iS5nbs7rpO+Ycx7p/iMgbaSBN/Si1bz+5DUqL1KEoiI3EUJh8+S+t97aaWJc9hyA6CkScQ64fDNNxn4bTXmuFhLEgD8RFPqbf+U2OqPwqFDJgcpIpIzxcZdmfStkSYRZ9GjB4+t6stPedtRBOvo0u88RO3oWeyu8TRs2WJygCIiOcyZM8QkXykvEEA0lCljYkA3p6RJ5GqPPELw1tFs8X2UezkIwBFKMejk2xiNm8C8eSYHKCKSg8TGkoSPbYRfI00izuahh7jvl9mEV+pLbbYQQBQzeRzLhfPQuTN89hkYhtlRiog4v5gYnmYiZ8nLMYrRplA45M9vdlQ3pKRJ5HpKlqRY+CJ+bvYRP9MEP45a2w0DBg+GF1+E1FRzYxQRcXb/LdRrAYqRSP6AIubGcwtKmkRupEAB8iybS7mnm9o1J+HNG2N9udAhFM6eNSk4EZEcICbGftuB5zOBkiaRm3N3h6+/hg8/BOAi7jzGPD7kDZov7c+Jem3h6FGTgxQRcVJKmkRyGIsFhg6F6dP51S2IcIIBWE8jgiO+JLJ6Z9i/3+QgRUScz5nIYzzGXAbyGT/QWUmTSI7xxBNUX/MR6/K3pfh/c5z2U4HacXPYUfN567IsIiKSYbGRl5jPY4xhIItpp6RJJEdp2JCa279kS6nOPIB1dOkYvjQ8tYRFj3wBM2aYHKCIiJNISyMm3t22WYYYJU0iOU6FCpTb+QPhVZ6nAesBOEdeHr30A2O7bYEPPlBJAhGRW/nnH2JSrizOq6RJJKfy86PwpsWsajOWJ5gOgIELAxjLoDfzkvrk05CSYnKQIiIOLCaGGK4kSWVc/gY/v5scYD4lTSK3K18+PBfO5vsXtvMG79uaj1Ecl6mToHVrSE42MUAREQd2bdLkdxFcXU0M6NaUNIncCVdXLF+M4f3P8vM/nqYJPzGZJ7EArF4N9erZireJiMhVrk2aAiw36ewYlDSJZIWBA3lqfitWe7XDk4tX2n/7jUu16kJEhHmxiYg4oquSJh9O4l2uqMkB3ZqSJpGs8uijuKz7GYoVszUd5F4qxP/E+rpDYflyE4MTEXEsadGxxGJdnNcZJoGDkiaRrFWrFmzdCg88wD8UpSUrOMR9NDu3mO/bzIIJE8yOUETEIfwTeZqLeAJKmu668ePHU7ZsWby8vAgKCmLjxo037T9u3DgqVKhAnjx5eOCBB5g2bVq6PvPmzaNixYp4enpSsWJFFixYcLfCl5ysXDkID8crOIj7OQBACh6EGdMY/lw8xsuvQFqayUGKiJjL8nccgxjNY8ylARucImnCcEKzZs0y3N3djf/973/G3r17jRdffNHIly+fER0dfd3+48ePNwoUKGDMmjXL+Ouvv4yZM2ca+fPnNxYvXmzrEx4ebri6uhoffvihsW/fPuPDDz803NzcjK1bt2Y4rqSkJAMwkpKS7vgaJQc4f95IeTzM6Md4w1q4yfrpyRTjwqOhhnH2rNkRioiY49w5w+5/jGAYv/1mWjgZ/f1tMQznq8JXq1YtqlWrxoSrHnVUqFCBDh06MGLEiHT9g4ODqVu3Lh9//LGtbeDAgezcuZNNmzYBEBoaSnJyMitWrLD1adGiBYUKFWLmzJkZiis5ORkfHx+SkpLw9va+3cuTnMQwMN4exqfvn+UVPrE1N+Zn5lcfQcFl06F4cRMDFBExwaFDcN999m1JSWDS786M/v52usdzFy9eZNeuXYSEhNi1h4SEEB4eft1jLly4gJeXl11bnjx52L59Oyn/FSDcsmVLunM2b978hue8fN7k5GS7j4gdiwXLe8N5eUol5riE4sU5ANbShOCdY4gKekyL/YpI7hMTY7/t42NawpQZTpc0JSYmkpqaiq+vr127r68vCQkJ1z2mefPmTJw4kV27dmEYBjt37mTy5MmkpKSQmJgIQEJCQqbOCTBixAh8fHxsH39//zu8OsmxevWi06pnWJuvLcU4BsA+KlIn7geS6jSH9etNDlBEJBvFxJBMAWyPupxhPhNOmDRdZrHYF8EyDCNd22VvvfUWLVu2pHbt2ri7u9O+fXt69eoFgOtV1Uczc06AoUOHkpSUZPvEqoih3Mwjj1B7+xdsLfmYbbHfgXyOz8kYaNYMvv/e5ABFRLJJTAyP8BN5OEd59pHmH2B2RBnidElT0aJFcXV1TTcCdOzYsXQjRZflyZOHyZMnc/bsWaKiooiJiSEwMJACBQpQtKi1mJafn1+mzgng6emJt7e33UfkpipWpNyuOYRX7c9nDORVRlnbU1IgLAzefVeL/YpIzvdfYcsLeHGGfLgEOMeTGqdLmjw8PAgKCmL16tV27atXryY4OPimx7q7u1O6dGlcXV2ZNWsWbdq0wcXF+ldQp06ddOdctWrVLc8pkmn/LfY7sEM0145jbnpnNZfCesOFC6aEJiKSHc5FJnAM66CEs9RoAidMmgAGDx7MxIkTmTx5Mvv27WPQoEHExMTQr18/wPrYrEePHrb+Bw4c4Pvvv+fgwYNs376drl278vvvv/Phhx/a+rz44ousWrWKkSNHsn//fkaOHMmaNWsYOHBgdl+e5AZ588LcuTBokK1pFc1oxDraT+/MqUc6wL//mhefiMhdFBeZYvuzMyVNbmYHcDtCQ0M5fvw4w4cPJz4+nkqVKrF8+XICAqzPROPj44m5amZ+amoqn376KX/++Sfu7u40btyY8PBwAgMDbX2Cg4OZNWsWb775Jm+99Rb33HMPs2fPplatWtl9eZJbuLrC6NFQrhynB7xON2M6qbixnNY02FySpTU6UGrVFLjnHrMjFRHJOoZBzN9X5hOXIQb8neOpjlPWaXJUqtMkt23ZMtZ1+pJHz8/gJIUAKEUcSwuGUWXZB6DHxCKSUyQmMqXYKzzJFADG0p/+Ua9AgHmTwXNsnSaRHKl1axqFf8iWYu0py2EA/qY09U4uYXnDkfDDDyYHKCKSRf6bBH5ZGUsclCxpYkAZp6RJxFFUrUr5X2awtWIfarMFgDPkp+2l+YwPXQcffaQ360TE+cXG2idNxc6Bu7uJAWWckiYRR1K6NMW3LubnkJF0xjq6lIYrzzOel4a6k9rnGWt5AhERZ3XtSFPAjeshOholTSKOpkAB8iyby6x+6xnClbUUv6Yvh6esg5Yt4eRJ08ITEbkjVyVN+ThNoXKFTA4o45Q0iTgiNzdcxn/JiE89+YZn8OACs+jKfRyCn36CunUhMtLsKEVEMi8mhuW04iea8C09sQQ4R7kBUNIk4rgsFhg8mKfnteCw14O0YdmVfXv3Qu3asG2befGJiNyOmBju4TBNWMtjzHeaGk2gpEnE8XXsSKkNM+GqJX0M4LVjg1lZ/wNrkUwREWdxVR1FQEmTiGSxGjWso0oPPgjAGF5kFK/RJmU+Ezr/BCNH6s06EXF8Fy9CfLx9m5ImEclyAQGweTNGsxA2UxeAVNx4jgm8NMSN1Kf66s06EXFsf//NNqMGk+nNGh7hJD5KmkTkLvHxwbJsKbOf+ZmX+djWPJqX6DS5JWead9SbdSLiuGJimENn+jCZZqxht1cdKFjQ7KgyTEmTiLNxd8flq/F8/LGFr+mLK5cAWMijNFw7jPia7fVmnYg4pmtqNPmXNqwvvTgJJU0izshigZdf5pl5zVnu8SjeJAGwi+rUOvgdv1Z/ErZuNTlIEZFrXJM0lS7rHJXAL1PSJOLMOnYkZNPbbC7SnjJEAxBLGer+u5gNDd/UmnUi4liuSpr8iMczsITJAWWOkiYRZ1ejBpV2fcu2B3pSE2vdpqIkUv7irxAaCh9+qDfrRMQhXIyOJwE/AMoQ41STwEFJk0jOEBCA37ZFrG36Ib2ZzDJaU5x/rPveeAOefNL6qq+IiIn+PnwB47/UQ0mTiJjHx4e8K+Yx+dmdVGSf3a6TUxdwqkl7+Pdfk4ITkVzPMIiJuzLpW0mTiJjLzQ3GjYPPPrO9kXIRdzoyn/qbRxBXvQMcOmRujCKSOyUlEXOumG1TSZOImM9igYEDYeFCyJuXV/iYtTRhD1WoGTmLXUHPwMaNZkcpIrnNNW/OlSEWSpUyMaDMU9IkklO1awcbN/JssXmU4y8A4ilJg+QlLGoyBr7/3uQARSRXiYkhL2e5nz/x4hxlip4BT0+zo8oUJU0iOVm1apT/ZQZbH3yKYDYDcJZ8PHrpBz4Ni8B46229WSci2SMmhkF8zp+U5yx5qVou2eyIMk1Jk0hOV7o0xbYu4aeWn/IE0wEwcOFlPqXf+6VI6RoG58+bHKSI5HgxMbY/WgCXAH/zYrlNSppEcoP8+fFaMofvB+zgHYbZmr+hL61+6MnJ+m3h6FETAxSRHO+qpAlwukngoKRJJPdwdcUy5nOGjfPle0sYHlwAYA3N+GRnQ6hVC/74w+QgRSTHUtIkIk7nuefotrwbP+dpQ1H+oQHreZvhEB0NwcHw449mRygiOdDevzypzg46Mo+ZdFXSJCJOokUL6m7/jG0lOzKfjniQYm1PTobWrWHCBHPjE5Gc5dIlDh/Nxy6qs4COHOB+JU0i4kQqVaLcL3MpUvt+u+Z9qffx4XOxGAMHQWqqScGJSI4SH0+MUdq2WYYY8NdEcBFxJr6+8PPP1oV9gUSK0IalvMGHdBtTg/NtO8OpUyYHKSJO79rClu4JULSoiQHdHiVNIrldnjwwYwa8+SY/8QiRlAVgJk/QZMXLHKvdLv0EThGRzLg2aSqValvqyZkoaRIRcHGB994jdFobFrh1IS9nANhCMLX2Tub3aj1g+3aTgxQRp3VN0lS6rLuJwdw+JU0ickVYGO1/fpGNPm0pyd8ARFGW4OOLWVnvfZgzx+QARcQpXZU0Fecoecr6mRzQ7VHSJCL26ten2q7/sf2eJ6jGLgBO4U3rlAWM67IOPvhAS6+ISKZciorjb6yL85YhxinfnAMlTSJyPffcQ6mdi9jQaBiPMh+ANFzpzzhefDM/9OwJFy6YHKSIOIsjh8+ThiugpElEcqKCBcm3agFzn1nNa3xkay5DDHz3HTRtComJJgYoIs4iJu5KuqGkSURyJnd3XL4az0ejPZlEH55jHIMZbd23aZN16ZV9+8yNUUQcW3IyAad/5zMGMojRPMJPTps0WQxDkxOySnJyMj4+PiQlJeHt7W12OCJZa8kSePxxOHPGrvmfAuUoNncChISYFJiIOLQ//oBKlezbzp61ljtxEBn9/a2RJhHJmLZtYfNmuyq+K2hB4KlfmdFiGowfb2JwIuKwrq3zVry4QyVMmaGkSUQyrnJl2LYNatTgIPcSymzOko9uxve8/XwiaS+8CJcumR2liDiSa5MmJ300B3c5aXJ1db2bpxcRM5QoAevWEfhYdboyy9b8Hm/z+JfBnGv1GCQlmRigiDiUmBh+50GOUhwDlDTdiKZLieRQefPi/sN0vn4zjtEMwkIaAD8QSqPVr5NQsx1ERpocpIg4hNhY6rEJP47yIH845UK9l93VpMnihOvKiEgGubhgeW84g76vziK3TuTHurDvdmpR88B37KnW2zoHSkRytaTDx0miIAB+JGikKTk5OVuPAxg/fjxly5bFy8uLoKAgNm7ceNP+06dPp3LlyuTNm5cSJUrQu3dvjh8/bts/depULBZLus/58+dvO0aRXKFbN9quf5nNhdrij3XuQixlqHtyKUsafQrff29ygCJiptioVNufnblGE2RB0vTvv//yzDPP8Mknn2TLcQCzZ89m4MCBvPHGG0RERFC/fn1atmxJzA1WYt+0aRM9evSgT58+/PHHH8yZM4cdO3bw1FNP2fXz9vYmPj7e7uPl5ZXp+ERyneBgHv5lKtvvD6Mm2wA4Q356XJrEibAX4M03IS3N5CBFJNulphKbcGVx3lyfNBUuXJiqVavin8lnlLd7HMDo0aPp06cPTz31FBUqVODzzz/H39+fCRMmXLf/1q1bCQwMZMCAAZQtW5Z69erRt29fdu7cadfPYrHg5+dn9xGRDAoMxG/HEtaFjCCUWbiQygyeoBAnrevVhYZaa7OISO5x9CgxqSVtm7k+aQJ49dVXCQ0NzZbjLl68yK5duwi5ppBeSEgI4eHh1z0mODiYuLg4li9fjmEYHD16lLlz59K6dWu7fqdPnyYgIIDSpUvTpk0bIiIibhrLhQsXSE5OtvuI5Gre3uRZNpeZL2xhM3Vpycor++bOhQYN4O+/zYtPRLJXTAwxXEmS/N0SrHWanFSmkqaRI0det/1GE74Nw2DUqFE3PN/tTBRPTEwkNTUVX19fu3ZfX18SEhKue0xwcDDTp08nNDQUDw8P/Pz8KFiwIGPHjrX1KV++PFOnTmXx4sXMnDkTLy8v6taty8GDB28Yy4gRI/Dx8bF9bmfUTCTHcXPD8sUYak/oBVeVHTGAYbvasq/qE7Brl2nhiUg2uiZpKlMiBVyct0RkpiL//r8JnY0aNbqrx2TEtQmXYRg3TML27t3LgAEDePvtt9m1axcrV64kMjKSfv362frUrl2b7t27U7lyZerXr88PP/zA/fffb5dYXWvo0KEkJSXZPrGxsVlzcSI5Qb9+sGIF+PgA8BmDGM4w6vyziFXB71hHnkQkZ7t2pCnQues3Zippql69Oq1ateLw4cMsWrSIv/7665bHBAUFZfqYmylatCiurq7pRpWOHTuWbvTpshEjRlC3bl1eeeUVHn74YZo3b8748eOZPHky8fHx1z3GxcWFGjVq3HSkydPTE29vb7uPiFylWTPYupWUcg8wnW4AJFGQVhcXMK7zWnj/fVA9N5Gc66qkqTDHyV/OeR/NQSaTpilTpjBixAjS0tJYv349/fr1o1y5ctSsWZPevXun62+xWDJ9zK14eHgQFBTE6tWr7dpXr15NcHDwdY85e/YsLtcMB16uVn6jApyGYbB7925KlCiR6RhF5Crly+O+fTPr671JexYCkIob/RnH828V4tITPUClPURypLToWP6mFOD8k8ABMG7D3r177bb/+ecf4+eff07Xz8XFJdPHZMSsWbMMd3d3Y9KkScbevXuNgQMHGvny5TOioqIMwzCMIUOGGGFhYbb+U6ZMMdzc3Izx48cbf/31l7Fp0yajevXqRs2aNW193nnnHWPlypXGX3/9ZURERBi9e/c23NzcjG3btmU4rqSkJAMwkpKSbuu6RHK0CxeM1D5PG6/ykWEdXrJ+mvGjcaJ6U8NISDA7QhHJalWrGufwNA5yj7GHhwzjf/8zO6Lryujv79tKmjLq6qQpq40bN84ICAgwPDw8jGrVqhnr16+37evZs6fRsGFDu/5ffPGFUbFiRSNPnjxGiRIljG7duhlxcXG2/QMHDjTKlCljeHh4GMWKFTNCQkKM8PDwTMWkpEnkFtLSDGP0aGMKvQx3LtgSp/LsNQ6WqG8Ye/aYHaGIZKUiRQy7fyX9+KPZEV1XRn9/Wwzj7k0ocHV1JTU19dYdc4jk5GR8fHxISkrS/CaRm1m2jI2dv+DRc9M5TlHAOt9hpdej1Jj9MrRrZ3KAInLHzp6FfPns2/btg/LlzYnnJjL6+/uO3vu70Sv+WX2MiOQwrVtTf9snbC/5KBX5A4CCnKTs+b3QoQOMGqUJ4iLOLjo6fZuTl+a5o6Tp2gKTd+sYEcmBHnqIchHzCK85iC7MZgltKcpxa7L02mvQuzdcuGB2lCJyu6Kj+Y7uDOMdptCL5MKB6UeenIzbnRx8O0/27uLTQBFxNsWL47N+MbOfeQa+22e36/i3S3DbH4/P4u+cuoKwSK4VFcUsurIc6+obLUs3x9knrtzRSNPtVPS+nWNEJAfz8oJvv4WPPoL//v9wEXceZQHB20ZzuOpj8NtvJgcpIpkWHU00AQB4cp7i9zp7ypRFa8+JiNwRi8X6SG7BAsiXj1cZxUYasJcHqXlkARtqvQJLl5odpYhkghEVTRSBgLVGk0ugk9doQkmTiDiS9u1h82b6+82jPNbHdccpStNzi5nUdiF88okmiIs4iX8P/csZ8gMQSBQEBJgbUBa4o6TJw8MjW44RkVykcmXujZjDluoDCOFHAFLw4Ckm8tIrFlJ79dEEcREnEB115R84AURDYKB5wWSRO0qadu7cmS3HiEgu4+dHwY1LWPbEDF7gC1vzaF6i3bTHSG7UDo4dMzFAEbmpixeJSsxv2wwgWiNNIiJ3jZcXbt9P5YsPzzCBfrhyCYDltKbOVk0QF3FosbFEc2UOkx7PiYjcbRYLDB1Kv/nNWeXZjkL8C8BeHmTckQ4QHAxLlpgbo4ikFxVle3MOICBvIhQsaF48WURJk4g4vkcfpcnWD9nu157y7KMh6xjBUDh92jp5XBXERRzLVeUGAALK5Iz7M9PFLbdt28bMmTPZvHkzCQkJeHl5UbFiRVq2bMnjjz+Oj49PlhwjImKnShXu3T2XLW3DSN2xCw9SrO2XK4j/8Qd88w14epobp4hAdDRBHOY0+YnFn5L35DE7oiyRqZGmVq1aMWXKFJo1a8bixYuJjIxk9+7dDB8+nIsXL9KpUycWLlxo628YBq1bt87UMSIiN+TrS8ENiykS1tqu+XcepPO0NiTVbwNHj5oUnIjYREXxJh+wmhD2UwG3ss695txlFiMT65qcPHmSgrd4Jnl1HxcXF06cOHHLkaSMnNcZZHSVZBG5Q4ZhfSQ3dCj/GEWoyXaiKEt59rGkRF/uXTEWKlc2O0qR3KtRI1i//sr2J5/ASy+ZFs6tZPT3d6ZGmjKS2Fzdx2KxZOjRW05ImEQkG12uIL5wIVFeFThFAQD2U4Fa8Qv4udZQa3VxETFHdLT9dg54cw6yeCL4jBkzMtRv9erV9OjRg549e9KrVy9WrVqVlWGISG7Rrh01tn3J9pIdqMgfAPxLEZpfWMSEjqvggw80QVwku126hBEbZ9+WQ5KmTE8Ev9rbb79t+7NhGKxcuZInnnjilsfNmjWLadOm2bb79u1LSEjInYQiIrnVww9TLmI+W9p15/FtL7Kc1lzCneeYwO9vjuPzX8Nwn/o/yJMzJqKKOLwjR5iQ+jTv8A4BRDOS12iipAkOHDjAyJEjbduRkZEZOi4tLY2ffvoJf39/YmNjSUlJuZMwRCS3K14c7/VLWNz3OYZ8u5dPeAWA8TzP/h/KM+dAGwovnQalSpkcqEguEG1dqPcfivMPxTE8vKBYMbOjyhK39Xju66+/BmDIkCEEBATYPu+///4tjwH48ssviY+PZ8GCBcTHx/PFF1/c8DgRkQzx9MR1ykQ+/tSVqZbeeGBdn+5nHiF49zguVK8LO3aYHKRILvBf0nRZQOlU6zzEHOC2kqYtW7bwwgsv8PDDDwPw559/EhYWRuBNFuO7fExaWhr58uWjevXq/P7773Tv3p38+fPf8DgRkQyzWGDwYHou68LavG0ojrX8wLNMwDMhGho0gJkzTQ5SJIe7qhq4hTT87/EwOaCsc1uP56ZOncro0aNp1aoVBQsW5ODBg7zyyiuZPubVV1+9raBFRG6qZUuCdwayo0Unvo+pz4DLi/6ePw9PPGEthDl8OLhoUQSRLHdVNfASxONZtqTJAWWd20qafvnlFzZv3szRo0c5cOAAa9euJeAWk7xu5xgRkdtWoQJlflnI6126wM/2u1Z+sJPGv4biOWMKaKRbJEudOxzPUfwACCAabvIUytnc1j+znnvuOfr06UNERASzZs2iffv2bN68OcuPERG5I0WKwMqV8NxztqaltKYVy3lkyYscrdEGoqLMi08kB4o5fMn25wCic0y5AchkRfAb+fvvv+ncuTPh4eF27a6urqSmpmbqGGemiuAiDmzCBM72f5WyaYc4hi8A/sSwuGBPqix61zrfSUTuTFoaq7za0TxlKQBDGMGITQ2gbl2TA7u5u1IR/EZKlSrFzz//fOuOd3iMiMhte/ZZ8q5exDLvJyiFtfBeLGWoe3Ip8xp/Cf/7n8kBiuQAx44RnVLCtpmrH881b96ciRMncuzYMbv2tLQ0du/eTf/+/fn2229t7YZh0KJFi0wdIyJy1zRpQvVfvmHHvU9Qi60AnCUfndJ+4N1n4kh74UW4dOkWJxGRG7pqEjhAgOvfUKLETQ5wLpmaCN6wYUPOnTtHhw4diI+Pp2DBgly4cIFz587RsGFDnn32WWrVqnXHx4iI3DX33EOJXUtZF9qTZ1Y+ynf0AOAd3uX3L+cw9Y9HyTf3Wyhc2ORARZxQVBRPMpkgdhFFIJVLJeaot1QzlTTNnDmT3377jblz53LgwAESExPx8vKiUKFCNz3m119/zdQxIiJ3lbc3Xkvn8u3Q16n08asM4SMMXJhLZw6tvZdF1TpQZsXXUKGC2ZGKOJfoaMoRSTn+WyHknsbmxpPFMpX+Va9endatWxMZGcmKFSs4e/bsLZOfoKAgWrVqlaljRETuOldXLKNG8up3D7PErSMFSAYgkrKcjT4GtWvD8uUmByniZKKj7bdz0HwmyGTSNGXKFD788EPS0tJYt24d/fr1o1y5ctSsWZPevXun62+xWJgyZQojRozI8DEiItmqe3dabxrK1qJtuZ8/mUVXyvMnJCdDmzbwySdw5y8Zi+QO15bwyEHlBuA2iltWrlyZ1atXU+GqYevExER+++23dH0vVzPIzDEiItmuVi0qRkzn9/aP4f7L9ivthsGFV97AdffvuE38Cry8zItRxAmcOHyCn3iMAKK5l0MUymFJU5bUaRIr1WkScXLnzsGTT8KsWQAYQG+mEE8JZlX7mEJLpkHJnLMkhEiWMgzW5W1F4/MrABjMp3y6NggaNTI3rgzI1jpNIiI5Qp48MGMGfPABWCx8xiC+pReraE6tX8azr8rjsGOH2VGKOKYTJ4g+X9y2mdOqgYOSJhERexYLvP46LFxI9Tx7Kco/ABzkfmr/s5jlwe/D9OkmBynigKKiiCLQthlgiYXSpc2L5y5Q0iQicj3t2tFgx6fs8H+Mh9kDQDI+tLm0gI+778Z49TW4wTJRIrnSNYUtA4udAXd3EwPKekqaRERu5MEHCYxYwOYGr9OReQAYuPAqH9Pj40qcb/0YJCWZHKSIg7i2Gng5VxODuTuUNImI3EyRIuRfs5A5/TcwjHdszd8TRsMfh3IkqC0cPGhefCKOIirKljR5k0TBe4qYHFDWU9IkInIr7u64jB3DO9+UYq5rKHk5A8B2avHqX89AzZqwapXJQYqYKy0qhhjKADlzEjgoaRIRybinn+axtf0JL9SGMkRzD4f4ggFw8iS0bAmjR6sQpuRa8YfOkIIHAIFE5bhq4KCkSUQkc+rXp3LEVHY+2IvltKIwJ6ztaWnw0kvQqxecP29qiCJmiI6x2P6skSYREbEKCKDYtqXc37mKXfNRitN7WiNO1GsLR46YE5uIGU6d4tQpA18SACVNDmf8+PGULVsWLy8vgoKC2Lhx4037T58+ncqVK5M3b15KlChB7969OX78uF2fefPmUbFiRTw9PalYsSILFiy4m5cgIs4sXz6YPRveew+Ai7jzGPOYSm9q7RrHvspdYds2k4MUySbR0TRnFQmU4Cx56MdXUKaM2VFlOadMmmbPns3AgQN54403iIiIoH79+rRs2ZKYmJjr9t+0aRM9evSgT58+/PHHH8yZM4cdO3bw1FNP2fps2bKF0NBQwsLC2LNnD2FhYXTp0oVt+p+eiNyIxQJvvgkLF/JX3of5kweA/wphJi5hWb0RMG2ayUGKZIPoaNsf83Ce/L75rRX2cxinXHuuVq1aVKtWjQkTJtjaKlSoQIcOHRgxYkS6/p988gkTJkzgr7/+srWNHTuWUaNGERsbC0BoaCjJycmsWLHC1qdFixYUKlSImTNnXjeOCxcucOHCBdt2cnIy/v7+WntOJDf6/XeiWj1Hh9gv2EMVACyk8SGv89rgS1hGfgRumV4jXcQ5jBsH/ftf2a5Z06lGWnPs2nMXL15k165dhISE2LWHhIQQHh5+3WOCg4OJi4tj+fLlGIbB0aNHmTt3Lq1bt7b12bJlS7pzNm/e/IbnBBgxYgQ+Pj62j7+//x1cmYg4tUqVrIUwG75BJ+YA1kKYQ/mIJ0YHcbZFRzhxwuQgRe6Sq0aagBw5nwmcMGlKTEwkNTUVX19fu3ZfX18SEhKue0xwcDDTp08nNDQUDw8P/Pz8KFiwIGPHjrX1SUhIyNQ5AYYOHUpSUpLtc3nUSkRyqSJFyLdmET+8sInhvGVrnsXj1P9pGDFV28PevSYGKHJ3GFHRtGQ5vZnMBPrlyHID4IRJ02UWi8Vu2zCMdG2X7d27lwEDBvD222+za9cuVq5cSWRkJP369bvtcwJ4enri7e1t9xGRXM7NDcsXY3hrYiALXDuRn1MA/EIQNaLnkFCzHSxZYnKQIlkr8dBJVtKSqfRmEe010uQoihYtiqura7oRoGPHjqUbKbpsxIgR1K1bl1deeYWHH36Y5s2bM378eCZPnkx8fDwAfn5+mTqniMhN9elDhw2D2VKkLeWwzqd8jHn4nfkL2reH999XIUzJMa5+OpdTyw2AEyZNHh4eBAUFsXr1arv21atXExwcfN1jzp49i4uL/aW6uloXErw8D75OnTrpzrlq1aobnlNE5JaCg6m0+3t2VHmGVxnJ5wy0thsGvPUWdOkCp0+bGqLIHTt/nqh/C9g2A4lS0uRIBg8ezMSJE5k8eTL79u1j0KBBxMTE2B63DR06lB49etj6t23blvnz5zNhwgQOHz7M5s2bGTBgADVr1qRkyZIAvPjii6xatYqRI0eyf/9+Ro4cyZo1axg4cKAZlygiOUXp0hQOX8rI7r/jQYrdrp/nHudYrbYQGWlScCJZICbGtlAv5OyRJqd8/zU0NJTjx48zfPhw4uPjqVSpEsuXLyfgvy8pPj7ermZTr169OHXqFF9++SUvvfQSBQsWpEmTJowcOdLWJzg4mFmzZvHmm2/y1ltvcc899zB79mxq1aqV7dcnIjlMnjzWek1VqsCrr0JaGr/yEO1YTJG9x1lYtRdVF7wNjRubHalI5kVF2SVNgQX+hRw6x9cp6zQ5qozWeRCRXOzHHzFCu9IgaTGbqA9AHs4yxdKH0DHB1lo3N3kBRcTh/O9/tHvGlyW0AyCuYgil/lhlclCZk2PrNImIOLXmzbHs2M7se9+kFlsBOEdeuhozGTrgNKlPPg1XFc0VcXjR0baRJncuUuK+/CYHdPcoaRIRyW733UfJXUtY1+pjejHF1vwRQ2k7tSMn67XRgr/iPK56PFeGGFwCc96ac5cpaRIRMYO3N15L5jD5jcOMYQCuXAJgBa2ouVML/orzOPnXcZIoCOTsSeCgpElExDwuLljef48BcxqwyrMdRUgErAv+1kpcyvJ6H8KUKbc4iYjJYmN5l7d5kkm0ZEWOTpqc8u05EZEcpVMnmtx/Pztad6RD3Fh+pTJnyYvXpVPw5JMQEQGffgru7mZHKmIvJYWC8ft4m/eutAU+YV48d5lGmkREHMHDD1N29wLCG75OZ37gU16iCWut+8aOhebNITHR3BhFrhUXB2lp9m05eKRJSZOIiKP4b8Hf2S9uYQBf2O0y1q4lvkpL2L3bnNhErufq9VMA8uWDwoXNiSUbKGkSEXEkbm5YPv8My7ffgqenrfkjhlDp75X8VOt1mD3bxABFrhIdTTx+nMPLuh0YmKPrjClpEhFxRD16wIYNUKoUq2nKG3zAvxQh5OISPuu6FeO1IZCaanaUkttFRdGOxeTlHKWII7VMWbMjuquUNImIOKqaNWHnTmrWtNCK5QCk4cpgPqPHqAc51+JROHHC5CAlV7uqsKUrqbgG+psc0N2lpElExJH5+eGzYQmLn1rCG7xva/6eMOqtGUZMlXbwxx8mBii52ZnDR/mH4kDOr9EESppERByfpycu//ua978qxhyXUPJxGoBfCKJ6zDw21HgJFiwwOUjJjWIOX7L9OZAo65ymHExJk4iIs+jbl07rX2BL4TaU4y8A/qE4j5xbwriOazDeHpb+9W+RuyUtjagjHrZNjTSJiIhjqVePh/Z8z44qz9AM60ryl3DnS/pz7r2P4dFHITnZ5CAlV4iPJzq1lG1TSZOIiDie0qUpvGUZy7vP5BVG4cNJFtKBvJyDxYuhVi3480+zo5Sc7qpJ4AAB7vHg62tiQHefkiYREWfk5YXbtMmM+tyT/S4P8gAHruzbv5+0GrVg6VLz4pOcLyqKKAJtm4ElL4JLzk4rcvbViYjkZBYLvPgifqu/gyJFbM3n8aTBqaV83XYJvPee5jnJ3XHNSFOZcjl/OVslTSIizq5JE9i5EypXxgD68RWbqUc/vuaZt3250CEUTp0yO0rJaa5KmnxJwKtcSZMDuvuUNImI5ASBgRAeTlroExTiSsHL//EMjZcM4ki1NnDgwI2PF8msqCh2U4UdVGc63XJ8uQFQ0iQiknPkzYvrzO/57JM0pll64sU5ALYQTPVDM9lS7XlYtszkICXHiI6mGIlUZxeP8HOOf3MOlDSJiOQsFgu89BJhP3Znk3dr/IkBIJ6SNDyzjP+1WQQffACGYXKg4tQMA6Kj7duUNImIiFNq1oyg3ZPYWbEnDVkHQAoePMM39HuzCBc7dtU8J7l9iYlw7px9mx7PiYiI0ypbluLbl7K68/8YwBhb89f045uFxaB2bTh40MQAxWlFRbGCFoxmEPPoyEmXwlBSE8FFRMSZ5cuH++zvGTPqIlMtvfHkPE1ZTT++gr17oUYNzXOSzIuKYhZdeYnRdGIecb5B4KaSAyIi4uwsFnjlFXqufJzNBVoyi664kWrdl5QEbdvC+++rnpNkXGQkkZS1bQbe42piMNlHSZOISG4REkLQ7kkUebi0XfNOoxr93yporeekdeskI65KmopxjPz3lTA5oOyhpElEJDcpVw7Cw6FrVwCOUYyOzGcc/Wm0ZLC1npPWrZNbuHD4b/7GulhvIFFQtuzND8ghlDSJiOQ2+fLBjBnw8cdEWIL4h2IAbKUOQX/NZnO1F6wL/4rcQMzBCxj/pRBlicwVb86BkiYRkdzJYoGXX6b5qpfY7N2KMlhr7iRQgsZnl/JV++UYw97RPCdJLy2NqLgrk77LEqmRJhERyQWaNqXa7snsrNSbxvwMWOs5PctXPD28NOfbdrZOFhe5LCGByJRStk09nhMRkdyjbFmKbVvKqq5TGMRoW/MknqLB8teIrdLWWp5ABCAqyu7NubLucVBCE8FFRCS3yJsXtxnTGD3awveWMPJwFoAd1KRu1Pecq9EA5s41OUhxCNeUGyhbKgVcckc6kTuuUkREbs1igUGD6PbTk4QXbE0gkQC8xXvkOXscOneGoUMhNdXkQMVUkZHcyyFqsJ1iHCPgXnezI8o2SppERMRe48ZU2fMtOys/xVj68zQTr+z76CNo1Qr+/de8+MRckZG8z1tspxbH8MXzntK3PiaHUNIkIiLplSlDkS1L6d/rTLpdE1aVI6pye9izx4TAxHSRkfbbuWQSOChpEhGRG8mTByZPhnHjbOuKzedRnmMCQXELWV3zDWu9J8ldoqLst5U0iYiIYJ3n9NxzsHYtab4l+IA3APiXIrS4uIiR3fZgDBwEKSkmByrZ4tIliImxb8slhS1BSZOIiGREvXq4/LKTn2oMpQ1LAEjDlSGMpPOYupxq3A6OHjU5SLnr4uL4OrUP93CIpqxmM8EaaRIREUmnZEkKblzComeWM4x3bM3z6EStzZ/y58OdYds28+KTuy8ykgPcz2Hu4SeakuLlDUWLmh1VtlHSJCIiGefpicvXE3hnoj9L3B7FG2u18H1UpOaxJSyq9zF8843JQcpdc01hy8AyadZHuLmE0yZN48ePp2zZsnh5eREUFMTGjRtv2LdXr15YLJZ0nwcffNDWZ+rUqdftc/78+ey4HBER59KnD23CX2enbxse5HcAkvGhw6W5fN13Fzz9NFy4YHKQkuWuKmzpyiVK35fH5ICyl1MmTbNnz2bgwIG88cYbREREUL9+fVq2bEnMtZPT/jNmzBji4+Ntn9jYWAoXLkznzp3t+nl7e9v1i4+Px8vLKzsuSUTE+dSowX2/zmNr/VfpwmwACnOc5vwIEydCgwYQG2tykJKlIiOJIhCAMsTgVq6MufFkM6dMmkaPHk2fPn146qmnqFChAp9//jn+/v5MmDDhuv19fHzw8/OzfXbu3MmJEyfo3bu3XT+LxWLXz8/PLzsuR0TEeRUvTv6fFzPrpZ18zMvM5HECibbu274dgoJg3TpTQ5Ssc/LgP5ykEABlicxVk8DBCZOmixcvsmvXLkJCQuzaQ0JCCA8Pz9A5Jk2aRNOmTQkICLBrP336NAEBAZQuXZo2bdoQERFx0/NcuHCB5ORku4+ISK7j5oblk495eVYNQvJuttt1+p+zLHzkCxg9GgzDpAAlq0QeTrP9OZAoJU2OLjExkdTUVHx9fe3afX19SUhIuOXx8fHxrFixgqeeesquvXz58kydOpXFixczc+ZMvLy8qFu3LgcPHrzhuUaMGIGPj4/t4+/vf3sXJSKSE4SGWt+eu/deAAygD5N4NG0+A19yISW0O5w+bW6McvsuXCDyn/y2TY00ORHLNbP1DcNI13Y9U6dOpWDBgnTo0MGuvXbt2nTv3p3KlStTv359fvjhB+6//37Gjh17w3MNHTqUpKQk2ydWz+5FJLerVAl27IA2bfiR5vxAKABjGMgjc/qSENQabvKPUXFg0dG2+UzwX9KUiwpbghMmTUWLFsXV1TXdqNKxY8fSjT5dyzAMJk+eTFhYGB4eHjft6+LiQo0aNW460uTp6Ym3t7fdR0Qk1ytYEBYtovmwOnxFX9y5CMBGGlDtwEzCqzwHixebG6Nk3lVvzgGULXAcfHxMDCj7OV3S5OHhQVBQEKtXr7ZrX716NcHBwTc9dv369Rw6dIg+ffrc8ucYhsHu3bspUaLEHcUrIpIrubhgeWcYfZe2Y0P+1pQiDoB4StLo7DLGt1+J8eZbkJpqcqCSYZGRPMM3TKEXb/MuD5S9aHZE2c7pkiaAwYMHM3HiRCZPnsy+ffsYNGgQMTEx9OvXD7A+NuvRo0e64yZNmkStWrWoVKlSun3vvvsuP/74I4cPH2b37t306dOH3bt3284pIiK3oXVrau/+il3lu9OQdQCk4MHzjKfXB/dyrsWj8O+/5sYoGRMVxUP8Ti++5V3eoch9hc2OKNu5mR3A7QgNDeX48eMMHz6c+Ph4KlWqxPLly21vw8XHx6er2ZSUlMS8efMYM2bMdc958uRJnnnmGRISEvDx8aFq1aps2LCBmjVr3vXrERHJ0e65B9+dy1jzVD9em7WL0bwEwDR68tuah1hdtSlFFk2GKlXMjVNuLjLSfjuXzWcCsBiG3gHNKsnJyfj4+JCUlKT5TSIi1zIMGDuW2YO20iftG86Qn7YsZiEdcPHyhK+/hus8JRAHUbOmdZL/ZV9+Cc8/b148WSijv7+d8vGciIg4IYsFBgwgdN2zbCvSmlYsYxo9cMGA8+ehZ0/rL+GLuW+ujDM4+tdpVtGMg9zLBTxyXbkBUNIkIiLZrX59Hvx1JsuCP6Tgfwv+XrZ7/GZO1m0Nf/9tUnByXadPs/bfh2nOKu7nIF8wQEmTiIhItihZEtautXu8c4QStGAlNXaO57eHu2n5FUcSFWVfbiAX1mgCJU0iImIWDw/rvJhp08DLi758zVH8OMR91Pp3OTOaTIRPP9XyK47gmhpNgYVPQZ48JgZkDiVNIiJirrAw2LKFsf4fU41dAJwjL92M7xnwsjsXOz8Bp06ZHGQuFxlpXw089z2ZA5Q0iYiII6hShcA9i9jU/H16M9nWPJYBNJn3PEeqtYH9+00MMJe7aqSpAMkUvq+IyQGZQ0mTiIg4hkKFyLN8HpPeieMbnsGDCwBsph5Bh2axsdqLMH++yUHmTqmRMURjrYVYlkgs5XLnUJOSJhERcRwuLliGvc3Tyx9lY4HW+GMtVJxACRqfW8b4x9bAa6/BpUsmB5q7HDlwmhSsa7YGEpUrJ4GDkiYREXFELVtSc/c37KrUi0dYA0AqbhTiBIwaBSEhcPSoyUHmEoZBZPSVdKEskbl2UpOSJhERcUzlylFs+zJWhs1gCCMYwBgeZ5Z139q1UK0abNliboy5wYkTRJ0tZttU0iQiIuKI8uTB7dtJjJhQiM/dXrHfd+QIuxsMsJYtUFmCuycqilMUIA9nAShriYYyZUwOyhxKmkRExLFZLNCvH5ZNG6F0aVvzd3Sn6qUdvPLCOS516wlnzpgYZA4WGcnzjOcM+UjAl6al9oG7u9lRmUJJk4iIOIdateCXX6BJE6IIoC9fA/AJr9BsZm+OVm8NBw+aHGQOFBkJgAXw5Rh5y/mZG4+JlDSJiIjzKFYMfvyRgNceZxSv4kYKAOtoTLX90wmv8hwsXGhujDnNf0mTTS6dzwRKmkRExNm4uWH5aAT9FzZjfd5WlMS6uO8RStHw7HLGPvoTxmtDVJYgqyhpslHSJCIizql9e4J3j+eX8t1oxFoALuHOAMbSbdTDnG7STmUJskDswfN0YAED+YzltFTSJCIi4pTuuw/fnctY3XUyrzDK1jyTJ6i18WMOPdwRwsNNDNDJGQYHYrxYRAfGMJB1NMq1hS1BSZOIiDi7fPlwmzGNUWPzMs+lMwVIBuBfCpPv2GFo2BDGjlVZgttx9CiRF0vaNnNzjSZQ0iQiIjmBxQL9+9Nx02B2Fm9NFSL4gS6UIME6t2nAAOjWDU6fNjtS53LVQr0Aga5xULLkTQ7I2ZQ0iYhIzlGnDvf/No9djV+hPpvsdp2YuYL4aq1h/36TgnNCUVF2SVPZUhfB1dXEgMylpElERHKW4sVxWf0jDB1qa0rDQhjfUe3gLDZWexHmzjUxQCdy7UjTvW4mBmM+JU0iIpLzuLrChx9aazb5+DCGF1lGGxIoQeNzyxjdORxj8EuQkmJ2pI7tqqSpBEfwuqeUyQGZS0mTiIjkXO3bw86ddK8YwSOsASAVN15iNF0+q01ygzZw5IjJQTqus4eOcBRrBfBAonL1JHBQ0iQiIjndvfdSbMdyfuz+Pa/zga15Lp2psfULfn/4CVi3zrz4HFj0oSsjcbn9zTlQ0iQiIrlB3ry4TpvCB18VZbFbR3w4CcABHqDW8WV832QyjBypsgRXS00l8oinbVNJk5ImERHJLSwW6NuXtlte55eSbanKLwCcJR9hxjSeHeLNpfaPwcmT5sbpKP7+G/+0KF7iEzoyjxrsyNWFLUFJk4iI5DbVq1Pu14VsDhlOHybampPxxnXJAqheHfbsMTFABxEZyUP8zie8wjw60T7vGihe3OyoTKWkSUREcp8iRcizYj4Th8cziT5UZwff8AwWgL/+gtq1YepUk4M02bUL9QYGWkfrcjElTSIikju5uMBbb/Hkqq5sLdyafJy9su/8efb3/ojUPs/A+fPmxWimqCj77Vw+nwmUNImISG7XrBmuETuhVi1bUySB1GELrSY/RmLNVnD4sIkBmiQyknj8SOO/0aVcPp8JlDSJiIhAmTKwYQP0708aFkKZzUkKsYrmVPttKtsefhoWLzY7ymyVdPAYJYknL2fpwbcaaUJJk4iIiJWHB4wdi8uM6Yz0HEZxjgIQSxnqn1nB2ParMV4bYl0AOBeI+isVgAt44cYlJU0oaRIREbH3+OM0/uVTIu7pTD02ApCCBwMYyxOjKnO6cVtISDA5yLvs4kUij+WzbapGk5WSJhERkWtVrEjJ3cv5ucvXvMQntuZZPE6NTaPZ+1Co9XFeThUTQySBtk0toWKlpElEROR68ufHfdZ3fDLWi3muXfAmCYD9VKBG4nLmNB4Ho0blzCriVy3UC1A23z9QsKB58TgIN7MDyI1SU1NJ0cra2crDwwMXF/0bQUQyyWKB/v3pWKMGD3VoS6eEsfxKZc6SD6+0s/DaaxAebq3plJOSishIoq4aaSobkGZeLA5ESVM2MgyDhIQETqpEf7ZzcXGhbNmyeHh4mB2KiDijWrW477f5bH38SZ5f0wFfjtKWpdZ9ixZBUBDMmQPVqpkbZ1aJjCSSOgB4cIES9xcwOSDHoKQpG11OmIoXL07evHmx5PLKqtklLS2NI0eOEB8fT5kyZfT3LiK3p2hR8vy4kMnvv0/asHftdhmHDxNR+zmqffkkPP2001fONiKjbI/nAojGpVyguQE5CCVN2SQ1NdWWMBUpUsTscHKdYsWKceTIES5duoS7u7vZ4YiIs3JxgbffxqVOHXjiCUhMBOBr+vJsylcM7fshwzf0xu3rcZAv3y1O5rgSD57gDPmB/96cU2FLQBPBs83lOUx58+Y1OZLc6fJjudTUVJMjEZEcoVkziIiAOnU4wH28yBgARvA6Taf3IqFaK9i/3+Qgb19U5JXJ7So3cIWSpmymR0Pm0N+7iGS50qVh/XruG9iGEQzFFWvRy/U0ouqBWayvNhBmzTI3xttx5gxVT/zEIe5hNU15lglKmv7jtEnT+PHjKVu2LF5eXgQFBbFx48Yb9u3VqxcWiyXd58EHH7TrN2/ePCpWrIinpycVK1ZkwYIFd/syRETEmbm7Y/lsNIPn1mVd3taU5G8AEihBk3PLGPl4BGn9B8CFCyYHmgnR0biRyj0cpik/UZlf9XjuP06ZNM2ePZuBAwfyxhtvEBERQf369WnZsiUxMTHX7T9mzBji4+Ntn9jYWAoXLkznzp1tfbZs2UJoaChhYWHs2bOHsLAwunTpwrZt27LrsnKtdevWYbFY9FahiDivxx6j3u4viajYnaasBiANV4YwkvbjmnGiTiuIjjY5yAyKjLTfLl7cqednZSnDCdWsWdPo16+fXVv58uWNIUOGZOj4BQsWGBaLxYiKirK1denSxWjRooVdv+bNmxtdu3a94XnOnz9vJCUl2T6xsbEGYCQlJaXre+7cOWPv3r3GuXPnMhSjI+nZs6cBGIDh5uZmlC1b1njppZeM06dPG5GRkbZ91362bNliGIZhTJkyxa7dz8/P6Ny5s3H48GHDMAzjwoULRnx8vJGWlmbr7+Pjk6XX4Mx//yLiRM6eNS716mO8zTuGhVTDWvnSMAKINP7wrm0YS5eaHeGtffqpYQscDKNmTbMjuuuSkpJu+Pv7ak739tzFixfZtWsXQ4YMsWsPCQkhPDw8Q+eYNGkSTZs2JSAgwNa2ZcsWBg0aZNevefPmfP755zc8z4gRI3j33XdvuP+G0tLg+PHMH5eVihSxvgWSQS1atGDKlCmkpKSwceNGnnrqKc6cOcNrr70GwJo1a9I97rz6LUFvb2/+/PNPDMNg//799O3bl3bt2rF79248PDzw8/PLmusSETFTnjy4TpnIuw2mENy3Pd1SpnCcogD4Jf8JbdrAkCHw3nvg5pi/gk/NX003FvEoC2jPIgpXrGh2SA7DMb+xm0hMTCQ1NRVfX1+7dl9fXxIysIBifHw8K1asYMaMGXbtCQkJmT7n0KFDGTx4sG07OTkZf3//W1/E8ePW4U4zHTsGxYpluLunp6ctsXniiSdYu3YtCxcutCVNRYoUuWniY7FYbPtLlCjBsGHD6N69O4cOHSI+Pp7GjRtz4sQJdu/eTe/evW3HAAwbNox33nnndq5SRMQcvXvTvFo1Ijp0pEfUu4ziVQpzwrrvo4+sVcRnzoSSJc2N81pHj7J0cyGW0I4ltON5vuTLDhn4vZZLOOWcJkj/NpRhGBl6Q2rq1KkULFiQDh063PE5PT098fb2tvvkFnny5LmjpWDy5MkDkO4cwcHBfP7553h7e9vmoL388st3FKuIiCkqV8Z/z1J+fmw8Ndhptythw5/89tAT8PPPJgV3A/PnM5fHbJudvJZBSIiJATkWp0uaihYtiqura7oRoGPHjqUbKbqWYRhMnjyZsLCwdMtp+Pn53dY5c6Pt27czY8YMHnnkEVtbcHAw+fPnt/vcqCZSXFwcH3/8MaVLl+b++++32+fh4YGPj49tZMrPz4/8+fPf1esREblrvL2xzPkBvvgC/iusewlXHmcmtf5dztSm31sf1aU5xtpup2ctZTmtACjOUeq3Lwz//SNXnDBp8vDwICgoiNWrV9u1r169muDg4Jseu379eg4dOkSfPn3S7atTp066c65ateqW58wtli5dSv78+fHy8qJOnTo0aNCAsWPH2vbPnj2b3bt3231cXV1t+5OSksifPz/58uXD39+fixcvMn/+fK0FJyI5n8UCL7wAGzdCmTKM5znW0Zhz5KW3MZkn3y7F2eaP2qqLm+aff1i+sQDnsSZJHZmPa5fHbnFQ7uJ0c5oABg8eTFhYGNWrV6dOnTp88803xMTE0K9fP8A61+jvv/9m2rRpdsdNmjSJWrVqUalSpXTnfPHFF2nQoAEjR46kffv2LFq0iDVr1rBp06asv4AiRaxzisyUyaVcGjduzIQJE3B3d6dkyZK2pUiioqIA8Pf35957773h8QUKFOCXX37BxcUFX19f8un1VRHJbWrVgogInunWh70rv+JrrL+zpvAkO9dUZ26ljtw//yMw6x/rCxcy1+ho2+zkuRRazDEnFgfllElTaGgox48fZ/jw4cTHx1OpUiWWL19uexsuPj4+Xc2mpKQk5s2bx5gxY657zuDgYGbNmsWbb77JW2+9xT333MPs2bOpVatW1l+Ai0umJmE7gnz58t00KboVFxeXDB/v4eGh5U5EJGcqXBivZfP4atQo6r3eg77GBM6Sj994mKCjy5hYvy+ho7bA4MHZvujv2VmLWYa1gnkREmnYpgBo6S87Tpk0ATz33HM899xz1903derUdG0+Pj6cPXv2pufs1KkTnTp1yorwcp3jx4+nmxNWsGBBvLy8Mn2uwMBATp8+zU8//UTlypXJmzev1uwTkZzDxQWGDKF7nfVU69SKTokT2EdFTlOArmkz2PDyOEav7YTndxOhUKHsien4cVau8+Qs1qcAj7IAty4db3FQ7uN0c5rEMTVt2pQSJUrYfRYuXHhb5woODqZfv36EhoZSrFgxRo0albXBiog4goYNqfj7D2xv8Ard+c7WPJ7nqbtsKGeq1IUdO7InlkWLmJN2Zf5SZ4/F0KpV9vxsJ2IxDMO4dTfJiOTkZHx8fEhKSkpXfuD8+fNERkba1suT7KW/fxFxWKmpGO8OZ9J7R+jPWC7gRT8mMIHnrG/cjR4Nzz9/Vx/XXWzRjiI/Tuc0BSjEvxzt0A/3BT/ctZ/naG72+/tqTvt4TkREJEdwdcUy/F2eqreKGqEt+ODkc3zGfytUpKRY37zbsAEmToS7UQ/wxAk8fl7JrzzMPB4jBXfcuzya9T8nB1DSJCIi4ghCQqj8+4P80LUrbLpgt2vlnGQqbm9DmYVfQJUqWftzFy+GlBTKEsXLfAqentDmn6z9GTmE5jSJiIg4ilKlYO1a+G+JKoD9PEAn5lI1egHLawyDb76xLqWbVebOtd9u0QIKFMi68+cgSppEREQciZubdX26JUugUCFe4WPOkJ9/KULrS4sY2vc4l57oAadP3/nPSkqCVavs2/QW+Q0paRIREXFEbdpARATTqo2hPQttzR8xlCaznubvyq3gt9/u7GcsWcKbF99iKB+yi2oYbu7Qtu2dnTMHU9IkIiLiqAICKLRlOQsGrONTBuOGdZHzjTSgyuF5/Bj0OkyadNuP6y7+sJAv6c9HDKUxa7nQtDX4+GTlFeQoSppEREQcmYcHljGfM3h+fTbka4U/1hUvEilGy5RFvPXUEVLDesGZM5k776lT/LTiIkkUBKAdi/EKbZ+1secwSppEREScwaOPUufXr4mo3JvWLAXAwIX3eYtu01tCjRrwxx8ZP9/Spcy9dCVJ6uSyANoraboZJU0iIiLOolw5imxbzuLnVzGKV3DlEi6k8gzfwL59ULMmfPtthk6V8sMCFtIBgPycovkjl7Jv2RYnpaRJRETEmXh64vLlF7wypxbr87bicwbShLXWfWfPQq9e8OST1j/fyOnTrF12ln8pAkAblpIntN3dj93JKWmSW+rVqxcdOnSwa5s7dy5eXl5aF05ExCydOlF3z3heqLrZrjkNC8OmBBBftRXs3Xv9Y1esYG7KlSSpk8t8PZrLACVNkmkTJ06kW7dufPnll7z66qtmhyMiknvdey+Eh8Ozz9qaRjOY4QyjyoHZrKn2Kkyblu6wS7PnsQDrUil5OUPLRuehaNFsC9tZKWmSTBk1ahT9+/dnxowZPPXUU8CVkahPPvmEEiVKUKRIEZ5//nlSUlJsx504cYIePXpQqFAh8ubNS8uWLTl48CAAhmFQrFgx5s2bZ+tfpUoVihcvbtvesmUL7u7unP6vmJvFYmHixIk8+uij5M2bl/vuu4/Fixdnx1+BiIhj8fKC8eNh5kzO5SvKl/QH4Bi+hFxYzLCekaT2fPLK23Vnz7JhaTKJFAOgNcvIG6raTBmhpMlko0dD6dK3/rS7zqPmdu0yduzo0VkT65AhQ3jvvfdYunQpjz32mN2+tWvX8tdff7F27Vq+/fZbpk6dytSpU237e/Xqxc6dO1m8eDFbtmzBMAxatWpFSkoKFouFBg0asG7dOsCaYO3du5eUlBT2/je0vG7dOoKCgsifP7/tnO+++y5dunTh119/pVWrVnTr1o1///03ay5WRMTZdO1KnohwdjzYm+asBKxv1w1nGM2mdb/yuG7lShZcaGk7rJNlPlwzBUNuwJAsk5SUZABGUlJSun3nzp0z9u7da5w7d86ufdgww7BWJbv5p3bt9D+vdu2MHTts2J1dV8+ePQ0PDw8DMH766afr7g8ICDAuXbpka+vcubMRGhpqGIZhHDhwwACMzZs32/YnJiYaefLkMX744QfDMAzjiy++MCpVqmQYhmEsXLjQqF69utGxY0dj3LhxhmEYRkhIiPHaa6/ZjgeMN99807Z9+vRpw2KxGCtWrLjuNdzo719EJMc5d85I7fusMYLXDFdSbL8LipNgrPZsbRiVKhnn8DQW0dboyRTjVP2WZkdsupv9/r6aRppM5u1tXZ/xVp9ixdIfW6xYxo719r7zOB9++GECAwN5++23OXXqVLr9Dz74IK6urrbtEiVKcOzYMQD27duHm5sbtWrVsu0vUqQIDzzwAPv27QOgUaNG/PHHHyQmJrJ+/XoaNWpEo0aNWL9+PZcuXSI8PJyGDRumi+myfPnyUaBAAdvPFBHJtby8cPlqPENmVmFtntaUIg646nHd751wJ4V2LGEqvcnftY3JATsPN7MDyO0GD7Z+bkd2TuEpVaoU8+bNo3HjxrRo0YKVK1dS4KpVsN3d3e36WywW0tLSAOucpesxDAOLxQJApUqVKFKkCOvXr2f9+vUMHz4cf39/PvjgA3bs2MG5c+eoV6+e3fE3+5kiIrle167UDwoi4tEwevzxKitpaXtc58V5hvIRWCzQsaPZkToNjTRJhpUpU4b169dz7NgxQkJCSE5OztBxFStW5NKlS2zbts3Wdvz4cQ4cOECFChUAbPOaFi1axO+//079+vV56KGHSElJ4auvvqJatWp2SZqIiGTAffdRbOcKlvVbyke8hiuXuJ8/6c+X1v3164Ofn7kxOhElTZIppUuXZt26dRw/fpyQkBCSkpJuecx9991H+/btefrpp9m0aRN79uyhe/fulCpVivZX1QVp1KgRM2bM4OGHH8bb29uWSE2fPp1GjRrdxasSEcnBvLxwmTCO12ZVY12eVsyhMwWwvolMWJi5sTkZJU2SaaVKlWL9+vWcPHmSZs2acfLkyVseM2XKFIKCgmjTpg116tTBMAyWL19u94itcePGpKam2iVIDRs2JDU1Nd18JhERyaTQUOrtGcfDbQOhSBHo189aOVwyzGLcaMKJZFpycjI+Pj4kJSXhfc3s6/PnzxMZGUnZsmXx8vIyKcLcS3//IiJXMQzrfCYBbv77+2oaaRIREcltlDDdFiVNIiIiIhmgpElEREQkA5Q0iYiIiGSAkqZspnn35tDfu4iI3CklTdnk8qv1Z8+eNTmS3OnixYsAdku9iIiIZIaWUckmrq6uFCxY0LY2Wt68eW1LiMjdlZaWxj///EPevHlxc9N/8iIicnv0GyQb+f1Xql6LymY/FxcXypQpo0RVRERum5KmbGSxWChRogTFixcnJSXF7HByFQ8PD1xc9DRaRERun5ImE7i6umpujYiIiJPRP71FREREMkBJk4iIiEgGKGkSERERyQDNacpClwsoJicnmxyJiIiIZNTl39u3KoSspCkLnTp1CgB/f3+TIxEREZHMOnXqFD4+PjfcbzG0vkSWSUtL48iRIxQoUCBL6wElJyfj7+9PbGws3t7eWXZeR5LTr1HX5/xy+jXm9OuDnH+Nur7bZxgGp06domTJkjctT6ORpizk4uJC6dKl79r5vb29c+SNcLWcfo26PueX068xp18f5Pxr1PXdnpuNMF2mieAiIiIiGaCkSURERCQDlDQ5AU9PT4YNG4anp6fZodw1Of0adX3OL6dfY06/Psj516jru/s0EVxEREQkAzTSJCIiIpIBSppEREREMkBJk4iIiEgGKGkSERERyQAlTSYZP348ZcuWxcvLi6CgIDZu3HjT/uvXrycoKAgvLy/KlSvHV199la7PvHnzqFixIp6enlSsWJEFCxbcrfBvKTPXN3/+fJo1a0axYsXw9vamTp06/Pjjj3Z9pk6disViSfc5f/783b6U68rM9a1bt+66se/fv9+unyN9f5C5a+zVq9d1r/HBBx+09XGk73DDhg20bduWkiVLYrFYWLhw4S2PcaZ7MLPX54z3YGav0dnuw8xen7PdgyNGjKBGjRoUKFCA4sWL06FDB/78889bHmf2faikyQSzZ89m4MCBvPHGG0RERFC/fn1atmxJTEzMdftHRkbSqlUr6tevT0REBK+//joDBgxg3rx5tj5btmwhNDSUsLAw9uzZQ1hYGF26dGHbtm3ZdVk2mb2+DRs20KxZM5YvX86uXbto3Lgxbdu2JSIiwq6ft7c38fHxdh8vL6/suCQ7mb2+y/7880+72O+77z7bPkf6/iDz1zhmzBi7a4uNjaVw4cJ07tzZrp+jfIdnzpyhcuXKfPnllxnq72z3YGavz9nuQcj8NV7mLPdhZq/P2e7B9evX8/zzz7N161ZWr17NpUuXCAkJ4cyZMzc8xiHuQ0OyXc2aNY1+/frZtZUvX94YMmTIdfu/+uqrRvny5e3a+vbta9SuXdu23aVLF6NFixZ2fZo3b2507do1i6LOuMxe3/VUrFjRePfdd23bU6ZMMXx8fLIqxDuS2etbu3atARgnTpy44Tkd6fszjDv/DhcsWGBYLBYjKirK1uZI3+HVAGPBggU37eNs9+DVMnJ91+PI9+C1MnKNzngfXnY736Ez3YOGYRjHjh0zAGP9+vU37OMI96FGmrLZxYsX2bVrFyEhIXbtISEhhIeHX/eYLVu2pOvfvHlzdu7cSUpKyk373Oicd8vtXN+10tLSOHXqFIULF7ZrP336NAEBAZQuXZo2bdqk+1dwdriT66tatSolSpTgkUceYe3atXb7HOX7g6z5DidNmkTTpk0JCAiwa3eE7/B2ONM9mBUc+R68U85yH94pZ7sHk5KSANL9N3c1R7gPlTRls8TERFJTU/H19bVr9/X1JSEh4brHJCQkXLf/pUuXSExMvGmfG53zbrmd67vWp59+ypkzZ+jSpYutrXz58kydOpXFixczc+ZMvLy8qFu3LgcPHszS+G/ldq6vRIkSfPPNN8ybN4/58+fzwAMP8Mgjj7BhwwZbH0f5/uDOv8P4+HhWrFjBU089ZdfuKN/h7XCmezArOPI9eLuc7T68E852DxqGweDBg6lXrx6VKlW6YT9HuA/dsuQskmkWi8Vu2zCMdG236n9te2bPeTfdbiwzZ87knXfeYdGiRRQvXtzWXrt2bWrXrm3brlu3LtWqVWPs2LF88cUXWRd4BmXm+h544AEeeOAB23adOnWIjY3lk08+oUGDBrd1zuxwu/FMnTqVggUL0qFDB7t2R/sOM8vZ7sHb5Sz3YGY56314O5ztHuzfvz+//vormzZtumVfs+9DjTRls6JFi+Lq6pou6z127Fi67PgyPz+/6/Z3c3OjSJEiN+1zo3PeLbdzfZfNnj2bPn368MMPP9C0adOb9nVxcaFGjRrZ/i+kO7m+q9WuXdsudkf5/uDOrtEwDCZPnkxYWBgeHh437WvWd3g7nOkevBPOcA9mJUe+D2+Xs92DL7zwAosXL2bt2rWULl36pn0d4T5U0pTNPDw8CAoKYvXq1Xbtq1evJjg4+LrH1KlTJ13/VatWUb16ddzd3W/a50bnvFtu5/rA+q/bXr16MWPGDFq3bn3Ln2MYBrt376ZEiRJ3HHNm3O71XSsiIsIudkf5/uDOrnH9+vUcOnSIPn363PLnmPUd3g5nugdvl7Pcg1nJke/D2+Us96BhGPTv35/58+fz888/U7Zs2Vse4xD3YZZMJ5dMmTVrluHu7m5MmjTJ2Lt3rzFw4EAjX758trcchgwZYoSFhdn6Hz582MibN68xaNAgY+/evcakSZMMd3d3Y+7cubY+mzdvNlxdXY2PPvrI2Ldvn/HRRx8Zbm5uxtatWx3++mbMmGG4ubkZ48aNM+Lj422fkydP2vq88847xsqVK42//vrLiIiIMHr37m24ubkZ27Ztc/jr++yzz4wFCxYYBw4cMH7//XdjyJAhBmDMmzfP1seRvj/DyPw1Xta9e3ejVq1a1z2nI32Hp06dMiIiIoyIiAgDMEaPHm1EREQY0dHRhmE4/z2Y2etztnvQMDJ/jc52H2b2+i5zlnvw2WefNXx8fIx169bZ/Td39uxZWx9HvA+VNJlk3LhxRkBAgOHh4WFUq1bN7jXLnj17Gg0bNrTrv27dOqNq1aqGh4eHERgYaEyYMCHdOefMmWM88MADhru7u1G+fHm7/xlkt8xcX8OGDQ0g3adnz562PgMHDjTKlCljeHh4GMWKFTNCQkKM8PDwbLwie5m5vpEjRxr33HOP4eXlZRQqVMioV6+esWzZsnTndKTvzzAy/9/oyZMnjTx58hjffPPNdc/nSN/h5dfPb/TfnLPfg5m9Pme8BzN7jc52H97Of6POdA9e79oAY8qUKbY+jngfWv4LXkRERERuQnOaRERERDJASZOIiIhIBihpEhEREckAJU0iIiIiGaCkSURERCQDlDSJiIiIZICSJhEREZEMUNIkIiIikgFKmkREREQyQEmTiIiISAYoaRIRuYn777+fOnXqcO7cOVubYRjUrl2bV1991cTIRCS7KWkSEbmJ2bNnExERwebNm21t06dPJzIykjfffNPEyEQkuylpEhG5iapVq1K5cmX2798PwNmzZxk6dCjvvfce3t7eJkcnItlJSZOIyC3cf//9/PnnnwCMGjWKwoUL06dPH5OjEpHs5mZ2ACIiju6BBx5gw4YNxMXF8fHHH7NkyRJcXV3NDktEsplGmkREbuHySNOQIUNo1qwZTZo0MTskETGBxTAMw+wgREQc2e7du6lWrRoeHh78/vvv3HvvvWaHJCIm0EiTiMgt3H///QD0799fCZNILqakSUTkFs6fP49hGPTo0cPsUETEREqaRERuYc+ePXh4eFChQgWzQxEREylpEhG5hT179lCxYkXc3d3NDkVETKSJ4CIiIiIZoJEmERERkQxQ0iQiIiKSAUqaRERERDJASZOIiIhIBihpEhEREckAJU0iIiIiGaCkSURERCQDlDSJiIiIZICSJhEREZEMUNIkIiIikgH/B551Fwv/76g5AAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "verbose = 0\n", + "\n", + "gamma_min, gamma_max = 0.001, 2 # only test the step sizes of interest here\n", + "nb_gammas = 50\n", + "gamma_list = np.linspace(gamma_min,gamma_max,nb_gammas)\n", + "\n", + "pepit_worst_case_value = list()\n", + "known_worst_case_value = list()\n", + "\n", + "for gamma in gamma_list:\n", + " pepit_tau, _ = wc_gradient_descent_function_values_sparse_proof(mu,L,gamma, verbose)\n", + " pepit_worst_case_value.append(pepit_tau)\n", + " known_worst_case_value.append(max((1-gamma*L)**2,(1-gamma*mu)**2))\n", + " \n", + "plt.plot(gamma_list, pepit_worst_case_value, color='red', linestyle='-', linewidth=3, label='PEPit')\n", + "\n", + "plt.plot(gamma_list, known_worst_case_value, color='blue', linestyle='--', linewidth=2, label='Known')\n", + "\n", + "plt.legend()\n", + "plt.xlabel(r'$\\gamma$')\n", + "plt.ylabel(r'$\\frac{f(x_1) - f_\\star}{f(x_0) - f_\\star}$')\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 135, + "id": "996a028d-0feb-411f-a14b-05e4445967fe", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/png": "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X78e8+fPx6OPPorExES8/vrriI6OxubNm+0e/80332DIkCFYvHgxYmNjcfPNN2PBggU4evSomysnIiIiT+UxYaelpQWZmZlISUmR7E9JScHhw4ftPmfChAk4e/Ys9u7dC0EQcP78eXz00UdIS0vr8DzNzc2ora2VbERERKRcHhN2qqqq0NbWhoiICMn+iIgIlJfbWfcDYtj54IMPMHPmTOh0OgwYMADBwcHYuHFjh+dZu3YtgoKCzFt0dLRTr4OIiIg8i8eEHROV1cArQRBs9pmcOHECixcvxnPPPYfMzEz8+9//RlFRERYuXNjh669cuRI1NTXmraSkxKn1ExERkWfxmKnn/fv3h0ajsWnFqaiosGntMVm7di0mTpyIp556CgBw3XXXISAgAJMmTcJvf/tbREZG2jxHr9dDr9c7/wKIiIjII3lMy45Op0NycjIyMjIk+zMyMjBhwgS7z2lsbIRaLb0EjUYDQGwRIiIiIvKYsAMAy5Ytw7vvvov33nsPubm5WLp0KYqLi83dUitXrsScOXPMx999993YtWsXNm/ejNOnT+PQoUNYvHgxbrrpJkRFRcl1GURERORBPKYbCwBmzpyJ6upqrFmzBmVlZRg5ciT27t2LmJgYAEBZWZnknjtz585FXV0d3nzzTfzv//4vgoODcfvtt+OVV16R6xKIiIjIw6iEXt7fU1tbi6CgINTU1CAwMFDucoiIiKgLHPn97VHdWERERETOxrBDREREisawQ0RERIrGsENERESKxrBDREREisawQ0RERIrGsENERESKxrBDREREisawQ0RERIrGsENERESKxrBDREREisawQ0RERIrGsENERESKxrBDREREisawQ0RERIrGsENERESKxrBDREREisawQ0RERIqmlbsAIiIi6lhbWxtaW1vlLkMWOp0OanXP22UYdoiIiDyQIAgoLy/HpUuX5C5FNmq1GrGxsdDpdD16HYYdIiIiD2QKOuHh4fD394dKpZK7JLcyGo04d+4cysrKMHjw4B5dP8MOERGRh2lrazMHndDQULnLkU1YWBjOnTsHg8EAHx+fbr8OBygTERF5GNMYHX9/f5krkZep+6qtra1Hr8OwQ0RE5KF6W9eVNWddP8MOERERKRrDDhERESkaww4REREpGsMOEREROd2qVaug1+sxa9YsuUth2CEiIiLnW758Odav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wtixY+2+pid9D+vq6oSsrCwhKytLACCsX79eyMrKEn766SdBELz/PSgIjl+jt70PHb0+b3sPCoLj12jiDe/DX/3qV0JQUJCwb98+yf+3xsZG8zGe+j5k2HHAW2+9JcTExAg6nU4YNWqUZLrdww8/LNx6662S4/ft2yfceOONgk6nE4YMGSJs3rzZ5jV37twpJCQkCD4+PsI111wjeRO7myPXd+uttwoAbLaHH37YfMySJUuEwYMHCzqdTggLCxNSUlKEw4cPu/GKbDlyja+88oowbNgwwdfXV+jXr59w8803C5999pnNa3rr91AQBOHSpUuCn5+f8M4779h9PU/6HpqmIXf0f04J70FHr9Hb3oeOXp83vge78//UW96H9q4LgPD++++bj/HU96HqygUQERERKRLH7BAREZGiMewQERGRojHsEBERkaIx7BAREZGiMewQERGRojHsEBERkaIx7BAREZGiMewQERGRojHsEBERkaIx7BAREZGiMewQkeLEx8dj/PjxuHz5snmfIAgYN24cli9fLmNlRCQHhh0iUpwdO3YgKysLhw4dMu/74IMPUFRUhFWrVslYGRHJgWGHiBTnxhtvxPXXX4+TJ08CABobG7Fy5Uq89NJLCAwMlLk6InI3hh0iUqT4+Hjk5eUBAP7whz8gJCQE8+fPl7kqIpKDVu4CiIhcISEhAQcOHMDZs2exbt06/POf/4RGo5G7LCKSAVt2iEiRTC07K1aswJQpU3D77bfLXRIRyUQlCIIgdxFERM6WnZ2NUaNGQafTIScnB8OHD5e7JCKSCVt2iEiR4uPjAQCLFi1i0CHq5Rh2iEiRmpqaIAgC5syZI3cpRCQzhh0iUqRjx45Bp9MhMTFR7lKISGYMO0SkSMeOHcOIESPg4+MjdylEJDMOUCYiIiJFY8sOERERKRrDDhERESkaww4REREpGsMOERERKRrDDhERESkaww4REREpGsMOERERKRrDDhERESkaww4REREpGsMOERERKdr/Bz73Et+uAKWzAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "verbose = 0\n", + "\n", + "gamma_min, gamma_max = 0.001, 2\n", + "nb_gammas = 50\n", + "gamma_list = np.linspace(gamma_min,gamma_max,nb_gammas)\n", + "\n", + "pepit_worst_case_value = list()\n", + "pepit_dual_value1 = list()\n", + "pepit_dual_value2 = list()\n", + "pepit_dual_value3 = list()\n", + "pepit_dual_value4 = list()\n", + "pepit_dual_value5 = list()\n", + "pepit_dual_value6 = list()\n", + "known_worst_case_value = list()\n", + "\n", + "for gamma in gamma_list:\n", + " pepit_tau, list_of_constraints = wc_gradient_descent_function_values_sparse_proof(mu,L,gamma, verbose)\n", + " pepit_worst_case_value.append(pepit_tau)\n", + " known_worst_case_value.append(max((1-gamma*L)**2,(1-gamma*mu)**2))\n", + " pepit_dual_value1.append(list_of_constraints[2]._dual_variable_value)\n", + " pepit_dual_value2.append(list_of_constraints[3]._dual_variable_value)\n", + " pepit_dual_value3.append(list_of_constraints[4]._dual_variable_value)\n", + " pepit_dual_value4.append(list_of_constraints[5]._dual_variable_value)\n", + " pepit_dual_value5.append(list_of_constraints[6]._dual_variable_value)\n", + " pepit_dual_value6.append(list_of_constraints[7]._dual_variable_value)\n", + " \n", + " \n", + "plt.plot(gamma_list, pepit_dual_value1, color='red', linestyle='-', linewidth=3, label=r'$\\lambda_1$')\n", + "plt.plot(gamma_list, pepit_dual_value2, color='blue', linestyle='-', linewidth=3, label=r'$\\lambda_2$')\n", + "plt.plot(gamma_list, pepit_dual_value3, color='green', linestyle='-', linewidth=3, label=r'$\\lambda_3$')\n", + "plt.plot(gamma_list, pepit_dual_value4, color='gold', linestyle='-', linewidth=3, label=r'$\\lambda_4$')\n", + "plt.plot(gamma_list, pepit_dual_value5, color='orange', linestyle='--', linewidth=3, label=r'$\\lambda_5$')\n", + "plt.plot(gamma_list, pepit_dual_value6, color='brown', linestyle='-.', linewidth=3, label=r'$\\lambda_6$')\n", + "\n", + "plt.legend()\n", + "plt.xlabel(r'$\\gamma$')\n", + "plt.ylabel(r'$\\lambda_i(\\gamma)$')\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "e43af9f8-1de8-4e10-ba79-b8c4508fbef3", + "metadata": {}, + "source": [ + "... much better! one can actually even fit; defining $\\rho(\\gamma)=\\max\\{|1-\\gamma L|,|1-\\gamma\\mu|\\}$, we find:\n", + "* $\\lambda_1(\\gamma)= (1-\\rho(\\gamma))\\rho(\\gamma)$,\n", + "* $\\lambda_2 (\\gamma)= 1-\\rho(\\gamma)$,\n", + "* $\\lambda_4 (\\gamma)= \\rho(\\gamma)$.\n", + "\n", + "Those results, along with the corresponding proofs, are presented in [here, Theorem 3.3](https://arxiv.org/pdf/1705.04398), a numerical comparison is provided just below.\n", + "In the next sections, we provide a constructive few way to find such expressions beyond guessing." + ] + }, + { + "cell_type": "code", + "execution_count": 144, + "id": "23948925-8a27-4b84-86b2-0c71f1f62a7a", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "rho = np.array([ max(abs(1-gamma*L),abs(1-gamma*mu)) for gamma in gamma_list ])\n", + "plt.plot(gamma_list, pepit_dual_value1, color='red', linestyle='-', linewidth=1, label=r'$\\lambda_1$ (numerics)')\n", + "plt.plot(gamma_list, pepit_dual_value2, color='blue', linestyle='-', linewidth=1, label=r'$\\lambda_2$ (numerics)')\n", + "plt.plot(gamma_list, pepit_dual_value4, color='gold', linestyle='-', linewidth=1, label=r'$\\lambda_4$ (numerics)')\n", + "plt.plot(gamma_list, (1-rho)*rho, color='red', linestyle='--', linewidth=3, label=r'$\\lambda_1$ (closed-form)')\n", + "plt.plot(gamma_list, 1-rho, color='blue', linestyle='--', linewidth=3, label=r'$\\lambda_2$ (closed-form)')\n", + "plt.plot(gamma_list, rho, color='gold', linestyle='--', linewidth=3, label=r'$\\lambda_4$ (closed-form)')\n", + "\n", + "plt.legend()\n", + "plt.xlabel(r'$\\gamma$')\n", + "plt.ylabel(r'$\\lambda_i(\\gamma)$')\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "e4359eb1-7a58-4114-aef2-98a82b44c41f", + "metadata": {}, + "source": [ + "## 4. Using SymPy for the distance analysis " + ] + }, + { + "cell_type": "markdown", + "id": "304a0611-4e21-4664-b883-cf1de9377d9a", + "metadata": {}, + "source": [ + "This section requires SymPy (!pip install sympy)" + ] + }, + { + "cell_type": "code", + "execution_count": 149, + "id": "46d553b6-3495-45fd-9b32-b0298d63fc8f", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\left[\\begin{matrix}\\frac{\\frac{L \\lambda_{1} \\mu}{2} + \\frac{L \\lambda_{2} \\mu}{2} + \\left(L - \\mu\\right) \\left(\\rho - 1\\right)}{L - \\mu} & \\frac{- \\frac{L \\lambda_{1}}{2} + \\gamma \\left(L - \\mu\\right) - \\frac{\\lambda_{2} \\mu}{2}}{L - \\mu}\\\\\\frac{- \\frac{L \\lambda_{1}}{2} + \\gamma \\left(L - \\mu\\right) - \\frac{\\lambda_{2} \\mu}{2}}{L - \\mu} & \\frac{4 \\gamma^{2} \\left(- L + \\mu\\right) + 2.0 \\lambda_{1} + 2.0 \\lambda_{2}}{4 \\left(L - \\mu\\right)}\\end{matrix}\\right]$" + ], + "text/plain": [ + "Matrix([\n", + "[(L*lambda_1*mu/2 + L*lambda_2*mu/2 + (L - mu)*(rho - 1))/(L - mu), (-L*lambda_1/2 + gamma*(L - mu) - lambda_2*mu/2)/(L - mu)],\n", + "[ (-L*lambda_1/2 + gamma*(L - mu) - lambda_2*mu/2)/(L - mu), (4*gamma**2*(-L + mu) + 2.0*lambda_1 + 2.0*lambda_2)/(4*(L - mu))]])" + ] + }, + "execution_count": 149, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import sympy as sm\n", + "\n", + "# create symbols for the problem parameters:\n", + "L = sm.Symbol('L')\n", + "mu = sm.Symbol('mu')\n", + "gamma = sm.Symbol('gamma')\n", + "\n", + "# create symbols for the \"primal\" variables:\n", + "x0 = sm.Symbol('x0')\n", + "g0 = sm.Symbol('g0')\n", + "f0 = sm.Symbol('f0')\n", + "xs = 0 # wlog, x_* = 0\n", + "gs = 0 # constraint g_* = 0\n", + "fs = 0 # wlog, f_* = 0\n", + "x1 = x0 - gamma * g0 # define x1 using previous symbols:\n", + "\n", + "# create symbols for the \"dual\" variables\n", + "rho = sm.Symbol('rho')\n", + "l1 = sm.Symbol('lambda_1')\n", + "l2 = sm.Symbol('lambda_2')\n", + "\n", + "\n", + "# the two interpolation constraints in the form \"constraint <= 0\"\n", + "constraint1 = f0 - fs + g0*(xs-x0) + 1/2/L * g0**2 + mu/(2*(1-mu/L)) * (x0-xs-1/L*g0)**2\n", + "constraint2 = fs - f0 + 1/2/L * g0**2 + mu/(2*(1-mu/L)) * (x0-xs-1/L*g0)**2\n", + "# the objective and the \"initial condition\" constraint: (also in the form \"constraint <= 0\")\n", + "primal_objective = (x1-xs)**2\n", + "initial_condition = (x0-xs)**2-1\n", + "\n", + "# Lagrangian:\n", + "Lagrangian = - l1*constraint1 - l2*constraint2 - rho * initial_condition + primal_objective\n", + "\n", + "# This is the LMI:\n", + "LMI = sm.simplify(sm.hessian( -Lagrangian , (x0,g0))/2) \n", + "LMI" + ] + }, + { + "cell_type": "code", + "execution_count": 150, + "id": "ba73d008-d96f-4425-ae0f-ecb265a53601", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\lambda_{1} - \\lambda_{2}$" + ], + "text/plain": [ + "lambda_1 - lambda_2" + ] + }, + "execution_count": 150, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# This is the linear constraint ==0 in the LMI\n", + "LinearConst = sm.simplify(sm.diff(-Lagrangian,f0))\n", + "\n", + "LinearConst # show linear constraint (==0)" + ] + }, + { + "cell_type": "code", + "execution_count": 151, + "id": "c95f8df2-1f84-43fb-80a7-405f12f3fa88", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\left[\\begin{matrix}\\frac{L \\lambda_{1} \\mu + \\left(L - \\mu\\right) \\left(\\rho - 1\\right)}{L - \\mu} & \\frac{- \\frac{L \\lambda_{1}}{2} + \\gamma \\left(L - \\mu\\right) - \\frac{\\lambda_{1} \\mu}{2}}{L - \\mu}\\\\\\frac{- \\frac{L \\lambda_{1}}{2} + \\gamma \\left(L - \\mu\\right) - \\frac{\\lambda_{1} \\mu}{2}}{L - \\mu} & \\frac{- L \\gamma^{2} + \\gamma^{2} \\mu + \\lambda_{1}}{L - \\mu}\\end{matrix}\\right]$" + ], + "text/plain": [ + "Matrix([\n", + "[ (L*lambda_1*mu + (L - mu)*(rho - 1))/(L - mu), (-L*lambda_1/2 + gamma*(L - mu) - lambda_1*mu/2)/(L - mu)],\n", + "[(-L*lambda_1/2 + gamma*(L - mu) - lambda_1*mu/2)/(L - mu), (-L*gamma**2 + gamma**2*mu + lambda_1)/(L - mu)]])" + ] + }, + "execution_count": 151, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# For getting the same LMI as in the document, substitute l2 by l1 and simplify\n", + "LMI_simplified = sm.simplify(LMI.subs(l2,l1))\n", + "\n", + "LMI_simplified # show the LMI (>=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 153, + "id": "929299d6-c1d4-4fde-8360-ef593fd9be9b", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\frac{\\lambda_{1} \\cdot \\left(4 L \\gamma^{2} \\mu - 4 L \\gamma + L \\lambda_{1} - 4 \\gamma \\mu - \\lambda_{1} \\mu + 4\\right)}{4 \\left(- L \\gamma^{2} + \\gamma^{2} \\mu + \\lambda_{1}\\right)}$" + ], + "text/plain": [ + "lambda_1*(4*L*gamma**2*mu - 4*L*gamma + L*lambda_1 - 4*gamma*mu - lambda_1*mu + 4)/(4*(-L*gamma**2 + gamma**2*mu + lambda_1))" + ] + }, + "execution_count": 153, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "candidate_rho=sm.solve(LMI_simplified.det(),rho)\n", + "candidate_rho[0]\n" + ] + }, + { + "cell_type": "markdown", + "id": "5863eb52-72f8-40b8-a472-13ac1a06e3ea", + "metadata": {}, + "source": [ + "There are two possibilities for choosing $\\lambda_1$:\n", + "\n", + "- so that the LMI is rank defficient (i.e., solution is on the boundary of the PSD cone),\n", + "- so that the LMI is full rank. Minimize $\\rho$ wrt $\\lambda_1$ and verify feasibility of the LMI.\n", + "\n", + "Experimenting with the numerics, one can observe that the rank of the LMI is one for most choices of $\\gamma$, let's focus on the second possibility.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 158, + "id": "82cd6e45-a792-4021-960b-c9fe02e4d4f5", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[2*gamma*(L*gamma - 1), 2*gamma*(-gamma*mu + 1)]" + ] + }, + "execution_count": 158, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "drho=sm.simplify(sm.diff(candidate_rho[0],l1)) #differentiate $\\rho$ with respect to lambda_1\n", + "l1sol=sm.solve(drho,l1) # solve drho/dlambda_1 == 0 in lambda1\n", + "l1sol # show the two possibilities!" + ] + }, + { + "cell_type": "markdown", + "id": "9bd5f23e-1eac-4870-b9b4-5bdfa638aaba", + "metadata": {}, + "source": [ + "The corresponding \"final\" expressions for that must be checked are therefore:" + ] + }, + { + "cell_type": "code", + "execution_count": 159, + "id": "7c9685dc-0cdb-4b2e-9eb0-67d47494b630", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[(L*gamma - 1)**2, (gamma*mu - 1)**2]" + ] + }, + "execution_count": 159, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "exprrho1=sm.simplify(candidate_rho[0].subs(l1,l1sol[0]))\n", + "exprrho2=sm.simplify(candidate_rho[0].subs(l1,l1sol[1]))\n", + "\n", + "[exprrho1.factor(), exprrho2.factor()]" + ] + }, + { + "cell_type": "markdown", + "id": "1edb17da-6d63-4658-a961-05f9cd09df09", + "metadata": {}, + "source": [ + "... and we are done!" + ] + }, + { + "cell_type": "markdown", + "id": "17d79ecf-2254-4eba-89ba-9270263485b0", + "metadata": {}, + "source": [ + "## 5. Using SymPy for the function value accuracy analysis " + ] + }, + { + "cell_type": "markdown", + "id": "cbc80f5f-7e6f-4712-a040-d5967aeebdb9", + "metadata": {}, + "source": [ + "... same game with the already-simplified LMI. But using a few shortcuts." + ] + }, + { + "cell_type": "code", + "execution_count": 173, + "id": "ec070ccd-4be9-48b1-a407-303030523631", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\left[\\begin{matrix}\\frac{L \\mu \\left(\\lambda_{1} + \\lambda_{2}\\right)}{2 \\left(L - \\mu\\right)} & \\frac{- L \\lambda_{1} - \\lambda_{2} \\mu}{2 \\left(L - \\mu\\right)} & - \\frac{L \\lambda_{2}}{2 L - 2 \\mu}\\\\\\frac{- L \\lambda_{1} - \\lambda_{2} \\mu}{2 \\left(L - \\mu\\right)} & \\frac{L \\lambda_{1} + \\lambda_{2} \\mu + \\lambda_{4} \\left(L - \\mu\\right)}{2 L \\left(L - \\mu\\right)} & \\frac{\\lambda_{2}}{2 \\left(L - \\mu\\right)}\\\\- \\frac{L \\lambda_{2}}{2 L - 2 \\mu} & \\frac{\\lambda_{2}}{2 \\left(L - \\mu\\right)} & \\frac{0.5 \\left(\\lambda_{2} + \\lambda_{4}\\right)}{L - \\mu}\\end{matrix}\\right]$" + ], + "text/plain": [ + "Matrix([\n", + "[ L*mu*(lambda_1 + lambda_2)/(2*(L - mu)), (-L*lambda_1 - lambda_2*mu)/(2*(L - mu)), -L*lambda_2/(2*L - 2*mu)],\n", + "[(-L*lambda_1 - lambda_2*mu)/(2*(L - mu)), (L*lambda_1 + lambda_2*mu + lambda_4*(L - mu))/(2*L*(L - mu)), lambda_2/(2*(L - mu))],\n", + "[ -L*lambda_2/(2*L - 2*mu), lambda_2/(2*(L - mu)), 0.5*(lambda_2 + lambda_4)/(L - mu)]])" + ] + }, + "execution_count": 173, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import sympy as sm\n", + "\n", + "# create symbols for the problem parameters:\n", + "L = sm.Symbol('L')\n", + "mu = sm.Symbol('mu')\n", + "gamma = 1/L\n", + "\n", + "# create symbols for the \"primal\" variables:\n", + "x0 = sm.Symbol('x0')\n", + "g0 = sm.Symbol('g0')\n", + "g1 = sm.Symbol('g1')\n", + "f0 = sm.Symbol('f0')\n", + "f1 = sm.Symbol('f1')\n", + "xs = 0 # wlog, x_* = 0\n", + "gs = 0 # constraint g_* = 0\n", + "fs = 0 # wlog, f_* = 0\n", + "x1 = x0 - gamma * g0 # define x1 using previous symbols:\n", + "\n", + "# create symbols for the \"dual\" variables\n", + "rho = sm.Symbol('rho')\n", + "l1 = sm.Symbol('lambda_1')\n", + "l2 = sm.Symbol('lambda_2')\n", + "l4 = sm.Symbol('lambda_4')\n", + "\n", + "\n", + "# the two interpolation constraints in the form \"constraint <= 0\"\n", + "constraint1 = f0 - fs + g0*(xs-x0) + 1/2/L * g0**2 + mu/(2*(1-mu/L)) * (x0-xs-1/L*g0)**2\n", + "constraint2 = f1 - fs + g1*(xs-x1) + 1/2/L * g1**2 + mu/(2*(1-mu/L)) * (x1-xs-1/L*g1)**2\n", + "constraint4 = f1 - f0 + g1*(x0-x1) + 1/2/L * (g0-g1)**2 + mu/(2*(1-mu/L)) * (x1-x0-1/L*g1+1/L*g0)**2\n", + "\n", + "# the objective and the \"initial condition\" constraint: (also in the form \"constraint <= 0\")\n", + "primal_objective = f1-fs\n", + "initial_condition = f0-fs\n", + "\n", + "# Lagrangian:\n", + "Lagrangian = - l1*constraint1 - l2*constraint2 - l4*constraint4 - rho**2 * initial_condition + primal_objective\n", + "\n", + "# This is the LMI:\n", + "LMI = sm.simplify(sm.hessian( -Lagrangian , (x0,g0,g1))/2) \n", + "LMI" + ] + }, + { + "cell_type": "code", + "execution_count": 188, + "id": "27cbfe9c-48fb-4e4d-a315-9f6f21b44268", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[lambda_1 - lambda_4 + rho**2, lambda_2 + lambda_4 - 1]" + ] + }, + "execution_count": 188, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# This is the linear constraint ==0 in the LMI\n", + "LinearConst1 = sm.simplify(sm.diff(-Lagrangian,(f0)))\n", + "LinearConst2 = sm.simplify(sm.diff(-Lagrangian,(f1)))\n", + "\n", + "[LinearConst1, LinearConst2] # show linear constraint (==0)" + ] + }, + { + "cell_type": "code", + "execution_count": 192, + "id": "cf51b9da-6147-4576-8786-d4685127c192", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\left[\\begin{matrix}\\frac{L \\mu \\left(1 - \\rho^{2}\\right)}{2 \\left(L - \\mu\\right)} & \\frac{- L \\lambda_{1} + \\mu \\left(\\lambda_{1} + \\rho^{2} - 1\\right)}{2 \\left(L - \\mu\\right)} & \\frac{L \\left(\\lambda_{1} + \\rho^{2} - 1\\right)}{2 \\left(L - \\mu\\right)}\\\\\\frac{- L \\lambda_{1} + \\mu \\left(\\lambda_{1} + \\rho^{2} - 1\\right)}{2 \\left(L - \\mu\\right)} & \\frac{L \\lambda_{1} - \\mu \\left(\\lambda_{1} + \\rho^{2} - 1\\right) + \\left(L - \\mu\\right) \\left(\\lambda_{1} + \\rho^{2}\\right)}{2 L \\left(L - \\mu\\right)} & \\frac{- \\lambda_{1} - \\rho^{2} + 1}{2 \\left(L - \\mu\\right)}\\\\\\frac{L \\left(\\lambda_{1} + \\rho^{2} - 1\\right)}{2 \\left(L - \\mu\\right)} & \\frac{- \\lambda_{1} - \\rho^{2} + 1}{2 \\left(L - \\mu\\right)} & \\frac{0.5}{L - \\mu}\\end{matrix}\\right]$" + ], + "text/plain": [ + "Matrix([\n", + "[ L*mu*(1 - rho**2)/(2*(L - mu)), (-L*lambda_1 + mu*(lambda_1 + rho**2 - 1))/(2*(L - mu)), L*(lambda_1 + rho**2 - 1)/(2*(L - mu))],\n", + "[(-L*lambda_1 + mu*(lambda_1 + rho**2 - 1))/(2*(L - mu)), (L*lambda_1 - mu*(lambda_1 + rho**2 - 1) + (L - mu)*(lambda_1 + rho**2))/(2*L*(L - mu)), (-lambda_1 - rho**2 + 1)/(2*(L - mu))],\n", + "[ L*(lambda_1 + rho**2 - 1)/(2*(L - mu)), (-lambda_1 - rho**2 + 1)/(2*(L - mu)), 0.5/(L - mu)]])" + ] + }, + "execution_count": 192, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# For getting the same LMI as in the document, substitute l2 by l1 and simplify\n", + "LMI_simplified = sm.simplify(LMI.subs(l4,l1+rho**2))\n", + "LMI_simplified = sm.simplify(LMI_simplified.subs(l2,1-l1-rho**2))\n", + "\n", + "LMI_simplified # show the LMI (>=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 193, + "id": "334f59d7-e6d6-4a2d-82ac-12472bdf90f9", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\left[\\begin{matrix}\\frac{\\mu^{2} \\left(L - \\frac{\\mu}{2}\\right)}{L \\left(L - \\mu\\right)} & \\frac{- L^{3} \\lambda_{1} + \\mu \\left(L^{2} \\left(\\lambda_{1} - 1\\right) + \\left(L - \\mu\\right)^{2}\\right)}{2 L^{2} \\left(L - \\mu\\right)} & \\frac{L^{2} \\left(\\lambda_{1} - 1\\right) + \\left(L - \\mu\\right)^{2}}{2 L \\left(L - \\mu\\right)}\\\\\\frac{- L^{3} \\lambda_{1} + \\mu \\left(L^{2} \\left(\\lambda_{1} - 1\\right) + \\left(L - \\mu\\right)^{2}\\right)}{2 L^{2} \\left(L - \\mu\\right)} & \\frac{L^{3} \\lambda_{1} - \\mu \\left(L^{2} \\left(\\lambda_{1} - 1\\right) + \\left(L - \\mu\\right)^{2}\\right) + \\left(L - \\mu\\right) \\left(L^{2} \\lambda_{1} + \\left(L - \\mu\\right)^{2}\\right)}{2 L^{3} \\left(L - \\mu\\right)} & \\frac{L^{2} \\cdot \\left(1 - \\lambda_{1}\\right) - \\left(L - \\mu\\right)^{2}}{2 L^{2} \\left(L - \\mu\\right)}\\\\\\frac{L^{2} \\left(\\lambda_{1} - 1\\right) + \\left(L - \\mu\\right)^{2}}{2 L \\left(L - \\mu\\right)} & \\frac{L^{2} \\cdot \\left(1 - \\lambda_{1}\\right) - \\left(L - \\mu\\right)^{2}}{2 L^{2} \\left(L - \\mu\\right)} & \\frac{0.5}{L - \\mu}\\end{matrix}\\right]$" + ], + "text/plain": [ + "Matrix([\n", + "[ mu**2*(L - mu/2)/(L*(L - mu)), (-L**3*lambda_1 + mu*(L**2*(lambda_1 - 1) + (L - mu)**2))/(2*L**2*(L - mu)), (L**2*(lambda_1 - 1) + (L - mu)**2)/(2*L*(L - mu))],\n", + "[(-L**3*lambda_1 + mu*(L**2*(lambda_1 - 1) + (L - mu)**2))/(2*L**2*(L - mu)), (L**3*lambda_1 - mu*(L**2*(lambda_1 - 1) + (L - mu)**2) + (L - mu)*(L**2*lambda_1 + (L - mu)**2))/(2*L**3*(L - mu)), (L**2*(1 - lambda_1) - (L - mu)**2)/(2*L**2*(L - mu))],\n", + "[ (L**2*(lambda_1 - 1) + (L - mu)**2)/(2*L*(L - mu)), (L**2*(1 - lambda_1) - (L - mu)**2)/(2*L**2*(L - mu)), 0.5/(L - mu)]])" + ] + }, + "execution_count": 193, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "LMI_simplified = sm.simplify(LMI_simplified.subs(rho,(1-mu*gamma)))\n", + "LMI_simplified" + ] + }, + { + "cell_type": "code", + "execution_count": 194, + "id": "baa01841-1ac3-4c5f-ae26-9e22699117b7", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\frac{\\mu \\left(L - \\mu\\right)}{L^{2}}$" + ], + "text/plain": [ + "mu*(L - mu)/L**2" + ] + }, + "execution_count": 194, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "candidate_lambda1=sm.solve(LMI_simplified.det(),l1)\n", + "candidate_lambda1[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 195, + "id": "ce0cbfc9-7549-48b1-af42-b74a1bad3f9e", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\frac{\\mu \\left(1 - \\frac{\\mu}{L}\\right)}{L}$" + ], + "text/plain": [ + "mu*(1 - mu/L)/L" + ] + }, + "execution_count": 195, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(1-mu*gamma)*(1-(1-mu*gamma))" + ] + }, + { + "cell_type": "markdown", + "id": "0a48916a-1e37-440f-8160-025489d53d32", + "metadata": {}, + "source": [ + "## 6. Using symbolic regression (PySR) " + ] + }, + { + "cell_type": "markdown", + "id": "c90bea86", + "metadata": {}, + "source": [ + "Up to this point, two complementary approaches have been used to obtain the Lagrange multipliers needed to reconstruct a proof:\n", + "\n", + "1. **By inspection** — guess the functional form from numerical data \n", + "2. **Symbolic exploitation of the LMI** — exploit the LMI to solve for the multipliers symbolically \n", + "\n", + "This section focuses on automating the “inspection” step in (1).\n", + "\n", + "The task can be framed as **symbolic regression**: learning a function from measurements without restricting it to a prescribed functional form.\n", + "\n", + "Symbolic regression is **NP-hard** in general, but effective heuristics are often available in practice. This demo uses [PySR](https://github.com/MilesCranmer/PySR). \n", + "Install it first (note: PySR’s backend is implemented in the Julia programming language)." + ] + }, + { + "cell_type": "markdown", + "id": "3ca45317", + "metadata": {}, + "source": [ + "First, imagine that you do not know the closed form of $\\lambda_1(\\gamma)$ given at the end of Section 3. The next cell automatically learns the closed form of $\\lambda_1(\\gamma)$ using measurements from PEPit:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "1300c9e0-4d69-4183-a57e-00c5a1ccaa0b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Detected IPython. Loading juliacall extension. See https://juliapy.github.io/PythonCall.jl/stable/compat/#IPython\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "from pysr import PySRRegressor\n", + "\n", + "# seed for reproducibility\n", + "np.random.seed(42)\n", + "\n", + "X = []\n", + "y = []\n", + "mu = 0.1\n", + "L = 1\n", + "gamma_list = np.linspace(0.01, 1.99, 20)\n", + "\n", + "for gamma in gamma_list:\n", + " pepit_tau, list_of_constraints = wc_gradient_descent_function_values_sparse_proof(mu, L, gamma, verbose=0)\n", + " l1 = list_of_constraints[2]._dual_variable_value\n", + " \n", + " X.append([np.sqrt(pepit_tau)])\n", + " y.append(l1)\n", + "\n", + "model = PySRRegressor(\n", + " maxsize=10,\n", + " niterations=10,\n", + " binary_operators=[\"+\", \"-\", \"*\"],\n", + " verbosity=0,\n", + " progress=False,\n", + " deterministic=True, # Just to maintain consistency in outputs\n", + " parallelism='serial',\n", + ")\n", + " \n", + "result = model.fit(np.array(X), np.array(y), variable_names=[\"rho\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "51806a09", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(1.0 - rho) * rho\n" + ] + } + ], + "source": [ + "print(model.get_best().equation)" + ] + }, + { + "cell_type": "markdown", + "id": "293091d7", + "metadata": {}, + "source": [ + "This recovers the expression $\\lambda_1(\\gamma)= (1-\\rho(\\gamma))\\rho(\\gamma)$. This was a simple, univariate function, which is where symbolic regression works best.\n", + "\n", + "The next cell uses the flexibility of the PySR API in order to learn the convergence rate of gradient descent." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "59855db5", + "metadata": {}, + "outputs": [], + "source": [ + "import itertools\n", + "np.random.seed(42)\n", + "\n", + "X = []\n", + "y = []\n", + "\n", + "# Use different values for L and mu to generate dataset\n", + "L_values = [1, 2, 10]\n", + "mu_values = [0.1, 0.9]\n", + "\n", + "for L_val in L_values:\n", + " for mu_val in mu_values:\n", + " \n", + " # Generate uniform points between 0 and 2/L (at which point we do not have convergence)\n", + " limit = 2.0 / L_val\n", + " gammas = np.linspace(0.01, limit - 0.01, 5)\n", + " \n", + " for g_val in gammas:\n", + " pepit_tau, _ = wc_gradient_descent_function_values_sparse_proof(mu_val, L_val, g_val, verbose=0)\n", + " X.append([mu_val, L_val, g_val])\n", + " y.append(pepit_tau)\n", + "\n", + "# Increased maxsize to allow for the expression complexity\n", + "model = PySRRegressor(\n", + " niterations=200,\n", + " binary_operators=[\"+\", \"-\", \"*\", \"max\"], # PySR supports many operators, such as max, min, abs, etc\n", + " unary_operators=[\"square\"],\n", + " maxsize=15,\n", + " verbosity=0,\n", + " progress=False,\n", + " deterministic=True,\n", + " parallelism='serial',\n", + ")\n", + "\n", + "result = model.fit(np.array(X), np.array(y), variable_names=[\"mu\", \"L\", \"g\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "d8f49ee1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "square(max(1.0000066 - (g * mu), (g * L) + -0.99999446))\n" + ] + } + ], + "source": [ + "print(model.get_best().equation)" + ] + }, + { + "cell_type": "markdown", + "id": "7e518abc", + "metadata": {}, + "source": [ + "PySR was able to effectively learn this convergence rate, which is a function of 3 different variables. This did, however, require guiding it to use the max and square operators. In other problems, a larger number of operators should be used, which does decrease the speed of convergence of the heuristic. This is why this type of approach works best for problems with relatively simple closed forms. When it works, it can save a lot of time." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "pepit", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.14.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tests/test_constraints.py b/tests/test_constraints.py index e286ebb8..9eaccca8 100644 --- a/tests/test_constraints.py +++ b/tests/test_constraints.py @@ -74,7 +74,7 @@ def test_counter(self): def test_name(self): - self.assertIsNone(self.initial_condition.get_name()) + self.assertEqual(self.initial_condition.get_name(), "Constraint 0") self.assertIsNone(self.performance_metric.get_name()) self.initial_condition.set_name("init") @@ -93,6 +93,13 @@ def test_equality_inequality(self): self.assertIsInstance(self.problem.list_of_constraints[i].equality_or_inequality, str) self.assertIn(self.problem.list_of_constraints[i].equality_or_inequality, {'equality', 'inequality'}) + def test_activated(self): + self.assertIs(self.initial_condition.activated, True) + self.initial_condition.deactivate() + self.assertIs(self.initial_condition.activated, False) + self.initial_condition.activate() + self.assertIs(self.initial_condition.activated, True) + def test_eval(self): for i in range(len(self.func.list_of_class_constraints)): diff --git a/tests/test_pep.py b/tests/test_pep.py index ab24ba3b..51b14ed6 100644 --- a/tests/test_pep.py +++ b/tests/test_pep.py @@ -160,12 +160,40 @@ def test_lmi_constraints_in_real_problem(self): def test_consistency(self): # Solve twice the same problem in a row and verify the two lists of constraints have same length. + self.assertEqual(len(self.problem._list_of_prepared_constraints), 0) + self.assertEqual(len(self.problem._list_of_constraints_sent_to_wrapper), 0) + + # Run solve _ = self.problem.solve(verbose=self.verbose) - l1 = self.problem._list_of_constraints_sent_to_wrapper + lp1 = self.problem._list_of_prepared_constraints + ls1 = self.problem._list_of_constraints_sent_to_wrapper + + # Rerun solve _ = self.problem.solve(verbose=self.verbose) - l2 = self.problem._list_of_constraints_sent_to_wrapper + lp2 = self.problem._list_of_prepared_constraints + ls2 = self.problem._list_of_constraints_sent_to_wrapper - self.assertEqual(len(l1), len(l2)) + # Deactivate one constraint, then rerun solve + self.problem.list_of_constraints[0].deactivate() + _ = self.problem.solve(verbose=self.verbose) + lp3 = self.problem._list_of_prepared_constraints + ls3 = self.problem._list_of_constraints_sent_to_wrapper + + # Reactivate the constraint, then rerun solve + self.problem.list_of_constraints[0].activate() + _ = self.problem.solve(verbose=self.verbose) + lp4 = self.problem._list_of_prepared_constraints + ls4 = self.problem._list_of_constraints_sent_to_wrapper + + # Compare lengths + self.assertEqual(len(lp1), len(lp2)) + self.assertEqual(len(lp1), len(lp3)) + self.assertEqual(len(lp1), len(lp4)) + + self.assertEqual(len(lp1), len(ls1)) + self.assertEqual(len(lp2), len(ls2)) + self.assertEqual(len(lp3), len(ls3)+1) + self.assertEqual(len(lp4), len(ls4)) def test_dimension_reduction(self): diff --git a/tests/test_psd_matrix.py b/tests/test_psd_matrix.py index 26e7b5e8..0a97cd69 100644 --- a/tests/test_psd_matrix.py +++ b/tests/test_psd_matrix.py @@ -103,6 +103,13 @@ def test_getitem(self): self.assertIs(self.psd1[0, 0], self.expr1) self.assertIs(self.psd2[0, 1], self.expr3) + def test_activated(self): + self.assertIs(self.psd1.activated, True) + self.psd1.deactivate() + self.assertIs(self.psd1.activated, False) + self.psd1.activate() + self.assertIs(self.psd1.activated, True) + def test_eval(self): # The PEP has not been solved yet, so no value is accessible. diff --git a/tests/test_wrappers.py b/tests/test_wrappers.py index f8a1ee80..5473312a 100644 --- a/tests/test_wrappers.py +++ b/tests/test_wrappers.py @@ -112,6 +112,7 @@ def test_dual_sign_in_equality_constraints(self): 1 == (self.x0 - self.xs) ** 2, ]: self.problem.list_of_constraints = [constraint] + self.problem._prepare_constraints(verbose=self.verbose) self.problem.solve(verbose=self.verbose, wrapper=self.wrapper) elements_of_proof.append(constraint.eval_dual() * constraint.expression)