text:
# Footwear scraper

I've done this parser to scrape all footwear data, but I don't know if it is good to use OOP in this case. Can you please check this out and give me the strongest feedback? I'm working on improving my coding style and looking for an opportunity to do coding better. How can I make this parser more maintainable for the future?

#!/usr/bin/env python3
# coding=utf-8

import re
from datetime import datetime
from bs4 import BeautifulSoup
import http
import requests
import urllib.request

html_hdrs = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 ('
'KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
'Accept-Encoding': 'none',
'Accept-Language': 'en-US,en;q=0.8',
'X-Requested-With': 'XMLHttpRequest',
'Connection': 'keep-alive'}

def make_soup(input_url):
try:
html = e.partial
return BeautifulSoup(html, "html.parser")

class Items(object):
"""Exporting all Matches Fashion website items
to a list of soups"""

def __init__(self):
self._ul_tag = 'ul'
self._li_tag = 'li'
self._href_attr = 'href'
self.main_url = 'https://www.matchesfashion.com'
self._gender_urls = ('https://www.matchesfashion.com/intl/mens/shop/shoes',
'https://www.matchesfashion.com/intl/womens/shop/shoes',
'https://www.matchesfashion.com/intl/mens/sale/shoes',
'https://www.matchesfashion.com/intl/womens/sale/shoes')

def _get_categories(self):
category_box_class = 'filter__box__list'
sale_category_box_class = 'innerFilterMobile catLevel3'
out_categories = set()
for gender in self._gender_urls:
if '/sale' in gender:
raw_page = make_soup(gender)
raw_categories = raw_page.findAll(name=self._ul_tag, class_=sale_category_box_class)
raw_categories = raw_categories[0].findAll(name=self._li_tag)
for raw_category in raw_categories:
else:
raw_page = make_soup(gender)
raw_categories = raw_page.findAll(name=self._ul_tag, class_=category_box_class)
raw_categories = raw_categories[0].findAll(name=self._li_tag)
for raw_category in raw_categories:
self._category_urls = out_categories

def _get_pages(self):
pagination_class = 'redefine__right__pager'
self._pages = list()

def _paginate(input_url, input_num):
out_url = '{}?page={}&noOfRecordsPerPage=240&sort='.format(input_url, input_num)
return out_url

for url in self._category_urls:
page_soup = make_soup(url)
last_page_num = page_soup.findAll(name=self._ul_tag, class_=pagination_class)
if len(last_page_num) != 0:
last_page_num = int(last_page_num[0].findAll(name=self._li_tag)[-3].text)
for page_num in range(1, last_page_num+1):
page_list_url = _paginate(url, page_num)
self._pages.append(page_list_url)
else:
self._pages.append(url)

def get(self):
def get_gender(input_url):
if '/womens/' in input_url:
return 'women'
elif '/mens/' in input_url:
return 'men'

def is_sale(input_url):
if '/sale' in input_url:
return True
else:
return False

def get_category(input_url):
if '?page=' in input_url:
out_category = re.search(r'/shoes/(.*)(\?)', input_url).group(1)
else:
out_category = re.search(r'/shoes/(.*)', input_url).group(1)
return out_category
out_items = list()
item_class = 'lister__item'
self._get_categories()
self._get_pages()
for url in self._pages:
gender = get_gender(url)
category = get_category(url)
sale = is_sale(url)
url_soup = make_soup(url)
url_soup = url_soup.findAll(name=self._li_tag, class_=item_class)
for item_soup in url_soup:
out_items.append((sale, gender, category, item_soup))
return out_items

class Info(object):
"""Getting item info out of soup to an Info object"""

def __init__(self, input_item):
self._div_tag = 'div'
self._strike_tag = 'strike'
self._span_tag = 'span'
self._li_tag = 'li'
self._alt_attr = 'alt'
self._pic_attr = 'data-original'
self._href_attr = 'href'
self._shop_name = 'Matches Fashion'
self.sale, self.gender, self.category, self.item_soup = input_item

def _get_raw_info(self):
vendor_class = 'lister__item__title'
self.title = self.item_soup.img[self._alt_attr]
self.description = self.title
self.model = self.title
self.time = datetime.now(timezone('Europe/Moscow')).strftime('%Y-%m-%d %H:%M:%S')
self.picture = 'https:{}'.format(self.item_soup.img[self._pic_attr])
self.url = 'https://www.matchesfashion.com{}'.format(self.item_soup.a[self._href_attr])
self.vendor = self.item_soup.findAll(name=self._div_tag, class_=vendor_class)[0].text
self.shop = self._shop_name
self.freeship = False

def _get_prices(self):
full_price_class = 'lister__item__price-full'
new_price_class = 'lister__item__price-down'
discount_class = 'lister__item__price-save'
try:
self.price = self.item_soup.findAll(name=self._span_tag, class_=full_price_class)[0].text
self.oldprice = self.price
self.discount = 0
except IndexError:
self.price = self.item_soup.findAll(name=self._span_tag, class_=new_price_class)[0].text
self.oldprice = self.item_soup.findAll(name=self._strike_tag)[0].text
self.discount = self.item_soup.findAll(name=self._span_tag, class_=discount_class)[0].text

def _get_sizes(self):
no_stock_class = 'noStock'
raw_sizes = self.item_soup.select("{}[class!={}]".format(self._li_tag, no_stock_class))
self.sizes = []
for raw_size in raw_sizes:
size = raw_size.text
self.sizes.append(size)
if len(raw_sizes) != 0:
size = raw_sizes[0].text
if 'eu' in size.lower():
self.sizetype = 'eu'
if 'us' in size.lower():
self.sizetype = 'us'
if 'uk' in size.lower():
self.sizetype = 'uk'

def get(self):
self._get_raw_info()
self._get_prices()
self._get_sizes()

raw_items = Items()
items = raw_items.get()

for item in items:
info = Info(item)
info.get()

This code is a bit raw, but the only thing that is left is the one more class Process(object) to process all data left.

• The current question title, which states your concerns about the code, is too general to be useful here. Please edit to the site standard, which is for the title to simply state the task accomplished by the code. Please see How to get the best value out of Code Review: Asking Questions for guidance on writing good question titles. Jul 30, 2019 at 12:47
• @BCdotWEB Thanks! I've tried to change the title, but I'm more interested in a feedback and advises of how to make this code better to be readable and to maintain. Jul 30, 2019 at 12:52
• Such expectations belong in the body of your question, not your title. As I state in my comment: "the site standard, which is for the title to simply state the task accomplished by the code". Jul 30, 2019 at 12:53
• Welcome to Code Review! What Python version did you write this for and why doesn't it seem like this code ever exports its data?
– Mast
Jul 30, 2019 at 13:02
• @Mast Thank you! it's Python 3.6 and it doesn't exports the data just because I haven't written the Process class yet. The data has to be processed before export. But the last lines of code creates objects with data inside. Jul 30, 2019 at 13:09

It looks very procedural at a glance, it might just not be useful to use custom objects here. In any case you don't need to explicitly inherit from object, class Process: is fine already.

So, more maintainable, well, the headers look dubious, but obviously chosen from a real-life browser. The character set / encoding values would be the most concerning to me wrt. maintenance, but likely the encoding detection will take care of that. Similarly the Connection probably doesn't belong there and should be handled by the HTTP client instead (like most of them, except the user agent I suppose).

_ul_tag, _li_tag, _href_attr those are way unlikely to change. If defined at all they should be global constants instead.

The _gender_urls should be constructed from the main_url.

_get_categories has two almost identical blocks, better unify them into a new method.

I'd perhaps consider move all of the named classes etc. that might change into constants at the start of the class or file so changing some doesn't require having to look all over the file. Then again, minor complaint and perhaps not worth it if they're really only used once. Giving them good names is nice.

_paginate can just return '...'.format(...) instead of having the variable? Goes for some more places in the code too. If the variable is only used once and the line is short enough, just inline them.

get_gender - what if neither is in the input?

is_sale can simply be return '/sale' in input_url.

get_category can be simplified for sure. Also the regex can be precompiled with compile once and globally instead of every time the method runs. Also the two branches can be simplified into a single regex, look for "non-greedy" matching in the re documentation.

_get_sizes - the append bit could be a for comprehension, self.sizes = [raw_size.text for raw_size in raw_sizes]. For most (all?) objects if len(x) != 0 will mean exactly the same as if x:, though that might be a stylistic thing. Hmm and the whole if ... in size.lower(): part, well firstly, what about if none of them match? Or more than one? Actually I'd suggest a loop here, lower = size.lower(); for x in ['eu', 'us', 'uk']: if x in lower: self.sizetype = x.

You probably also want if __name__ == '__main__': ... at the bottom instead of just running code whenever the file is loaded.

• These are really useful to me, thanks! By the way, what do you think about using inheritance to create more parsers with other shops? I mean, what if I create new parser with such OOP style, but is it good to inherit these classes? Or it's better to create just the same ones? Or maybe it's a good idea to use OOP at all? Aug 23, 2019 at 12:45
• Right, well I can see that being useful if there's common functionality between different parsers. Do you think that will be the case for other shops? I imagine the structure might be too different. I'd first do one more then see if you can share code on the whole class level and if not extract helper functions etc. as you notice duplication or patterns occurring. Aug 23, 2019 at 15:49


text:
Stochastic Subspace DescentSubmitted to the editors DATE.      Funding: AD acknowledges funding by the US Department of Energyâs Office of Science Advanced Scientific Computing Research, Award DE-SC0006402 and National Science Foundation Grant CMMI-145460.

# Stochastic Subspace Descent††thanks: Submitted to the editors DATE.      Funding: AD acknowledges funding by the US Department of Energyâs Office of Science Advanced Scientific Computing Research, Award DE-SC0006402 and National Science Foundation Grant CMMI-145460.

David Kozak Department of Applied Mathematics and Statistics, Colorado School of Mines, Golden, CO    Stephen Becker Department of Applied Mathematics, University of Colorado, Boulder, CO    Alireza Doostan Aerospace Engineering Sciences Department, University of Colorado, Boulder, CO    Luis Tenorio44footnotemark: 4
###### Abstract

We present two stochastic descent algorithms that apply to unconstrained optimization and are particularly efficient when the objective function is slow to evaluate and gradients are not easily obtained, as in some PDE-constrained optimization and machine learning problems. The basic algorithm projects the gradient onto a random subspace at each iteration, similar to coordinate descent but without restricting directional derivatives to be along the axes. This algorithm is previously known but we provide new analysis. We also extend the popular SVRG method to this framework but without requiring that the objective function be written as a finite sum. We provide proofs of convergence for our methods under various convexity assumptions and show favorable results when compared to gradient descent and BFGS on non-convex problems from the machine learning and shape optimization literature. We also note that our analysis gives a proof that the iterates of SVRG and several other popular first-order stochastic methods, in their original formulation, converge almost surely to the optimum; to our knowledge, prior to this work the iterates of SVRG had only been known to converge in expectation.

Key words. Randomized methods, optimization, derivative-free, Gaussian processes, shape optimization, stochastic gradients

AMS subject classifications. 90C06, 93B40, 65K10

## 1 Introduction

