# The Catenary Problem

## Introduction

A chain with uniformly distributed mass hangs from the endpoints \((0,1)\) and \((1,1)\) on a 2-D plane. Gravitational force acts in the negative \(y\) direction. Our goal is to find the shape of the chain in equilibrium, which is equivalent to determining the \((x,y)\) coordinates of every point along its curve when its potential energy is minimized.

This is the famous catenary problem.

## A Discrete Version

To formulate as an optimization problem, we parameterize the chain by its arc length and divide it into \(m\) discrete links. The length of each link must be no more than \(h > 0\). Since mass is uniform, the total potential energy is simply the sum of the \(y\)-coordinates. Therefore, our (discretized) problem is

\[ \begin{array}{ll} \underset{x,y}{\mbox{minimize}} & \sum_{i=1}^m y_i \\ \mbox{subject to} & x_1 = 0, \quad y_1 = 1, \quad x_m = 1, \quad y_m = 1 \\ & (x_{i+1} - x_i)^2 + (y_{i+1} - y_i)^2 \leq h^2, \quad i = 1,\ldots,m-1 \end{array} \]

with variables \(x \in {\mathbf R}^m\) and \(y \in {\mathbf R}^m\). This discretized version which has been studied by Griva and Vanderbei (2005) was suggested to us by Hans Werner Borchers.

The basic catenary problem has a well-known analytical solution (see Gelfand and Fomin (1963)) which we can easily verify with `CVXR`

.

```
suppressMessages(suppressWarnings(library(CVXR)))
## Problem data
m <- 101
L <- 2
h <- L / (m - 1)
## Form objective
x <- Variable(m)
y <- Variable(m)
objective <- Minimize(sum(y))
## Form constraints
constraints <- list(x[1] == 0, y[1] == 1,
x[m] == 1, y[m] == 1,
diff(x)^2 + diff(y)^2 <= h^2)
## Solve the catenary problem
prob <- Problem(objective, constraints)
result <- solve(prob)
```

We can now plot it and compare it with the ideal solution. Below we use alpha blending and differing line thickness to show the ideal in red and the computed solution in blue.

```
library(ggplot2)
xs <- result$getValue(x)
ys <- result$getValue(y)
catenary <- ggplot(data.frame(x = xs, y = ys)) +
geom_line(mapping = aes(x = x, y = y), color = "blue", size = 1) +
geom_point(data = data.frame(x = c(xs[1], ys[1]), y = c(xs[m], ys[m])),
mapping = aes(x = x, y = y), color = "red")
ideal <- function(x) { 0.22964 *cosh((x -0.5) / 0.22964) - 0.02603 }
catenary + stat_function(fun = ideal , colour = "brown", alpha = 0.5, size = 3)
```

## Additional Ground Constraints

A more interesting situation arises when the ground is not flat. Let \(g \in {\mathbf R}^m\) be the elevation vector (relative to the \(x\)-axis), and suppose the right endpoint of our chain has been lowered by \(\Delta y_m = 0.5\). The analytical solution in this case would be difficult to calculate. However, we need only add two lines to our constraint definition,

```
constr[[4]] <- (y[m] == 0.5)
constr <- c(constr, y >= g)
```

to obtain the new result.

Below, we define \(g\) as a staircase function and solve the problem.

```
## Lower right endpoint and add staircase structure
ground <- sapply(seq(0, 1, length.out = m), function(x) {
if(x < 0.2)
return(0.6)
else if(x >= 0.2 && x < 0.4)
return(0.4)
else if(x >= 0.4 && x < 0.6)
return(0.2)
else
return(0)
})
constraints <- c(constraints, y >= ground)
constraints[[4]] <- (y[m] == 0.5)
prob <- Problem(objective, constraints)
result <- solve(prob)
```

to obtain the new result.

The figure below shows the solution of this modified catenary problem for \(m = 101\) and \(h = 0.04\). The chain is shown hanging in blue, bounded below by the red staircase structure, which represents the ground.

```
xs <- result$getValue(x)
ys <- result$getValue(y)
ggplot(data.frame(x = xs, y = ys)) +
geom_line(mapping = aes(x = x, y = y), color = "blue") +
geom_point(data = data.frame(x = c(xs[1], ys[1]), y = c(xs[m], ys[m])),
mapping = aes(x = x, y = y), color = "red") +
geom_line(data.frame(x = xs, y = ground),
mapping = aes(x = x, y = y), color = "brown")
```

## Session Info

`sessionInfo()`

```
## R version 3.5.1 (2018-07-02)
## Platform: x86_64-apple-darwin17.7.0 (64-bit)
## Running under: macOS 10.14.1
##
## Matrix products: default
## BLAS/LAPACK: /usr/local/Cellar/openblas/0.3.3/lib/libopenblasp-r0.3.3.dylib
##
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
##
## attached base packages:
## [1] stats graphics grDevices datasets utils methods base
##
## other attached packages:
## [1] ggplot2_3.1.0 CVXR_0.99-2
##
## loaded via a namespace (and not attached):
## [1] gmp_0.5-13.2 Rcpp_0.12.19 highr_0.7
## [4] bindr_0.1.1 pillar_1.3.0 compiler_3.5.1
## [7] plyr_1.8.4 R.methodsS3_1.7.1 R.utils_2.7.0
## [10] tools_3.5.1 digest_0.6.18 bit_1.1-14
## [13] evaluate_0.12 tibble_1.4.2 gtable_0.2.0
## [16] lattice_0.20-35 pkgconfig_2.0.2 rlang_0.3.0.1
## [19] Matrix_1.2-15 yaml_2.2.0 blogdown_0.9.2
## [22] xfun_0.4 bindrcpp_0.2.2 withr_2.1.2
## [25] dplyr_0.7.7 Rmpfr_0.7-1 ECOSolveR_0.4
## [28] stringr_1.3.1 knitr_1.20 tidyselect_0.2.5
## [31] rprojroot_1.3-2 bit64_0.9-7 grid_3.5.1
## [34] glue_1.3.0 R6_2.3.0 rmarkdown_1.10
## [37] bookdown_0.7 purrr_0.2.5 magrittr_1.5
## [40] backports_1.1.2 scales_1.0.0 htmltools_0.3.6
## [43] scs_1.1-1 assertthat_0.2.0 colorspace_1.3-2
## [46] labeling_0.3 stringi_1.2.4 lazyeval_0.2.1
## [49] munsell_0.5.0 crayon_1.3.4 R.oo_1.22.0
```

## Source

## References

Gelfand, I. M., and S. V. Fomin. 1963. *Calculus of Variations*. Prentice-Hall.

Griva, I. A., and R. J. Vanderbei. 2005. “Case Studies in Optimization: Catenary Problem.” *Optimization and Engineering* 6 (4). Springer: 463–82.