什么是auto layout
auto layout是苹果公司提供的一个基于约束布局,动态计算视图大小和位置的库,并且已经集成到xcode开发环境里。以下两个时间点需要注意。
- 1997年,auto layout所用到的布局算法cassorwary被发明了出来。
- 2011年,苹果公司将cassowary算法运用到了自家的布局引擎auto layout中
autolayout 的生命周期
Auto Layout不只有布局算法Casswory,还包含了布局在运行时的生命周期等一整套布局引擎系统,用来同意管理布局的创建、更新和销毁。
这一整套布局引擎系统叫做Layout Engine,是Auto Layout的核心,主导着整个界面布局。
每个视图在得到自己的布局前,Layout Engine会将试图、约束、优先级、固定大小通过计算转换成最终的大小和位置。每当约束发生变化,就会触发Deffered Layout Pass,完成后进入监听约束变化的状态。当再次监听到约束变化,就会进入到下一轮的循环中。过程如下图。
UIStackView
UIStackView是一个容器决定排版的布局模式,容器大小的变化,会影响子项的排版。类似于前端体系中的flexbox的简化版。
- UIStackView是一个虚拟容器,它的layer不被绘制,设置背景、边框、阴影这些外观是无效的。
- 如果我们使用约束,不定义栈视图的大小,只定义位置,这个时候,栈视图不会再改变管理内容的大小,但是它会自动计算出自己需要的大小,也就是变成了不会换行的流逝布局。也就是说会生成一个固有大小,进行内容自适应的排版。
线性规划问题
线性规划(Linear programming,简称LP),是运筹学中研究较早、发展较快、应用广泛、方法较成熟的一个重要分支,它是辅助人们进行科学管理的一种数学方法。研究线性约束条件下线性目标函数的极值问题的数学理论和方法。
例如下面例子,就是一个线性规划问题:
要求所买食物中,至少有2000能量,55蛋白质,800钙,求最省钱的方案。
可以列出不等式组:
这就是一个线性规划问题。
可行域
来看一个例子,考虑如下线性规划:
可以画出如下的图:
灰色部分的区域称作为可行域,从途中可以直观的看出,x1 = 2, x2 = 6时,取到最大值为8。
这里有一个定理是,可以证明总是在交点处取到最大值。
标准形式
标准形式为:
min cT X
s.t. A X <= b
松弛形式
min cT X
s.t. A X = b
X >= 0
注意:
- 所有的线性规划形式都是>=或<=,等号不可以去掉,否则可能无解。
- 上述所有变量为列向量,cT代表c的转置矩阵。
- 松弛形式和松弛变量会在后文提到。
- 注意标准形式为<=,求min,如果是反过来的,只需要增加一个负号是不等式翻转即可。
单纯形算法
单纯形法是求解线性规划的经典方法,虽然它的执行时间在最坏的情况下是非多项式的(指数时间复杂度),但是在绝大部分情况或者说实际运行过程中,它的确是多项式时间。
步骤:
- 找出一个初始的基本可行解。
- 不断执行旋转(pivot)操作。
- 重复步骤2直到结果不能改进为止。
例题
考虑如下线性规划问题:
引入松弛变量后的形式:
分离基本变量和非基本变量:
注:等号右边的叫基本变量,左边的叫非基本变量。即引入的松弛变量为基本变量,原变量为非基本变量。
考虑基本解为,将非基本变量设为0,并计算左边基本变量的值,这里很容易得到,基本解为:(0, 0, 0, 4, 2, 3, 6)T。一般而言基本解是可行的,我们称之为基本可行解(不可行的问题后面讨论)。
现在来进行第二个步骤,旋转的操作:
每次选择一个在目标函数中系数为负数的非基本变量Xe,然后尽可能的增加Xe而不违反约束,并选取基本变量Xi,然后将其位置互换。
例如,我们选择替入变量为X1,替出变量为X5,然后替换二者的角色。执行一次转动的过程与之前所描述的线性规划是等价的。替换后如下:
同样的,将非基本变量设为0,于是得到解:(2, 0, 0, 2, 0, 3, 6)T,目标函数的值减少为-2。
继续转动,只能选取X2或者X3,不能选择X5,因为此时X5的系数是正的。假设选取替入变量X2,替出变量X4,将会得到以下结果:
此时基本解变为了(2, 2, 0, 0, 0, 3, 0)T,目标函数值为-30。
继续选择增大X5,选取最严格的等式4进行替换,得:
基本解变成了(2, 2, 0, 0, 0, 3, 0)T,目标函数值为-30。
接着还可以转动X3,过程省略,最后目标值为-32,已经没有可以转动的值了,因此得到目标值为-32。
特殊情况
退化
在旋转过程中,可能会存在保持目标值不变的情况,这种现象称之为退化。比如上面的例子里出现了两次-30。不过没有产生循环的情况。
- 目标条件中,系数为负的第一个作为替入变量。
- 对所有约束条件中,选择对xe约束最近的第一个。
- 加入随机扰动。
无界
在运算过程中可能会出现无界的情况,需要注意,例如作图出来是两条平行的线的情况
矩阵 & 程序
对于上方的例题来说:
我们可以得到如下几个矩阵:
C = (-1, -14, -6, 0, 0, 0, 0)
B = (4, 2, 3, 6)T
<img style="border-radius: 0.3125em;"
src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/20f1e8f4192a4b4ab499c1feab89a775~tplv-k3u1fbpfcp-zoom-1.image">
> 矩阵A:约束条件的系数
> 矩阵B:约束函数的值
> 矩阵C:目标函数的系数
现在需要将这些矩阵拼接成一个矩阵:
这里不难看出,左下角放的是B,右上角放的是C,右下角放的是A,而左上角那一个数字,放的是-z。
可以看出,如果将等式改写成 基本变量 = F(非基本变量)的形式的话,B和C是不变的,A矩阵中,基本变量符号相同,非基本变量符号相反。
我们这里选取X1和X5进行翻转,得到矩阵如下:
那么这里是怎么变换过来的呢?
首先看矩阵第三行,我们需要改写成X1 = X5,其实非常简单,将该行每一个元素除以X1的系数就可以了。
那么其它行呢,其他行其实是将X1消去,例如第一行,实际上是将X1的系数和第三行中X1的系数变成一样后作差。例如这里第一行* -1后减去第三行。其它行同理。
这里通过尝试就可以发现,左上角实际上是-z,具体原因可以在尝试中体会。
不断进行替入与替出,直到第一行中所有的系数都为正。
这里我们贴出 demo 代码,大家可以自行尝试:
import numpy as np
class Simplex(object):
def __init__(self, obj, max_mode=False):
self.max_mode = max_mode
self.mat = np.array([[0] + obj]) * (-1 if max_mode else 1)
def add_constraint(self, a, b):
self.mat = np.vstack([self.mat, [b] + a])
def solve(self):
m, n = self.mat.shape
temp, B = np.vstack([np.zeros((1, m - 1)), np.eye(m - 1)]), list(range(n - 1, n + m - 1)) # add diagonal array
mat = self.mat = np.hstack([self.mat, temp])
while mat[0, 1:].min() < 0:
col = np.where(mat[0, 1:] < 0)[0][0] + 1
row = np.array([mat[i][0] / mat[i][col] if mat[i][col] > 0 else 0x7fffffff for i in range(1, mat.shape[0])]).argmin() + 1 # find the theta index
if mat[row][col] <= 0: return None
mat[row] /= mat[row][col]
ids = np.arange(mat.shape[0]) != row
mat[ids] -= mat[row] * mat[ids, col:col + 1]
B[row] = col
return mat[0][0] * (1 if self.max_mode else -1), {B[i]: mat[i, 0] for i in range(1, m) if B[i] < n}
from Simplex import Simplex
t = Simplex([-1, -14, -6])
t.add_constraint([1, 1, 1], 4)
t.add_constraint([1, 0, 0], 2)
t.add_constraint([0, 0, 1], 3)
t.add_constraint([0, 3, 1], 6)
print(t.solve())
print(t.mat)
文中如有错误,欢迎指出。
参考文献
- [1] [线性规划-单纯形算法详解] www.hrwhisper.me/introductio…
- [2] [Auto Layout是怎么进行自动布局的,性能如何?] time.geekbang.org/column/arti…
- [3] [Solving Linear Arithmetic Constraints for User Interface Applications] constraints.cs.washington.edu/solvers/uis…