We consider optimization problems of the form

 minx∈Rdf(x), (1.1)

or sometimes

 argminx∈Rdf(x), (1.2)

where has -Lipschitz derivative. Throughout the document we will consider additional restrictions such as convexity or -strong convexity of , restrictions that will be made clear as they are required. In the most basic form discussed in Section LABEL:sect:_SSD, we project the gradient onto a random -dimensional subspace and descend along that subspace as in gradient descent. This is accomplished using a random matrix , for some , with the properties

 E PPT=Id,PTP=dℓIℓ,

in the following iteration scheme

 xk+1=xk−αPkPTk∇f(xk). (1.3)

This algorithm has convergence properties consistent with gradient descent (see Theorem LABEL:thm:convergence) and allows us to leverage techniques from the substantial literature surrounding stochastic gradient descent (see Theorem LABEL:thm:VarianceReducedRandomGradient). Note that (LABEL:eq:_iterations) with a diagonal reduces to randomized block-coordinate descent [6].

A particular case of (LABEL:eq:_minimize_f) is Empirical Risk Minimization (ERM) commonly used in machine learning

 minx∈Rdf(x)\lx@stackrel\tiny def=1nn∑i=1fi(x),

where is typically very large, and hence the problem is amenable to iterative stochastic methods that approximate using randomly sampled observations at each iteration with where . While the methods discussed in this paper do not require this type of finite-sum structure, they can be employed to tackle such problems. In fact, the canonical parameter estimation problem in machine learning is one application we envision for our work.

There are several important classes of functions that do not fit into the ERM framework and therefore do not benefit from the recent stochastic algorithms tailored to ERM. Partial Differential Equation (PDE) constrained optimization is one such example, and except in special circumstances (such as [39]), a stochastic approach leveraging the ERM structure (such as stochastic gradient descent and its variants) does not provide any benefits. This is due to the fact that in PDE-constrained optimization the cost of evaluating each is often identical to the cost of evaluating . A primary goal of this paper is to use variations on the prototypical iterative scheme (LABEL:eq:_iterations) to adapt recent developments from the machine learning optimization literature so that stochastic methods can be used effectively in the PDE-constrained optimization setting. Along the way we present results that we think will be useful to the machine learning community. An example that comes directly from the machine learning literature is Gaussian processes, specifically the sparse Gaussian process framework of [85, 92]. The placement of so-called inducing points is rolled into the continuous optimization setting causing the dimension of the problem to increase linearly with the desired number of points. This leads to high-dimensional problems for which traditional stochastic optimization algorithms provide no benefit.

### 1.1 PDE-constrained optimization

Partial differential equations are well-studied tools in applied mathematics, ubiquitous for their use in modeling physical phenomena. Successful application of PDEs to modeling is contingent upon appropriate discretization and parameter estimation. Parameter estimation in this setting is referred to as PDE-constrained optimization, and arises in optimal control, or whenever the parameters of the PDE are unknown, as in inverse problems. Algorithmic and hardware advances for PDE-constrained optimization have allowed for previously impossible modeling capabilities. Examples include fluid dynamics models with millions of parameters for tracking atmospheric contaminants [32], modeling the flow of the Antarctic ice sheet [48, 74], parameter estimation in seismic inversion [1, 14], groundwater hydrology [11], experimental design [47, 40], and atmospheric remote sensing [21].

In Section LABEL:sect:_EmpiricalResults we take a discretize-then-optimize approach and assume that the infinite-dimensional PDE has already been discretized by some appropriate mechanism such as finite differences or finite elements. With this in mind, the PDE-constrained optimization problem can be written as follows

 minx(f(x)\lx@stackrel\tiny def=L(u(x);y)+ωR(x)). (1.4)

That is, the goal is to minimize a tradeoff between (a) the loss which depends on the solution to the PDE and the observed data , and (b) a regularization functional that serves to keep the problem well-posed. The PDE is parameterized by , the dimension of which may be subject to the choice of discretization, and may be in the millions. The regularization parameter controls the balance between the data misfit and the regularity of the solution. Typically is unknown but there are a number of techniques for estimating it, see [91, §3.3], [64, §5.4], [44, 84]; we do not treat this issue here.

### 1.2 Gaussian processes

Gaussian processes are a very important class of stochastic processes used for modeling processes that are correlated in input space. Here we use them to model an unknown function in the context of regression. Elegant results from functional analysis, developed over the past 100 years, allow for the flexibility of working in function space using only machinery from linear algebra but the applications of Gaussian processes are somewhat hamstrung in many modern settings because their time complexity scales as and their storage as . One recourse is to approximate the Gaussian process, allowing time complexity to be reduced to with storage requirements of where is the number of points used in lieu of the full data set. Methods have been developed [85, 92] which place these inducing points, also called landmark points, along the domain at points different from the original inputs; optimal placement of these points is a continuous optimization problem with dimension at least the number of inducing points to be placed. Such a framework places heavy burden on the optimization procedure as improperly placed points may result in a poor approximation.

### 1.3 A historical perspective of iterative optimization

Despite being among the easiest to understand and oldest variants of gradient descent, subspace methods (by far the most common of which is coordinate descent) have been conspicuously absent from the optimization literature. The reasons for this vary but such under-representation may be partially attributed to the fact that until recently the performance of these types of algorithms did not justify the difficult theoretical work.

#### Coordinate descent schemes

The simplest variant of subspace descent is a deterministic method that cycles over the coordinates. Convergence results for coordinate descent requires challenging analysis and the class of functions for which it will converge is restricted; indeed, [98, 77] provide simple examples for which the method fails to converge while simpler-to-analyze methods such as gradient descent will succeed. It was shown in [57] that relaxing the cyclic nature of the updates so that the schedule for updating along each coordinate is “almost cyclic” (that is, the function is updated along each coordinate at least once every iterations for some ) allows for convergence guarantees under conditions only moderately more restrictive than those of gradient descent. Also, it was shown in [57] that using the deterministic Gauss-Southwell rule for selecting the descent direction results in convergence at a linear rate, a result corroborated by theoretical and experimental evidence in [19], and38 expanded upon in the paper [72] which shows that the rate of convergence is competitive with the rates of the randomized method provided by [67].

The analysis in [67] for the case where the coordinates are chosen randomly provides convergence results on par with gradient descent without additional restrictions on the class of functions that can be optimized. This was generalized in [78] with slightly tighter analysis and an extension to composite functions. An overview of the recent progress until 2015, along with simplifications of the proofs for several results can be found in [101]. The algorithm described in Section LABEL:sect:_SSD is a generalization of results that can be found in [101, 67].

Since 2015, much emphasis has been placed on accelerating coordinate descent methods [2, 46] but those improvements require knowledge of the Lipschitz constants of the partial derivatives of the functions and/or special structure in the function to make updates inexpensive; in Section LABEL:sect:_Conclusions we discuss how recent analysis in [54] allows for acceleration of our methods without such an unrealistic assumption.

#### Optimization without derivatives

Our methods use directions where P is with , which is computationlly identical to taking directional derivatives of , and can therefore be estimated by forward- or centered-differences in or function evaluations, respectively. We assume the error due to the finite difference approximation is negligible, which is realistic for low-precision optimization. Because our methods only evaluate and not directly, they fall into the class of derivative-free optimization (DFO) and “zeroth-order” optimization. Recent analysis has shown that many first-order methods (e.g., gradient descent, SVRG) maintain asymptotic convergence properties [55] when the gradients are estimated via finite differences. Additionally, non-asymptotic bounds on the rate of convergence for zeroth-order methods have been shown to be similar, albeit slightly worse, to their first-order counterparts [26].

To be clear, when is readily available, zeroth-order optimization methods are not competitive with first-order methods and second-order methods (e.g., Newton’s method). For example, if and is a matrix small enough to store in the memory of a computer, then evaluating and evaluating have nearly the same computational cost, namely . In fact, such a statement is always true regardless of the structure of : by using reverse-mode automatic differentiation (AD), one can theoretically evaluate in about four-times the cost of evaluating , regardless of the dimension [37]. In the context of PDE-constrained optimization, the popular adjoint-state method, which is a form of AD applied to either the continuous or discretized PDE, also evaluates in time independent of the dimension.

However, there are many situations when AD and the adjoint-state method are inefficient or not applicable. Finding the adjoint equation requires a careful derivation (which depends on the PDE as well as on initial and boundary conditions), and then a numerical method must be implemented to solve it, which takes considerable development time. For this reason, complicated codes that are often updated with new features, such as weather models, rarely have the capability to compute a full gradient. There are software packages that solve for the adjoint automatically, or run AD, but these require a programming environment that restricts the user, and may not be efficient in parallel high-performance computing environments. Even when the gradient is calculated automatically via software, the downside of these reverse-mode methods is a potential explosion of memory when creating temporary intermediate variables. For example, in unsteady fluid flow, the naive adjoint method requires storing the entire time-dependent PDE solution [70] and hybrid check-pointing schemes [96] are the subject of active research. Furthermore, in black-box simulations which only return function evaluations given inputs (see [20, §1.2] for examples) the derivative may not be available by any means.

Many DFO algorithms have been developed for the cases that do not admit obtaining a full gradient. Classic methods include grid search, Nelder-Mead, (quasi-) Monte-Carlo sampling, simulated annealing and MCMC methods [51]. More powerful modern algorithms include randomized methods, Evolution Strategies (ES) such as CMA-ES [43], Hit-and-Run [7] and random cutting planes [22], as well as textbook modern DFO methods ([20, Algo. 10.3], [71, Algo. 9.1]) based on interpolation and trust-regions. A limitation of all these methods is that they do not scale well to high-dimensions (typical dimensionality is , and extreme cases would be dimension ), thus limiting their applicability. For this reason, and motivated by the success of stochastic gradient methods in machine learning, we turn to cheaper methods that scale well to high dimensions.

#### Stochastic DFO

Our basic stochastic subspace descent (SSD) method (LABEL:eq:_iterations) has been previously explored under the name “random gradient,” “random pursuit,” “directional search,” and “random search” (not to be confused with the hit-and-run style “random search” algorithm [79]). The algorithm dates back to the 1970s, with some analysis (cf. [29, Ch. 6] and [33, 86]), but it never achieved prominence since zeroth-order methods are not competitive with first-order methods when the gradient is available. Most analysis has focused on the specific case [66, 69, 89, 52].

Recently, the random gradient method has seen renewed interest. [52] analyzes the case when is quadratic, and [89] provides an analysis (assuming a line search oracle). A variant of the method, using and P comprised of IID Gaussian entries with mean zero and variance such that , was popularized by Nesterov [66, 69], and various proximal, acceleration and noise-tolerant extensions and analysis appeared in [28, 27, 35, 17]. The novelty of our work, and distinguishing feature compared to prior work, is that the methods in the literature have not focused on high-dimensional projections or practical demonstrations. Another variant of random gradient has recently been proposed in the reinforcement learning community. The Google Brain Robotics team used orthogonal sampling to train artificial intelligence systems [18], but treated it as a heuristic to approximate Gaussian smoothing. Previous use of orthogonal sampling by the OpenAI team [81] used variance reduction, but only in the sense of antithetic pairs.

