├── .gitignore ├── LICENSE ├── README.md ├── examples ├── demo_simple_set.ipynb └── demo_unconstr_solvers.ipynb ├── liboptpy ├── __init__.py ├── base_optimizer.py ├── constr_solvers │ ├── __init__.py │ ├── _frank_wolfe.py │ └── _proj_gd.py ├── restarts.py ├── step_size.py └── unconstr_solvers │ ├── __init__.py │ ├── fo │ ├── __init__.py │ ├── _acc_gd.py │ ├── _cg.py │ ├── _dual_average.py │ ├── _gd.py │ ├── _quasi_newton.py │ └── _subgrad.py │ └── so │ ├── __init__.py │ ├── _inexact_newton.py │ └── _newton.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | /doc 100 | 101 | # mypy 102 | .mypy_cache/ 103 | 104 | .DS_Store 105 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Alexandr Katrutsa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # liboptpy 2 | 3 | Library with implementations of optimization methods in Python 3 4 | 5 | ## Installing from source 6 | 7 | - ```git clone https://github.com/amkatrutsa/liboptpy.git``` 8 | - ```cd liboptpy``` 9 | - ```python setup.py install``` 10 | 11 | or 12 | 13 | ```pip install git+https://github.com/amkatrutsa/liboptpy``` 14 | 15 | ## Examples 16 | 17 | 1. [Unconstrained smooth and non-smooth optimization](./examples/demo_unconstr_solvers.ipynb) 18 | 2. [Comparison of projected gradient descent and Frank-Wolfe method](./examples/demo_simple_set.ipynb) 19 | 20 | ## Available optimization methods 21 | 22 | ### Unconstrained optimization problem 23 | 24 | #### Smooth objective functon 25 | 1. Gradient descent 26 | 2. Nesterov accelerated gradient descent 27 | 3. Newton method and inexact (truncated) Newton method with CG as linear solver 28 | 4. Conjugate gradient method 29 | - for convex quadratic function 30 | - for non-quadratic function (Fletcher-Reeves method) 31 | 5. Barzilai-Borwein method 32 | 33 | #### Non-smooth objective function 34 | 35 | 1. Subgradient method 36 | 2. Dual averaging method 37 | 38 | ### Constrained optimization problem 39 | 40 | 1. Projected gradient method 41 | 2. Frank-Wolfe method 42 | 3. Primal barrier method 43 | 44 | ### Available step size 45 | 46 | 1. Constant 47 | 2. Inverse number on iteration and scaled by gradient norm version 48 | 3. Inverse square root of number of iterationas and scaled by gradient norm version 49 | 4. Backtracking 50 | - Armijo rule 51 | - Wolfe rule 52 | - Strong Wolfe rule 53 | - Goldstein rule 54 | 5. Exact line search for quadratic function 55 | 56 | ## Contributing 57 | 58 | If you find any bugs, please fix them and send pull-request. 59 | If you want add some enhancement or something new, please open an issue for discussion. 60 | 61 | To send pull-request, you should make the following steps 62 | 63 | 1. Fork this repository 64 | 2. Clone the forked repository 65 | 3. Add original repositore as remote one 66 | 4. Create a branch in your local repository with specific name for your changes, e.g. ```bugfix``` 67 | 5. Switch to this branch 68 | 6. Change something that you assume make this repository better 69 | 7. Commit your changes in the branch ```bugfix``` with a meaningful comment, e.g. ```Fix typo``` 70 | 8. Switch to the branch ```master``` 71 | 9. Pull new commits to the branch ```master``` from this repository, not forked one 72 | 10. Switch to branch ```bugfix``` 73 | 11. Make ```git rebase master``` to take all new commits from original repository to branch ```bugfix``` 74 | 12. Make push to your forked repository in new remote branch ```bugfix``` 75 | 13. Send pull-request from your remote branch ```bugfix``` to ```master``` branch of the original repository 76 | -------------------------------------------------------------------------------- /examples/demo_simple_set.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import numpy as np\n", 10 | "import liboptpy.base_optimizer as base\n", 11 | "import liboptpy.constr_solvers as cs\n", 12 | "import liboptpy.step_size as ss\n", 13 | "import matplotlib.pyplot as plt\n", 14 | "%matplotlib inline\n", 15 | "plt.rc(\"text\", usetex=True)\n", 16 | "fontsize = 24\n", 17 | "figsize = (8, 6)\n", 18 | "import seaborn as sns\n", 19 | "sns.set_context(\"talk\")\n", 20 | "from tqdm import tqdm" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "metadata": {}, 26 | "source": [ 27 | "## Box constrained least-squares problem\n", 28 | "\n", 29 | "\\begin{align*}\n", 30 | "& \\min \\frac{1}{2} \\|Ax - b\\|^2_2\\\\\n", 31 | "\\text{s.t. } & 0 \\leq x_i \\leq 1\n", 32 | "\\end{align*}" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": 2, 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "def func(x, A, b):\n", 42 | " return 0.5 * np.linalg.norm(A.dot(x) - b)**2\n", 43 | "\n", 44 | "f = lambda x: func(x, A, b)\n", 45 | "\n", 46 | "def grad_f(x, A, b):\n", 47 | " grad = -A.T.dot(b)\n", 48 | " grad = grad + A.T.dot(A).dot(x)\n", 49 | " return grad\n", 50 | "\n", 51 | "grad = lambda x: grad_f(x, A, b)" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": 3, 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "def linsolver(gradient):\n", 61 | " x = np.zeros(gradient.shape[0])\n", 62 | " pos_grad = gradient > 0\n", 63 | " neg_grad = gradient < 0\n", 64 | " x[pos_grad] = np.zeros(np.sum(pos_grad == True))\n", 65 | " x[neg_grad] = np.ones(np.sum(neg_grad == True))\n", 66 | " return x" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": 4, 72 | "metadata": {}, 73 | "outputs": [], 74 | "source": [ 75 | "def projection(y):\n", 76 | " return np.clip(y, 0, 1)" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": 10, 82 | "metadata": {}, 83 | "outputs": [], 84 | "source": [ 85 | "m = 50\n", 86 | "n = 100\n", 87 | "A = np.random.randn(m, n)\n", 88 | "x_true = np.random.rand(n)\n", 89 | "b = A.dot(x_true) + 0.01 * np.random.randn(m)" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": 11, 95 | "metadata": {}, 96 | "outputs": [], 97 | "source": [ 98 | "methods = {\"FW\": cs.FrankWolfe(f, grad, linsolver, ss.Backtracking(rule_type=\"Armijo\", rho=0.5, beta=0.1, init_alpha=1.)),\n", 99 | " \"PGD\": cs.ProjectedGD(f, grad, projection, ss.Backtracking(rule_type=\"Armijo\", rho=0.5, beta=0.1, init_alpha=1.))\n", 100 | " }" 101 | ] 102 | }, 103 | { 104 | "cell_type": "code", 105 | "execution_count": 12, 106 | "metadata": {}, 107 | "outputs": [], 108 | "source": [ 109 | "x0 = np.random.randn(n)\n", 110 | "max_iter = 300\n", 111 | "tol = 1e-5" 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": 13, 117 | "metadata": {}, 118 | "outputs": [ 119 | { 120 | "name": "stdout", 121 | "output_type": "stream", 122 | "text": [ 123 | "\t FW\n", 124 | "Convergence in 75 iterations\n", 125 | "Function value = 5.503265417124177e-05\n", 126 | "Difference in function values = 7.738903387263182e-06\n", 127 | "Difference in argument = 0.0005312599507423358\n", 128 | "\t PGD\n", 129 | "Convergence in 32 iterations\n", 130 | "Function value = 4.9117890657412715e-05\n", 131 | "Difference in function values = 8.574133898022826e-06\n", 132 | "Difference in argument = 0.00043779727486897987\n" 133 | ] 134 | } 135 | ], 136 | "source": [ 137 | "for m_name in methods:\n", 138 | " print(\"\\t\", m_name)\n", 139 | " x = methods[m_name].solve(x0=x0, max_iter=max_iter, tol=tol, disp=1)" 140 | ] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "execution_count": 14, 145 | "metadata": {}, 146 | "outputs": [ 147 | { 148 | "data": { 149 | "image/png": "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\n", 150 | "text/plain": [ 151 | "" 152 | ] 153 | }, 154 | "metadata": {}, 155 | "output_type": "display_data" 156 | } 157 | ], 158 | "source": [ 159 | "plt.figure(figsize=figsize)\n", 160 | "for m_name in methods:\n", 161 | " plt.semilogy([f(x) for x in methods[m_name].get_convergence()], label=m_name)\n", 162 | "plt.legend(fontsize=fontsize)\n", 163 | "plt.xlabel(\"Number of iteration, $k$\", fontsize=fontsize)\n", 164 | "plt.ylabel(r\"$f(x_k)$\", fontsize=fontsize)\n", 165 | "plt.xticks(fontsize=fontsize)\n", 166 | "_ = plt.yticks(fontsize=fontsize)" 167 | ] 168 | }, 169 | { 170 | "cell_type": "code", 171 | "execution_count": 10, 172 | "metadata": {}, 173 | "outputs": [ 174 | { 175 | "name": "stdout", 176 | "output_type": "stream", 177 | "text": [ 178 | "\t FW\n", 179 | "31 ms ± 2.87 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", 180 | "\t PGD\n", 181 | "8.89 ms ± 458 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" 182 | ] 183 | } 184 | ], 185 | "source": [ 186 | "for key in methods:\n", 187 | " print(\"\\t {}\".format(key))\n", 188 | " %timeit methods[key].solve(x0, max_iter, tol)" 189 | ] 190 | }, 191 | { 192 | "cell_type": "markdown", 193 | "metadata": {}, 194 | "source": [ 195 | "## Dependance accuracy and number of iterations on the required accuarcy " 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": 11, 201 | "metadata": {}, 202 | "outputs": [ 203 | { 204 | "name": "stderr", 205 | "output_type": "stream", 206 | "text": [ 207 | "8it [01:27, 10.88s/it]\n" 208 | ] 209 | } 210 | ], 211 | "source": [ 212 | "eps = [10**(-i) for i in range(8)]\n", 213 | "time_pg = np.zeros(len(eps))\n", 214 | "time_cg = np.zeros(len(eps))\n", 215 | "iter_pg = np.zeros(len(eps))\n", 216 | "iter_cg = np.zeros(len(eps))\n", 217 | "pg = cs.ProjectedGD(f, grad, projection)\n", 218 | "cg = cs.FrankWolfe(f, grad, linsolver, ss.Backtracking(rule_type=\"Armijo\", rho=0.5, beta=0.1, init_alpha=1.))\n", 219 | "for i, tol in tqdm(enumerate(eps)):\n", 220 | " res = %timeit -o -q pg.solve(x0=x0, tol=tol, max_iter=100000)\n", 221 | " time_pg[i] = res.average\n", 222 | " iter_pg[i] = len(pg.get_convergence())\n", 223 | " res = %timeit -o -q cg.solve(x0=x0, tol=tol, max_iter=100000)\n", 224 | " time_cg[i] = res.average\n", 225 | " iter_cg[i] = len(cg.get_convergence())" 226 | ] 227 | }, 228 | { 229 | "cell_type": "code", 230 | "execution_count": 12, 231 | "metadata": {}, 232 | "outputs": [ 233 | { 234 | "data": { 235 | "text/plain": [ 236 | "Text(0,0.5,'Time, s')" 237 | ] 238 | }, 239 | "execution_count": 12, 240 | "metadata": {}, 241 | "output_type": "execute_result" 242 | }, 243 | { 244 | "data": { 245 | "image/png": "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\n", 246 | "text/plain": [ 247 | "" 248 | ] 249 | }, 250 | "metadata": {}, 251 | "output_type": "display_data" 252 | } 253 | ], 254 | "source": [ 255 | "plt.figure(figsize=figsize)\n", 256 | "plt.loglog(eps, time_cg, label=\"FW\")\n", 257 | "plt.loglog(eps, time_pg, label=\"PGD\")\n", 258 | "plt.legend(fontsize=fontsize)\n", 259 | "plt.xticks(fontsize=fontsize)\n", 260 | "plt.yticks(fontsize=fontsize)\n", 261 | "plt.xlabel(r\"Accuracy, $\\varepsilon$\", fontsize=fontsize)\n", 262 | "plt.ylabel(r\"Time, s\", fontsize=fontsize)" 263 | ] 264 | }, 265 | { 266 | "cell_type": "code", 267 | "execution_count": 13, 268 | "metadata": {}, 269 | "outputs": [ 270 | { 271 | "data": { 272 | "text/plain": [ 273 | "Text(0,0.5,'Number of iterations')" 274 | ] 275 | }, 276 | "execution_count": 13, 277 | "metadata": {}, 278 | "output_type": "execute_result" 279 | }, 280 | { 281 | "data": { 282 | "image/png": "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\n", 283 | "text/plain": [ 284 | "" 285 | ] 286 | }, 287 | "metadata": {}, 288 | "output_type": "display_data" 289 | } 290 | ], 291 | "source": [ 292 | "plt.figure(figsize=figsize)\n", 293 | "plt.loglog(eps, iter_cg, label=\"FW\")\n", 294 | "plt.loglog(eps, iter_pg, label=\"PGD\")\n", 295 | "plt.legend(fontsize=fontsize)\n", 296 | "plt.xticks(fontsize=fontsize)\n", 297 | "plt.yticks(fontsize=fontsize)\n", 298 | "plt.xlabel(r\"Accuracy, $\\varepsilon$\", fontsize=fontsize)\n", 299 | "plt.ylabel(r\"Number of iterations\", fontsize=fontsize)" 300 | ] 301 | }, 302 | { 303 | "cell_type": "markdown", 304 | "metadata": {}, 305 | "source": [ 306 | "## Least-squares problem on simplex\n", 307 | "\\begin{align*}\n", 308 | "& \\min \\frac{1}{2} \\|Ax - b\\|^2_2\\\\\n", 309 | "\\text{s.t. } & \\|x\\|_1 \\leq 1\\\\\n", 310 | "& x_i \\geq 0,\n", 311 | "\\end{align*}\n", 312 | "$A \\in \\mathbb{R}^{m \\times n}$, $n \\gg m$" 313 | ] 314 | }, 315 | { 316 | "cell_type": "code", 317 | "execution_count": 15, 318 | "metadata": {}, 319 | "outputs": [], 320 | "source": [ 321 | "def func(x, A, b):\n", 322 | " return 0.5 * np.linalg.norm(A.dot(x) - b)**2\n", 323 | "\n", 324 | "f = lambda x: func(x, A, b)\n", 325 | "\n", 326 | "def grad_f(x, A, b):\n", 327 | " grad = -A.T.dot(b)\n", 328 | " grad = grad + A.T.dot(A).dot(x)\n", 329 | " return grad\n", 330 | "\n", 331 | "grad = lambda x: grad_f(x, A, b)" 332 | ] 333 | }, 334 | { 335 | "cell_type": "code", 336 | "execution_count": 16, 337 | "metadata": {}, 338 | "outputs": [], 339 | "source": [ 340 | "m = 50\n", 341 | "n = 100\n", 342 | "A = np.random.randn(m, n)\n", 343 | "x_true = np.random.rand(n)\n", 344 | "b = A.dot(x_true) + 0.01 * np.random.randn(m)" 345 | ] 346 | }, 347 | { 348 | "cell_type": "code", 349 | "execution_count": 17, 350 | "metadata": {}, 351 | "outputs": [], 352 | "source": [ 353 | "def linsolver(gradient):\n", 354 | " x = np.zeros(gradient.shape[0])\n", 355 | " idx_min = np.argmin(gradient)\n", 356 | " if gradient[idx_min] > 0:\n", 357 | " x[idx_min] = 0\n", 358 | " else:\n", 359 | " x[idx_min] = 1\n", 360 | " return x" 361 | ] 362 | }, 363 | { 364 | "cell_type": "code", 365 | "execution_count": 18, 366 | "metadata": {}, 367 | "outputs": [], 368 | "source": [ 369 | "def projection(y):\n", 370 | " x = y.copy()\n", 371 | " if np.all(x >= 0) and np.sum(x) <= 1:\n", 372 | " return x\n", 373 | " x = np.clip(x, 0, np.max(x))\n", 374 | " if np.sum(x) <= 1:\n", 375 | " return x\n", 376 | " n = x.shape[0]\n", 377 | " bget = False\n", 378 | " x.sort()\n", 379 | " x = x[::-1]\n", 380 | " temp_sum = 0\n", 381 | " t_hat = 0\n", 382 | " for i in range(n - 1):\n", 383 | " temp_sum += x[i]\n", 384 | " t_hat = (temp_sum - 1.0) / (i + 1)\n", 385 | " if t_hat >= x[i + 1]:\n", 386 | " bget = True\n", 387 | " break\n", 388 | " if not bget:\n", 389 | " t_hat = (temp_sum + x[n - 1] - 1.0) / n\n", 390 | " return np.maximum(y - t_hat, 0)" 391 | ] 392 | }, 393 | { 394 | "cell_type": "code", 395 | "execution_count": 20, 396 | "metadata": {}, 397 | "outputs": [], 398 | "source": [ 399 | "methods = {\n", 400 | " \"FW\": cs.FrankWolfe(f, grad, linsolver, ss.Backtracking(rule_type=\"Armijo\", rho=0.5, beta=0.1, init_alpha=1.)),\n", 401 | " \"PGD\": cs.ProjectedGD(f, grad, projection, ss.Backtracking(rule_type=\"Armijo\", rho=0.5, beta=0.1, init_alpha=1.))\n", 402 | " }" 403 | ] 404 | }, 405 | { 406 | "cell_type": "code", 407 | "execution_count": 21, 408 | "metadata": {}, 409 | "outputs": [], 410 | "source": [ 411 | "x0 = np.random.randn(n)\n", 412 | "max_iter = 300\n", 413 | "tol = 1e-5" 414 | ] 415 | }, 416 | { 417 | "cell_type": "code", 418 | "execution_count": 22, 419 | "metadata": {}, 420 | "outputs": [ 421 | { 422 | "name": "stdout", 423 | "output_type": "stream", 424 | "text": [ 425 | "\t FW\n", 426 | "Convergence in 32 iterations\n", 427 | "Function value = 619.1425573630355\n", 428 | "Difference in function values = 5.300833890942158e-06\n", 429 | "Difference in argument = 0.0003707118312833002\n", 430 | "\t PGD\n", 431 | "Convergence in 11 iterations\n", 432 | "Function value = 619.1425429905358\n", 433 | "Difference in function values = 2.5743413516465807e-06\n", 434 | "Difference in argument = 0.0003181933658590257\n" 435 | ] 436 | } 437 | ], 438 | "source": [ 439 | "for m_name in methods:\n", 440 | " print(\"\\t\", m_name)\n", 441 | " x = methods[m_name].solve(x0=x0, max_iter=max_iter, tol=tol, disp=1)" 442 | ] 443 | }, 444 | { 445 | "cell_type": "code", 446 | "execution_count": 23, 447 | "metadata": {}, 448 | "outputs": [ 449 | { 450 | "data": { 451 | "image/png": "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\n", 452 | "text/plain": [ 453 | "" 454 | ] 455 | }, 456 | "metadata": {}, 457 | "output_type": "display_data" 458 | } 459 | ], 460 | "source": [ 461 | "plt.figure(figsize=figsize)\n", 462 | "for m_name in methods:\n", 463 | " plt.semilogy([f(x) for x in methods[m_name].get_convergence()], label=m_name)\n", 464 | "plt.legend(fontsize=fontsize)\n", 465 | "plt.xlabel(\"Number of iteration, $k$\", fontsize=fontsize)\n", 466 | "plt.ylabel(r\"$f(x_k)$\", fontsize=fontsize)\n", 467 | "plt.xticks(fontsize=fontsize)\n", 468 | "_ = plt.yticks(fontsize=fontsize)" 469 | ] 470 | }, 471 | { 472 | "cell_type": "code", 473 | "execution_count": 21, 474 | "metadata": {}, 475 | "outputs": [ 476 | { 477 | "name": "stdout", 478 | "output_type": "stream", 479 | "text": [ 480 | "\t FW\n", 481 | "3.33 ms ± 327 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", 482 | "\t PGD\n", 483 | "6.58 ms ± 222 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" 484 | ] 485 | } 486 | ], 487 | "source": [ 488 | "for key in methods:\n", 489 | " print(\"\\t {}\".format(key))\n", 490 | " %timeit methods[key].solve(x0, max_iter, tol)" 491 | ] 492 | }, 493 | { 494 | "cell_type": "code", 495 | "execution_count": 22, 496 | "metadata": {}, 497 | "outputs": [ 498 | { 499 | "name": "stderr", 500 | "output_type": "stream", 501 | "text": [ 502 | "8it [01:13, 9.13s/it]\n" 503 | ] 504 | } 505 | ], 506 | "source": [ 507 | "eps = [10**(-i) for i in range(8)]\n", 508 | "time_pg = np.zeros(len(eps))\n", 509 | "time_cg = np.zeros(len(eps))\n", 510 | "iter_pg = np.zeros(len(eps))\n", 511 | "iter_cg = np.zeros(len(eps))\n", 512 | "pg = cs.ProjectedGD(f, grad, projection)\n", 513 | "cg = cs.FrankWolfe(f, grad, linsolver, ss.Backtracking(rule_type=\"Armijo\", rho=0.5, beta=0.1, init_alpha=1.))\n", 514 | "for i, tol in tqdm(enumerate(eps)):\n", 515 | " res = %timeit -o -q pg.solve(x0=x0, tol=tol, max_iter=100000)\n", 516 | " time_pg[i] = res.average\n", 517 | " iter_pg[i] = len(pg.get_convergence())\n", 518 | " res = %timeit -o -q cg.solve(x0=x0, tol=tol, max_iter=100000)\n", 519 | " time_cg[i] = res.average\n", 520 | " iter_cg[i] = len(cg.get_convergence())" 521 | ] 522 | }, 523 | { 524 | "cell_type": "code", 525 | "execution_count": 23, 526 | "metadata": {}, 527 | "outputs": [ 528 | { 529 | "data": { 530 | "text/plain": [ 531 | "Text(0,0.5,'Time, s')" 532 | ] 533 | }, 534 | "execution_count": 23, 535 | "metadata": {}, 536 | "output_type": "execute_result" 537 | }, 538 | { 539 | "data": { 540 | "image/png": "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\n", 541 | "text/plain": [ 542 | "" 543 | ] 544 | }, 545 | "metadata": {}, 546 | "output_type": "display_data" 547 | } 548 | ], 549 | "source": [ 550 | "plt.figure(figsize=figsize)\n", 551 | "plt.loglog(eps, time_cg, label=\"FW\")\n", 552 | "plt.loglog(eps, time_pg, label=\"PGD\")\n", 553 | "plt.legend(fontsize=fontsize)\n", 554 | "plt.xticks(fontsize=fontsize)\n", 555 | "plt.yticks(fontsize=fontsize)\n", 556 | "plt.xlabel(r\"Accuracy, $\\varepsilon$\", fontsize=fontsize)\n", 557 | "plt.ylabel(r\"Time, s\", fontsize=fontsize)" 558 | ] 559 | }, 560 | { 561 | "cell_type": "code", 562 | "execution_count": 24, 563 | "metadata": {}, 564 | "outputs": [ 565 | { 566 | "data": { 567 | "text/plain": [ 568 | "Text(0,0.5,'Number of iterations')" 569 | ] 570 | }, 571 | "execution_count": 24, 572 | "metadata": {}, 573 | "output_type": "execute_result" 574 | }, 575 | { 576 | "data": { 577 | "image/png": "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\n", 578 | "text/plain": [ 579 | "" 580 | ] 581 | }, 582 | "metadata": {}, 583 | "output_type": "display_data" 584 | } 585 | ], 586 | "source": [ 587 | "plt.figure(figsize=figsize)\n", 588 | "plt.loglog(eps, iter_cg, label=\"FW\")\n", 589 | "plt.loglog(eps, iter_pg, label=\"PGD\")\n", 590 | "plt.legend(fontsize=fontsize)\n", 591 | "plt.xticks(fontsize=fontsize)\n", 592 | "plt.yticks(fontsize=fontsize)\n", 593 | "plt.xlabel(r\"Accuracy, $\\varepsilon$\", fontsize=fontsize)\n", 594 | "plt.ylabel(r\"Number of iterations\", fontsize=fontsize)" 595 | ] 596 | } 597 | ], 598 | "metadata": { 599 | "kernelspec": { 600 | "display_name": "Python 3 (cvxpy)", 601 | "language": "python", 602 | "name": "cvxpy" 603 | }, 604 | "language_info": { 605 | "codemirror_mode": { 606 | "name": "ipython", 607 | "version": 3 608 | }, 609 | "file_extension": ".py", 610 | "mimetype": "text/x-python", 611 | "name": "python", 612 | "nbconvert_exporter": "python", 613 | "pygments_lexer": "ipython3", 614 | "version": "3.6.4" 615 | } 616 | }, 617 | "nbformat": 4, 618 | "nbformat_minor": 2 619 | } 620 | -------------------------------------------------------------------------------- /liboptpy/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amkatrutsa/liboptpy/a40d8839dd12edb07fb6860d1337f034a2ea4754/liboptpy/__init__.py -------------------------------------------------------------------------------- /liboptpy/base_optimizer.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from collections import deque 3 | 4 | class LineSearchOptimizer(object): 5 | def __init__(self, f, grad, step_size, memory_size=1, **kwargs): 6 | self.convergence = [] 7 | self._f = f 8 | self._grad = grad 9 | if step_size is not None: 10 | step_size.assign_function(f, grad, self._f_update_x_next) 11 | self._step_size = step_size 12 | self._par = kwargs 13 | self._grad_mem = deque(maxlen=memory_size) 14 | 15 | def get_convergence(self): 16 | return self.convergence 17 | 18 | def solve(self, x0, max_iter=100, tol=1e-6, disp=False): 19 | self.convergence = [] 20 | self._x_current = x0.copy() 21 | self.convergence.append(self._x_current) 22 | iteration = 0 23 | self._current_grad = None 24 | while True: 25 | self._h = self.get_direction(self._x_current) 26 | if self._current_grad is None: 27 | raise ValueError("Variable self._current_grad has to be initialized in method get_direction()!") 28 | self._grad_mem.append(self._current_grad) 29 | if self.check_convergence(tol): 30 | if disp > 0: 31 | print("Required tolerance achieved!") 32 | break 33 | if disp > 1: 34 | print("Iteration {}/{}".format(iteration, max_iter)) 35 | print("Current function val =", self._f(self._x_current)) 36 | self._print_info() 37 | self._alpha = self.get_stepsize() 38 | self._update_x_next() 39 | self._update_x_current() 40 | self._append_conv() 41 | iteration += 1 42 | if iteration >= max_iter: 43 | if disp > 0: 44 | print("Maximum iteration exceeds!") 45 | break 46 | if disp: 47 | print("Convergence in {} iterations".format(iteration)) 48 | print("Function value = {}".format(self._f(self._x_current))) 49 | self._print_info() 50 | return self._get_result_x() 51 | 52 | def get_direction(self, x): 53 | raise NotImplementedError("You have to provide method for finding direction!") 54 | 55 | def _update_x_current(self): 56 | self._x_current = self._x_next 57 | 58 | def _update_x_next(self): 59 | self._x_next = self._f_update_x_next(self._x_current, self._alpha, self._h) 60 | 61 | def _f_update_x_next(self, x, alpha, h): 62 | return x + alpha * h 63 | 64 | def check_convergence(self, tol): 65 | return np.linalg.norm(self._current_grad) < tol 66 | 67 | def get_stepsize(self): 68 | raise NotImplementedError("You have to provide method for finding step size!") 69 | 70 | def _print_info(self): 71 | print("Norm of gradient = {}".format(np.linalg.norm(self._current_grad))) 72 | 73 | def _append_conv(self): 74 | self.convergence.append(self._x_next) 75 | 76 | def _get_result_x(self): 77 | return self._x_current 78 | 79 | class TrustRegionOptimizer(object): 80 | def __init__(self): 81 | raise NotImplementedError("Trust region methods are not implemented yet") -------------------------------------------------------------------------------- /liboptpy/constr_solvers/__init__.py: -------------------------------------------------------------------------------- 1 | from ._frank_wolfe import FrankWolfe 2 | from ._proj_gd import ProjectedGD -------------------------------------------------------------------------------- /liboptpy/constr_solvers/_frank_wolfe.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from ..base_optimizer import LineSearchOptimizer 3 | 4 | class FrankWolfe(LineSearchOptimizer): 5 | 6 | ''' 7 | Class represents conditional gradient descent method aka Frank Wolfe algorithm 8 | ''' 9 | 10 | def __init__(self, f, grad, linsolver, step_size): 11 | super().__init__(f, grad, step_size) 12 | self._linsolver = linsolver 13 | self._h = None 14 | 15 | def get_direction(self, x): 16 | s = self._linsolver(self._grad(x)) 17 | self._current_grad = self._grad(x) 18 | self._h = s - x 19 | return self._h 20 | 21 | def check_convergence(self, tol): 22 | if len(self.convergence) == 1: 23 | return False 24 | if self._f(self.convergence[-2]) - self._f(self.convergence[-1]) < tol: 25 | return True 26 | else: 27 | return False 28 | 29 | def get_stepsize(self): 30 | return self._step_size.get_stepsize(self._h, self.convergence[-1], len(self.convergence)) 31 | 32 | def _print_info(self): 33 | print("Difference in function values = {}".format(self._f(self.convergence[-2]) - self._f(self.convergence[-1]))) 34 | print("Difference in argument = {}".format(np.linalg.norm(self.convergence[-1] - self.convergence[-2]))) 35 | -------------------------------------------------------------------------------- /liboptpy/constr_solvers/_proj_gd.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from ..base_optimizer import LineSearchOptimizer 3 | 4 | class ProjectedGD(LineSearchOptimizer): 5 | 6 | ''' 7 | Class represents projected gradient method 8 | ''' 9 | 10 | def __init__(self, f, grad, projector, step_size): 11 | super().__init__(f, grad, step_size) 12 | self._projector = projector 13 | 14 | def get_direction(self, x): 15 | self._current_grad = self._grad(x) 16 | return -self._current_grad 17 | 18 | def _f_update_x_next(self, x, alpha, h): 19 | return self._projector(x + alpha * h) 20 | 21 | def check_convergence(self, tol): 22 | if len(self.convergence) == 1: 23 | return False 24 | if self._f(self.convergence[-2]) - self._f(self.convergence[-1]) < tol: 25 | return True 26 | else: 27 | return False 28 | 29 | def get_stepsize(self): 30 | return self._step_size.get_stepsize(-self._grad_mem[-1], self.convergence[-1], len(self.convergence)) 31 | 32 | def _print_info(self): 33 | print("Difference in function values = {}".format(self._f(self.convergence[-2]) - self._f(self.convergence[-1]))) 34 | print("Difference in argument = {}".format(np.linalg.norm(self.convergence[-1] - self.convergence[-2]))) 35 | -------------------------------------------------------------------------------- /liboptpy/restarts.py: -------------------------------------------------------------------------------- 1 | class Restart(object): 2 | def __init__(self, limit_dim=None): 3 | self._dim = limit_dim 4 | 5 | def __call__(self, num_iter, x): 6 | if num_iter % self._dim == 0: 7 | return True 8 | else: 9 | return False 10 | 11 | def assign_function(self, f, grad): 12 | self._f = f 13 | self._grad = grad 14 | -------------------------------------------------------------------------------- /liboptpy/step_size.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | __all__ = ["ConstantStepSize", "Backtracking", "ExactLineSearch4Quad", "InvIterStepSize", "ScaledInvIterStepSize"] 4 | 5 | class StepSize(object): 6 | ''' 7 | Base class for all classes for defining step size 8 | ''' 9 | def __init__(self): 10 | pass 11 | def get_stepsize(self, *args, **kwargs): 12 | raise NotImplementedError("Method to get current step size has to be implemented!") 13 | 14 | def assign_function(self, f, grad, *args): 15 | pass 16 | 17 | class ConstantStepSize(StepSize): 18 | ''' 19 | Class represents interface for constant step size 20 | ''' 21 | def __init__(self, stepsize): 22 | self.stepsize = stepsize 23 | 24 | def get_stepsize(self, h, x, num_iter, *args): 25 | return self.stepsize 26 | 27 | class ScaledConstantStepSize(StepSize): 28 | def __init__(self, stepsize): 29 | self.stepsize = stepsize 30 | 31 | def get_stepsize(self, h, x, num_iter, *args): 32 | return self.stepsize / np.linalg.norm(h) 33 | 34 | class InvIterStepSize(StepSize): 35 | def __init__(self): 36 | pass 37 | 38 | def get_stepsize(self, h, x, num_iter, *args): 39 | return 1. / num_iter 40 | 41 | class ScaledInvIterStepSize(StepSize): 42 | def __init__(self): 43 | pass 44 | 45 | def get_stepsize(self, h, x, num_iter, *args): 46 | s = 1. / num_iter 47 | return s / np.linalg.norm(h) 48 | 49 | class InvSqrootIterStepSize(StepSize): 50 | def __init__(self): 51 | pass 52 | 53 | def get_stepsize(self, h, x, num_iter, *args): 54 | return 1. / np.sqrt(num_iter) 55 | 56 | class Backtracking(StepSize): 57 | ''' 58 | Class represents different rules for backtracking search of step size 59 | ''' 60 | def __init__(self, rule_type, **kwargs): 61 | self.rule = rule_type 62 | self.par = kwargs 63 | if self.rule == "Lipschitz" and "eps" not in self.par: 64 | self.par["eps"] = 0. 65 | if "disp" not in self.par: 66 | self.par["disp"] = False 67 | if self.rule == "Lipschitz": 68 | self._alpha = None 69 | 70 | def assign_function(self, f, grad, update_x_next): 71 | self._f = f 72 | self._grad = grad 73 | self._update_x_next = update_x_next 74 | 75 | def get_stepsize(self, h, x, num_iter, *args): 76 | alpha = self.par["init_alpha"] 77 | if self.rule == "Armijo": 78 | rho = self.par["rho"] 79 | beta = self.par["beta"] 80 | assert beta < 0.5, "Armijo rule is applicable for beta less than 0.5" 81 | assert rho < 1, "Decay factor has to be less than 1" 82 | current_grad = self._grad(x) 83 | current_f = self._f(x) 84 | x_next = self._update_x_next(x, alpha, h) 85 | while True: 86 | if np.isnan(self._f(x_next)): 87 | alpha *= rho 88 | else: 89 | if self._f(x_next) >= current_f + beta * current_grad.dot(x_next - x): 90 | alpha *= rho 91 | else: 92 | break 93 | if alpha < 1e-16: 94 | raise ValueError("Step size is too small!") 95 | x_next = self._update_x_next(x, alpha, h) 96 | return alpha 97 | elif self.rule == "Wolfe": 98 | # https://sites.math.washington.edu/~burke/crs/408/notes/nlp/line.pdf 99 | rho = self.par["rho"] 100 | lb = 0 101 | ub = np.inf 102 | assert rho < 1, "Decay factor has to be less than 1" 103 | beta1 = self.par["beta1"] 104 | beta2 = self.par["beta2"] 105 | assert 0 < beta1 < beta2 < 1, "Wolfe rule is applicable for betas such that 0 < beta1 < beta2 < 1" 106 | current_grad = self._grad(x) 107 | current_f = self._f(x) 108 | while True: 109 | if np.isnan(self._f(x + alpha * h)): 110 | alpha *= rho 111 | else: 112 | if self._f(x + alpha * h) > current_f + beta1 * alpha * current_grad.dot(h): 113 | ub = alpha 114 | alpha = 0.5 * (lb + ub) 115 | elif h.dot(self._grad(x + alpha * h)) < beta2 * h.dot(current_grad): 116 | lb = alpha 117 | if np.isinf(ub): 118 | alpha = 2 * lb 119 | else: 120 | alpha = 0.5 * (lb + ub) 121 | else: 122 | break 123 | if alpha < 1e-16: 124 | raise ValueError("Step size is too small!") 125 | return alpha 126 | elif self.rule == "Goldstein": 127 | pass 128 | elif self.rule == "Wolfe strong": 129 | rho = self.par["rho"] 130 | assert rho < 1, "Decay factor has to be less than 1" 131 | beta1 = self.par["beta1"] 132 | beta2 = self.par["beta2"] 133 | lb = 0 134 | ub = np.inf 135 | assert 0 < beta1 < beta2 < 1, "Wolfe rule is applicable for betas such that 0 < beta1 < beta2 < 1" 136 | current_grad = self._grad(x) 137 | current_f = self._f(x) 138 | while True: 139 | if np.isnan(self._f(x + alpha * h)): 140 | alpha *= rho 141 | else: 142 | if self._f(x + alpha * h) > current_f + beta1 * alpha * current_grad.dot(h): 143 | ub = alpha 144 | alpha = 0.5 * (lb + ub) 145 | elif np.abs(h.dot(self._grad(x + alpha * h))) > beta2 * np.abs(h.dot(current_grad)): 146 | lb = alpha 147 | if np.isinf(ub): 148 | alpha = 2 * lb 149 | else: 150 | alpha = 0.5 * (lb + ub) 151 | else: 152 | break 153 | if alpha < 1e-16: 154 | raise ValueError("Step size is too small!") 155 | return alpha 156 | elif self.rule == "Lipschitz": 157 | rho = self.par["rho"] 158 | assert rho < 1, "Decay factor has to be less than 1" 159 | current_grad = self._grad(x) 160 | current_f = self._f(x) 161 | eps = self.par["eps"] 162 | if self._alpha is None: 163 | self._alpha = alpha 164 | else: 165 | self._alpha /= rho 166 | x_next = self._update_x_next(x, self._alpha, h) 167 | while True: 168 | if self.par["disp"]: 169 | print("Current test alpha = {}".format(self._alpha)) 170 | if np.isnan(self._f(x_next)): 171 | self._alpha *= rho 172 | else: 173 | if self._f(x_next) > current_f + current_grad.dot(x_next - x) + np.linalg.norm(x_next - x)**2 / (2 * self._alpha) + eps: 174 | self._alpha *= rho 175 | else: 176 | if self.par["disp"]: 177 | print("Found alpha = {}".format(self._alpha)) 178 | break 179 | if self._alpha < 1e-16: 180 | raise ValueError("Step size is too small!") 181 | x_next = self._update_x_next(x, self._alpha, h) 182 | return self._alpha 183 | else: 184 | raise NotImplementedError("Available rules for backtracking are 'Armijo', 'Goldstein', 'Wolfe', 'Wolfe strong' and 'Lipschitz'") 185 | 186 | class ExactLineSearch4Quad(StepSize): 187 | def __init__(self, A, b=None): 188 | self._A = A 189 | if b is None: 190 | self._b = np.zeros(A.shape[0]) 191 | else: 192 | self._b = b 193 | 194 | def get_stepsize(self, h, x, num_iter): 195 | return h.dot(self._b - self._A.dot(x)) / h.dot(self._A.dot(h)) 196 | -------------------------------------------------------------------------------- /liboptpy/unconstr_solvers/__init__.py: -------------------------------------------------------------------------------- 1 | from . import so 2 | from . import fo -------------------------------------------------------------------------------- /liboptpy/unconstr_solvers/fo/__init__.py: -------------------------------------------------------------------------------- 1 | from ._gd import GradientDescent 2 | from ._cg import ConjugateGradientFR, ConjugateGradientPR 3 | from ._cg import ConjugateGradientQuad 4 | from ._acc_gd import AcceleratedGD 5 | from ._subgrad import SubgradientMethod 6 | from ._dual_average import DualAveraging 7 | from ._quasi_newton import BFGS, LBFGS, DFP, BarzilaiBorweinMethod 8 | 9 | __all__ = ["BarzilaiBorweinMethod", 10 | "AcceleratedGD", 11 | "GradientDescent", 12 | "ConjugateGradientFR", 13 | "ConjugateGradientPR", 14 | "ConjugateGradientQuad", 15 | "SubgradientMethod", 16 | "DualAveraging", 17 | "BFGS", "LBFGS", "DFP"] -------------------------------------------------------------------------------- /liboptpy/unconstr_solvers/fo/_acc_gd.py: -------------------------------------------------------------------------------- 1 | from ... import base_optimizer as _base 2 | import numpy as _np 3 | from ... import step_size as ss 4 | 5 | class AcceleratedGD(_base.LineSearchOptimizer): 6 | def __init__(self, f, grad, step_size, momentum_size=None, **kwargs): 7 | super().__init__(f, grad, step_size, **kwargs) 8 | if momentum_size is not None: 9 | momentum_size.assign(f, grad) 10 | self._momentum_size = momentum_size 11 | self._lam0 = 0 12 | self._lam1 = 1 13 | 14 | def get_direction(self, x): 15 | self._current_grad = self._grad(x) 16 | return -self._current_grad 17 | 18 | def _update_x_current(self): 19 | if self._momentum_size is None: 20 | beta = (self._lam0 - 1) / self._lam1 21 | t = self._lam0 22 | self._lam0 = self._lam1 23 | self._lam1 = (1 + _np.sqrt(1 + 4 * t**2)) / 2. 24 | self._x_current = self._x_next + beta * (self._x_next - self.convergence[-1]) 25 | 26 | def get_stepsize(self): 27 | return self._step_size.get_stepsize(self._h, self.convergence[-1], len(self.convergence)) -------------------------------------------------------------------------------- /liboptpy/unconstr_solvers/fo/_cg.py: -------------------------------------------------------------------------------- 1 | from ... import base_optimizer as _base 2 | import numpy as _np 3 | 4 | class ConjugateGradientFR(_base.LineSearchOptimizer): 5 | def __init__(self, f, grad, step_size, restart=None, **kwargs): 6 | super().__init__(f, grad, step_size, **kwargs) 7 | if restart is not None: 8 | restart.assign_function(f, grad) 9 | self._restart = restart 10 | 11 | def get_direction(self, x): 12 | if (len(self.convergence) == 1) or (self._restart is not None and 13 | self._restart(len(self.convergence), x)): 14 | self._current_grad = self._grad(x) 15 | h = -self._current_grad 16 | else: 17 | self._current_grad = self._grad(self.convergence[-1]) 18 | beta = self._current_grad.dot(self._current_grad) / self._grad_mem[-1].dot(self._grad_mem[-1]) 19 | h = -self._current_grad + beta * self._h 20 | return h 21 | 22 | def get_stepsize(self): 23 | return self._step_size.get_stepsize(self._h, self.convergence[-1], len(self.convergence)) 24 | 25 | class ConjugateGradientPR(_base.LineSearchOptimizer): 26 | def __init__(self, f, grad, step_size, restart=None, **kwargs): 27 | super().__init__(f, grad, step_size, **kwargs) 28 | if restart is not None: 29 | restart.assign_function(f, grad) 30 | self._restart = restart 31 | 32 | def get_direction(self, x): 33 | if (len(self.convergence) == 1): 34 | self._current_grad = self._grad(x) 35 | h = -self._current_grad 36 | else: 37 | self._current_grad = self._grad(self.convergence[-1]) 38 | beta = self._current_grad.dot(self._current_grad - self._grad_mem[-1]) / self._grad_mem[-1].dot(self._grad_mem[-1]) 39 | h = -self._current_grad + beta * self._h 40 | return h 41 | 42 | def get_stepsize(self): 43 | return self._step_size.get_stepsize(self._h, self.convergence[-1], len(self.convergence)) 44 | 45 | class ConjugateGradientQuad(_base.LineSearchOptimizer): 46 | def __init__(self, A, b=None): 47 | if b is None: 48 | b = _np.zeros(A.shape[0]) 49 | f = lambda x: 0.5 * x.dot(A.dot(x)) - b.dot(x) 50 | grad = lambda x: A.dot(x) - b 51 | super().__init__(f, grad, None) 52 | self._A = A 53 | self._b = b 54 | 55 | def get_direction(self, x): 56 | if (len(self.convergence) == 1): 57 | self._current_grad = self._grad(x) 58 | h = -self._current_grad 59 | self._r = -h 60 | else: 61 | r_next = self._r + self._alpha * self._A.dot(self._h) 62 | beta = r_next.dot(r_next) / self._r.dot(self._r) 63 | h = -r_next + beta * self._h 64 | self._r = r_next 65 | return h 66 | 67 | def get_stepsize(self): 68 | # h = self._grad_mem[-1] 69 | self._alpha = self._r.dot(self._r) / self._h.dot(self._A.dot(self._h)) 70 | return self._alpha 71 | 72 | def check_convergence(self, tol): 73 | return _np.linalg.norm(self._grad(self.convergence[-1])) < tol 74 | -------------------------------------------------------------------------------- /liboptpy/unconstr_solvers/fo/_dual_average.py: -------------------------------------------------------------------------------- 1 | from ... import base_optimizer as _base 2 | import numpy as _np 3 | 4 | class DualAveraging(_base.LineSearchOptimizer): 5 | def __init__(self, f, subgrad, primal_step_size, dual_step_size): 6 | super().__init__(f, subgrad, primal_step_size) 7 | self._dual_step_size = dual_step_size 8 | self._sum_lam = 0 9 | 10 | def get_direction(self, x): 11 | self._current_grad = self._grad(x) 12 | if len(self.convergence) == 1: 13 | self._s = _np.zeros(x.shape[0]) 14 | self._lam = self._dual_step_size.get_stepsize(x, self._current_grad, len(self.convergence)) 15 | self._s = (self._sum_lam * self._s + self._lam * self._current_grad) / (self._sum_lam + self._lam) 16 | self._sum_lam += self._lam 17 | return -self._s 18 | 19 | def get_stepsize(self): 20 | return self._step_size.get_stepsize(self._h, self._x_current, len(self.convergence)) 21 | 22 | def _f_update_x_next(self, x, alpha, h): 23 | return self.convergence[0] + alpha * h 24 | 25 | def _append_conv(self): 26 | self.convergence.append(self._x_current) 27 | 28 | def _update_x_current(self): 29 | self._x_current = self._x_next -------------------------------------------------------------------------------- /liboptpy/unconstr_solvers/fo/_gd.py: -------------------------------------------------------------------------------- 1 | from ... import base_optimizer as _base 2 | 3 | class GradientDescent(_base.LineSearchOptimizer): 4 | def __init__(self, f, grad, step_size, **kwargs): 5 | super().__init__(f, grad, step_size, **kwargs) 6 | 7 | def get_direction(self, x): 8 | self._current_grad = self._grad(x) 9 | return -self._current_grad 10 | 11 | def get_stepsize(self): 12 | return self._step_size.get_stepsize(self._h, self.convergence[-1], len(self.convergence)) -------------------------------------------------------------------------------- /liboptpy/unconstr_solvers/fo/_quasi_newton.py: -------------------------------------------------------------------------------- 1 | import numpy as _np 2 | from ... import base_optimizer as _base 3 | from ... import step_size as _ss 4 | from collections import deque 5 | 6 | 7 | class BFGS(_base.LineSearchOptimizer): 8 | 9 | def __init__(self, f, grad, step_size=None, 10 | H=None, **kwargs): 11 | if step_size is None: 12 | step_size = _ss.Backtracking("Wolfe", rho=0.5, beta1=1e-3, beta2=0.9, init_alpha=1.) 13 | super().__init__(f, grad, step_size, memory_size=1, **kwargs) 14 | self._H0 = H 15 | self._H = H 16 | 17 | def get_direction(self, x): 18 | if self._H is None: 19 | self._current_grad = self._grad(x) 20 | return -self._current_grad 21 | else: 22 | return -self._H.dot(self._current_grad) 23 | 24 | def get_stepsize(self): 25 | return self._step_size.get_stepsize(self._h, self.convergence[-1], len(self.convergence)) 26 | 27 | def _update_x_current(self): 28 | self._current_grad = self._grad(self._x_next) 29 | s = self._x_next - self._x_current 30 | y = self._current_grad - self._grad_mem[-1] 31 | rho = 1. / y.dot(s) 32 | if self._H is None: 33 | self._H = _np.eye(self._x_current.shape[0]) / y.dot(y) / rho 34 | Hy = self._H.dot(y) 35 | Hys = _np.outer(Hy, s) 36 | ss = _np.outer(s, s) 37 | self._H = rho * ss + self._H - rho * Hys - rho * Hys.T + \ 38 | rho**2 * y.dot(Hy) * ss 39 | self._x_current = self._x_next 40 | 41 | def _get_result_x(self): 42 | self._H = self._H0 43 | return self._x_current 44 | 45 | 46 | class LBFGS(_base.LineSearchOptimizer): 47 | 48 | def __init__(self, f, grad, step_size=None, 49 | H=None, hist_size=10, **kwargs): 50 | if step_size is None: 51 | step_size = _ss.Backtracking("Wolfe", rho=0.5, beta1=1e-3, beta2=0.9, init_alpha=1.) 52 | super().__init__(f, grad, step_size, memory_size=1, **kwargs) 53 | self._H0 = H 54 | self._H = H 55 | self._s_hist = deque(maxlen=hist_size) 56 | self._y_hist = deque(maxlen=hist_size) 57 | 58 | def get_direction(self, x): 59 | if self._H is None: 60 | self._current_grad = self._grad(x) 61 | return -self._current_grad 62 | else: 63 | q = self._current_grad 64 | alpha = _np.zeros(len(self._s_hist)) 65 | rho = _np.zeros(len(self._s_hist)) 66 | for i in range(len(self._s_hist) - 1, -1, -1): 67 | rho[i] = 1. / self._s_hist[i].dot(self._y_hist[i]) 68 | alpha[i] = self._s_hist[i].dot(q) * rho[i] 69 | q = q - alpha[i] * self._y_hist[i] 70 | r = q * self._H 71 | for i in range(len(self._s_hist)): 72 | beta = rho[i] * self._y_hist[i].dot(r) 73 | r = r + self._s_hist[i] * (alpha[i] - beta) 74 | return -r 75 | 76 | def get_stepsize(self): 77 | return self._step_size.get_stepsize(self._h, self.convergence[-1], len(self.convergence)) 78 | 79 | def _update_x_current(self): 80 | self._current_grad = self._grad(self._x_next) 81 | s = self._x_next - self._x_current 82 | y = self._current_grad - self._grad_mem[-1] 83 | self._s_hist.append(s) 84 | self._y_hist.append(y) 85 | if self._H is None or self._s_hist.maxlen <= len(self.convergence) - 1: 86 | self._H = y.dot(s) / y.dot(y) 87 | self._x_current = self._x_next 88 | 89 | def _get_result_x(self): 90 | self._H = self._H0 91 | return self._x_current 92 | 93 | 94 | class DFP(_base.LineSearchOptimizer): 95 | 96 | def __init__(self, f, grad, step_size=None, 97 | H=None, **kwargs): 98 | if step_size is None: 99 | step_size = _ss.Backtracking("Wolfe", rho=0.5, beta1=1e-3, beta2=0.9, init_alpha=1.) 100 | super().__init__(f, grad, step_size, memory_size=2, **kwargs) 101 | self._H0 = H 102 | self._H = H 103 | 104 | def get_direction(self, x): 105 | if self._H is None: 106 | self._current_grad = self._grad(x) 107 | return -self._current_grad 108 | else: 109 | return -self._H.dot(self._current_grad) 110 | 111 | def get_stepsize(self): 112 | return self._step_size.get_stepsize(self._h, self.convergence[-1], len(self.convergence)) 113 | 114 | def _update_x_current(self): 115 | self._current_grad = self._grad(self._x_next) 116 | s = self._x_next - self._x_current 117 | y = self._current_grad - self._grad_mem[-1] 118 | rho = 1. / y.dot(s) 119 | if self._H is None: 120 | self._H = _np.eye(self._x_current.shape[0]) / y.dot(y) / rho 121 | Hy = self._H.dot(y) 122 | self._H = self._H - ((_np.outer(Hy, Hy)) / (y.dot(Hy))) + (_np.outer(s, s) * rho) 123 | self._x_current = self._x_next 124 | 125 | def _get_result_x(self): 126 | self._H = self._H0 127 | return self._x_current 128 | 129 | class BarzilaiBorweinMethod(_base.LineSearchOptimizer): 130 | def __init__(self, f, grad, **kwargs): 131 | super().__init__(f, grad, None, memory_size=2, **kwargs) 132 | 133 | def get_direction(self, x): 134 | self._current_grad = self._grad(x) 135 | return -self._current_grad 136 | 137 | def get_stepsize(self): 138 | if len(self.convergence) == 1: 139 | return self._par["init_alpha"] 140 | else: 141 | g = self._grad_mem[-1] - self._grad_mem[-2] 142 | s = self.convergence[-1] - self.convergence[-2] 143 | if self._par["type"] == 1: 144 | alpha = g.dot(s) / g.dot(g) 145 | elif self._par["type"] == 2: 146 | alpha = s.dot(s) / g.dot(s) 147 | return alpha -------------------------------------------------------------------------------- /liboptpy/unconstr_solvers/fo/_subgrad.py: -------------------------------------------------------------------------------- 1 | from ... import base_optimizer as _base 2 | import numpy as np 3 | 4 | class SubgradientMethod(_base.LineSearchOptimizer): 5 | def __init__(self, f, subgrad, step_size): 6 | super().__init__(f, subgrad, step_size) 7 | self._x_best = None 8 | self._f_best = np.inf 9 | 10 | def get_direction(self, x): 11 | self._current_grad = self._grad(x) 12 | return -self._current_grad 13 | 14 | def check_convergence(self, tol): 15 | current_f = self._f(self._x_current) 16 | if current_f < self._f_best: 17 | self._x_best = self._x_current 18 | self._f_best = current_f 19 | return False 20 | 21 | def get_stepsize(self): 22 | return self._step_size.get_stepsize(self._h, self._x_current, len(self.convergence)) 23 | 24 | def _print_info(self): 25 | pass 26 | 27 | def _get_result_x(self): 28 | return self._x_best -------------------------------------------------------------------------------- /liboptpy/unconstr_solvers/so/__init__.py: -------------------------------------------------------------------------------- 1 | from ._newton import NewtonMethod 2 | from ._inexact_newton import InexactNewtonMethod 3 | 4 | __all__ = ["NewtonMethod", "InexactNewtonMethod"] -------------------------------------------------------------------------------- /liboptpy/unconstr_solvers/so/_inexact_newton.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from ... import base_optimizer as base 3 | from ..fo import _cg as cg 4 | 5 | class InexactNewtonMethod(base.LineSearchOptimizer): 6 | def __init__(self, f, grad, hess_matvec, step_size, **kwargs): 7 | super().__init__(f, grad, step_size, **kwargs) 8 | self._hess_matvec = hess_matvec 9 | 10 | def get_direction(self, x): 11 | self._current_grad = self._grad(x) 12 | hess = self._hess_matvec(x) 13 | lin_cg = cg.ConjugateGradientQuad(hess, -self._current_grad) 14 | eta = np.minimum(0.5, np.sqrt(np.linalg.norm(self._current_grad))) 15 | h = np.zeros(self._current_grad.shape[0]) 16 | while True: 17 | h = lin_cg.solve(x0=h, tol=eta) 18 | if h.dot(self._current_grad) < 0: 19 | break 20 | else: 21 | eta = eta / 10. 22 | return h 23 | 24 | def get_stepsize(self): 25 | return self._step_size.get_stepsize(self._h, self.convergence[-1], len(self.convergence)) -------------------------------------------------------------------------------- /liboptpy/unconstr_solvers/so/_newton.py: -------------------------------------------------------------------------------- 1 | import numpy as _np 2 | from ... import base_optimizer as _base 3 | 4 | class NewtonMethod(_base.LineSearchOptimizer): 5 | def __init__(self, f, grad, hess, step_size, linsolver=None, **kwargs): 6 | super().__init__(f, grad, step_size, **kwargs) 7 | self._hess = hess 8 | self._linsolver = linsolver 9 | 10 | def get_direction(self, x): 11 | self._current_grad = self._grad(x) 12 | hess = self._hess(x) 13 | if self._linsolver: 14 | h = self._linsolver(hess, -self._current_grad) 15 | else: 16 | h = _np.linalg.solve(hess, -self._current_grad) 17 | return h 18 | 19 | def get_stepsize(self): 20 | return self._step_size.get_stepsize(self._h, self.convergence[-1], len(self.convergence)) 21 | 22 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | name='liboptpy', 5 | version='0.0.1', 6 | description='Implementation of various optimization methods for research and study purposes', 7 | author='Alexandr Katrutsa', 8 | author_email="aleksandr.katrutsa@phystech.edu", 9 | packages=['liboptpy', 'liboptpy.unconstr_solvers','liboptpy.unconstr_solvers.fo', 'liboptpy.unconstr_solvers.so', 10 | 'liboptpy.constr_solvers'], 11 | install_requires=['numpy>=1.12', 'scipy>=1.0'], 12 | keywords=[ 'Convex optimization', 'numerical optimization', 13 | 'Python', 'Numpy', 'Scipy'], 14 | url='https://github.com/amkatrutsa/liboptpy', 15 | license='MIT', 16 | classifiers=['License :: OSI Approved :: MIT License', 17 | 'Programming Language :: Python :: 3.5'], 18 | ) 19 | --------------------------------------------------------------------------------