We note that the methods we propose may appear similar to stochastic gradient descent (SGD) methods popular in machine learning, but the analysis is completely different. Indeed, even under strong convexity and with a finite sum structure, SGD methods require diminishing stepsizes and hence converge slowly or else converge only to a radius of the solution [12].

The most relevant recent work to the SSD scheme is the recent SEGA algorithm [45] which takes similar random measurements but then uses them in a completely different way, following their “sketch-and-project” methodology. Given a sketch and an estimate of the gradient at the previous step , the simplest version of SEGA finds a new estimate

 gk=argming∥g−gk−1∥2subject to PTg=PT∇f(xk),

followed by a debiasing step.

#### Alternatives

As a baseline, one could use function evaluations to estimate using finite differences, which is clearly costly when is large and evaluating is expensive. Once is computed, one can run gradient descent, accelerated variants [65], non-linear conjugate gradient methods [41], or quasi-Newton methods like BFGS and its limited-memory variant [71]. We will compare with these baselines in the numerical results section, particularly with plain gradient descent since it is less sensitive to step-size and errors compared to accelerated variants, and to BFGS since it is widely used. We do not consider Newton, nor inexact Newton (Newton-Krylov) solvers such as [8, 9, 10], because these require estimating the Hessian as well. Some authors have recently investigated estimating the Hessian stochastically (or adapting BFGS to work naturally in the stochastic sampling case), such as [15, 61, 82, 63, 4, 5, 36, 97], but none apply directly to our setup as they require an ERM structure.

### 1.4 Structure of this document

The remainder of the paper is organized as follows: In Section LABEL:sect:_SSD we investigate the convergence behavior of the stochastic subspace descent method under various convexity assumptions, and provide rates of convergence. In Section LABEL:sect:_SVRG we recall the Stochastic Variance Reduced Gradient (SVRG) method of [50], and show how control variates can be used to reduce the variance in stochastic subspace descent to improve the rate of convergence. Along the way, we provide a simple lemma that relates convergence in expectation at a linear rate with almost sure convergence of our method. It can also be used to show that the convergence of SVRG and other popular first order methods can be trivially extended to almost sure convergence. In Section LABEL:subsect:synthetic-data we provide empirical results on a simulated function that Nesterov has dubbed “the worst function in the world” [68]. In Section LABEL:subsect:_experiments-GP we find the optimal placement of inducing points for sparse Gaussian processes in the framework of [92]. As a final empirical demonstration, in Section LABEL:subsect:_experiments-plate we test our algorithms in the PDE-constrained optimization setting on a shape optimization problem where the goal is to identify the shape of a hole of fixed area which minimizes the maximum stress subject to boundary forces. We make concluding remarks and discuss future extensions in Section LABEL:sect:_Conclusions. For the sake of readability, proofs are relegated to the Appendix.

In this document, uppercase-boldfaced letters represent matrices, lowercase-boldfaced letters are vectors. The vector norm is assumed to be the 2-norm, and the matrix norm is the operator norm.

## 2 Main results

This section contains our main theoretical results. We present two algorithms in the SSD framework and provide convergence results under various assumptions. We additionally provide proof that the popular SVRG algorithm [50], along with several other commonly used stochastic descent methods, provides almost sure convergence of the iterates to the optimal solution.

### 2.1 Ssd

In the following theorem and corollary we provide conditions under which function evaluations of stochastic subspace descent converge to a function evaluation at the optimum . In the case of a unique optimum we also provide conditions for the iterates to converge to the optimum . Stochastic subspace descent, so-called because at each iteration the method descends in a random low-dimensional subspace of a vector space containing the gradient, is a gradient-free method as it only requires computation of directional derivatives at each iteration without requiring direct access to the gradient. Scaled Haar-distributed random matrices define randomized directions (in the subspace) along which to descend at each iteration. Neither Theorem LABEL:thm:convergence, nor the subsequent theorems require these Haar-distributed matrices in particular but whatever matrices are used must satisfy Assumption (A0) below. See Appendix LABEL:App:_Misc for an algorithm for generating draws from a Haar-distributed matrix, and a brief discussion of the advantages of using Haar over random coordinate descent type schemes.

###### Assumptions 2.1.

For the remainder of this section we make use of the following assumptions on the matrices and the function to be optimized.

1. , , are independent random matrices such that and with .

1. is continuously-differentiable with a -Lipschitz first derivative.

2. The function attains its minimum .

3. For some and all , the function satisfies the Polyak-Lojasiewicz (PL) inequality of Lemma LABEL:PLLemma:

 (2.1)

Also, where is the Lipschitz constant in (A1).

4. is -strongly-convex for some and all . Also, where is the Lipschitz constant in (A1).

5. is convex and attains its minimum on a set , and there is an such that for the parameter initialization ,

 maxx, x∗∈D{∥x−x∗∥:f(x)≤f(x0)}≤R.

Coercivity of implies the existence of the constant in (A3”), hence Assumption (A3”) is mathematically equivalent to coercivity of . For the results below, particularly the rate, in Theorem LABEL:thm:_convergence-convex, we require knowledge of the value of . Also note that (A3’) implies (A3) (Lemma LABEL:PLLemma).

Algorithm LABEL:Alg:_SSD provides basic pseudocode to implement stochastic subspace descent using the recursion (LABEL:eq:_iterations).

###### Theorem 2.2 (Convergence of SSD).

Assume (A0), (A1), (A2), (A3) and let be an arbitrary initialization. Then recursion (LABEL:eq:_iterations) with results in and .

Formal definitions of the different modes of convergence are provided in the appendix. Since non-convex functions may satisfy the PL-inequality (LABEL:eq:PL), Theorem LABEL:thm:convergence provides a convergence result for well-behaved non-convex functions. More practically, in Corollary LABEL:corr:strong-convexity we show that Theorem LABEL:thm:convergence allows linear convergence for relevant classes of convex functions such as least squares, even when the functions are not strongly convex [42, §2.3].

###### Corollary 2.3 (Convergence under strong-convexity and rate of convergence).
1. Assume (A0), (A1), (A2), (A3’) and let be an arbitrary initialization. Then recursion (LABEL:eq:_iterations) with results in where is the unique minimizer of .

2. Assume (A0), (A1), (A2), and (A3). Then with the step-size , the recursion defined in (LABEL:eq:_iterations) attains the following expected rate of convergence

 0≤Ef(xk)−f∗≤βk(f(x0)−f∗), (2.2)

where .

We note that if we recover a textbook rate of convergence for gradient descent [13, §9.3]. Under the more restrictive assumption of strong-convexity the result of Corollary LABEL:corr:strong-convexity is much stronger than Theorem LABEL:thm:convergence; we get almost sure convergence of the function evaluations and of the iterates to the optimal solution at a linear rate. In inverse problems it is typically the convergence of not of that is sought. Furthermore, if either assumption (A3) or (A3’) is satisfied, SSD has a linear rate of convergence. This result may be somewhat counter-intuitive for those more familiar with stochastic gradient descent, which is well known to provide a sub-linear rate of convergence. By applying random sampling to dimensions in input space rather than to observations the step-size need not decay, allowing for a linear rate. In addition to the linear rate, we provide guidance for selecting an optimal step-size, which in theory alleviates the need for the user to tune any hyperparameters. The optimal step-size is easily interpreted as the quotient of the sample rate and the global Lipschitz constant. This is consistent with our intuition: more directional derivatives make for a better approximation of the gradient. In practice the Lipschitz and strong-convexity constants are rarely known and a line search can be used.

Thus far, we have provided results for cases when the function satisfies the PL-inequality or is strongly-convex. The proof in the convex case is different, but substantively similar to a proof of coordinate descent on convex functions found in [101].

###### Theorem 2.4 (Convergence under convexity).

Assume (A0), (A1), (A2), (A3”). Then recursion (LABEL:eq:_iterations) with gives

 Ef(xk)−f∗≤2dλR2/(kℓ).

### 2.2 Variance Reduced Stochastic Subspace Descent (VRSSD)

In its most basic formulation SGD suffers from a sub-linear rate of convergence. This is due to a requirement for the step-size to gradually decay to assure convergence of the iterates. Several methods have been designed to address this short-coming, one of which is SVRG [50] which controls the variance of the gradient estimate using a control variate, and admits convergence with a constant step-size, resulting in a linear rate of convergence. In this section we recall some results regarding SVRG from [50] before proving almost sure convergence of the iterates and function evaluations, and ultimately adapting it to the framework of SSD. SVRG minimizes the functional via the iterative scheme

 xs,k=xs,k−1−α(∇fik(xs,k−1)−∇fik(~xs)+~μs), (2.3)

where is chosen uniformly at random, is a past iterate updated every iterations, and the full gradient is also calculated every iterations:

 ~μs=∇f(~xs)=1nn∑i=1∇fi(~xs). (2.4)

In [50] a proof is presented for the case where is updated after iterations by setting , where is chosen uniformly at random from . The authors call this updating scheme “Option 2” and recommend an alternative “Option 1”, without proof, which involves setting instead. A proof of convergence for Option 1 is provided in [90]. The SVRG method is presented in Algorithm LABEL:alg:SVRG, and the convergence result of [50], is presented in Theorem LABEL:SVRG.

###### Theorem 2.5 (Convergence of SVRG [50]).

Assume that each is convex with -Lipschitz derivative and that is -strongly-convex. Assume that the memory parameter is sufficiently large so that

 β=1γα(1−2λα)m+2λα1−2λα<1.

Then, for the sequences (LABEL:eq:_SVRG1) and (LABEL:eq:_SVRG2), using Option 2 to update , we have the following expected rate of convergence,

 0≤Ef(~xs)−f(x∗)≤βs[f(~x0)−f(x∗)]. (2.5)

The proof, omitted here, can be found in [50]. Since is a constant and , Theorem LABEL:SVRG implies that . We further show that the convergence is also in other modes. This is a particular result of the following simple lemma:

###### Lemma 2.6 (a.s. convergence from a linear rate of convergence).

Consider the general problem of minimizing an objective function and set . If a minimization algorithm converges in expectation at a linear rate; that is, if there exists and a constant such that

 0≤Ef(xk)−f∗≤C(1−β)k,

then . If in addition, is strongly-convex, then .

The distinction between modes of convergence is not merely academic, see for instance [31, p.4] for a simple example of a sequence that converges in for any but does not converge almost surely. As discussed in [54], the class of algorithms that satisfy the conditions required to invoke Lemma LABEL:thm:SVRG-AS is substantial. This class includes many of the most popular gradient-based optimization methods such as block-coordinate descent, SAG [80], SAGA [23], SDCA [83], SVRG [50], Finito/MISO [24, 59], and their proximal variants. Though the conditions of Lemma LABEL:thm:SVRG-AS are sufficient for almost sure convergence, they are not necessary: there are optimization algorithms, such as stochastic gradient descent, that converge almost surely for which the rate of convergence is sub-linear. Of the aforementioned algorithms only SVRG is relevant to our present discussion:

###### Remark 1 (a.s. convergence of SVRG).

For the SVRG algorithm discussed in Theorem LABEL:SVRG, and .

###### Proof.

The problems for which the theory of SVRG can be applied are strongly-convex. Also, by construction , and . Thus the result follows from Lemma LABEL:thm:SVRG-AS.

As stated, SVRG is stochastic in that it randomly samples observations from the dataset. Our goal is different in that we are interested in random sampling along the dimensions of input space, motivating a new algorithm we call Variance Reduced Stochastic Subspace Descent (VRSSD). For subspace selection we generate a random matrix using Algorithm LABEL:Haar, though again any matrices satisfying assumption (A0) suffice. The main algorithm is described in Algorithm LABEL:alg:varprod. Notice that the similarity of SVRG and VRSSD is in their use of a control variate; in VRSSD we additionally incorporate a parameter which allows to weight the influence of the control variate.

Theorem LABEL:thm:VarianceReducedRandomGradient allows for, but (unlike SVRG) does not require, to have a finite-sum representation and as a consequence it does not require Lipschitz-continuity of the individual samples, , like Theorem LABEL:SVRG does.

###### Theorem 2.7 (a.s. convergence of VRSSD).

Assume that is a -strongly convex continuously-differentiable function with -Lipschitz gradient for some . Define . Let be the minimizer of .

1. Fix a memory parameter , a sampling rate , and a step-size such that

 β=1αγm(1−αλρ)+αλ(ρ−1)1−αλρ<1.

Then, Algorithm LABEL:alg:varprod with option 2 and has the following expected rate of convergence:

 0≤Ef(~xs)−f(x∗)≤βs[f(~x0)−f(x∗)], (2.6)

and .

2. Fix , , and such that

 β=1αγm(1−αλρ)<1. (2.7)

Then, with the control variate parameter:

 ηs,k−1=∇f(~xs−1)T∇f(xs,k−1)∥∇f(~xs−1)∥2, (2.8)

Algorithm LABEL:alg:varprod using Option 2 has the following expected rate of convergence:

 0≤Ef(~xs)−f(x∗))≤βs[f(~x0)−f(x∗))], (2.9)

and .

For appropriately chosen parameters and , the variance reduction introduced in Theorem LABEL:thm:VarianceReducedRandomGradient leads to an improved convergence rate compared to the simpler method presented in Theorem LABEL:thm:convergence. The benefits can be seen in practice as we show in Section LABEL:subsect:_experiments-plate. In part () of Theorem LABEL:thm:VarianceReducedRandomGradient we show that it is possible to further improve the rate by selecting a control variate parameter to optimally weight the impact of the full gradient that is held in memory. In theory we see the following effects on the rate for VRSSD with the optimal control variate, all of which are consistent with our intuition:

• A large sampling rate improves per-iteration convergence.

• A large improves per-iteration convergence, but each iteration is only counted after inner loops have been completed, so the effect of cancels (in theory).

• Poor conditioning () has a deleterious effect on the convergence rate commensurate with its effect on the convergence rate of gradient descent.

• A large Lipschitz constant must be offset by a small step-size.

• It is possible to find the optimal step for a known local Lipschitz constant and strong-convexity constant, and a fixed .

In many of the problems for which SSD is useful it is undesirable to compute the term to find the optimal control variate as this would amount to additional function evaluations per iteration. For this reason, in practice, we recommend approximating it with the current estimate of the gradient instead,

 ∇f(xs,k−1)≈Ps,kP⊤s,k∇f(xs,k−1). (2.10)

Though this approximation is not supported by the theory, empirical performance in Section LABEL:sect:_EmpiricalResults suggests the validity of such an approximation. We chose the approximation in (LABEL:eqn:_VRSSD-approximation) because it is an unbiased estimate of the optimal control variate parameter at each iteration and has the advantage that no additional function evaluations are required for each iteration. It also has the effect that some of the intuitions outlined above may not hold; this in itself is not necessarily a problem as the Lipschitz and strong convexity constants are rarely known and a line search can be used to determine the step-size; in our experiments we use an Armijo backtracking line search as discussed in [71].

In order to understand the role of more clearly, we consider three possible scenarios: corresponds to standard SSD as outlined in Theorem LABEL:thm:convergence, corresponds to part () of Theorem LABEL:thm:VarianceReducedRandomGradient, and finally the optimal is given by (LABEL:eqn:_optimal-eta) and used in part () of Theorem LABEL:thm:VarianceReducedRandomGradient. With the understanding that the true gradient is the optimal search direction with respect to one-step improvement, we would like our search direction to vary around it as little as possible. To this end, we ascertain the conditional mean-square error defined as the expectation of

 ∥∥∇f(xs,k−1)−(Ps,kPTs,k∇f(xs,k−1)−ηs,k−1(Ps,kPTs,k−I)∇f(~xs−1))∥∥2,

given information at the current iteration (i.e., conditional on algebras defined in the appendix). We denote this conditional error as CMSE.

• Case (Theorem LABEL:thm:convergence)

 CMSE=(ρ−1)∥∇f(xs,k−1)∥2
• Case (Theorem LABEL:thm:VarianceReducedRandomGradient part (i))

 CMSE=(ρ−1)(∥∇f(xs,k−1)∥2+∥∇f(~xs−1)∥2−2 ∇f(xs,k−1)T∇f(~xs−1)).
• Case (Theorem LABEL:thm:VarianceReducedRandomGradient part (ii))

 CMSE (2.11)

These identities follow from the proofs in the appendix. Equation (LABEL:eqn:_eta-analysis) shows that the optimal never increases the variance compared to SSD and can in fact drop it to zero, though an increase in the variance is possible if (e.g., in the event is negative, which may occur if is too large and the iterates traverse substantial portions of parameter space between full gradient calculations). These results are in agreement with Theorem LABEL:thm:VarianceReducedRandomGradient which suggests that the per-iteration rate of convergence using an optimal is strictly less than the rate when .

## 3 Experimental results

In this section we provide results for a synthetic problem (Section LABEL:subsect:synthetic-data), a problem from the machine learning literature (Section LABEL:subsect:_experiments-GP), and a shape-optimization problem (Section LABEL:subsect:_experiments-plate). For the sake of fair comparisons, we compare to zeroth-order variants of gradient descent and BFGS where the gradient is calculated via forward-differences. In the synthetic problem we also compare to a randomized block-coordinate descent. For VRSSD we use the approximation (LABEL:eqn:_VRSSD-approximation) of the optimal , and we use Option 1 for updating .

### 3.1 Synthetic data

We explore the performance of the algorithms on Nesterov’s “worst function in the world” [68]. Fix a Lipschitz constant and let

 fL,r(x)=L4(12(x21+r−1∑i=1(xi−xi+1)2+x2r)−x1), (3.1)

where represents the coordinate of and is a constant integer that defines the intrinsic dimension of the problem. This function is convex with global minimum

 f∗=L8(−1+1r+1).

Nesterov has shown that a broad class of iterative first-order solvers perform poorly when minimizing with . We compare our results to randomized block-coordinate descent and gradient descent for two illustrative examples from the family of functions defined by (LABEL:eq:_NesterovWorst). We do not compare to BFGS as we do not run enough iterations for it to differ substantially from gradient descent. For the randomized methods we use ; in Section LABEL:subsect:_experiments-GP we explore the impact that different choices of have on convergence. We expect coordinate descent to perform poorly as there is only a single coordinate of this function that provides a descent direction from the initialization; for high-dimensional problems it becomes exceedingly unlikely that the “correct” coordinate is chosen. Also, since it is a block coordinate descent with , the impact of the other two coordinates chosen outweighs the benefit, and the step-size gets pushed to zero; hence, in both examples shown in Figure LABEL:fig:_NesterovExample we see no improvement from coordinate descent. Had we used instead for coordinate descent we could only expect improvement to be made one in every iterations, rather than at every iteration as in the other methods.

If the function is intrinsically low-dimensional but it is embedded into a high-dimensional ambient space, then SSD and VRSSD perform exceptionally well (see left plot of Figure LABEL:fig:_NesterovExample). This holds true for the Gaussian process example of Section LABEL:subsect:_experiments-GP as well. On the other hand, if the space is truly high-dimensional then the stochastic methods do not appear to provide any benefit.

There are hyperparameters to set in our methods. We reserve discussion of for Section LABEL:subsect:_experiments-GP. In Figure LABEL:fig:_VRSSD-performanceprofile we use performance profiles [25] to examine the impact of varying in VRSSD. A performance profile is conducted by running each parameterization with 300 randomized restarts with termination only once some pre-specified tolerance for accuracy has been reached. We count the proportion of realizations from each parameterization that achieves the specified tolerance within function evaluations where is the fewest function evaluations required in any of the trials, is twice as many function evaluations, etc. We use a function from the family defined in (LABEL:eq:_NesterovWorst) and fix . The objective value threshold we set is within of the optimal objective.

Figure LABEL:fig:_VRSSD-performanceprofile shows that the Lipschitz constant has little bearing on the relative performance of the different parameterizations, but the intrinsic dimension has a large role to play. This is so significant that the performance profiles are inverted from a high- to low- intrinsic dimension case. The top plots in Figure LABEL:fig:_VRSSD-performanceprofile paint a bleak picture for these stochastic methods: the more similar to gradient descent () the better their performance. Conversely, the bottom plots show that randomized methods provide a distinct advantage when the data is intrinsically low-dimensional. Recent work [30] takes a rigorous look at the manifold hypothesis which suggests that most real, high-dimensional data tend to lie near a low-dimensional manifold. This is corroborated in [94] where the authors provide theoretical rationale for the observed low-rank structure of large matrices. These two theoretical papers, along with ample empirical evidence [95, 3, 53, 93], suggest that the lower plots in Figure LABEL:fig:_VRSSD-performanceprofile, and the left plot in Figure LABEL:fig:_NesterovExample are more representative of problems that arise in practice. We have presented two extremes in an effort to provide a heuristic for choosing if the intrinsic dimension can be approximated. The paper [53] provides a method for estimating the intrinsic dimension via maximum likelihood. More recently, [16] provides a method for estimating the intrinsic dimension of an arbitrary data set by exploiting concentration inequalities of norms and angles for random samples in high dimensional space. In [16] the authors also conduct a thorough review of the literature and compare to several other methods for estimating intrinsic dimension.

### 3.2 Sparse Gaussian process parameter estimation

We apply the methods developed in Section LABEL:sect:_MainResults to hyperparameter estimation for Gaussian processes used in regression, where the goal is inference on a function based on noisy observations at points . The observations are modeled as

 yi=f(zi)+ϵi,

where the function is modeled as a zero-mean Gaussian process with covariance function

 Cov(f(zi),f(zj)) =K(zi,zj;θ),

and is a symmetric positive-definite kernel that depends on a vector of parameters . The parameters can be used to control various characteristics of the process, among them the variance (kernel amplitude) and the scale of the correlation between inputs (length-scale). The process is assumed to be independent of the noise vector with unknown variance . The covariance matrix of the vector will be written as

 Σf=Var(f)=⎛⎜ ⎜⎝K(z1,z1;θ)⋯K(z1,zn;θ)⋮⋱⋮K(zn,z1;θ)⋯K(zn,zn;θ)⎞⎟ ⎟⎠. (3.2)

Maximum likelihood estimates of the parameters are obtained by maximizing the log-marginal likelihood of of observations with density [99]:

 ℓ(Θ;y)=logpy(y;Θ)=−12y⊤(Σf+σ2I)−1y−12logdet(Σf+σ2I)−n2log2π, (3.3)

Difficulties arise in finding the optimal parameterization of Gaussian processes when the number of observations is large: due to the inversion and determinant calculation in equation (LABEL:eqn:_MLE), the cost of this maximization is . Various approximations exist, perhaps most popular among them in the machine learning community is that of [92]. The basic idea is as follows: Let , , be points in different from the original (these are called “inducing points”), and let . Let be a multivariate density function on , and define the density on , where is the conditional density of f given . The Gaussian density that minimizes the Kullback-Leibler divergence between the density and the posterior density of given leads to the following lower bound for the loglikelihood [92]:

 ℓ(Θ;y)≥F(˜z1,…˜zm,Θ)=˜ℓ(Θ;y)−12σ2tr(Var(f∣˜f)). (3.4)

Here is the loglikelihood of the multivariate Gaussian , where

 ˆΣf=Σf−Var(f∣˜f)=Cov(f,˜f)Σ−1˜fCov(˜f,f)

is the the Nyström approximation of introduced in [100]. Note that

 tr(Var(f∣˜f))=E∥E(f∣˜f)−f∥2.

That is, the Nyström approximation is controlled by the mean-squared error of the prediction of f based on . The trace term in (LABEL:eq:llbound) controls the size of this mean-square error. We note that the Nyström approximation is a low-rank non-negative update of and that optimal approximations of this form were studied in [88, 87] using Rao’s geodesic distance between SPD matrices as a measure of optimality. We do not pursue this approach here but recognize it as a potential alternative to the method of [92] that we use. Derivations of the conditional means and variances of a multivariate Gaussian can be found in, for example, [91].

Gradient-based methods are used to find an optimal placement of the inducing points by maximizing the lower bound in (LABEL:eq:llbound), which we re-state as a function of to be consistent with notation in previous sections:

 F(x)=˜ℓ(Θ;y)−12σ2tr(Var(f∣˜f)). (3.5)

Practically speaking, the optimization problem is -dimensional: represents the location of inducing points in dimensions, is the number of hyperparameters of the kernel, and we must estimate the noise variance. The benefit of moving to this high-dimensional optimization problem is that the time complexity is reduced to and the storage costs to . Consider that this objective function fits directly into the framework described by equation (LABEL:eq:_PDE): If we multiply (LABEL:eqn:_VariationalUpperBound) by -1 so that it becomes a minimization problem then the first term on the right-hand-side can be regarded as the loss functional, and the second term can be viewed as a regularization functional penalizing a large mean-square error. Figure LABEL:fig:_GPExample is a test problem using the same data as was used in [92] with fifteen inducing points. No recommendation is made in [92] regarding which optimization routine to use. In the left pane of Figure LABEL:fig:_GPExample we show the optimal result for the placement of the inducing points and the setting of the hyperparameters where the optimum is found using a BFGS solver on equation (LABEL:eqn:_VariationalUpperBound). The Gaussian process that arises from the initial settings is shown in the right pane of Figure LABEL:fig:_GPExample.

We use the variations of Algorithm LABEL:alg:varprod introduced in this paper to determine the placement of the inducing points and the settings of the hyperparameters for the same data set used in the original paper on variational learning of inducing points [92] and by its intellectual predecessor [85]. The results are compared with gradient descent and BFGS solvers. The problem is non-convex and does not satisfy the PL-inequality so the theory introduced in this paper does not provide insight into what to expect. As is common with non-convex optimization problems we perform multiple random restarts to improve the chance of converging to the global minimum.

The data set contains 200 training points. We use a squared-exponential kernel defined by . The parameters to be learned are the amplitude , the lengthscale ,the noise variance , and the locations of inducing points in so that our optimization problem is -dimensional. For testing purposes we can control the dimension of the optimization problem by increasing the number of inducing points. We acknowledge that for such a simple problem the use of a zeroth order method is not required as tools such as autograd [58] for Python are able to find the gradient of (LABEL:eqn:_MLE) with respect to each of the parameters by automatic differentiation; in general though, the gradient may not be available, even through automatic differentiation packages as not all functions have been incorporated into such packages. It is also possible to take individual derivatives by hand, but this is not feasible in more complex problems in high-dimensions. Once again, we use performance profiles [25] to determine the effect of varying the parameters for different problem sizes. We run each parameterization 300 times. Results for SSD for are shown in Figure LABEL:fig:_SSD-PerformanceProfile for 30 and 60 inducing points.

The cut-off threshold is of the distance between the objective function at the parameter initialization and at the optima, as found by BFGS. It is apparent that for this problem, is not a good option. Similarly, can be ruled out due to the fact that it underperforms and approximately 90% (resp. 99%) of the time in the 30- (resp. 60-) dimensional problem. The case claims the best single performance: in the fastest trial it is roughly 100 (resp. 800) times faster than BFGS for the 30- (resp. 60-) dimensional problem, but the variance of the performance for is high, and about 1% of the time it performs at least 10 times slower than BFGS (not pictured). On the other hand, beats BFGS by a similar factor and seems to be insulated from the high variance that was observed for . A few trials of and found their way to a local minima, resulting in the methods not achieving the target threshold.

Figure LABEL:fig:_GP-performance shows the performance for single trials on several problems of different dimension. For high-dimensional problems the performance of BFGS degrades due to the fact that at each iteration the Hessian update is only rank two. This acts doubly against BFGS because high-dimensional problems have more expensive function evaluations, and more iterations are required before the Hessian is reasonably approximated. In contrast, the performance of SSD does not appear to degrade noticeably as the dimension increases. The performance of VRSSD is impacted by the occasional expensive full gradient evaluations but not to the same extent as BFGS. The value for the memory parameter in VRSSD is labeled to signify that 100 iterations of SSD are taken before any variance reduction is used, after which the memory parameter becomes 10. This is in recognition of the fact that SSD descends very quickly until it is near the solution, at which point it becomes beneficial to make use of full gradient information.

### 3.3 Shape optimization

As our third numerical example, we consider a shape optimization problem involving a linear, elastic structure. Consider a square plate of size with a hole subject to uniform boundary traction =1, as illustrated in Fig. LABEL:fig:_HoleGeometry.

We adopt a discretize-then-optimize approach to solving the PDE-constrained optimization problem. The discretization and optimization steps do not generally commute and an optimize-then-discretize approach may be preferable for some types of problems [38, §2.9], but we do not pursue this question here.

Our goal is to identify a shape of the hole that minimizes the maximum stress along the direction over a quarter of the plate corresponding to . To this end, we parameterize the radius of the hole for a given (see Figure LABEL:fig:_HoleGeometry) via

 r(θ)=1+δd∑i=1i−1/2(ξisin(iθ)+νicos(iθ)), (3.6)

where is a user-defined parameter controlling the potential deviation from an n-gon of radius 1. For large values of it is possible to have a negative radius. The parameters that dictate the shape are and . Subscripts indicate the index of the vector. For our experiments we set so that the minimum possible radius of any particular control point is 0.2 at the initialization. We initialize the entries of and uniformly at random between 0 and 1. For each instance of and – equivalently – we generate a conforming triangular finite element mesh of the plate which we subsequently use within the FEniCS package [56] to solve for the maximum stress . A mesh refinement study is performed to ensure the spatial discretizatin errors are negligible. As we only model a quarter of the plate, we apply symmetry boundary conditions so that and displacements along and are zero. The Young’s modulus and Poisson’s ratio of the plate material are set to and , respectively.

As expected, BFGS outperforms gradient descent, but it is slow to provide a reasonable estimate of the Hessian and hence, relatively slow to converge. On low- or medium-dimensional problems this is not an issue, but since BFGS makes a rank-2 update to the Hessian at every iteration, and -dimensional problems of the form explained in this section with radius specified by (LABEL:eqn:_parametric-radius) have a rank- Hessian. Thus, high-dimensional problems may require many iterations before the Hessian is well-approximated.

In the 100-dimensional problem in the left plot of Figure LABEL:fig:_SSD-Plate we notice convergence of SSD and VRSSD after few function evaluations; so few, in fact, that the difference in performance between SSD and VRSSD likely has more to do with random chance than variance reduction. In multiple restarts (not shown), similar performance was observed wherein the methods had converged before any variance reduction had occurred. In all cases, convergence occurs by the time gradient descent of BFGS are able to take more than a couple of steps.

In the 200-dimensional problem in the right plot of Figure LABEL:fig:_SSD-Plate the progress of gradient descent, SSD, and BFGS stall prematurely, apparently settling into local optima at different locations despite being initialized identically. The figure is somewhat deceptive as each method is indeed still descending along shallow valleys of the objective function as shown in the inset. VRSSD does not appear to be as susceptible to getting caught in such valleys for reasons we do not yet fully understand. We hypothesize that there are two phenomena at play. First, as the -dimensional subspace along which SSD and VRSSD descend changes with each iteration, they explore parameter space more erratically than deterministic methods, making them less likely to get funnelled into long, shallow basins; this is intuitively similar to the recent line of research which suggests that noisy perturbation of iterative algorithms helps avoid saddle points [34]. Second, VRSSD uses past information from a full-gradient evaluation that push it in directions that may not be optimal from a single-step perspective but that may help it traverse these valleys in a way that is heuristically similar to the heavy ball method of Polyak [76]; this phenomena has recently been explored in the context of non-convex minimization, e.g., [49]. Since SSD still appears to get caught in these low-gradient valleys, it is apparently the combination of these two reasons, the second of them, or some as-yet-undescribed property of VRSSD that allows it to avoid them. It could also be the case that this particular problem is amenable to VRSSD; however, further investigation on different problems is required to verify the exact reasons that VRSSD appears to perform so well.

## 4 Conclusions

We have presented a generalization of coordinate descent and gradient descent algorithms and have shown asymptotic convergence at a linear rate under various convexity assumptions. We have demonstrated empirical improvements compared to the status quo for several practical problems that do not necessarily adhere to the assumptions required by the theory. We have provided analysis that puts the ideas of the SVRG algorithm [50] in a stochastic subspace framework, making it a feasible alternative to deterministic gradient-based methods for problems that cannot be represented with a finite-sum structure. This analysis opens the doors to adapting other stochastic iterative methods designed for an ERM framework into a more general form. We also showed that any stochastic algorithm that converges in expectation at a linear rate also converges almost surely.

In the future we plan to adapt other first-order stochastic optimization techniques such as stochastic quasi-Newton [62] to the stochastic subspace descent framework. The Haar-distributed random matrices may not be the optimal choice for subspace projections, and some clever adaptive scheme could be beneficial for determining the decent directions; these ideas have been discussed at length in the coordinate descent literature [78, 67], and similar techniques may be available within the SSD framework. We would like to explore the feasibility of implementing our methods in parallel as has been discussed in the coordinate descent case in [73]. A computationally straightforward extension may allow sketching methods (see e.g. [75]) to improve our results with minimal programmatic overhead, but analysis must be conducted to confirm the theoretical properties of such modifications. The analysis we have performed thus far does not explain some phenomena we have observed in our experiments; in particular, it appears as though the intrinsic dimension rather than the ambient dimension dictates the convergence rate of our methods, and that VRSSD is resistant to getting trapped in the shallow basins common to ill-conditioned non-convex problems.

Finally, recent work on a universal “catalyst” scheme [54] also applies to our method, allowing for Nesterov-style acceleration without requiring additional knowledge of the Lipschitz constants along any particular direction.

## A Preliminary results

We summarize results from optimization and probability used in the proofs of convergence.

###### Lemma A.1 (A property of Lipschitz-continuous first derivatives).

Let be continuously-differentiable with -Lipschitz first derivative. Then for any ,

 |f(y)−f(x)−⟨∇f(x),y−x⟩|≤λ2∥y−x∥2.

The proof can be found in [68, pg. 25-26].

###### Lemma A.2 (Strong-convexity implies PL-inequality).

Let be a -strongly convex, continuously-differentiable function. Denote the unique minimizer of by . Then:

 f(x)−f(x∗)≤12γ∥∇f(x)∥2. (A.1)

Inequality (LABEL:PLineq) is the PL-inequality. The proof is simple and can be found in the Appendix of [42].

###### Lemma A.3 (A characterization of convex functions).

A function is convex with -Lipschitz derivative if and only if for all

 ⟨∇f(x)−∇f(y),x−y⟩≥1λ∥∇f(x)−∇f(y)∥2≥0.

The proof can be found in [68, pg. 56]. If the function is strongly convex then the bound is sharpened according to the following theorem, the proof of which can be found in [68, pg. 62].

###### Theorem A.4 (Strongly-convex functions).

If a function is -strongly convex with -Lipschitz derivative then for all

We now recall some basic definitions and results regarding convergence of random variables. A sequence of random vectors is said to converge a.s. to a random vector if and only if . It is said to converge in probability if and only if for all , as . It converges in for some integer if and only if . We will write , , and , respectively.

It is readily apparent that if and only if for all

 limn→∞P(⋂k≥n{∥xk−x∥<ϵ})=1

as [31]. It follows from this characterization that if . By subadditivity,

 ∑nP(∥xn−x∥>ϵ)<∞∀ ϵ>0⟹xna.s.⟶x. (A.2)

Finally, by Markov’s inequality, if , then .

## B Proofs of main results

### Proof of Theorem LABEL:thm:convergence

Define the filtration , and . Because is continuously-differentiable with a -Lipschitz derivative, Lemma LABEL:Lipschitz yields

 f(xk+1)≤f(xk)+∇f(xk)T(xk+1−xk)+λ2∥xk+1−xk∥2 (B.1)

Let be the error for a particular . Then, equations (LABEL:eq:_iterations) and (LABEL:Taylor) yield:

 fe(xk+1)−fe(xk) ≤−α⟨∇f(xk), PkPTk∇f(xk)⟩+α2λ2⟨PkPTk∇f(xk), PkPTk∇f(xk)⟩ =−α⟨∇f(xk), PkPTk∇f(xk)⟩+dα2λ2ℓ⟨∇f(xk), PkPTk∇f(xk)⟩ =(−α+dα2λ2ℓ)⟨∇f(xk), PkPTk∇f(xk)⟩ =αλ⟨∇f(xk), PkPTk∇f(xk)⟩withαλ=(−α+dα2λ2ℓ),

where we have used the fact that . We can choose such that ; that is, . With this choice the right-hand side is non-positive and the errors are non-increasing. Since the error is bounded below by zero the sequence converges almost surely but the actual limit remains to be determined. Furthermore, since the sequence is bounded above by , Lebesgue’s dominated convergence implies convergence of the sequence in . To find the limit we take conditional expectations of both sides to get

 E[fe(xk+1)∣Fk]≤αλE[⟨∇f(xk),PkPTk∇f(xk)⟩∣∣∣Fk]+fe(xk).

Since is -measurable, the gradients can be pulled out of the conditional expectation, the expectation can be passed through due to linearity. Noting that , this leaves us with

 E[fe(xk+1)∣Fk]≤αλ∥∇f(xk)∥2+fe(xk). (B.2)

The first term on the right-hand side in equation (LABEL:intermediate) is negative so the PL-inequality leads to:

 E[fe(xk+1)∣Fk]≤2γαλfe(xk)+fe(xk)=(1+2γαλ)fe(xk).

Recursive application yields

 E[f(xk+1)−f∗∣Fk]≤(1−2γαλ)k+1(f(x0)−f∗).

Taking an expectation of both sides yields

 Ef(xk+1)−f∗≤(1+2γαλ)k+1(f(x0)−f∗).

Any step-size forces the right-hand side to converge to zero. Thus, since for some and , we have both and .

### Proof of Corollary LABEL:corr:strong-convexity part (i)

By Lemma LABEL:PLLemma, the strong-convexity assumed by this corollary implies the assumptions of Theorem LABEL:thm:convergence, so that . Now by strong-convexity,

 f(xk)−f(x∗)≥γ2∥x∗−xk∥.

Since the left-hand side converges almost surely to zero and , we have .

### Proof of Corollary LABEL:corr:strong-convexity part (ii)

We begin by providing an upper bound for . Rearranging the terms in equation (LABEL:intermediate) we have

 (B.3)

Combing (LABEL:UpperBound) with (LABEL:PLineq) we get

That is,

 E[fe(xk+1)∣Fk]≤(1+2γαλ)fe(xk). (B.4)

Repeated recursion then yields

format: plain


text:
Fit models with differing numbers of regimes to trend data

fit_regimes(
y,
sds = NULL,
n_regimes = 2,
iter = 2000,
thin = 1,
chains = 1,
...
)

## Arguments

y Data, time series or trend from fitted DFA model. Optional time series of standard deviations of estimates. If passed in, residual variance not estimated. Defaults to NULL. Number of regimes to evaluate, defaults 2 MCMC iterations, defaults to 2000. MCMC thinning rate, defaults to 1. MCMC chains, defaults to 1 (note that running multiple chains may result in a label switching problem where the regimes are identified with different IDs across chains). Other parameters to pass to rstan::sampling().

## Examples

data(Nile)
fit_regimes(log(Nile), iter = 50, n_regimes = 1)
#>
#> SAMPLING FOR MODEL 'regime_1' NOW (CHAIN 1).
#> Chain 1:
#> Chain 1: Gradient evaluation took 1.1e-05 seconds
#> Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.11 seconds.
#> Chain 1:
#> Chain 1:
#> Chain 1: WARNING: There aren't enough warmup iterations to fit the
#> Chain 1:          three stages of adaptation as currently configured.
#> Chain 1:          Reducing each adaptation stage to 15%/75%/10% of
#> Chain 1:          the given number of warmup iterations:
#> Chain 1:            init_buffer = 3
#> Chain 1:            adapt_window = 20
#> Chain 1:            term_buffer = 2
#> Chain 1:
#> Chain 1: Iteration:  1 / 50 [  2%]  (Warmup)
#> Chain 1: Iteration:  5 / 50 [ 10%]  (Warmup)
#> Chain 1: Iteration: 10 / 50 [ 20%]  (Warmup)
#> Chain 1: Iteration: 15 / 50 [ 30%]  (Warmup)
#> Chain 1: Iteration: 20 / 50 [ 40%]  (Warmup)
#> Chain 1: Iteration: 25 / 50 [ 50%]  (Warmup)
#> Chain 1: Iteration: 26 / 50 [ 52%]  (Sampling)
#> Chain 1: Iteration: 30 / 50 [ 60%]  (Sampling)
#> Chain 1: Iteration: 35 / 50 [ 70%]  (Sampling)
#> Chain 1: Iteration: 40 / 50 [ 80%]  (Sampling)
#> Chain 1: Iteration: 45 / 50 [ 90%]  (Sampling)
#> Chain 1: Iteration: 50 / 50 [100%]  (Sampling)
#> Chain 1:
#> Chain 1:  Elapsed Time: 0.00095 seconds (Warm-up)
#> Chain 1:                0.000839 seconds (Sampling)
#> Chain 1:                0.001789 seconds (Total)
#> Chain 1: #> Warning: The largest R-hat is 1.52, indicating chains have not mixed.
#> Running the chains for more iterations may help. See
#> http://mc-stan.org/misc/warnings.html#r-hat#> Warning: Bulk Effective Samples Size (ESS) is too low, indicating posterior means and medians may be unreliable.
#> Running the chains for more iterations may help. See
#> http://mc-stan.org/misc/warnings.html#bulk-ess#> Warning: Tail Effective Samples Size (ESS) is too low, indicating posterior variances and tail quantiles may be unreliable.
#> Running the chains for more iterations may help. See
#> http://mc-stan.org/misc/warnings.html#tail-ess#> Warning: Some Pareto k diagnostic values are too high. See help('pareto-k-diagnostic') for details.#> $model #> Inference for Stan model: regime_1. #> 1 chains, each with iter=50; warmup=25; thin=1; #> post-warmup draws per chain=25, total post-warmup draws=25. #> #> mean se_mean sd 2.5% 25% 50% 75% 97.5% n_eff Rhat #> mu_k 6.81 0.00 0.02 6.77 6.79 6.81 6.82 6.83 25 0.96 #> sigma_k 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[1] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[2] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[3] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[4] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[5] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[6] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[7] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[8] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[9] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[10] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[11] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[12] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[13] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[14] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[15] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[16] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[17] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[18] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[19] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[20] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[21] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[22] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[23] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[24] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[25] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[26] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[27] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[28] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[29] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[30] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[31] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[32] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[33] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[34] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[35] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[36] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[37] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[38] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[39] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[40] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[41] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[42] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[43] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[44] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[45] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[46] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[47] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[48] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[49] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[50] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[51] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[52] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[53] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[54] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[55] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[56] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[57] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[58] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[59] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[60] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[61] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[62] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[63] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[64] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[65] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[66] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[67] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[68] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[69] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[70] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[71] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[72] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[73] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[74] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[75] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[76] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[77] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[78] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[79] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[80] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[81] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[82] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[83] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[84] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[85] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[86] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[87] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[88] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[89] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[90] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[91] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[92] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[93] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[94] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[95] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[96] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[97] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[98] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[99] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> sigmas[100] 0.18 0.01 0.02 0.16 0.16 0.19 0.19 0.21 5 1.40 #> log_lik[1] 0.07 0.02 0.13 -0.14 -0.02 0.07 0.18 0.24 35 1.02 #> log_lik[2] -0.18 0.03 0.15 -0.43 -0.29 -0.18 -0.05 0.04 23 1.14 #> log_lik[3] 0.72 0.04 0.11 0.56 0.64 0.71 0.82 0.88 6 1.19 #> log_lik[4] -0.54 0.06 0.20 -0.84 -0.72 -0.53 -0.35 -0.24 10 1.29 #> log_lik[5] -0.18 0.03 0.15 -0.43 -0.29 -0.18 -0.05 0.04 23 1.14 #> log_lik[6] -0.18 0.03 0.15 -0.43 -0.29 -0.18 -0.05 0.04 23 1.14 #> log_lik[7] 0.61 0.02 0.07 0.48 0.55 0.61 0.67 0.72 10 1.25 #> log_lik[8] -0.69 0.08 0.22 -1.03 -0.88 -0.69 -0.48 -0.36 8 1.34 #> log_lik[9] -1.91 0.18 0.42 -2.59 -2.13 -1.98 -1.53 -1.23 5 1.53 #> log_lik[10] -0.05 0.02 0.14 -0.28 -0.13 -0.05 0.05 0.14 32 1.07 #> log_lik[11] 0.64 0.04 0.11 0.48 0.55 0.64 0.73 0.81 8 1.09 #> log_lik[12] 0.77 0.04 0.10 0.61 0.70 0.74 0.87 0.91 5 1.28 #> log_lik[13] 0.13 0.02 0.12 -0.08 0.04 0.13 0.25 0.29 35 1.00 #> log_lik[14] 0.64 0.04 0.11 0.48 0.56 0.65 0.73 0.81 8 1.09 #> log_lik[15] 0.56 0.03 0.11 0.38 0.47 0.56 0.62 0.72 10 1.03 #> log_lik[16] 0.73 0.04 0.11 0.57 0.65 0.71 0.83 0.89 6 1.20 #> log_lik[17] -0.32 0.04 0.17 -0.59 -0.46 -0.32 -0.16 -0.07 15 1.20 #> log_lik[18] 0.55 0.02 0.08 0.43 0.49 0.56 0.61 0.66 20 1.12 #> log_lik[19] 0.73 0.04 0.10 0.57 0.65 0.71 0.83 0.89 6 1.20 #> log_lik[20] -0.05 0.02 0.14 -0.28 -0.13 -0.05 0.05 0.14 32 1.07 #> log_lik[21] 0.18 0.02 0.12 -0.02 0.10 0.18 0.29 0.33 31 0.98 #> log_lik[22] -0.54 0.06 0.20 -0.84 -0.72 -0.53 -0.35 -0.24 10 1.29 #> log_lik[23] -0.12 0.03 0.15 -0.36 -0.21 -0.12 0.00 0.09 29 1.10 #> log_lik[24] -0.85 0.09 0.24 -1.23 -1.05 -0.88 -0.62 -0.48 7 1.39 #> log_lik[25] -0.93 0.10 0.26 -1.34 -1.13 -0.96 -0.69 -0.53 7 1.41 #> log_lik[26] -0.61 0.07 0.21 -0.93 -0.80 -0.60 -0.42 -0.30 9 1.32 #> log_lik[27] 0.52 0.03 0.11 0.34 0.43 0.53 0.58 0.69 11 1.00 #> log_lik[28] 0.18 0.02 0.12 -0.02 0.10 0.18 0.29 0.33 31 0.98 #> log_lik[29] 0.41 0.02 0.09 0.29 0.33 0.39 0.49 0.55 35 0.98 #> log_lik[30] 0.70 0.03 0.08 0.56 0.64 0.71 0.74 0.83 6 1.43 #> log_lik[31] 0.77 0.04 0.09 0.62 0.71 0.73 0.86 0.90 5 1.45 #> log_lik[32] -0.30 0.08 0.23 -0.69 -0.43 -0.27 -0.10 0.05 9 1.05 #> log_lik[33] 0.76 0.04 0.10 0.61 0.68 0.73 0.86 0.91 6 1.26 #> log_lik[34] 0.68 0.03 0.08 0.54 0.62 0.70 0.72 0.80 6 1.40 #> log_lik[35] -0.22 0.07 0.21 -0.58 -0.33 -0.20 -0.04 0.11 10 1.04 #> log_lik[36] 0.78 0.04 0.10 0.64 0.71 0.75 0.90 0.92 5 1.34 #> log_lik[37] -0.32 0.08 0.23 -0.73 -0.46 -0.30 -0.12 0.03 9 1.05 #> log_lik[38] 0.56 0.03 0.11 0.38 0.47 0.56 0.62 0.72 10 1.03 #> log_lik[39] 0.44 0.03 0.11 0.24 0.34 0.46 0.51 0.60 15 0.97 #> log_lik[40] 0.71 0.04 0.11 0.55 0.63 0.70 0.81 0.87 6 1.17 #> log_lik[41] 0.68 0.03 0.08 0.54 0.62 0.69 0.71 0.80 6 1.39 #> log_lik[42] 0.04 0.04 0.16 -0.23 -0.07 0.02 0.17 0.29 13 0.99 #> log_lik[43] -6.50 0.66 1.50 -8.88 -7.78 -5.99 -5.32 -4.50 5 1.29 #> log_lik[44] 0.65 0.03 0.08 0.52 0.59 0.66 0.70 0.77 7 1.34 #> log_lik[45] -0.21 0.07 0.21 -0.57 -0.32 -0.19 -0.03 0.12 10 1.04 #> log_lik[46] 0.07 0.02 0.13 -0.14 -0.02 0.07 0.18 0.24 35 1.02 #> log_lik[47] 0.18 0.02 0.12 -0.02 0.10 0.18 0.29 0.33 31 0.98 #> log_lik[48] 0.68 0.03 0.08 0.54 0.62 0.69 0.72 0.80 6 1.39 #> log_lik[49] 0.35 0.02 0.10 0.21 0.27 0.33 0.44 0.50 30 0.96 #> log_lik[50] 0.64 0.03 0.07 0.51 0.58 0.64 0.69 0.76 8 1.32 #> log_lik[51] 0.37 0.02 0.10 0.24 0.30 0.35 0.46 0.52 33 0.97 #> log_lik[52] 0.71 0.03 0.08 0.57 0.66 0.72 0.76 0.84 5 1.45 #> log_lik[53] 0.75 0.04 0.09 0.61 0.70 0.73 0.83 0.89 5 1.47 #> log_lik[54] 0.75 0.04 0.08 0.61 0.70 0.73 0.82 0.88 5 1.47 #> log_lik[55] -0.25 0.07 0.22 -0.63 -0.37 -0.23 -0.06 0.08 10 1.04 #> log_lik[56] 0.71 0.03 0.08 0.57 0.66 0.72 0.76 0.84 5 1.45 #> log_lik[57] 0.20 0.03 0.13 -0.01 0.11 0.18 0.31 0.40 18 0.96 #> log_lik[58] 0.53 0.02 0.08 0.42 0.47 0.55 0.60 0.65 24 1.10 #> log_lik[59] 0.48 0.03 0.11 0.29 0.39 0.49 0.55 0.64 13 0.99 #> log_lik[60] 0.31 0.02 0.11 0.16 0.23 0.29 0.41 0.48 26 0.96 #> log_lik[61] 0.45 0.01 0.09 0.34 0.37 0.45 0.52 0.58 35 1.01 #> log_lik[62] 0.75 0.04 0.09 0.61 0.70 0.73 0.83 0.89 5 1.47 #> log_lik[63] 0.71 0.03 0.08 0.57 0.66 0.72 0.76 0.84 5 1.45 #> log_lik[64] 0.76 0.04 0.10 0.60 0.68 0.73 0.85 0.91 6 1.25 #> log_lik[65] 0.67 0.04 0.11 0.51 0.59 0.67 0.76 0.84 7 1.12 #> log_lik[66] 0.78 0.04 0.10 0.64 0.72 0.75 0.89 0.92 5 1.40 #> log_lik[67] 0.64 0.03 0.07 0.51 0.59 0.65 0.70 0.76 8 1.32 #> log_lik[68] 0.59 0.04 0.11 0.42 0.51 0.59 0.67 0.76 9 1.05 #> log_lik[69] 0.39 0.02 0.09 0.27 0.31 0.37 0.47 0.54 35 0.97 #> log_lik[70] -0.53 0.10 0.28 -1.00 -0.71 -0.52 -0.28 -0.12 8 1.08 #> log_lik[71] -0.92 0.13 0.36 -1.54 -1.19 -0.89 -0.60 -0.42 7 1.12 #> log_lik[72] 0.72 0.03 0.08 0.57 0.66 0.72 0.76 0.84 5 1.45 #> log_lik[73] 0.61 0.02 0.07 0.48 0.55 0.61 0.67 0.71 10 1.24 #> log_lik[74] 0.18 0.03 0.13 -0.03 0.08 0.16 0.29 0.39 17 0.97 #> log_lik[75] 0.56 0.02 0.08 0.44 0.50 0.57 0.62 0.67 18 1.14 #> log_lik[76] 0.48 0.03 0.11 0.29 0.39 0.49 0.55 0.64 13 0.99 #> log_lik[77] 0.75 0.04 0.08 0.60 0.69 0.73 0.82 0.88 5 1.47 #> log_lik[78] 0.77 0.04 0.09 0.62 0.71 0.73 0.86 0.90 5 1.45 #> log_lik[79] 0.72 0.04 0.08 0.58 0.67 0.72 0.77 0.85 5 1.46 #> log_lik[80] 0.78 0.04 0.09 0.64 0.72 0.75 0.88 0.92 5 1.42 #> log_lik[81] 0.20 0.03 0.13 -0.01 0.11 0.18 0.31 0.40 18 0.96 #> log_lik[82] 0.24 0.03 0.12 0.05 0.16 0.23 0.35 0.43 20 0.96 #> log_lik[83] 0.70 0.03 0.08 0.55 0.64 0.70 0.73 0.82 6 1.42 #> log_lik[84] 0.44 0.03 0.11 0.24 0.34 0.46 0.51 0.60 15 0.97 #> log_lik[85] 0.78 0.04 0.10 0.64 0.71 0.75 0.89 0.92 5 1.33 #> log_lik[86] 0.67 0.04 0.11 0.50 0.58 0.66 0.76 0.83 7 1.12 #> log_lik[87] 0.54 0.02 0.08 0.42 0.48 0.56 0.60 0.65 23 1.11 #> log_lik[88] 0.78 0.04 0.10 0.63 0.71 0.75 0.88 0.92 5 1.32 #> log_lik[89] 0.70 0.04 0.11 0.53 0.61 0.68 0.79 0.86 7 1.15 #> log_lik[90] 0.62 0.02 0.07 0.49 0.56 0.62 0.68 0.73 9 1.26 #> log_lik[91] 0.56 0.03 0.11 0.38 0.47 0.56 0.62 0.72 10 1.03 #> log_lik[92] 0.78 0.04 0.10 0.64 0.71 0.74 0.90 0.92 5 1.37 #> log_lik[93] 0.78 0.04 0.10 0.64 0.72 0.74 0.89 0.92 5 1.39 #> log_lik[94] -0.25 0.04 0.16 -0.51 -0.37 -0.25 -0.11 -0.01 18 1.17 #> log_lik[95] 0.78 0.04 0.10 0.64 0.71 0.74 0.90 0.92 5 1.35 #> log_lik[96] 0.21 0.03 0.13 0.02 0.13 0.20 0.32 0.41 19 0.96 #> log_lik[97] 0.78 0.04 0.10 0.64 0.71 0.75 0.89 0.92 5 1.33 #> log_lik[98] -0.04 0.05 0.17 -0.33 -0.15 -0.04 0.11 0.24 12 1.01 #> log_lik[99] -0.08 0.05 0.18 -0.39 -0.19 -0.08 0.08 0.21 11 1.01 #> log_lik[100] 0.16 0.03 0.13 -0.05 0.06 0.15 0.27 0.38 17 0.97 #> lp__ 113.34 0.44 1.19 111.43 112.13 113.48 114.37 114.92 7 1.50 #> #> Samples were drawn using NUTS(diag_e) at Tue Sep 28 10:44:14 2021. #> For each parameter, n_eff is a crude measure of effective sample size, #> and Rhat is the potential scale reduction factor on split chains (at #> convergence, Rhat=1). #> #>$y
#> Time Series:
#> Start = 1871
#> End = 1970
#> Frequency = 1
#>   [1] 7.021084 7.056175 6.870053 7.098376 7.056175 7.056175 6.700731 7.114769
#>   [9] 7.222566 7.038784 6.902743 6.840547 7.012115 6.901737 6.927558 6.866933
#>  [17] 7.073270 6.683361 6.864848 7.038784 7.003065 7.098376 7.047517 7.130899
#>  [25] 7.138867 7.106606 6.937314 7.003065 6.651572 6.733402 6.773080 6.542472
#>  [33] 6.845880 6.725034 6.552508 6.820016 6.539586 6.927558 6.956545 6.876265
#>  [41] 6.722630 6.587550 6.122493 6.714171 6.553933 7.021084 7.003065 6.723832
#>  [49] 6.638568 6.710523 6.643790 6.739337 6.761573 6.759255 6.548219 6.739337
#>  [57] 6.612041 6.679599 6.946976 6.632002 6.660575 6.762730 6.739337 6.850126
#>  [65] 6.891626 6.799056 6.711740 6.917706 6.647688 6.516193 6.475433 6.740519
#>  [73] 6.699500 6.609349 6.685861 6.946976 6.756932 6.773080 6.742881 6.791221
#>  [81] 6.612041 6.618739 6.731018 6.956545 6.822197 6.893656 6.680855 6.827629
#>  [89] 6.882437 6.703188 6.927558 6.809039 6.803505 7.064759 6.815640 6.614726
#>  [97] 6.823286 6.576470 6.570883 6.606650
#>
#> \$looic
#> [1] -46.52446
#>


text:
## Construct Linear Time Invariant Models

Model Predictive Control Toolbox™ software supports the same LTI model formats as does Control System Toolbox™ software. You can use whichever is most convenient for your application and convert from one format to another. For more details, see Basic Models.

### Transfer Function Models

A transfer function (TF) relates a particular input/output pair of (possibly vector) signals. For example, if u(t) is a plant input and y(t) is an output, the transfer function relating them might be:

`$\frac{Y\left(s\right)}{U\left(s\right)}=G\left(s\right)=\frac{s+2}{{s}^{2}+s+10}{e}^{-1.5s}$`

This TF consists of a numerator polynomial, s+2, a denominator polynomial, s2+s+10, and a delay, which is 1.5 time units here. You can define G using Control System Toolbox `tf` function:

```Gtf1 = tf([1 2], [1 1 10],'OutputDelay',1.5) ```
```Transfer function: s + 2 exp(-1.5*s) * ------------ s^2 + s + 10 ```

### Zero/Pole/Gain Models

Like the TF format, the zero/pole/gain (ZPK) format relates an input/output pair of (possibly vector) signals. The difference is that the ZPK numerator and denominator polynomials are factored, as in

`$G\left(s\right)=2.5\frac{s+0.45}{\left(s+0.3\right)\left(s+0.1+0.7i\right)\left(s+0.1-0.7i\right)}$`

(zeros and/or poles are complex numbers in general).

You define the ZPK model by specifying the zero(s), pole(s), and gain as in

```poles = [-0.3, -0.1+0.7*i, -0.1-0.7*i]; Gzpk1 = zpk(-0.45,poles,2.5); ```

### State-Space Models

The state-space format is convenient if your model is a set of LTI differential and algebraic equations.

The linearized model of a Continuously Stirred Tank Reactor (CSTR) is shown in CSTR Model. In the model, the first two state variables are the concentration of reagent (here referred to as CA and measured in kmol/m3) and the temperature of the reactor (here referred to as T, measured in K), while the first two inputs are the coolant temperature (Tc, measured in K, used to control the plant), and the inflow feed reagent concentration CAf, measured in kmol/m3, (often considered as unmeasured disturbance).

A state-space model can be defined as follows:

```A = [ -5 -0.3427; 47.68 2.785]; B = [ 0 1 0.3 0]; C = [0 1 1 0]; D = zeros(2,2); CSTR = ss(A,B,C,D); ```

This defines a continuous-time state-space model stored in the variable `CSTR`. The model is continuous time because no sampling time was specified, and therefore a default sampling value of zero (which means that the model is continuous time) is assumed. You can also specify discrete-time state-space models. You can specify delays in both continuous-time and discrete-time models.

### LTI Object Properties

The `ss` function in the last line of the above code creates a state-space model, `CSTR`, which is an LTI object. The `tf` and `zpk` commands described in Transfer Function Models and Zero/Pole/Gain Models also create LTI objects. Such objects contain the model parameters as well as optional properties.

#### Additional LTI Input and Output Properties

The following code sets some optional input and outputs names and properties for the `CSTR` state-space object:

```CSTR.InputName = {'T_c', 'C_A_f'}; % set names of input signals CSTR.OutputName = {'T', 'C_A'}; % set names of output signals CSTR.StateName = {'C_A', 'T'}; % set names of state variables % assign input and output signals to different MPC categories CSTR=setmpcsignals(CSTR,'MV',1,'UD',2,'MO',1,'UO',2)```

The first three lines specify labels for the input, output and state variables. The next four specify the signal type for each input and output. The designations `MV`, `UD`, `MO`, and `UO` mean manipulated variable, unmeasured disturbance, measured output, and unmeasured output. (See MPC Signal Types for definitions.) For example, the code specifies that input 2 of model `CSTR` is an unmeasured disturbance. The last line causes the LTI object to be displayed, generating the following lines in the MATLAB® Command Window:

```CSTR = A = C_A T C_A -5 -0.3427 T 47.68 2.785 B = T_c C_A_f C_A 0 1 T 0.3 0 C = C_A T T 0 1 C_A 1 0 D = T_c C_A_f T 0 0 C_A 0 0 Input groups: Name Channels Manipulated 1 Unmeasured 2 Output groups: Name Channels Measured 1 Unmeasured 2 Continuous-time state-space model.```

#### Input and Output Names

The optional `InputName` and `OutputName` properties affect the model displays, as in the above example. The software also uses the `InputName` and `OutputName` properties to label plots and tables. In that context, the underscore character causes the next character to be displayed as a subscript.

#### Input and Output Types

As mentioned in MPC Signal Types, Model Predictive Control Toolbox software supports three input types and two output types. In a Model Predictive Control Toolbox design, designation of the input and output types determines the controller dimensions and has other important consequences.

For example, suppose your plant structure were as follows:

Plant Inputs

Plant Outputs

Two manipulated variables (MVs)

Three measured outputs (MOs)

One measured disturbance (MD)

Two unmeasured outputs (UOs)

Two unmeasured disturbances (UDs)

The resulting controller has four inputs (the three MOs and the MD) and two outputs (the MVs). It includes feedforward compensation for the measured disturbance, and assumes that you wanted to include the unmeasured disturbances and outputs as part of the regulator design.

If you didn't want a particular signal to be treated as one of the above types, you could do one of the following:

• Eliminate the signal before using the model in controller design.

• For an output, designate it as unmeasured, then set its weight to zero.

• For an input, designate it as an unmeasured disturbance, then define a custom state estimator that ignores the input.

Note

By default, the software assumes that unspecified plant inputs are manipulated variables, and unspecified outputs are measured. Thus, if you didn't specify signal types in the above example, the controller would have four inputs (assuming all plant outputs were measured) and five outputs (assuming all plant inputs were manipulated variables).

Note

Since the D matrix is zero, the output does not instantly respond to change in the input. The Model Predictive Control Toolbox software prohibits direct (instantaneous) feedthrough from a manipulated variable to an output. For example, the CSTR state-space model could include direct feedthrough from the unmeasured disturbance, CAf, to either CA or T but direct feedthrough from Tc to either (measured or not) output would violate this restriction. When the model has a direct feedthrough from Tc, you can add a small delay at this input to circumvent the problem.

For `CSTR`, the default Model Predictive Control Toolbox assumptions are incorrect. You must set its `InputGroup` and `OutputGroup` properties, as illustrated in the above code, or modify the default settings when you load the model into MPC Designer.

Use `setmpcsignals` to make type definition. For example:

```CSTR = setmpcsignals(CSTR,'UD',2,'UO',2); ```

sets `InputGroup` and `OutputGroup` to the same values as in the previous example. The `CSTR` display would then include the following lines:

```Input groups: Name Channels Unmeasured 2 Manipulated 1 Output groups: Name Channels Unmeasured 2 Measured 1 ```

Notice that `setmpcsignals` sets unspecified inputs to `Manipulated` and unspecified outputs to `Measured`.

### LTI Model Characteristics

Control System Toolbox software provides functions for analyzing LTI models. Some of the more commonly used are listed below. Type the example code at the MATLAB prompt to see how they work for the `CSTR` example.

Example

Intended Result

`damp(CSTR)`Displays the damping ratio, natural frequency, and time constant of the poles of `CSTR`.
`pzmap(CSTR)`

Plots the poles and zeros of `CSTR`.

`pole(CSTR)`

Calculates the poles of `CSTR` (to check stability, etc.).

`tzero(CSTR)`

Calculates the transmission zeros of `CSTR`.

`dcgain(CSTR)`

Calculates the steady state gain matrix of `CSTR`.

`step(CSTR)`

Plots unit-step responses of `CSTR`.

`stepinfo(CSTR)`Calculates rise time, settling time, and other step-response characteristics of `CSTR`.
`impulse(CSTR)`

Plots the unit-impulse responses of `CSTR`.

`sigma(CSTR)`

Plots the singular values of the frequency response of `CSTR`.

`bode(CSTR)`

Plots the Bode frequency responses of `CSTR`.

`nyquist(CSTR)`

Plots the Nyquist frequency responses of `CSTR`.

`nichols(CSTR)`

Plots the Nichols frequency responses of `CSTR`.

`linearSystemAnalyzer(CSTR)`

Opens the Linear System Analyzer with the `CSTR` model loaded. You can then display model characteristics by making menu selections.


text:
# Problem: What is the overall order of the following reaction, given the rate law?2NO(g) + H2(g) → N2(g) + 2H2O(g)Rate = k [NO]2[H2]A. 1st orderB. 2nd orderC. 3rd orderD. 4th orderE. 0th order

🤓 Based on our data, we think this question is relevant for Professor Taylor-Perry's class at SCAR.

###### Problem Details

What is the overall order of the following reaction, given the rate law?

2NO(g) + H2(g) → N2(g) + 2H2O(g)

Rate = k [NO]2[H2]

A. 1st order

B. 2nd order

C. 3rd order

D. 4th order

E. 0th order