Compare commits

...
62 Commits
Author SHA1 Message Date
josh 9785f013c7 new post 2025-07-02 10:12:16 +08:00
josh e722750086 Merge branch 'master' of https://github.com/joshgao22/josh-blog-source 2025-06-26 14:38:29 +08:00
josh 3e39baaee4 update dependencies, config and post 2025-06-26 14:38:07 +08:00
Josh Gao 4009348802 Merge pull request #44 from joshgao22/dependabot/npm_and_yarn/hexo-word-counter-0.2.1
Bump hexo-word-counter from 0.2.0 to 0.2.1
2025-06-17 19:13:59 +08:00
dependabot[bot] 929cb50354 Bump hexo-word-counter from 0.2.0 to 0.2.1
Bumps [hexo-word-counter](https://github.com/next-theme/hexo-word-counter) from 0.2.0 to 0.2.1.
- [Release notes](https://github.com/next-theme/hexo-word-counter/releases)
- [Commits](https://github.com/next-theme/hexo-word-counter/compare/v0.2.0...v0.2.1)

---
updated-dependencies:
- dependency-name: hexo-word-counter
  dependency-version: 0.2.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2025-06-05 03:41:13 +00:00
Josh Gao a190552c0c Merge pull request #43 from joshgao22/dependabot/npm_and_yarn/next-theme/plugins-8.23.1
Bump @next-theme/plugins from 8.23.0 to 8.23.1
2025-06-05 11:40:06 +08:00
Josh Gao 3a0103be03 Merge pull request #42 from joshgao22/dependabot/npm_and_yarn/hexo-theme-next-8.23.1
Bump hexo-theme-next from 8.23.0 to 8.23.1
2025-06-05 11:39:56 +08:00
dependabot[bot] a406b98bac Bump @next-theme/plugins from 8.23.0 to 8.23.1
Bumps [@next-theme/plugins](https://github.com/next-theme/plugins) from 8.23.0 to 8.23.1.
- [Release notes](https://github.com/next-theme/plugins/releases)
- [Commits](https://github.com/next-theme/plugins/compare/v8.23.0...v8.23.1)

---
updated-dependencies:
- dependency-name: "@next-theme/plugins"
  dependency-version: 8.23.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2025-06-04 23:27:41 +00:00
dependabot[bot] be8b9ba539 Bump hexo-theme-next from 8.23.0 to 8.23.1
Bumps [hexo-theme-next](https://github.com/next-theme/hexo-theme-next) from 8.23.0 to 8.23.1.
- [Release notes](https://github.com/next-theme/hexo-theme-next/releases)
- [Commits](https://github.com/next-theme/hexo-theme-next/compare/v8.23.0...v8.23.1)

---
updated-dependencies:
- dependency-name: hexo-theme-next
  dependency-version: 8.23.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2025-06-04 23:27:32 +00:00
Josh Gao 2c43000367 Merge pull request #40 from joshgao22/dependabot/npm_and_yarn/hexo-markmap-2.0.8
Bump hexo-markmap from 1.2.5 to 2.0.8
2025-04-15 08:58:28 +08:00
dependabot[bot] 6b4afd1e42 Bump hexo-markmap from 1.2.5 to 2.0.8
Bumps [hexo-markmap](https://github.com/MaxChang3/hexo-markmap) from 1.2.5 to 2.0.8.
- [Release notes](https://github.com/MaxChang3/hexo-markmap/releases)
- [Commits](https://github.com/MaxChang3/hexo-markmap/compare/v1.2.5...v2.0.8)

---
updated-dependencies:
- dependency-name: hexo-markmap
  dependency-version: 2.0.8
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
2025-04-14 23:40:20 +00:00
josh 08b722f278 feat: add new server 2025-04-12 10:56:13 +08:00
josh 5cd88bb922 Revert "Merge pull request #37 from joshgao22/dependabot/npm_and_yarn/hexo-renderer-pandoc-0.5.0"
This reverts commit 7717b21612, reversing
changes made to 43aebe64fe.

hexo-renderer-pandoc 0.5.0 renders file header latex definition wrongly,
and should be checked later
2025-04-11 12:59:46 +08:00
Josh Gao 4c4201dd8c Merge pull request #39 from joshgao22/dependabot/npm_and_yarn/hexo-markmap-2.0.8
Bump hexo-markmap from 1.2.5 to 2.0.8
2025-04-11 10:58:54 +08:00
Josh Gao 7717b21612 Merge pull request #37 from joshgao22/dependabot/npm_and_yarn/hexo-renderer-pandoc-0.5.0
Bump hexo-renderer-pandoc from 0.4.0 to 0.5.0
2025-04-11 10:58:35 +08:00
Josh Gao 43aebe64fe Merge pull request #36 from joshgao22/dependabot/npm_and_yarn/hexo-generator-searchdb-1.5.0
Bump hexo-generator-searchdb from 1.4.1 to 1.5.0
2025-04-11 10:58:17 +08:00
Josh Gao 43b3a85289 Merge pull request #35 from joshgao22/dependabot/npm_and_yarn/hexo-theme-next-8.23.0
Bump hexo-theme-next from 8.22.0 to 8.23.0
2025-04-11 10:58:05 +08:00
dependabot[bot] 91cdcfa52f Bump hexo-theme-next from 8.22.0 to 8.23.0
Bumps [hexo-theme-next](https://github.com/next-theme/hexo-theme-next) from 8.22.0 to 8.23.0.
- [Release notes](https://github.com/next-theme/hexo-theme-next/releases)
- [Commits](https://github.com/next-theme/hexo-theme-next/compare/v8.22.0...v8.23.0)

---
updated-dependencies:
- dependency-name: hexo-theme-next
  dependency-version: 8.23.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2025-04-11 02:57:34 +00:00
Josh Gao 337f429ea7 Merge pull request #34 from joshgao22/dependabot/npm_and_yarn/next-theme/plugins-8.23.0
Bump @next-theme/plugins from 8.22.0 to 8.23.0
2025-04-11 10:57:04 +08:00
Josh Gao f1c3d5f6bd Merge pull request #30 from joshgao22/dependabot/npm_and_yarn/hexo-theme-landscape-1.1.0
Bump hexo-theme-landscape from 1.0.0 to 1.1.0
2025-04-11 10:56:21 +08:00
dependabot[bot] b688a474a8 Bump hexo-markmap from 1.2.5 to 2.0.8
Bumps [hexo-markmap](https://github.com/MaxChang3/hexo-markmap) from 1.2.5 to 2.0.8.
- [Release notes](https://github.com/MaxChang3/hexo-markmap/releases)
- [Commits](https://github.com/MaxChang3/hexo-markmap/compare/v1.2.5...v2.0.8)

---
updated-dependencies:
- dependency-name: hexo-markmap
  dependency-version: 2.0.8
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
2025-04-08 00:41:18 +00:00
dependabot[bot] 91b8d6c318 Bump hexo-renderer-pandoc from 0.4.0 to 0.5.0
Bumps [hexo-renderer-pandoc](https://github.com/hexojs/hexo-renderer-pandoc) from 0.4.0 to 0.5.0.
- [Commits](https://github.com/hexojs/hexo-renderer-pandoc/commits)

---
updated-dependencies:
- dependency-name: hexo-renderer-pandoc
  dependency-version: 0.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2025-04-03 23:12:13 +00:00
dependabot[bot] 285389294d Bump hexo-generator-searchdb from 1.4.1 to 1.5.0
Bumps [hexo-generator-searchdb](https://github.com/next-theme/hexo-generator-searchdb) from 1.4.1 to 1.5.0.
- [Release notes](https://github.com/next-theme/hexo-generator-searchdb/releases)
- [Commits](https://github.com/next-theme/hexo-generator-searchdb/compare/v1.4.1...v1.5.0)

---
updated-dependencies:
- dependency-name: hexo-generator-searchdb
  dependency-version: 1.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2025-04-01 00:02:29 +00:00
dependabot[bot] fa6b3f6ae2 Bump @next-theme/plugins from 8.22.0 to 8.23.0
Bumps [@next-theme/plugins](https://github.com/next-theme/plugins) from 8.22.0 to 8.23.0.
- [Release notes](https://github.com/next-theme/plugins/releases)
- [Commits](https://github.com/next-theme/plugins/compare/v8.22.0...v8.23.0)

---
updated-dependencies:
- dependency-name: "@next-theme/plugins"
  dependency-version: 8.23.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2025-03-31 23:55:14 +00:00
dependabot[bot] c967373488 Bump hexo-theme-landscape from 1.0.0 to 1.1.0
Bumps [hexo-theme-landscape](https://github.com/hexojs/hexo-theme-landscape) from 1.0.0 to 1.1.0.
- [Release notes](https://github.com/hexojs/hexo-theme-landscape/releases)
- [Commits](https://github.com/hexojs/hexo-theme-landscape/compare/v1.0.0...v1.1.0)

---
updated-dependencies:
- dependency-name: hexo-theme-landscape
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2025-02-14 23:29:39 +00:00
josh 5e51314dfe update packages and deploy server 2025-02-06 08:56:10 +08:00
Josh Gao fb06efb960 Merge pull request #26 from joshgao22/dependabot/npm_and_yarn/hexo-theme-next-8.22.0
Bump hexo-theme-next from 8.21.0 to 8.22.0
2025-02-05 22:20:32 +08:00
Josh Gao 99538a0e9e Merge pull request #28 from joshgao22/dependabot/npm_and_yarn/hexo-related-posts-1.6.2
Bump hexo-related-posts from 1.5.2 to 1.6.2
2025-02-05 22:20:21 +08:00
dependabot[bot] c4b5eecc85 Bump hexo-related-posts from 1.5.2 to 1.6.2
Bumps [hexo-related-posts](https://github.com/sergeyzwezdin/hexo-related-posts) from 1.5.2 to 1.6.2.
- [Release notes](https://github.com/sergeyzwezdin/hexo-related-posts/releases)
- [Commits](https://github.com/sergeyzwezdin/hexo-related-posts/commits/v1.6.2)

---
updated-dependencies:
- dependency-name: hexo-related-posts
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2025-01-15 23:56:18 +00:00
dependabot[bot] 9d9303e03f Bump hexo-theme-next from 8.21.0 to 8.22.0
Bumps [hexo-theme-next](https://github.com/next-theme/hexo-theme-next) from 8.21.0 to 8.22.0.
- [Release notes](https://github.com/next-theme/hexo-theme-next/releases)
- [Commits](https://github.com/next-theme/hexo-theme-next/compare/v8.21.0...v8.22.0)

---
updated-dependencies:
- dependency-name: hexo-theme-next
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2025-01-01 23:04:34 +00:00
josh 25e0a81a87 update posts 2024-10-11 20:58:04 +08:00
Josh Gao 4bcbbf54b0 Merge pull request #23 from joshgao22/dependabot/npm_and_yarn/hexo-theme-next-8.21.0
Bump hexo-theme-next from 8.20.0 to 8.21.0
2024-10-11 20:56:29 +08:00
Josh Gao c191a5af65 Merge pull request #22 from joshgao22/dependabot/npm_and_yarn/next-theme/plugins-8.21.0
Bump @next-theme/plugins from 8.20.0 to 8.21.0
2024-10-11 20:56:21 +08:00
dependabot[bot] 88ce267098 Bump hexo-theme-next from 8.20.0 to 8.21.0
Bumps [hexo-theme-next](https://github.com/next-theme/hexo-theme-next) from 8.20.0 to 8.21.0.
- [Release notes](https://github.com/next-theme/hexo-theme-next/releases)
- [Commits](https://github.com/next-theme/hexo-theme-next/compare/v8.20.0...v8.21.0)

---
updated-dependencies:
- dependency-name: hexo-theme-next
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2024-09-20 23:20:38 +00:00
dependabot[bot] 15aa117543 Bump @next-theme/plugins from 8.20.0 to 8.21.0
Bumps [@next-theme/plugins](https://github.com/next-theme/plugins) from 8.20.0 to 8.21.0.
- [Release notes](https://github.com/next-theme/plugins/releases)
- [Commits](https://github.com/next-theme/plugins/compare/v8.20.0...v8.21.0)

---
updated-dependencies:
- dependency-name: "@next-theme/plugins"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2024-09-20 23:20:26 +00:00
Josh Gao f0adb4a625 Merge pull request #21 from joshgao22/dependabot/npm_and_yarn/hexo-generator-index-4.0.0
Bump hexo-generator-index from 3.0.0 to 4.0.0
2024-08-19 10:19:17 +08:00
dependabot[bot] ae1862be8a Bump hexo-generator-index from 3.0.0 to 4.0.0
Bumps [hexo-generator-index](https://github.com/hexojs/hexo-generator-index) from 3.0.0 to 4.0.0.
- [Release notes](https://github.com/hexojs/hexo-generator-index/releases)
- [Commits](https://github.com/hexojs/hexo-generator-index/compare/v3.0.0...v4.0.0)

---
updated-dependencies:
- dependency-name: hexo-generator-index
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
2024-07-09 23:31:02 +00:00
josh c666cf18aa update posts 2024-07-07 17:12:20 +08:00
josh c8252851cb Merge branch 'master' of https://github.com/joshgao22/josh-blog-source 2024-07-07 17:04:27 +08:00
Josh Gao 56398591e7 Merge pull request #20 from joshgao22/dependabot/npm_and_yarn/hexo-7.3.0
Bump hexo from 7.2.0 to 7.3.0
2024-07-07 17:04:18 +08:00
josh a9ceb54cc6 new post josh-cvx-2.2, update josh-cvx-2.1, new draft zynq-debug-fsbl 2024-07-04 00:29:38 +08:00
dependabot[bot] 4dd6f0ffd3 Bump hexo from 7.2.0 to 7.3.0
Bumps [hexo](https://github.com/hexojs/hexo) from 7.2.0 to 7.3.0.
- [Release notes](https://github.com/hexojs/hexo/releases)
- [Commits](https://github.com/hexojs/hexo/compare/v7.2.0...v7.3.0)

---
updated-dependencies:
- dependency-name: hexo
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2024-07-01 23:52:29 +00:00
josh 5d0a940aea finish post, zynq dynamic ddr configuration 2024-06-28 10:39:55 +08:00
josh 83586f61d9 new post, zynq dynamic ddr configuration 2024-06-28 00:30:08 +08:00
josh ea44545b90 update post sv-1 2024-06-26 00:27:08 +08:00
josh 6218adecc8 update toc of post cvx-2.1 2024-06-24 10:37:04 +08:00
josh 3e4f48e36f finish post cvx-2.1 2024-06-16 13:32:18 +08:00
josh f1d95ce8b4 new post cvx-2.1, new hexo plugin to support mindmap 2024-06-15 16:36:21 +08:00
josh 565bdaaefd new post cvx-1.6, update cvx series 2024-06-13 22:39:02 +08:00
josh ade0322aa9 new post cvx-1.5 2024-06-13 10:31:45 +08:00
josh b9e587f5d5 new post cvx-1.4 2024-06-12 17:45:24 +08:00
josh a93552d9b9 finish post cvx-1.3 2024-06-12 11:31:27 +08:00
josh 3f40a887c9 update package 2024-06-11 20:12:56 +08:00
josh abbc0da71b update cvx post 2024-06-11 20:10:20 +08:00
josh 9e9b00b0dd fix some typo 2024-06-11 08:15:22 +08:00
josh 32b118f0e5 update post cvx-1.1, enlarge font size 2024-06-10 16:51:09 +08:00
josh 5ec621c28e new post cvx-1.3 2024-06-09 23:19:23 +08:00
josh af188d3046 new post cvx-1.2 2024-06-08 17:29:33 +08:00
josh da0fbe84dc finish post - convex optimization 1.1 2024-06-08 12:14:53 +08:00
josh 7c14960b5f release post on convex optimization, update opa references 2024-06-08 00:32:57 +08:00
josh 85e6bd77a3 update sv blogs
change a few translations, change how markdown images are  linked
2024-06-07 09:43:46 +08:00
josh 7b8d5d80cb update blog titles
split tiles of note & review serie into two lines, making it neat. but in archive view, the lines are still splited, which is a little annoying
2024-06-06 19:54:21 +08:00
100 changed files with 7197 additions and 2029 deletions
+2 -2
View File
@@ -367,8 +367,8 @@ codeblock:
# Code Highlight theme
# All available themes: https://theme-next.js.org/highlight/
theme:
light: default
dark: github-dark
light: vs
dark: github-dark-dimmed
prism:
light: prism
dark: prism-dark
+12 -18
View File
@@ -110,24 +110,12 @@ theme: next
## Docs: https://hexo.io/docs/one-command-deployment
deploy:
- type: git
repo: josh@101.43.227.73:/home/josh/documents/josh-blog-deploy.git
branch: master
- type: git
repo: [email protected]:/home/josh/documents/josh-blog-deploy.git
branch: master
- type: git
repo: [email protected]:josh-gao/josh-blog/josh-blog.git
repo: josh@129.153.124.210:/home/josh/documents/josh-blog-deploy.git
branch: master
- type: git
repo: https://github.com/joshgao22/joshgao22.github.io.git
branch: master
# MathJax [Redundant]
# math:
# engine: 'mathjax'
# mathjax:
# src: https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.min.js
# Local Search
search:
path: search.xml
@@ -201,12 +189,18 @@ neat_js:
related_posts:
enabled: true
enable_env_name: prod
filter_threshold: 0.13
related_count: 5
weight:
title: 0.1
description: 0
keywords: 0
tags: 0.01
categories: 0.05
text: 0
description: 0.01
keywords: 0.01
tags: 0.005
categories: 0.005
text: 0.2
# config of hexo-renderer-pandoc
pandoc:
args:
- --mathjax
+2894 -1332
View File
File diff suppressed because it is too large Load Diff
+11 -10
View File
@@ -9,30 +9,31 @@
"server": "hexo server"
},
"hexo": {
"version": "7.2.0"
"version": "7.3.0"
},
"dependencies": {
"@next-theme/plugins": "^8.20.0",
"hexo": "^7.2.0",
"@next-theme/plugins": "^8.23.1",
"hexo": "^7.3.0",
"hexo-abbrlink": "^2.2.1",
"hexo-deployer-git": "^4.0.0",
"hexo-filter-github-emojis": "^3.0.5",
"hexo-generator-archive": "^2.0.0",
"hexo-generator-category": "^2.0.0",
"hexo-generator-index": "^3.0.0",
"hexo-generator-searchdb": "^1.4.1",
"hexo-generator-index": "^4.0.0",
"hexo-generator-searchdb": "^1.5.0",
"hexo-generator-sitemap": "^3.0.1",
"hexo-generator-tag": "^2.0.0",
"hexo-helper-live2d": "^3.1.1",
"hexo-markmap": "^2.0.8",
"hexo-neat": "^1.0.9",
"hexo-related-posts": "^1.5.2",
"hexo-related-posts": "^1.6.2",
"hexo-renderer-ejs": "^2.0.0",
"hexo-renderer-pandoc": "^0.4.0",
"hexo-renderer-pandoc": "^0.5.0",
"hexo-renderer-stylus": "^3.0.1",
"hexo-server": "^3.0.0",
"hexo-tag-cloud": "2.1.*",
"hexo-theme-landscape": "^1.0.0",
"hexo-theme-next": "^8.20.0",
"hexo-word-counter": "^0.2.0"
"hexo-theme-landscape": "^1.1.0",
"hexo-theme-next": "^8.23.1",
"hexo-word-counter": "^0.2.1"
}
}
+3
View File
@@ -3,3 +3,6 @@ $border-radius-inner = 10px;
$border-radius = 10px;
// $font-family-chinese = "PingFang SC", "Microsoft YaHei";
// Font size of articles.
// $font-size-base = 18px
@@ -1,32 +0,0 @@
---
title: Josh 的学习笔记之凸优化 (Part 1 —— 凸集)
mathjax: true
comments: true
copyright: true
sticky: false
toc:
enable: true
number: false
wrap: true
expand_all: true
max_depth: 4
categories:
- - Josh 的学习笔记
- 凸优化
tags:
- 凸优化
abbrlink: 43146ee9
date: 2022-03-29 11:07:04
---
# 仿射集合和凸集
&emsp;&emsp;设 $x_1 \ne x_2$ 是 $\mathbf{R}^n$ 空间中的两个点,则具有下列形式的点
$$
y = \theta x_1 + (1-\theta)x_2,\theta \in \mathbf{R}
$$
组成一条穿过 $x_1$ 和 $x_2$ 的**直线**(*line*). 参数 $\theta = 0$ 对应 $y=x_2$,$\theta = 1$ 表明 $y = x_2$. 参数 $\theta$ 的值在
<!-- more -->
@@ -0,0 +1,36 @@
---
title: Zynq 系列 SoC / MPSoC 创建可调试的 FSBL
mathjax: true
comments: true
copyright: true
toc:
enable: true
number: true
wrap: true
expand_all: true
max_depth: 4
tags:
- 调试记录
- MPSoC
- RFSoC
- Zynq
- FSBL
categories:
- 调试记录
date: 2024-06-29 16:46:38
---
FSBL 可以初始化 SoC 设备,将所需的应用程序或数据加载到内存,并在目标 CPU 核心上启动应用程序。
在 Vitis 中创建 Platform 时,可以选择同时创建 FSBL,这样 FSBL 就会位于 Platform 下。也可以创建单独的 FSBL 程序,作为普通程序使用,以便进一步修改或调试。
本文以 Zynq UltraScale+ RFSoC 为例,对 FSBL 进行调试。
# 名词释义
- [FSBL](https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842019/Zynq+UltraScale+FSBL#ZynqUltraScale+FSBL-WhatisFSBL?):First Stage Bootloader,第一阶段引导加载程序
- [SoC](https://en.wikipedia.org/wiki/System_on_a_chip):System-on-Chip,片上系统
# 参考文档
[Creating a Debuggable First Stage Boot Loader](https://xilinx.github.io/Embedded-Design-Tutorials/docs/2021.1/build/html/docs/Feature_Tutorials/debuggable-fsbl/debuggable-fsbl.html)
@@ -0,0 +1,35 @@
---
title: Josh's Summary — 工科数学分析<br>Part 1.2 常微分方程
mathjax: true
comments: true
copyright: true
toc:
enable: true
number: true
wrap: true
expand_all: true
max_depth: 4
tags:
- 高等数学
- 数学分析
- 微积分
categories:
- - Josh 的学习笔记
- 高等数学
- - 数学
- 数学分析
abbrlink: 5a263f58
date: 2025-06-26 10:21:02
---
# 常见等价无穷小
1. $\sin x \sim x$
2. $\tan x \sim x$
3. $\arcsin x \sim x$
4. $\arctan x \sim x$
5. $1 - \cos x \sim \frac{x^2}{2}$
6. $\ln(1+x) \sim x$
7. $e^x - 1 \sim x$
8. $a^x - 1 \sim x \ln a$
9. $(1+x)^\alpha - 1 \sim \alpha x$
@@ -1,5 +1,5 @@
---
title: "Josh's Notes: Verilog(Part 1 — 初识 HDL 设计方法)"
title: "Josh's Note — Verilog<br>Part 1 初识 HDL 设计方法"
date: 2020-11-27 22:58:07
tags:
- Verilog
@@ -1,5 +1,5 @@
---
title: "Josh's Notes: Verilog(Part 2 — Verilog 语言基础)"
title: "Josh's Note — Verilog<br>Part 2 Verilog 语言基础"
date: 2020-11-28 11:42:50
tags:
- Verilog
@@ -1,5 +1,5 @@
---
title: "Josh's Notes: Verilog(Part 3 — 描述方式和设计层次)"
title: "Josh's Note — Verilog<br>Part 3 描述方式和设计层次"
date: 2020-11-30 00:57:49
tags:
- Verilog
@@ -1,5 +1,5 @@
---
title: "Josh's Notes: Verilog(Part 4 — RTL 概念与常用 RTL 建模)"
title: "Josh's Note — Verilog<br>Part 4 RTL 概念与常用 RTL 建模"
mathjax: true
comments: true
copyright: true
@@ -1,5 +1,5 @@
---
title: "Josh's Notes: Verilog(Part 5 — RTL 设计与编码指导)"
title: "Josh's Note — Verilog<br>Part 5 RTL 设计与编码指导"
mathjax: true
comments: true
copyright: true
+1 -1
View File
@@ -1,5 +1,5 @@
---
title: "Josh's Notes: 多抽样率信号处理 (Part 1 — 抽样率转换)"
title: "Josh's Note — 多抽样率信号处理<br>Part 1 抽样率转换"
mathjax: true
comments: true
copyright: true
+237
View File
@@ -0,0 +1,237 @@
---
title: "Josh's Note — 凸优化<br>Part 1.1 凸集—仿射集合和凸集"
mathjax: true
comments: true
copyright: true
sticky: false
toc:
enable: true
number: false
wrap: true
expand_all: true
max_depth: 4
categories:
- - Josh 的学习笔记
- 凸优化
- 凸集
- - 数学
- 凸优化
tags:
- 凸优化
- 凸集
- 仿射
- 锥
abbrlink: 43146ee9
date: 2022-03-29 11:07:04
---
# 1. 直线与线段
$
\newcommand{\bfR}{\mathbf{R}}
\def\aff{\mathop{\bf aff}}
\def\relint{\mathop{\bf relint}}
\def\cl{\mathop{\bf cl}}
\def\conv{\mathop{\bf conv}}
\newcommand{\dd}{\mathrm{d}}
\newcommand{\prob}{\mathbf{prob}}
$&emsp;&emsp;设 $x_1 \ne x_2$ 是 $\bfR^n$ 空间中的两个点,则具有下列形式的点
$$
y = \theta x_1 + (1-\theta)x_2,\theta \in \bfR
$$
组成一条穿过 $x_1$ 和 $x_2$ 的**直线**(*line*)。参数 $\theta = 0$ 和 $\theta = 1$ 分别对应 $y=x_2$ 和 $y = x_1$。参数 $\theta$ 的值在 0 和 1 之间变动,构成了 $x_1$ 和 $x_2$ 之间的(闭)**线段**((closed) *line segment*)。
&emsp;&emsp;另一种 $y$ 的表示形式
$$
y = x_2 + \theta (x_1 - x_2)
$$
可以解释为:$y$ 是**基点**(*base point*)$x_2$(对应 $\theta = 0$)和**方向**(*direction*)$x_1 - x_2$(由 $x_2$ 指向 $x_1$)乘以参数 $\theta$ 的和。因此,$\theta$ 给出了 $y$ 在由 $x_2$ 通向 $x_1$ 的路上的位置。当 $\theta$ 由 $0$ 增加到 $1$,点 $y$ 相应地由 $x_2$ 移动到 $x_1$。如果 $\theta > 1$,点 $y$ 在超越了 $x_1$ 的直线上。[图 1](#图1) 给出了直观的解释。
<a id="图1"></a>
![图 1. 通过 $x_1$ 和 $x_2$ 的直线可以参数化描述为 $\theta x_1 + (1-\theta)x_2$,其中 $\theta$ 在 $\bfR$ 上变化。$x_1$ 和 $x_2$ 之间的线段由深色所示,对应处于 $0$ 和 $1$ 之间的 $\theta$。](../images/post/2022-03-29-josh-cvx-1-1/2022-03-29-josh-cvx-1-1-010-TheLinePassingThroughX1AndX2.png){width=600px}
<!-- more -->
# 2. 仿射集合和凸集
&emsp;&emsp;如果通过集合 $C \subseteq \bfR^n$ 中任意两个不同点的直线仍然在集合 $C$ 中,那么称集合 $C$ 是**仿射**(*affine*)的。也就是说,$C \subseteq \bfR^n$ 是仿射的等价于:对于任意 $x_1, x_2 \in C$ 及 $\theta \in \bfR$ 有 $\theta x_1 + (1-\theta)x_2 \in C$。换言之,$C$ 包含了 $C$ 中任意两点的系数之和为 $1$ 的线性组合。
&emsp;&emsp;这个概念可以扩展到多个点的情况。若 $\theta_1 + \cdots + \theta_k = 1$,则称具有 $\theta_1 x_1 + \cdots + \theta_k x_k$ 形式的点为 $x_1, \cdots, x_k$ 的**仿射组合**(*affine combination*)。利用仿射集合的定义(即仿射集合包含其中任意两点的仿射组合),可以归纳出以下结论:一个仿射集合包含其中任意点的仿射组合,即如果 $C$ 是一个仿射集合,$x_1, \cdots, x_k \in C$,并且 $\theta_1 + \cdots + \theta_k = 1$,那么 $\theta_1 x_1 + \cdots + \theta_k x_k$ 仍然在 $C$ 中。
&emsp;&emsp;如果 $C$ 是一个仿射集合并且 $x_0 \in C$,则集合
$$
V = C - x_0 = \left\{ x - x_0\mid x \in C \right\}
$$
是一个子空间,即关于加法和数乘是封闭的。
> **简单说明**&emsp;设 $v_1, v_2 \in V$,$\alpha, \beta \in \bfR$,则有 $v_1 + x_0 \in C$,$v_2 + x_0 \in C$。因为 $C$ 是仿射的,且 $\alpha + \beta + (1 - \alpha - \beta) = 1$,所以
>
> $$
> \alpha v_1 + \beta v_2 + x_0 = \alpha (v_1 + x_0) + \beta(v_2 + x_0) + (1 - \alpha - \beta)x_0 \in C
> $$
>
> 由 $\alpha v_1 + \beta v_2 + x_0 \in C$,可知 $\alpha v_1 + \beta v_2 \in V$。
&emsp;&emsp;因此,仿射集合 $C$ 可以表示为
$$
C = V + x_0 = \left\{ v + x_0\mid v \in V \right\}
$$
即一个子空间加上一个偏移。与仿射集合 $C$ 相关联的子空间 $V$ 与 $x_0$ 的选取无关,所以 $x_0$ 可以是 $C$ 中的任意一点。定义仿射集合 $C$ 的维数为子空间 $V = C - x_0$ 的维数,其中 $x_0$ 是 $C$ 中的任意元素。
> **举例**&emsp;**线性方程组的解集**。线性方程组的解集 $C = \{x\mid Ax= b\}$ 是一个仿射集合,其中 $A\in\bfR^{m\times n}$,$b \in \bfR^{m}$ 。为说明这点,设 $x_1,x_2\in C$,即 $Ax_1 = b, Ax_2 = b$。则对于任意 $\theta$,有
>
> $$\begin{aligned}
> A(\theta x_1 + (1-\theta)x_2) &= \theta Ax_1 + (1-\theta)Ax_2 \\
> &= \theta b + (1-\theta)b \\
> &= b
> \end{aligned}$$
>
> 这表明任意的仿射组合 $\theta x_1 + (1-\theta)x_2$ 也在 $C$ 中,并且与仿射集合 $C$ 相关联的子空间就是 $A$ 的零空间。
>
> 反之,任意仿射集合可以表示为一个线性方程组的解集。
&emsp;&emsp;由集合 $C \subseteq \bfR^n$ 中的点的所有仿射组合组成的集合称为 $C$ 的**仿射包**(*affine hull*),记为 $\aff{C}$:
$$
\aff{C} = \left\{ \theta_1 x_1 + \cdots + \theta_k x_k\mid x_1, \cdots, x_k \in C, \theta_1 + \cdots + \theta_k = 1 \right\}
$$
仿射包是包含 $C$ 的最小的仿射集合,也就是说:如果 $S$ 是满足 $C \subseteq S$ 的仿射集合,那么 $\aff{C} \subseteq S$。
# 3. 仿射维数与相对内部
&emsp;&emsp;集合 $C$ 的仿射维数定义为其仿射包的维数。仿射维数在凸分析及凸优化中十分有用,但它与其他维数的定义常常不相容。
> **举例**&emsp;考虑 $\bfR^2$ 上的单位圆环 $\left\{x\in\bfR^2\mid x_1^2 + x_2^2 = 1 \right\}$。它的仿射包是全空间 $\bfR^2$,所以其仿射维数为 $2$。但是,在其他大多数维数的定义下,$\bfR^2$ 上的单位圆环的维数为 $1$。
&emsp;&emsp;如果集合 $C \subseteq \bfR^n$ 的仿射维数小于 $n$,那么这个集合在仿射集合 $\aff C \ne \bfR^n$ 中。定义集合 $C$ 的**相对内部**(*relative interior*)为 $\aff C$ 的内部,记为 $\relint C$,即
$$
\relint C = \left\{ x \in C\mid B(x,r) \cap \aff C \subseteq C\ 对于某些\ r > 0 \right\}
$$
其中 $B(x,r) = \left\{ y\mid \left\| y-x \right\| \leqslant r \right\}$,即半径为 $r$,中心为 $x$ 并由范数 $\| \cdot \|$ 定义的球(这里的 $\| \cdot \|$ 可以是任意范数,并且所有范数定义了相同的相对内部)。于是可以定义集合 $C$ 的**相对边界**(*relative boundary*)为 $\cl C\ \setminus \relint C$,此处 $\cl C$ 表示 $C$ 的闭包。
{% note info %}
这里的 “$\setminus$” 表示“集合减”,也即集合 $C$ 的相对边界为其闭包 $\mathbf{cl}\ C$ 减去其相对内部 $\mathbf{relint}\ C$。
{% endnote %}
> **举例**&emsp;考虑 $\bfR^3$ 中处于 $(x_1,x_2)$ 平面的一个正方形,定义
>
> $$
> C = \{x \in \bfR \mid -1\leqslant 1, -1\leqslant x_2\leqslant 1, x_3 = 0\}
> $$
>
> 其仿射包为 $(x_1,x_2)$-平面,即 $\aff C = \{x\in\bfR^3\mid x_3 = 0 \}$。$C$ 的内部为空,但其相对内部为
>
> $$
> \relint C = \{x\in\bfR^3\mid -1<x_1<1,-1<x_2<1,x_3 = 0\}
> $$
>
> $C$(在 $\bfR^3$ 中)的边界是其自身,而相对边界是其边框,
>
> $$
> \{x \in \bfR^3\mid \max\{|x_1|,|x_2|\} = 1,x_3 = 0\}
> $$
# 4. 凸集
&emsp;&emsp;集合 $C$ 被称为**凸集**(*convex set*),如果 $C$ 中任意两点间的线段仍然在 $C$ 中,即对于任意 $x_1, x_2 \in C$ 和满足 $0 \leqslant \theta \leqslant 1$ 的 $\theta$ 都有
$$
\theta x_1 + (1-\theta)x_2 \in C
$$
粗略地看,如果集合中的每一点都可以被其他点沿着它们之间一条无阻碍的路径看见,那么这个集合就是凸集。所谓无阻碍,是指整条路径都在集合中。由于仿射集包含穿过集合中任意不同两点的整条直线,任意不同两点间的线段自然也在集合中。因而仿射集是凸集。[图 2](#图2) 显示了 $\bfR^2$ 空间中一些简单的凸和非凸集合。
<a id="图2"></a>
![图 2. 一些简单的凸和非凸集合。**左**:包含其边界的六边形是凸的。**中**:肾形集合不是凸的,因为图中所示集合中两点间的线段不为集合所包含。**右**:仅包含部分边界的正方形不是凸的。](../images/post/2022-03-29-josh-cvx-1-1/2022-03-29-josh-cvx-1-1-020-SomeSimpleConvexAndNonconvexSets.png){width=1000px}
&emsp;&emsp;集合 $C$ 中所有点的凸组合的集合称为集合 $C$ 的**凸包**(*convex hull*),记为 $\conv C$:
$$
\conv C = \left\{ \theta_1 x_1 + \cdots + \theta_k x_k\mid x_i \in C, \theta_i \geqslant 0, i = 1,\cdots, k, \theta_1 + \cdots + \theta_k = 1 \right\}
$$
顾名思义,凸包 $\conv C$ 总是凸的。它是包含 $C$ 的最小的凸集。也就是说,如果 $B$ 是包含 $C$ 的凸集,那么 $\conv C \subseteq B$。[图 3](#图3) 展示了凸包的定义。
<a id="图3"></a>
![图 3. $\bfR^2$ 上两个集合的凸包。**左**:(如图所示的)十五个点的集合的凸包是一个五边形示)。**右**:[图 2](#图2) 中的肾形集合的凸包是阴影所示的集合。](../images/post/2022-03-29-josh-cvx-1-1/2022-03-29-josh-cvx-1-1-030-TheConvexHullsOfTwoSets.png){width=800px}
{% note info %}
集合 $C$ 的仿射包 $\mathbf{aff}\ C$ 和凸包 $\mathbf{Conv}\ C$ 的区别是参数 $\theta$ 的定义域。可以看出,仿射包 $\mathbf{aff}\ C$ 包含凸包 $\mathbf{Conv}\ C$,因此集合 $C$ 的仿射包是凸集。
{% endnote %}
&emsp;&emsp;凸组合的概念可以扩展到无穷级数、积分以及大多数形式的概率分布。假设 $\theta_1,\theta_2,\cdots$ 满足
$$
\theta_i \geqslant 0, \quad i = 1,2,\cdots,\quad \sum_{i=1}^\infty \theta_i = 1
$$
并且 $x_1, x_2, \cdots \in C$,其中 $C \subseteq \bfR^n$ 为凸集。那么,如果下面的级数收敛,则有
$$
\sum_{i=1}^\infty \theta_i x_i \in C
$$
更一般地,假设 $p:\bfR^n\to\bfR$ 对所有 $x \in C$ 满足 $p(x) \geqslant 0$,并且 $\displaystyle \int_C p(x) \dd x = 1$,其中 $C \subseteq \bfR^n$ 是凸集。那么,如果下面的积分存在,则有
$$
\int_C p(x)x \dd x \in C
$$
&emsp;&emsp;最一般的情况,设 $C \subseteq \bfR^n$ 是凸集,$x$ 是随机变量,并且 $x \in C$ 的概率为 $1$,那么 $\mathbb{E}\{x\} \in C$。事实上,这一形式包含了前述的特殊情况。例如,假设随机变量 $x$ 只在 $x_1$ 和 $x_2$ 中取值,其概率分别为 $\prob(x=x_1) = \theta$ 和 $\prob(x=x_2) = 1-\theta$,其中 $0 \leqslant \theta \leqslant 1$。于是,$\mathbb{E}\{x\} = \theta x_1 + (1-\theta)x_2$,即回到了两个点的简单的凸组合。
# 5. 锥
&emsp;&emsp;如果对于任意 $x \in C$ 和 $\theta \geqslant 0$ 都有 $\theta x \in C$,我们称集合 $C$ 是**锥**(*cone*)或者**非负齐次**(*nonnegative homogeneous*)。如果集合 $C$ 是锥,并且是凸的,则称 $C$ 为**凸锥**(*convex cone*),即对于任意 $x_1, x_2 \in C$ 和 $\theta_1, \theta_2 \geqslant 0$,都有
$$
\theta_1 x_1 + \theta_2 x_2 \in C
$$
在几何上,具有此类形式的点构成了二维的扇形,这个扇形以 $0$ 为顶点,边通过 $x_1$ 和 $x_2$(如[图 4](#图4)所示)。
<a id="图4"></a>
![图 4. 扇形展示了所有具有形式 $\theta_1 x_1 + \theta_2 x_2$ 的点,其中 $\theta_1, \theta_2 \geqslant 0$。扇形的顶点 ($\theta_1 = \theta_2 = 0$) 在 $0$;其边界(对应于 $$\theta_1 = 0$ 或 $\theta_2 = 0$) 穿过点 $x_1$ 和 $x_2$。](../images/post/2022-03-29-josh-cvx-1-1/2022-03-29-josh-cvx-1-1-040-ThePieSlice.png){width=400px}
&emsp;&emsp;具有 $\theta_1 x_1 + \cdots + \theta_k x_k, \theta_1,\cdots,\theta_k \geqslant 0$ 形式的点称为 $x_1,\cdots,x_k$ 的**锥组合**(*conic combination*)(或**非负线性组合**(*nonnegative linear combination*))。如果 $x_i$ 均属于凸锥 $C$,那么,$x_i$ 的每一个锥组合也在 $C$ 中。反言之,集合 $C$ 是凸锥的充要条件是它包含其元素的所有锥组合。如同凸(或仿射)组合一样,锥组合的概念可以扩展到无穷级数和积分中。
&emsp;&emsp;集合 $C$ 的**锥包**(*conic hull*)是 $C$ 中元素的所有锥组合的集合,即
$$
\left\{ \theta_1 x_1 + \cdots + \theta_k x_k\mid x_i \in C, \theta_i \geqslant 0, i = 1,\cdots,k \right\}
$$
它是包含 $C$ 的最小的凸锥(如[图 5](#图5) 所示)。
<a id="图5"></a>
![图 5. [图 3](#图3) 中两个集合的锥包(阴影所示)。](../images/post/2022-03-29-josh-cvx-1-1/2022-03-29-josh-cvx-1-1-050-TheConicHulls.png){width=600px}
{% note info %}
类似仿射包,集合 $C$ 的凸包 $\mathbf{Conv}\ C$ 和锥包的区别是参数 $\theta$ 的定义域。可以看出,锥包包含凸包 $\mathbf{Conv}\ C$,因此集合 $C$ 的锥包是凸集。
{% endnote %}
# 参考文献
1. Stephen P. Boyd and Lieven Vandenberghe, *Convex optimization*. Cambridge, UK: Cambridge University Press, 2004.
2. Stephen P. Boyd and Lieven Vandenberghe, *凸优化*. 北京: 清华大学出版社, 2013.
+230 -207
View File
@@ -1,5 +1,5 @@
---
title: "Josh's Notes: SystemVerilog 验证(Part 1 — 验证导论)"
title: "Josh's Note — SystemVerilog 验证<br>Part 1 验证导论"
mathjax: true
comments: true
copyright: true
@@ -15,243 +15,264 @@ date: 2022-05-30 11:40:49
tags:
- SystemVerilog
- Testbench
- 测试平台
- 验证
categories:
- [Josh 的学习笔记, SystemVerilog]
---
在开始学习有关 System Verilog 语言的细节之前,需要理解如何制订计划来验证手中的设计,以及整个验证计划对 testbench 结构的影响。就像所有房子都有厨房、卧室和浴室一样,所有 testbench 也都需要共享一些用于产生激励、检验响应的结构。本文对 testbench 的构建和设计给出一些引导性的建议和编码风格方面的参考,以满足不同的需要。
&emsp;&emsp;在开始学习有关 SystemVerilog 语言的细节之前,我们需要了解如何制订计划来验证手中的设计,以及这个验证计划对测试平台(testbench)结构的影响。所有测试平台都有用于产生激励、检验响应的结构。本文对测试平台的构建和设计给出一些引导性的建议和编码风格方面的参考,以满足不同的需要。
验证工程师能学到的最重要的原则是“Bugs are good”,不要因为害怕 bug 而不敢 debug,每次找到 bug 都应该及时告警并记录下来。任何一个项目中都不可能没有 bug,所以在流片之前每发现一个 bug 都意味着用户手中的产品少一个 bug。我们应该尽可能细致深入地去检验设计,找出所有可能存在的 bug,尽管有时候这些 bug 可能很容易修复。
&emsp;&emsp;对于验证工程师而言,最重要的原则是“有漏洞是好事(Bugs are good)”,要勇于寻找程序中的漏洞,每次找到漏洞都应该及时告警并记录下来。任何一个项目中都不可能没有漏洞,所以在流片之前每发现一个漏洞都意味着用户手中的产品少一个漏洞。我们应该尽可能细致深入地去检验设计,找出所有可能存在的漏洞,尽管有时候这些漏洞可能很容易修复。
本文需要 Verilog 语言基础,面向对 SystemVerilog HVL (Hard­ware Verification Language, 硬件验证语言) 感兴趣的读者。与 HDL (Hardware Desription Language, 硬件描述语言) 相比,HVL 具有一些特别的性质:
&emsp;&emsp;本文需要 Verilog 语言基础,面向对 SystemVerilog HVL(Hard­ware Verification Language,硬件验证语言)感兴趣的读者。与 HDL(Hardware Description Language,硬件描述语言)相比,HVL 具有一些特别的性质:
1. **约束下的随机激励生成** (*Constrained-random stimulus generation*)。
2. **功能覆盖率** (*Functional coverage*)。
3. **更高层次的结构**,尤其是面向对象的编程 (*Higher-level structures*, especially object-oriented programming)。
4. **多线程**及线程间的通信 (*Multithreading* and interprocess communication)。
5. **支持 HDL 数据类型** (*Support for HDL types* such as Verilog’s 4-state values)。
6. **集成了事件仿真器**,便于对设计施加控制 (*Tight integration with event-simulator* for control of the design)。
1. **受约束的随机激励生成**(*Constrained-random stimulus generation*)。
上述特性使得 HVL 可以创建高度抽象的 testbench,其抽象层次比使用 HDL 或计算机编程语言如 C 所能达到的还要高。
2. **功能覆盖率**(*Functional coverage*)。
3. **更高层次的结构**,尤其是面向对象的编程(*Higher-level structures*, especially object-oriented programming)。
4. **多线程**及线程间的通信(*Multithreading* and interprocess communication)。
5. **支持 HDL 数据类型**(*Support for HDL types*)。
6. **集成了事件仿真器**,便于对设计施加控制(*Tight integration with event-simulator* for control of the design)。
&emsp;&emsp;此外还有其他很多有用的特性,但上述特性使得 HVL 可以创建高度抽象的测试平台,其抽象层次比使用 HDL 或计算机编程语言(如 C 语言)所能达到的还要高。
<!-- more -->
# 1. 验证流程
验证的目的是什么?如果说是为了“寻找 bug”,那也只答对了一部分。硬件设计的目的是设计一个**基于设计规范并能完成特定任务的设计**,例如 DVD 播放器、路由器或者雷达信号处理器。验证工程师需要**确保这些设计能够成功地完成预定的任务**——也就是说,确保**设计能够准别表达这些规范**;而设计在超出预定目标之外的行为可以不用关心。
&emsp;&emsp;验证的目的是什么?如果说是为了“寻找漏洞”,那只答对了一部分。硬件设计的目的是设计一个**基于设计规范并能完成特定任务的设备**,例如 DVD 播放器、路由器或者雷达信号处理器。验证工程师需要**确保这些设备能够成功地完成预定的任务**——也就是说,该设计是**对规范的一种准确表达**;而设计在超出预定目标之外的行为可以不用关心。
验证和设计是并行的流程。对于每个设计模块,设计者需要首先了解硬件设计规范/设计输入,理解其中设计需求,然后使用 RTL 代码之类的机器语言创建相应的逻辑。为了完成这个过程,设计者需要知道输入格式、传输函数以及输出格式。在理解设计需求的过程中总是会有模糊的地方,可能因为是设计输入文档本身的表述不清楚,遗漏了细节或者前后不一致。验证工程师必须阅读硬件规范并拟定验证计划,然后按照计划,创建测试来检查 RTL 代码是否准确地实现了满足了所有的规范。
&emsp;&emsp;验证和设计是**并行**的流程。对于每个设计模块,设计工程师需要首先了解硬件设计规范/设计输入,理解其中的设计需求,然后使用 RTL 等的机器语言创建相应的逻辑。为了完成这个过程,设计工程师需要知道输入格式、传输函数以及输出格式。在理解设计需求的过程中总会有一定模糊(ambiguity),可能因为是设计输入文档本身的表述不清楚,遗漏了细节或者前后不一致。验证工程师必须阅读硬件规范并拟定验证计划,然后按照计划,创建测试来检查 RTL 代码是否准确地实现了所有的特性。
如果有多人按照同一规范进行解读,那么设计流程可能会出现冗余。验证工程师的工作是阅读同样的硬件设计规范并对其含义做出独立的判断,然后利用测试来检查对应的 RTL 代码是否与理解相一致。
&emsp;&emsp;如果有多人按照同一规范进行解读,那么设计流程可能会出现冗余。验证工程师的工作是阅读同样的硬件设计规范并对其含义做出独立的判断,然后利用测试来检查对应的 RTL 代码是否与理解相一致。
## 1.1. 不同层次上的测试
## 1.1. 不同层次的测试
设计中会潜藏着哪些类型的 bug 呢?最容易检测的是在**代码块 (*block*) 层次**上,代码块由每个设计者在模块 (module) 内创建。ALU (Arithmetic-Logic Unit, 运算逻辑单元) 是否正确地执行了两个数的加法?是否每个总线传输都能够成功完成?是否所有的数据包都经过了网络交换机?为了找出这些 bug 而去编写定向测试是一件十分繁琐的事情,原因是这些 bug 都被包含在设计的代码块里。
&emsp;&emsp;设计中会潜藏着哪些类型的漏洞呢?最容易检测的是在**代码块(*block*)层次**上,代码块由每个设计工程师在模块(module)内创建。ALU(Arithmetic-Logic Unit,运算逻辑单元)是否正确地执行了两个数的加法?是否每次总线传输都能够成功完成?是否所有的数据包都经过了网络交换机?为了找出这些漏洞而去编写定向测试是一件十分繁琐的事情,因为这些漏洞都被包含在设计的代码块里。
除了代码块以外,代码块的**输入输出接口**也是 bug 丛生的地方,通常是因为多个设计者对同一规范产生了不同理解。对于一个给定的协议,什么信号发生了变化?在什么时候变化?第一个设计者按照自己对规范的理解建立了一个总线驱动器,第二个设计者也按照自己的理解建立了一个总线接收器,但两者对规范的理解略有不同。我们的工作就是找到两者在硬件逻辑上有冲突的地方,然后将两者进行统一。
&emsp;&emsp;除了代码块以外,代码块的**输入输出接口**也是容易出现漏洞的地方,通常是因为多个设计工程师对同一规范产生了不同理解。对于一个给定的协议,什么信号发生了变化?在什么时候变化?第一个设计工程师按照自己对规范的理解建立了一个总线驱动器,第二个设计工程师也按照自己的理解建立了一个总线接收器,但两者对规范的理解略有不同。**验证工程师的工作就是找到两者在硬件逻辑上有冲突的地方,然后将两者进行统一。**
为了对一个代码块进行仿真,我们需要创建测试集来模拟周围代码块产生激励,这是一件困难而繁琐的事情。好消息是低层次的仿真运行起来会很快。但是,随着代码块数量的增加,可能会在设计和 testbench 中同时找到 bug,因为 testbench 为了提供足够的激励,代码也会很长。当开始对所有的代码块进行合并测试时,它们也会相互激励,测试负担就会相对减少。多个代码块同时仿真可能会发现更多的 bug,但是运行起来也会慢一些。
&emsp;&emsp;为了对一个代码块进行仿真,我们需要创建测试集来模拟周围代码块产生激励,这是一件困难而繁琐的事情。虽然低层次的仿真运行起来会很快,但是随着代码块数量的增加,可能会在设计和测试平台中同时找到漏洞,因为测试平台为了提供足够的激励,代码量也会很长。当开始对所有的代码块进行合并测试时,它们也会相互激励,测试负担就会相对减少。多个代码块同时仿真可能会发现更多的漏洞,但是运行起来也会慢一些。
在 DUT (Design under Test, DUT) 的最高层次中,整个系统都会被测试,但是仿真过程会简单很多。我们的测试应该尽可能让所有的代码块并发活动。所有的输入输出端口都被激活,处理器正在处理数据,而高速缓存也正在载入数据。有了这些行为以后,数据分配和时序上的 bug 肯定会出现。
&emsp;&emsp;在 DUT(Design under Test,待测设计)的最高层次中,整个系统都会被测试,但是仿真过程会简单很多。我们的测试应该尽可能让所有的代码块并发活动。所有的输入输出端口都被激活,处理器正在处理数据,而高速缓存也正在载入数据。有了这些行为以后,数据分配和时序上的漏洞肯定会出现。
在这个层次上,能够运行更加精细的测试,可以**让 DUT 并发执行多种操作以激活尽可能多的代码块**。如果一个 MP3 播放器正在播放音乐时,用户希望从计算机上下载新的音乐会发生什么?在下载的过程中,用户在播放器上按键又会发生什么?显然,一个实际的设备在被使用时,有些用户会去做这些事情,那为什么不在设备制造之初去做同样的测试呢?这种测试可以把易于使用的产品和经常发生故障的产品区分开来。
&emsp;&emsp;在这个层次能够运行更加精细的测试,可以**让 DUT 并发执行多种操作以激活尽可能多的代码块**。如果一个 MP3 播放器正在播放音乐时,用户希望从计算机上下载新的音乐会发生什么?在下载的过程中,用户在播放器上按键又会发生什么?显然,一个实际的设备在被使用时,有些用户会去做这些事情,那为什么不在设备制造之初去做同样的测试呢?这种测试可以把易于使用的产品和经常发生故障的产品区分开来。
一旦验证了 DUT 能够执行所有预期的功能以后,还需要看一下当出现错误时 DUT 会怎样操作。设计是否能应对只进行了一半的事件,已经受损的数据或控制字段?想要列举出所有可能的问题就很困难,更不用说去判断设计会如何从这些错误中恢复了。所以**错误注入和处理 (Error Injection and Handling) 是验证中最具挑战性的部分**。
&emsp;&emsp;一旦验证了 DUT 能够执行所有预期的功能以后,还需要看一下当出现错误时 DUT 会怎样操作。设计是否能应对只进行了一半的事件,已经受损的数据或控制字段?想要列举出所有可能的问题就很困难,更不用说去判断设计会如何从这些错误中恢复了。所以**错误注入和处理(Error Injection and Handling)是验证中最具挑战性的部分**。
随着设计抽象层次的提高,验证的挑战性也会加大。我们可以确定单个信元是否正确通过 ATM (Asynchronous Transfer Mode, 异步传输模式) 路由器,但如果是一系列有着不同优先权的数据流呢?在最高的抽象层次中,下一个操作应该选择哪个信元并不是显而易见的,可能不得不统计成千上万的信元,以便确定这种集总的操作是否正确。
&emsp;&emsp;随着设计抽象层次的提高,验证的挑战性也会加大。我们可以确定单个信元是否正确通过 ATM(Asynchronous Transfer Mode,异步传输模式)路由器,但如果是一系列有着不同优先权的数据流呢?在最高的抽象层次中,下一个操作应该选择哪个信元并不是显而易见的,可能不得不统计成千上万的信元,以便确定这种集总的操作是否正确。
最后,**我们永远也无法证明没有任何遗留的 bug**,所以需要不停地尝试新的验证策略。
&emsp;&emsp;最后,**我们永远也无法证明没有任何遗留的漏洞**,所以需要不停地尝试新的验证策略。
## 1.2. 验证计划
验证计划和硬件规范是紧密联系在一起的,它描述了需要验证什么样的特性,以及采用哪些技术。这些步骤可能包含有定向测试 (directed test) 或随机测试 (random test) 、断言 (assertion)、软硬件协同验证 (HW/SW co-verification)、硬件仿真 (emulation)、形式验证 (formal proof),以及对验证 IP 的使用等等。有关验证更全面的讨论,可参见 Bergeron 的 *Verification Methodology Manual for
SystemVerilog* (2006)。
&emsp;&emsp;验证计划和硬件规范是紧密联系在一起的,它描述了需要验证什么样的特性,以及采用哪些技术。这些步骤可能包含有定向测试(directed testing)或随机测试(random testing)、断言(assertion)、软硬件协同验证(HW/SW co-verification)、硬件仿真(emulation)、形式验证(formal proof),以及对验证 IP 的使用等等。有关验证更全面的讨论,可参见 Bergeron 的 *Verification Methodology Manual for
SystemVerilog*(2006)。
# 2. Testbench 的基本功能
# 2. 测试平台的基本功能
Testbench 的用途在于**确定 DUT 的正确性**。包含下列步骤:
&emsp;&emsp;测试平台的用途在于**确定 DUT 的正确性**。包含下列步骤:
1. 产生激励。
2. 把激励施加到 DUT 上。
3. 捕捉响应。
4. 检验正确性。
5. 对照整个验证目标测算进展情况。
1. 产生激励。
有些步骤是 testbench 自动完成的,有些则需要手动操作,所选择的验证方法学决定了上述步骤如何展开。
2. 把激励施加到 DUT 上。
3. 捕捉响应。
4. 检验正确性。
5. 对照整个验证目标测算进展情况。
&emsp;&emsp;有些步骤是测试平台自动完成的,有些则需要手动操作,所选择的验证方法学(methodology)决定了上述步骤如何展开。
# 3. 定向测试
当需要验证一个设计的正确性时,传统的做法可能是使用定向测试。使用这种方式,首先需要阅读硬件规范,然后写下验证计划,计划上列有各种测试,每个测试针对一系列相关的特性。按照这个计划,接着**编写针对 DUT 具体特性的激励向量,然后使用这些向量对 DUT 进行仿真**。仿真结束后,手动查看一下结果文件和波形,确保设计的行为与预期的一致。一旦测试结果正确,就可以开始下一个测试。
&emsp;&emsp;当需要验证一个设计的正确性时,传统的做法可能是使用**定向测试**(*directed testing*)。使用这种方式,首先需要阅读硬件规范,然后写下验证计划,计划上列有各种测试,每个测试针对一系列相关的特性。按照这个计划,接着**编写针对 DUT 具体特性的激励向量,然后使用这些向量对 DUT 进行仿真**。仿真结束后,手动查看一下结果文件和波形,确保设计的行为与预期的一致。一旦测试结果正确,就可以开始下一个测试。
这种渐进的方法比较容易取得稳步的进展,因而很受那些喜欢看到项目持续向前推进管理者的欢迎。由于创建每个激励向量时并不需要什么基础,所以定向测试的结果也会很快得到。只要给予足够的时间和人力,定向测试对于大部分设计验证来讲都是可以胜任的。
&emsp;&emsp;这种渐进的方法比较容易取得稳步的进展,因而很受那些喜欢看到项目持续向前推进的管理者的欢迎。由于创建每个激励向量时并不需要什么基础,所以定向测试的结果也会很快得到。只要给予足够的时间和人力,定向测试对于大部分设计验证来讲都是可以胜任的。
[图 1.1](#图1.1) 显示了定向测试如何逐步覆盖验证计划中的每个特性。每个测试都针对一个特别的设计元素集合。**如果有足够的时间**,可以写出 100% 覆盖整个验证计划所需要的全部测试。
&emsp;&emsp;[图 1](#图1) 显示了定向测试如何逐步覆盖验证计划中的每个特性。每个测试都针对一个特别的设计元素集合。**如果有足够的时间**,可以写出 100% 覆盖整个验证计划所需要的全部测试。
<span id="图1.1"></span>
<div align="center">
<img src="../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-010-DirectedTestProgressOverTime.png" width=500px alt="图 1.1 定向测试随时间的进展"/>
</div>
<a id="图1"></a>
如果没有足够的时间和资源来完成定向测试该怎么办?如[图 1.1](#图1.1),当在时间往前推进时,覆盖率 (coverage) 可能维持不变。如果设计复杂度翻倍,那么测试就需要增加一倍的时间或者人力,而这种情况是我们所不愿意看到的。因此为了达到 100% 覆盖率的目标,需要一种可以更快找出 bug 的方法。
![图 1. 定向测试随时间的进展](../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-010-DirectedTestProgressOverTime.png){width=500px}
[图 1.2](#图1.2) 所示为整个设计空间和各种特性被定向测试案例覆盖的情形。在设计空间里有很多特性 (feature),其中有些存在 bug,需要编写各种测试 (test) 去覆盖所有的特性并找出 bug。
&emsp;&emsp;如果没有足够的时间和资源来完成定向测试该怎么办?如[图 1](#图1),当在时间往前推进时,覆盖率(coverage)可能维持不变。如果设计复杂度翻倍,那么测试就需要增加一倍的时间或者人力,而这种情况是我们所不愿意看到的。因此为了达到 100% 覆盖率的目标,需要一种可以更快找出漏洞的方法。
<span id="图1.2"></span>
<div align="center">
<img src="../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-020-DirectedTestCoverage.png" width=800px alt="图 1.2 定向测试的覆盖率"/>
</div>
&emsp;&emsp;[图 2](#图2) 所示为整个设计空间和各种特性被定向测试案例覆盖的情形。在设计空间里有很多特性(feature),其中有些存在漏洞,需要编写各种测试(test)去覆盖所有的特性并找出漏洞。
<a id="图2"></a>
![图 2. 定向测试的覆盖率](../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-020-DirectedTestCoverage.png){width=800px}
# 4. 方法学基础
本文使用如下原则:
&emsp;&emsp;本文使用如下原则:
1. 约束下的随机激励。
2. 功能覆盖率。
3. 使用事件处理器的分层 testbench。
4. 对所有测试通用的 testbench。
5. 独立于 testbench 之外的个性化测试代码。
1. 受约束的随机激励。
这些原则是相关联的。随机激励对于测试复杂设计十分关键。**定向测试可以找出设计中预期的 bug,而随机测试则能够找出预料不到的 bug**。当使用随机激励时,需要用功能覆盖率来评估验证的进展情况。一旦开始使用自动生成的激励,就需要一种能够**自动预测结果**的方式——通常是记分板或者参考模型。建立包括自预测在内的 testbench 基础设施,是一件工作量很大的事情。分层 testbench (layered testbench) 能够把问题分解为容易处理的小块,这样有助于控制复杂度。事件处理器 (transactors) 能够为构建这些小块提供有用的模式。在适当的规划下,可以建立一个 testbench 所需的基础设施,它们能在所有测试中通用并且不需要经常修改,只需要在某些地方放置“hook”,以便测试能够在这些地方执行调整激励或注入错误等特定操作。相反,针对单一测试的个性化代码必须与 testbench 分开,这样可以避免增加基础设施的复杂度。
2. 功能覆盖率。
建立这种风格的 testbench 所需的时间要比传统的定向 testbench 多得多——尤其是自检的部分。其结果是,可能需要很长的准备时间才能进行第一次可运行的测试。这会给项目管理带来阵痛,所以需要在测试时间表上把这部分考虑进去。从[图 1.3](#图1.3) 中可以看到,第一个随机测试运行前有比较长的初始延迟。
3. 使用事件处理器的分层测试平台。
<span id="图1.3"></span>
<div align="center">
<img src="../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-030-ConstraineRandomTestProgressOverTimeVSDirectedTesting.png" width=500px alt="图 1.3 约束下的随机测试与定向测试随时间的进度比较"/>
</div>
4. 对所有测试通用的测试平台。
随机测试的前期准备工作看起来似乎令人不满意,但是其回报却很高。每个随机测试都可以共享这个通用的 testbench,不像每个定向测试都要从零开始编写。每个随机测试都会包含一部分代码,将激励约束到特定的方向上并触发期望的异常,比如创建一个协议违例。其结果是,约束下的随机 testbench 找起 bug 来会比很多定向测试快很多。随着 bug 出现率的下降,应该创建新的随机约束去探索新的区域。最后的几个 bug 可能只能通过定向测试来发现,但是绝大部分的 bug 都应该会在随机测试中出现。
5. 独立于测试平台之外的个性化测试代码。
# 5. 约束下的随机激励<a name="05"></a>
&emsp;&emsp;些原则是相关联的。随机激励对于测试复杂设计十分关键。**定向测试可以找出设计中预期的漏洞,而随机测试则能够找出预料不到的漏洞**。当使用随机激励时,需要用功能覆盖率来评估验证的进展情况。一旦开始使用自动生成的激励,就需要一种能够**自动预测结果**的方式——通常是记分板(scoreboard)或者参考模型(reference model)。建立包括自预测在内的测试平台是一件工作量很大的事情。**分层测试平台**(*layered testbench*)能够把问题分解为容易处理的小块,这样有助于控制复杂度。**事件处理器**(*transactors*)能够为构建这些小块提供有用的模式(pattern)。在适当的规划下,可以建立一个测试平台所需的基础设施,它们能在所有测试中通用并且不需要经常修改,只需要在某些地方放置“钩子(hook)”,以便测试能够在这些地方执行调整激励或注入错误等特定操作。相反,针对单一测试的个性化代码必须与测试平台分开,这样可以避免增加基础设施的复杂度。
虽然我们希望仿真器能产生随机激励,但同时又**不希望这些激励数值完全随机**。使用 SystemVerilog 语言可以描述激励的格式 (例如,地址是 32 位;操作码是 ADD 、 SUB 或 STORE;长度 < 32 字节),然后让仿真器产生满足约束的数值。这些数值会被发送到设计中去,同时也会被发送到一个负责预测仿真结果的高层模块中去。设计的实际输出最终需要和预测输出做对比。
&emsp;&emsp;建立这种风格的测试平台所需的时间要比传统的定向测试平台多得多,尤其是自检的部分,因此可能需要很长的准备时间才能进行第一次可运行的测试。这会给项目管理带来阵痛,所以需要在测试时间表上把这部分考虑进去。从[图 3](#图3) 中可以看到,第一个随机测试运行前有比较长的初始延迟。
[图 1.4](#图1.4) 所示为约束下的随机测试在整个设计空间中的覆盖率。
<a id="图3"></a>
- 值得注意的是,**一个随机测试的覆盖范围往往比一个定向测试大**。多出来的覆盖部分可能会与其他测试发生交叠,或者探测到事先没有预料到的新区域 (new area)。
- 在这些新区域中发现 bug 是一件幸运的事情。如果这些对新区域的测试不合法,则需要编写更多的约束去阻止随机测试产生非法的功能。
- 对于那些约束下的随机测试覆盖不到的地方,可能还需要编写一些定向测试。
![图 3. 受约束的随机测试与定向测试随时间的进度比较](../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-030-ConstraineRandomTestProgressOverTimeVSDirectedTesting.png){width=500px}
<span id="图1.4"></span>
<div align="center">
<img src="../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-040-ConstrainedRandomTestCoverage.png" width=800px alt="图 1.4 约束下的随机测试覆盖率"/>
</div>
&emsp;&emsp;随机测试的前期准备工作看起来似乎令人不满意,但是其回报却很高。每个随机测试都可以共享这个通用的测试平台,不像每个定向测试都要从零开始编写。每个随机测试都会包含一部分代码,将激励约束到特定的方向上并触发期望的异常,比如创建一个协议违例(protocol violation),受约束的随机测试平台找起漏洞来会比很多定向测试快很多。
[图 1.5](#图1.5) 所示为达到完全覆盖的技术路线:
&emsp;&emsp;随着漏洞出现率的下降,应该创建新的随机约束去探索新的区域。最后的几个漏洞可能只能通过定向测试来发现,但是绝大部分的漏洞都应该会在随机测试中出现。
1. 从左上角的基本的约束下的随机测试 (constrained random test) 开始,使用不同的种子 (seed) 运行。
2. 当我们查看功能覆盖率 (functional covrage) 报告时,注意找出覆盖率中的间隙 (hole),即覆盖盲区。
3. 针对这些盲区进行最小程度代码修改 (mininal code midification),可能是使用新的约束 (constraint),也可能是把错误或延迟加入到 DUT 中。这个外部循环会花掉我们大部分的时间,只有对少数使用随机测试达不到的特性才编写定向测试。
# 5. 受约束的随机激励<a name="05"></a>
<span id="图1.5"></span>
<div align="center">
<img src="../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-050-CoverageConvergence.png" width=500px alt="图 1.5 覆盖率收敛"/>
</div>
&emsp;&emsp;虽然我们希望仿真器能产生随机激励,但同时又**不希望这些激励数值完全随机**。使用 SystemVerilog 语言可以描述激励的格式(例如,地址是 32 位;操作码是 ADD、 SUB 或 STORE;长度 < 32 字节),然后让仿真器产生满足约束的数值。这些数值会被发送到设计中去,同时也会被发送到一个负责预测仿真结果的高层模块中去。设计的实际输出最终需要和预测输出做对比。
&emsp;&emsp;[图 4](#图4) 所示为受约束的随机测试在整个设计空间中的覆盖率。
- 值得注意的是,**一个随机测试的覆盖范围往往比一个定向测试大**。多出来的覆盖部分可能会与其他测试发生交叠,或者探测到事先没有预料到的新区域(new area)。
- 在这些新区域中发现漏洞是一件幸运的事情。如果这些对新区域的测试不合法,则需要编写更多的约束去阻止随机测试产生非法的功能。
- 对于那些受约束的随机测试覆盖不到的地方,可能还需要编写一些定向测试。
<a id="图4"></a>
![图 4. 受约束的随机测试覆盖率](../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-040-ConstrainedRandomTestCoverage.png){width=800px}
&emsp;&emsp;[图 5](#图5) 所示为达到完全覆盖的技术路线:
1. 从左上角的基本的受约束的随机测试(constrained random test)开始,使用不同的种子(seed)运行。
2. 当我们查看功能覆盖率(functional coverage)报告时,注意找出覆盖率中的间隙(hole),即覆盖盲区。
3. 针对这些盲区进行最小程度代码修改(minimal code modification),可能是使用新的约束(constraint),也可能是把错误或延迟加入到 DUT 中。这个外部循环会花掉我们大部分的时间,只有对少数使用随机测试达不到的特性才编写定向测试。
<a id="图5"></a>
![图 5. 覆盖率收敛](../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-050-CoverageConvergence.png){width=500px}
# 6. 我们的随机化对象是什么<a name="06"></a>
当考虑对一个设计的激励进行随机化时,首先想到的可能是数据字段。这种激励最容易创建——只需调用 `$random()` 即可。问题是这种随机数据在找 bug 方面的回报很小。能够使用随机数据找到的 bug 类型基本上都是在数据路径上的,很可能还都是比特级的错误,还需要找出**控制逻辑上的 bug**。
&emsp;&emsp;当考虑对一个设计的激励进行随机化时,首先想到的可能是数据字段。这种激励最容易创建——只需调用 `$random()` 即可。问题是这种随机数据在找漏洞方面的回报很小。能够使用随机数据找到的漏洞类型基本上都是在数据路径上的,很可能还都是比特级的错误,还需要找出**控制逻辑上的漏洞**。
此外,需要广泛地考虑所有的设计输入,如下所列:
&emsp;&emsp;此外,需要广泛地考虑所有的设计输入,如下所列:
1. 设备配置。
2. 环境配置。
3. 输入数据。
4. 协议异常。
5. 错误和违例。
6. 时延。
1. 设备配置。
2. 环境配置。
3. 输入数据。
4. 协议异常。
5. 错误和违例。
6. 时延。
## 6.1. 设备和环境配置
在对 RTL 设计进行测试的过程中,察觉不到 bug 的最常见的原因是什么?是因为**没有尝试足够多的不同配置**。很多测试只使用了仅仅经过复位的设计,或者施加固定的初始化向量集把设计引向一个已知的状态。这就好比是在个人电脑上刚刚安装完操作系统,还没有安装任何应用程序的时候,就对操作系统进行测试。测试结果当然会很好,但是并没有挖掘出实际的问题。
&emsp;&emsp;在对 RTL 设计进行测试的过程中,察觉不到漏洞的最常见的原因是什么?是因为**没有尝试足够多的不同配置(*configuration*)**。很多测试只使用了仅仅经过复位的设计,或者施加固定的初始化向量集把设计引向一个已知的状态。这就好比是在个人电脑上刚刚安装完操作系统,还没有安装任何应用程序的时候,就对操作系统进行测试。测试结果当然会很好,但是并没有挖掘出实际的问题。
在一个实际的应用环境中,随着 DUT 使用时间的增加,其配置会变得越来越随机。例如,验证一个分时复用的多路开关,它有 2000 个输入通道和 12 个输出通道。这些通道在另外一边可以映射成各种不同的配置。每个输入可能作为单个通道使用,也可能会被进一步分割成多个通道。棘手的是,虽然大部分时间里使用的是几种标准的通道分割方式,但由于其他分割方式的组合也是合法的,所以存在着大量可能的用户配置。
> &emsp;&emsp;在一个实际的应用环境中,随着 DUT 使用时间的增加,其配置会变得越来越随机。例如,验证一个分时复用的多路开关,它有 2000 个输入通道和 12 个输出通道。这些通道在另外一边可以映射成各种不同的配置。每个输入可能作为单个通道使用,也可能会被进一步分割成多个通道。棘手的是,虽然大部分时间里使用的是几种标准的通道分割方式,但由于其他分割方式的组合也是合法的,所以存在着大量可能的用户配置。
>
> &emsp;&emsp;为了测试这个设备,对于每个通道的配置,工程师都必须写出好几十行的定向测试代码。显然,验证工程师无力应对如此多的通道配置。后来编写了一个测试平台,对每个通道的参数都采用随机化策略,然后把这部分代码放到一个循环里去完成所有开关通道的配置。现在,找出与配置相关的漏洞变得更加容易,而这些漏洞在以前常常不被察觉。
为了测试这个设备,对于每个通道的配置,工程师都必须写出好几十行的定向测试代码。显然,验证工程师无力应对如此多的通道配置。后来编写了一个 testbench,对每个通道的参数都采用随机化策略,然后把这部分代码放到一个循环里去完成所有开关通道的配置。现在,找出与配置相关的 bug 变得更加容易,而这些 bug 在以前常常不被察觉。
&emsp;&emsp;在实际的应用中,我们的设计所在的环境里会包含其他的部件。当对 DUT 进行验证时,实际上就是把测试平台连接起来模仿这个环境,应该对整个环境的配置进行随机化,包括仿真的时长、设备的数量,以及它们的配置方式。当然,需要创建约束以确保配置的合法性。
在实际的应用中,我们的设计所在的环境里会包含其他的部件。当对 DUT 进行验证时,实际上就是把 testbench 连接起来模仿这个环境,应该对整个环境的配置进行随机化,包括仿真的时长、设备的数量,以及它们的配置方式。当然,需要创建约束以确保配置的合法性。
> &emsp;&emsp;在另外一个 Synopsys 公司的客户案例中,一家公司设计了一个 I/O 交换芯片,用于把多套 PCI 总线连接到一套内部总线上。在仿真一开始,他们就随机地选择了 PCI 总线的数目(1\~4)以及总线上设备的数目(1\~8),而且对每个设备上的参数也进行了随机化(如主从模式、 CSR 地址等等)。他们使用功能覆盖率对测试过的组合进行跟踪,以确保所有可能的组合都被覆盖。
在另外一个 Synopsys 公司的客户案例中,一家公司设计了一个 I/O 交换芯片,用于把多套 PCI 总线连接到一套内部总线上。在仿真一开始,他们就随机地选择了 PCI 总线的数目 (1~4) 以及总线上设备的数目 (1~8),而且对每个设备上的参数也进行了随机化(如主从模式、 CSR 地址等等)。他们使用功能覆盖率对测试过的组合进行跟踪,以确保所有可能的组合都被覆盖。
其他环境参数还包括测试长度、错误注入比率,以及时延模式等。Bergeron (2006) 在这方面有更多的例子。
&emsp;&emsp;其他环境参数还包括测试长度、错误注入比率,以及时延模式等。Bergeron(2006)在这方面有更多的例子。
## 6.2. 输入数据
当看到随机激励时,我们可能会想到**选取一个总线写入的事件或 ATM 信元,然后把随机数值填充到其中的数据字段里**。实际上,这种方式相当直接,需要事先估计好所有的分层协议和错误注入,以及记分板的内容和功能覆盖率。
&emsp;&emsp;当看到随机激励时,我们可能会想到**选取一个总线写入的事件或 ATM 信元,然后把随机数值填充到其中的数据字段里**。实际上,这种方式相当直接,需要事先估计好所有的分层协议和错误注入,以及记分板的内容和功能覆盖率。
## 6.3. 协议异常、错误和违例
最令人沮丧的事情莫过于个人电脑或移动电话之类的设备死机。大多数情况下,唯一的办法就是关机然后重新启动。死机最有可能的原因是,产品内部的一部分逻辑遇到了错误以后无法恢复过来,因此使得设备不能正常工作。
&emsp;&emsp;最令人沮丧的事情莫过于个人电脑或移动电话之类的设备死机。大多数情况下,唯一的办法就是关机然后重新启动。死机最有可能的原因是,产品内部的一部分逻辑遇到了错误以后无法恢复过来,因此使得设备不能正常工作。
如何才能阻止这些问题出现在我们创建的硬件上呢?应该尽量尝试去仿真在实际的硬件中可能出现的错误,而且应该针对所有可能出现的错误。如果一个总线事件没有完成会怎么样?如果遇到一个非法的操作呢?设计规范中有没有指出哪两个信号互斥?要对这些情况一一尝试,然后确保设备还能继续正常运作。
&emsp;&emsp;如何才能阻止这些问题出现在我们创建的硬件上呢?应该尽量尝试去仿真在实际的硬件中可能出现的错误,而且应该针对所有可能出现的错误。如果一个总线事件没有完成会怎么样?如果遇到一个非法的操作呢?设计规范中有没有指出哪两个信号互斥?要对这些情况一一尝试,然后确保设备还能继续正常运作。
**在尝试使用不当的命令去激励硬件的同时,也应该注意捕捉出现的问题**。例如,重新调用那些互斥的信号。可以增加用于检验的代码来帮忙找出问题所在。这些代码应该至少能够在出错的地方打印一个警告信息,如果能够报告出错误并且使测试停下来则更好。花费大最时间在代码中追溯故障的根源,是一件令人非常不愉快的事情,尤其是在本来如果使用一个简单的断言就可以定位这个错误的情况下。(关于如何在 testbench 和设计代码中编写断言,可以参考 Vijayaraghavan 和 Ramanathan 在 2005 出版的著作。) 只要确保能够使代码在出错的地方停止仿真,那么就很容易应对测试中的错误。
&emsp;&emsp;**在尝试使用不当的命令去激励硬件的同时,也应该注意捕捉出现的问题**。例如,重新调用那些互斥的信号。可以增加用于检验的代码来帮忙找出问题所在。这些代码应该至少能够在出错的地方打印一个警告信息,如果能够报告出错误并且使测试停下来则更好。花费大最时间在代码中追溯故障的根源,是一件令人非常不愉快的事情,尤其是在本来如果使用一个简单的断言就可以定位这个错误的情况下。(关于如何在测试平台和设计代码中编写断言,可以参考 Vijayaraghavan 和 Ramanathan 在 2005 出版的著作。)只要确保能够使代码在出错的地方停止仿真,那么就很容易应对测试中的错误。
## 6.4. 时延和同步
Testbench 应该以多快的速度发送激励呢?使用**约束下的随机时延**有助于捕捉协议上的 bug。时延最短的测试运行速度最快,但它产生不了所有可能的激励。可以创建一个 testbench 以最快的速度与另一个代码块通信,但那些隐蔽的 bug 往往是在引入间歇性时延之后才被发现的。
&emsp;&emsp;测试平台应该以多快的速度发送激励呢?使用**受约束的随机时延**有助于捕捉协议上的漏洞。时延最短的测试运行速度最快,但它产生不了所有可能的激励。可以创建一个测试平台以最快的速度与另一个代码块通信,但那些隐蔽的漏洞往往是在引入间歇性时延之后才被发现的。
一个代码块对于来自同一接口的所有可能激励也许都能正常工作,但如果同时面对多个输入,隐蔽的 bug 可能就会出现。尝试协调各个驱动器使它们能够在不同的速率下进行通信。如果输入以可能的最快速率到达,而输出却被卡在一个较低的速率上,该怎么办?如何处理来自多个输人的激励同时到达的情况?如果这此激励带有不同的时延又该怎么办?使用功能覆盖率,可以测量随机生成的各种组合。
&emsp;&emsp;一个代码块对于来自同一接口的所有可能激励也许都能正常工作,但如果同时面对多个输入,隐蔽的漏洞可能就会出现。尝试协调各个驱动器使它们能够在不同的速率下进行通信。如果输入以可能的最快速率到达,而输出却被卡在一个较低的速率上,该怎么办?如何处理来自多个输人的激励同时到达的情况?如果这此激励带有不同的时延又该怎么办?使用功能覆盖率,可以测量随机生成的各种组合。
## 6.5. 并行的随机测试
如何运行测试?每个定向测试都带有一个 testbench,能够产生一组特定的激励和响应向量。如果想改变激励,就需要改变测试。随机测试则包含了 testbench 代码和随机种子。如果对同一个测试运行 50 次,每次都采用不同的种子,那么将会得到 50 个不同的激励集合。使用多个种子运行同一个测试可以加大覆盖率,同时也能减少工作量。
&emsp;&emsp;如何运行测试?每个定向测试都带有一个测试平台,能够产生一组特定的激励和响应向量。如果想改变激励,就需要改变测试。随机测试则包含了测试平台代码和随机种子。如果对同一个测试运行 50 次,每次都采用不同的种子,那么将会得到 50 个不同的激励集合。使用多个种子运行同一个测试可以加大覆盖率,同时也能减少工作量。
我们需要**为每次仿真选定一个独特的种子**。有些人使用自然时间作为种子,但这依然会引起重复。如果半夜里在一个计算机集群系统上开始 10 项任务会怎么样?多项任务可能会于同一时间在不同的计算机上启动,这样还是会得到相同的随机种子并运行相同的激励。因此,应该把处理器的名称加入到种子里去。如果集群系统里面有多核计算机,那还是可能会出现两个相同的种子,所以在这种情况下应该把处理器核的编号也加到种子里去,这样就能得到独一无二的种子了。
&emsp;&emsp;我们需要**为每次仿真选定一个独特的种子**。有些人使用自然时间作为种子,但这依然会引起重复。如果半夜里在一个计算机集群系统上开始 10 项任务会怎么样?多项任务可能会于同一时间在不同的计算机上启动,这样还是会得到相同的随机种子并运行相同的激励。因此,应该把处理器的名称加入到种子里去。如果集群系统里面有多核计算机,那还是可能会出现两个相同的种子,所以在这种情况下应该把处理器核的编号也加到种子里去,这样就能得到独一无二的种子了。
> 我们还需要对并行仿真的文件组织进行规划。每次仿真都会有一系列的输出文件,例如日志文件和功能覆盖率文件,可以让每个仿真在不同的目录里运行,或者也可以尝试给每个文件取不同的名字。最简单的办法是在目录名后面加上随机种子的值。
{% note info %}
&emsp;&emsp;我们还需要对并行仿真的文件组织进行规划。每次仿真都会有一系列的输出文件,例如日志文件和功能覆盖率文件,可以让每个仿真在不同的目录里运行,或者也可以尝试给每个文件取不同的名字。最简单的办法是在目录名后面加上随机种子的值。
{% endnote %}
# 7. 功能覆盖率
本文[第 5 节](#05)和[第 6 节](#06)讲述了如何创建激励并使这些激励遍历整个可能的输入空间。使用这种方法,Testbench 会频繁访问部分区域,但需要花费很长的时间来达到所有可能的状态。即使对仿真时间不加限制,无法达到的状态还是永远也不会被访问到,因此需要知道哪些部分已经被验证过,这样才能对验证计划中的项目进行核对。
&emsp;&emsp;本文[第 5 节](#05)和[第 6 节](#06)讲述了如何创建激励并使这些激励遍历整个可能的输入空间。使用这种方法,测试平台会频繁访问部分区域,但需要花费很长的时间来达到所有可能的状态。即使对仿真时间不加限制,无法达到的状态还是永远也不会被访问到,因此需要知道哪些部分已经被验证过,这样才能对验证计划中的项目进行核对。
对功能覆盖率的测量和使用包含了几个步骤。首先,需要在 testbench 中加入代码,用于监控进入设备中的激励,以及设备对激励的反应,并据此确定哪些功能已经被验证过。运行几次仿真,每次使用不同的种子。接下来,把这些仿真的结果合并到一个报告中。然后需要对结果进行分析,最后决定如何采用新的激励来达到那些尚未被测试到的条件和逻辑。
&emsp;&emsp;对功能覆盖率的测量和使用包含了几个步骤。首先,需要在测试平台中加入代码,用于监控进入设备中的激励,以及设备对激励的反应,并据此确定哪些功能已经被验证过。运行几次仿真,每次使用不同的种子。接下来,把这些仿真的结果合并到一个报告中。然后需要对结果进行分析,最后决定如何采用新的激励来达到那些尚未被测试到的条件和逻辑。
## 7.1. 从功能覆盖率到激励的反馈
随机测试需要使用反馈 (feedback)。最初的测试会被运行很多次,使用不同的种子,创建很多互异的输入序列。但是到了最后,即使使用新的种子,所产生的激励也很可能无法在设计空间中探测到新区域。**随着功能覆盖率逐渐接近极限,需要改变测试,以期能找出新的方法去达到那些尚未被覆盖的区域**。这被称为“覆盖率驱动的验证”,如[图 1.6](#图1.6) 所示。
&emsp;&emsp;随机测试需要使用反馈(feedback)。最初的测试会被运行很多次,使用不同的种子,创建很多互异的输入序列。但是到了最后,即使使用新的种子,所产生的激励也很可能无法在设计空间中探测到新区域。**随着功能覆盖率逐渐接近极限,需要改变测试,以期能找出新的方法去达到那些尚未被覆盖的区域**。这被称为“覆盖率驱动的验证”,如[图 6](#图6) 所示。
<span id="图1.6"></span>
<div align="center">
<img src="../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-060-TestProgressWithAndWithoutFeedback.png" width=500px alt="图 1.6 带反馈和不带反馈的测试进展"/>
</div>
<a id="图6"></a>
Testbench 有没有可能为我们做到这一点呢?假设现在需要使用 testbench 在每个周期为处理器产生一个总线事件,并为总线事件做出终止判断(成功、校验错误、重试)。在没有使用 HVL 的时候,通常会编写一个很长的定向测试集,然后花费了很多天的工夫编排终止判断代码,并让它们在合适的周期里给出判断。经过了大量的手动分析以后才得出成功的结论达到 100 %的覆盖率。但之后可能由于处理器的时序有了一点微小的改变,不得不重新分析测试并改变激励。
![图 6. 带反馈和不带反馈的测试进展](../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-060-TestProgressWithAndWithoutFeedback.png){width=500px}
更加有效的测试策略是**使用随机总线事件和终止判断**。运行的时间越长,覆盖率就会越高。另外的一个好处是,这种测试在创建激励时灵活性很高,足以应对设计时序有改变的情形。为了做到这一点,可以在测试代码中加入一个反馈循环,用于监测己生成的激励 (是否已经产生所有写周期?) 并根据情况调整约束的权重 (把写的权重降到零)。这种改进能大大缩减达到完全覆盖的时间,而且只需要很少量的人工干预。
&emsp;&emsp;测试平台有没有可能为我们做到这一点呢?假设现在需要使用测试平台在每个周期为处理器产生一个总线事件,并为总线事件做出终止判断(成功、校验错误、重试)。在没有使用 HVL 的时候,通常会编写一个很长的定向测试集,然后花费了很多天的工夫编排终止判断代码,并让它们在合适的周期里给出判断。经过了大量的手动分析以后才得出成功的结论达到 100 %的覆盖率。但之后可能由于处理器的时序有了一点微小的改变,不得不重新分析测试并改变激励。
其实,这并不是一种典型的情况,因为从功能覆盖率到激励的反馈往往是微不足道的。在实际的设计中,应该如何改变激励以使它达到一个期望的设计状态呢?这不仅要求对设计有深入的了解,而且还需要高超的形式验证技术。总之答案并不简单,所以**在约束下的随机激励中很少采用动态反馈**。相反地,**需要手动分析覆盖率报告,然后调整随机约束**。
&emsp;&emsp;更加有效的测试策略是**使用随机总线事件和终止判断**。运行的时间越长,覆盖率就会越高。另外的一个好处是,这种测试在创建激励时灵活性很高,足以应对设计时序有改变的情形。为了做到这一点,可以在测试代码中加入一个反馈循环,用于监测己生成的激励(是否已经产生所有写周期?)并根据情况调整约束的权重(把写的权重降到零)。这种改进能大大缩减达到完全覆盖的时间,而且只需要很少量的人工干预。
有些形式分析工具如 Magellan (Synopsys, 2003) 用到了反馈。它首先对设计进行分析并找出所有可以达到的互异状态。然后运行一小段仿真看有多少状态被访问到。最后,在状态机和设计输入之间进行搜索并计算出达到所有遗留状态所需要的激励,然后 Ma­gellan 再把这些激励施加到 DUT 上。
&emsp;&emsp;其实,这并不是一种典型的情况,因为从功能覆盖率到激励的反馈往往是微不足道的。在实际的设计中,应该如何改变激励以使它达到一个期望的设计状态呢?这不仅要求对设计有深入的了解,而且还需要高超的形式验证技术。总之答案并不简单,所以**在受约束的随机激励中很少采用动态反馈**。相反地,**需要手动分析覆盖率报告,然后调整随机约束**。
# 8. Testbench 的构建
&emsp;&emsp;有些形式分析工具如 Magellan(Synopsys, 2003)用到了反馈。它首先对设计进行分析并找出所有可以达到的互异状态。然后运行一小段仿真看有多少状态被访问到。最后,在状态机和设计输入之间进行搜索并计算出达到所有遗留状态所需要的激励,然后 Ma­gellan 再把这些激励施加到 DUT 上。
在仿真时,**testbench 会把整个 DUT 包围起来**,就像一个硬件测试器连接到一个物理芯片上一样,如[图 1.7](#图1.7) 所示。testbench 和测试仪器都会产生激励并捕捉响应。不同的是,testbench 需要工作在一个很宽的抽象层次范围内,同时创建事件和激励序列并最终转换成比特向量。而测试仪器则只工作在比特级上。
# 8. 测试平台的构建
<span id="图1.7"></span>
<div align="center">
<img src="../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-070-TheTestbenchDesignEnvironment.png" width=450px alt="图 1.7 Testbench 与设计环境"/>
</div>
&emsp;&emsp;在仿真时,**测试平台会把整个 DUT 包围起来**,就像一个硬件测试器连接到一个物理芯片上一样,如[图 7](#图7) 所示。测试平台和测试仪器都会产生激励并捕捉响应。不同的是,测试平台需要工作在一个很宽的抽象层次范围内,同时创建事件和激励序列并最终转换成比特向量。而测试仪器则只工作在比特级上。
Testbench 模块里都包含了什么呢?有很多的 BFM (Bus Functional Models, 总线功能模型),可以把它们看成是 testbench 构件 (components) ——从 DUT 的角度看,它们和真实的构件没什么两样,但它们其实只是 testbench 的组成部分,并非 RTL 设计。如果实际应用中设备被连接到 AMBA、USB、PCI 和 SPI 总线上,那么就必须**在 testbench 中建立能够产生激励并校验响应的等效构件**,如[图 1.8](#图1.8) 所示。这些构件并不是带有细节的可综合模型,而是遵循协议并且执行速度更快的高层次事件处理器。如果把设计原型在 FPGA 上实现或者是进行硬件仿真,那么这些 BFM 就需要是可综合的。
<a id="图7"></a>
<span id="图1.8"></span>
<div align="center">
<img src="../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-080-TestbenchComponents.png" width=450px alt="图 1.8 Testbench 构件"/>
</div>
![图 7. 测试平台与设计环境](../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-070-TheTestbenchDesignEnvironment.png){width=450px}
# 9. 分层 testbench
&emsp;&emsp;测试平台模块里都包含了什么呢?有很多的 BFM(Bus Functional Models, 总线功能模型),可以把它们看成是测试平台构件(components)——从 DUT 的角度看,它们和真实的构件没什么两样,但它们其实只是测试平台的组成部分,并非 RTL 设计。如果实际应用中设备被连接到 AMBA、USB、PCI 和 SPI 总线上,那么就必须**在测试平台中建立能够产生激励并校验响应的等效构件**,如[图 8](#图8) 所示。这些构件并不是带有细节的可综合模型,而是遵循协议并且执行速度更快的高层次事件处理器。如果把设计原型在 FPGA 上实现或者是进行硬件仿真,那么这些 BFM 就需要是可综合的。
对于任何一种新型的验证方法学来讲,分层的 testbench 是一个关键的概念。虽然分层似乎会使 testbench 变得更复杂,但它能够把代码分而治之,**有助于减轻工作负担**。不要试图去编写一个包含所有功能 (随机产生所有合法和非法的激励,并使用多层协议进行错误注入) 的子程序,因为这样的子程序很快就会变得很复杂,并且难以维护。
<a id="图8"></a>
## 9.1. 不分层的 testbench
![图 8. 测试平台构件](../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-080-TestbenchComponents.png){width=450px}
在刚开始学习 Verilog 并尝试写测试程序的时候,这些程序看起来可能会和[例 1.1](#例1.1) 所示的用于执行一个简单 APB (AMBA Peripheral Bus, AMBA 外设总线)写入的低层次代码很相似。
# 9. 分层测试平台
<span id="例1.1"></span>
&emsp;&emsp;对于任何一种新型的验证方法学来讲,分层的测试平台是一个关键的概念。虽然分层似乎会使测试平台变得更复杂,但它能够把代码分而治之,**有助于减轻工作负担**。不要试图去编写一个包含所有功能(随机产生所有合法和非法的激励,并使用多层协议进行错误注入)的子程序,因为这样的子程序很快就会变得很复杂,并且难以维护。
``` verilog 例 1.1 驱动 APB 引脚
## 9.1. 不分层的测试平台
&emsp;&emsp;在刚开始学习 Verilog 并尝试写测试程序的时候,这些程序看起来可能会和[例 1.1](#例1.1) 所示的用于执行一个简单 APB(AMBA Peripheral Bus, AMBA 外围总线)写入的低层次代码很相似。
<a id="例1.1"></a>
``` verilog 例 1.1. 驱动 APB 引脚
module test(PAddr,PWrite,PSel,PWData,PEnable,Rst,clk);
// 此处省略端口声明
@@ -283,11 +304,11 @@ module test(PAddr,PWrite,PSel,PWData,PEnable,Rst,clk);
endmodule
```
经过几天连续编写这种代码以后,我们可能会意识到这是一种重复性的劳动,所以会尝试创建可用于总线写入这种普通操作的任务,如[例 1.2](#例1.2) 所示。
&emsp;&emsp;经过几天连续编写这种代码以后,我们可能会意识到这是一种重复性的劳动,所以会尝试创建可用于总线写入这种普通操作的任务,如[例 1.2](#例1.2) 所示。
<span id="例1.2"></span>
<a id="例1.2"></a>
``` verilog 例 1.2 一个用于驱动 APB 引脚的任务
``` verilog 例 1.2. 一个用于驱动 APB 引脚的任务
task write(reg [15:0] addr, reg [31:0] data);
// 驱动控制总线
@(posedge clk)
@@ -304,11 +325,11 @@ task write(reg [15:0] addr, reg [31:0] data);
endtask
```
这样,testbench 就会变得简单一些,如[例 1.3](#例1.3)。
&emsp;&emsp;这样,测试平台就会变得简单一些,如[例 1.3](#例1.3)。
<span id="例1.3"></span>
<a id="例1.3"></a>
``` verilog 例 1.3 低层次的 Verilog 测试
``` verilog 例 1.3. 低层次的 Verilog 测试
module test(PAddr,PWrite,PSel,PWData,PEnable,Rst,clk);
// 此处省略端口声明
// 此处省略如例 1.2 给出的任务函数
@@ -318,7 +339,7 @@ module test(PAddr,PWrite,PSel,PWData,PEnable,Rst,clk);
write(16'h50, 32'h50); // 把数据写入到存储器中
// 校验结果
if (top.mem.memory[16'h50] == 32'h50)
if(top.mem.memory[16'h50] == 32'h50)
$display("Success");
else
$display("Error, wrong value in memory");
@@ -327,140 +348,142 @@ module test(PAddr,PWrite,PSel,PWData,PEnable,Rst,clk);
endmodule
```
通过把一些通用的操作 (如复位、总线读出和总线写入) 放到一个子程序中,可以提高工作效率并减少错误。这里,物理和命令层的建立只是通往分层 testbench 的第一步。
&emsp;&emsp;通过把一些通用的操作(如复位、总线读出和总线写入)放到一个子程序中,可以提高工作效率并减少错误。这里,物理和命令层的建立只是通往分层测试平台的第一步。
## 9.2. 信号和命令层
[图 1.9](#图1.9) 所示为一个 testbench 中最低的几个层次。
&emsp;&emsp;[图 9](#图9) 所示为一个测试平台中最低的几个层次。
<span id="图1.9"></span>
<div align="center">
<img src="../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-090-SignalAndCommandLlayers.png" width=500px alt="图 1.9 信号和命令层"/>
</div>
<a id="图9"></a>
在底部的**信号层** (*signal*),包含 DUT 和把 DUT 连接到 testbench 的信号。
![图 9. 信号和命令层](../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-090-SignalAndCommandLlayers.png){width=500px}
再往上一层是**命令层** (*command*)。执行总线读写命令的驱动器驱动 DUT 的输入。DUT 的输出与监视器 (monitor) 相连,监视器负责检测信号的变化,并把这些变化按照命令分组。断言 (assertion) 也穿过命令层和信号层,它们负责监视独立的信号以寻找穿越整个命令的信号变化。
&emsp;&emsp;在底部的**信号层**(*signal*),包含 DUT 和把 DUT 连接到测试平台的信号。
&emsp;&emsp;再往上一层是**命令层**(*command*)。执行总线读写命令的驱动器驱动 DUT 的输入。DUT 的输出与监视器(monitor)相连,监视器负责检测信号的变化,并把这些变化按照命令分组。断言(assertion)也穿过命令层和信号层,它们负责监视独立的信号以寻找穿越整个命令的信号变化。
## 9.3. 功能层
[图 1.10](#图1.10) 给出了为加上**功能层** (*functional*) 的 testbench,功能层向下面对的是命令层。代理 (agent, 在 VMM 中称为事件处理器) 接收到来自上层的事件,例如,DMA 读或写,把它们分解成独立的命令。这些命令也被送往用于预测事件结果的记分板 (scoreboard)。检验器 (checker) 则负责比较来自监视器和记分板的命令。
&emsp;&emsp;[图 10](#图10) 给出了为加上**功能层**(*functional*)的测试平台,功能层向下面对的是命令层。代理(agent, 在 VMM 中称为事件处理器)接收到来自上层的事件,例如,DMA 读或写,把它们分解成独立的命令。这些命令也被送往用于预测事件结果的记分板(scoreboard)。检验器(checker)则负责比较来自监视器和记分板的命令。
<span id="图1.10"></span>
<div align="center">
<img src="../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-100-TestbenchWithFunctionalLlayerAdded.png" width=500px alt="图 1.10 加上功能层的 testbench"/>
</div>
<a id="图10"></a>
![图 10. 加上功能层的测试平台](../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-100-TestbenchWithFunctionalLlayerAdded.png){width=500px}
## 9.4. 场景层
[图 1.11](#图1.11) 所示,功能层被位于**场景层** (*scenario*) 中的发生器 (generator) 所驱动。什么是场景呢?记住一点,验证工程师的工作是确保 DUT 能够完成预期的任务。比如 MP3 播放器,它能一边播放事先存储好的音乐,一边从一台主机上下载新的音乐,并且同时对用户输入如音量调整或音轨控制等操作保持响应。这中间的每一个操作都能称为一个场景。下载一个音乐文件需要若于步骤,例如前期准备时的控制寄存器的读写操作,歌曲传送过程中多次 DMA 写操作,以及之后的很多读写操作。场景层就是负责组织协调这些步骤的,操作的参数如音轨大小和寄存器位置等都采用约束下的随机值。
&emsp;&emsp;[图 11](#图11) 所示,功能层被位于**场景层**(*scenario*)中的发生器(generator)所驱动。什么是场景呢?记住一点,验证工程师的工作是确保 DUT 能够完成预期的任务。比如 MP3 播放器,它能一边播放事先存储好的音乐,一边从一台主机上下载新的音乐,并且同时对用户输入如音量调整或音轨控制等操作保持响应。这中间的每一个操作都能称为一个场景。下载一个音乐文件需要若于步骤,例如前期准备时的控制寄存器的读写操作,歌曲传送过程中多次 DMA 写操作,以及之后的很多读写操作。场景层就是负责组织协调这些步骤的,操作的参数如音轨大小和寄存器位置等都采用受约束的随机值。
<span id="图1.11"></span>
<div align="center">
<img src="../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-110-TestbenchWithScenarioLayerAdded.png" width=500px alt="图 1.11 加上场景层的 testbench"/>
</div>
<a id="图11"></a>
在 testbench **环境** (*environment*) 中的这些块 ([图 1.11](#图1.11) 虚线框内) 是在刚开始开发的时候画出来的。随着项目的进展,它们可能会有一些变化,也可能会加入一些功能,但是这些块对于每个独立的测试都是不应改变的。可以通过在代码中留下“hook”来做到这一点,这样即使这些块的行为需要在测试时改变,也不必重新编写代码。“hook”可以使用工厂模式 (factory patterns) 和回调函数 (callbacks) 来创建。
![图 11. 加上场景层的测试平台](../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-110-TestbenchWithScenarioLayerAdded.png){width=500px}
&emsp;&emsp;在测试平台**环境**(*environment*)中的这些块([图 11](#图11)虚线框内)是在刚开始开发的时候画出来的。随着项目的进展,它们可能会有一些变化,也可能会加入一些功能,但是这些块对于每个独立的测试都是不应改变的。可以通过在代码中留下“钩子”来做到这一点,这样即使这些块的行为需要在测试时改变,也不必重新编写代码。“钩子”可以使用工厂模式(factory patterns)和回调函数(callbacks)来创建。
## 9.5. 测试的层次和功能覆盖率
现在到了 testbench 的最顶层——测试层,如[图 1.12](#图1.12)。DUT 模块间的 bug 是比较难以发现的,因为这些模块可能是不同的人按照不同的规范设计出来的。
&emsp;&emsp;现在到了测试平台的最顶层——测试层,如[图 12](#图12)。DUT 模块间的漏洞是比较难以发现的,因为这些模块可能是不同的人按照不同的规范设计出来的。
<span id="图1.12"></span>
<div align="center">
<img src="../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-120-FullTestbenchWithAllLayers.png" width=500px alt="图 1.12 带着所有层次的完整 testbench"/>
</div>
<a id="图12"></a>
这个顶层的测试 (test) 就像一个指挥官:他不演奏任何乐器,但引领着其他人的表演。测试包含了用于创建激励的约束。
![图 12. 带着所有层次的完整测试平台](../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-120-FullTestbenchWithAllLayers.png){width=500px}
功能覆盖率 (fonctional coverage) 可以衡量所有测试在满足验证计划要求方面的进展。随着各项测量标准的完成,功能覆盖率代码在整个项目过程中会经常变化。由于代码经常被修改,所以它不作为测试环境的组成部分。
&emsp;&emsp;这个顶层的测试(test)就像一个指挥官:他不演奏任何乐器,但引领着其他人的表演。测试包含了用于创建激励的约束。
我们可以在约束下的随机环境中创建“定向测试”。只需在随机序列中间插入定向测试的代码,或者把两部分代码并列。定向代码执行期望的任务,而随机的“背景噪声”可能会使 bug 暴露出来,而且 bug 还有可能来自从未被关注过的模块。
&emsp;&emsp;功能覆盖率(functional coverage)可以衡量所有测试在满足验证计划要求方面的进展。随着各项测量标准的完成,功能覆盖率代码在整个项目过程中会经常变化。由于代码经常被修改,所以它不作为测试环境的组成部分。
Testbench 中是否需要所有的层次呢?答案要视 DUT 而定。设计越复杂,所需的 testbench 就要越完备。测试层则是必须的。对于一个简单的设计来说,场景层可能过于简单以至于可以把它合并到代理中。
&emsp;&emsp;我们可以在受约束的随机环境中创建“定向测试”。只需在随机序列中间插入定向测试的代码,或者把两部分代码并列。定向代码执行期望的任务,而随机的“背景噪声”可能会使漏洞暴露出来,而且漏洞还有可能来自从未被关注过的模块。
当然,可能还需要更多的层次。如果 DUT 有多个协议层,那么每个层都应该在 testbench 环境中有对应的层。例如使用 IP 封装了 TCP 流量,然后通过以太网数据包的形式发送,对这种情况的测试应该考虑使用三个独立的层来产生和校验数据,如
&emsp;&emsp;测试平台中是否需要所有的层次呢?答案要视 DUT 而定。设计越复杂,所需的测试平台就要越完备。测试层则是必须的。对于一个简单的设计来说,场景层可能过于简单以至于可以把它合并到代理中。
&emsp;&emsp;当然,可能还需要更多的层次。如果 DUT 有多个协议层,那么每个层都应该在测试平台环境中有对应的层。例如使用 IP 封装了 TCP 流量,然后通过以太网数据包的形式发送,对这种情况的测试应该考虑使用三个独立的层来产生和校验数据,如
果能够使用已有的验证构件则更好。
[图 1.12](#图1.12) 中需要注意的最后一点是,它只给出了各块之间一些可能的连接方式,testbench 模块间的连接可能会与之不同。比如测试层可能需要连接到驱动器层以迫使物理 bug 出现。这里给出的只是一些引导——实际当中应该是,需要什么就创建什么。
&emsp;&emsp;[图 12](#图12) 中需要注意的最后一点是,它只给出了各块之间一些可能的连接方式,测试平台模块间的连接可能会与之不同。比如测试层可能需要连接到驱动器层以迫使物理漏洞出现。这里给出的只是一些引导——实际当中应该是,需要什么就创建什么。
# 10. 建立一个分层的 testbench
# 10. 建立一个分层的测试平台
现在是学习如何把前面图示的那些构件映射成 SystemVerilog 结构时候了。
&emsp;&emsp;现在是学习如何把前面图示的那些构件映射成 SystemVerilog 结构时候了。
## 10.1. 创建一个简单的驱动器
首先,来仔细看看其中的一个模块——驱动器。[图 1.13](#图1.13) 所示的驱动器接收来自代理的命令。驱动器可能会注入错误或者增加时延,然后再把命令分解成一些信号的变化,例如总线请求或握手。这样一个 testbench 模块通常被称为“事件处理器 (transactor)”,它的核心部分是一个循环:有关事件处理器的示范代码如[例 1.4](#例1.4) 所示。
&emsp;&emsp;首先,来仔细看看其中的一个模块——驱动器。[图 13](#图13) 所示的驱动器接收来自代理的命令。驱动器可能会注入错误或者增加时延,然后再把命令分解成一些信号的变化,例如总线请求或握手。这样一个测试平台模块通常被称为“事件处理器(transactor)”,它的核心部分是一个循环:有关事件处理器的示范代码如[例 1.4](#例1.4)所示。
<span id="图1.13"></span>
<div align="center">
<img src="../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-130-ConnectionsForTheDriver.png" width=120px alt="图 1.13 带着所有层次的完整 testbench"/>
</div>
<a id="图13"></a>
<span id="例1.4"></span>
![图 13. 带着所有层次的完整测试平台](../images/post/2022-05-30-josh-systemverilog-1/2022-05-30-josh-systemverilog-1-130-ConnectionsForTheDriver.png){width=120px}
``` verilog 例 1.4 基本的事件处理器代码
<a id="例1.4"></a>
``` verilog 例 1.4. 基本的事件处理器代码
task run();
done = 0;
while (!done) begin
// 获取下一个事件
// 进行变换
// 发送事件
end
done = 0;
while (!done) begin
// 获取下一个事件
// 进行变换
// 发送事件
end
endtask
```
后序的文章给出了:
&emsp;&emsp;后序的文章给出了:
- 基本的 OOP 以及如何创建一个对象并使对象里面包含事件处理器所需要的子程序和数据,事件处理器的另一个例子是代理,它可能会把一个复杂的事件如 DMA 读分解成多个总线命令;
- 如何创建一个对象并使对象里面包含构成一个命令所需要的数据和子程序。使用 SystemVerilog 信箱可以实现这些对象在不同的事件处理器之间传递;
- 还将介绍很多方法,用于在不同层之间交换数据并使事件处理器实现同步。
# 11. 仿真环境的阶段
到目前为止,已经学习了环境的构成部分。这些部分在什么时候执行呢?我们希望把各个阶段清楚地定义好,以便协调 testbench,使项目中的所有代码能在一起工作。三个基本的阶段是建立 (build)、运行 (run) 和收尾 (wrap-up)。每个阶段都可以再细分为更小的步骤。
&emsp;&emsp;到目前为止,已经学习了环境的构成部分。这些部分在什么时候执行呢?我们希望把各个阶段清楚地定义好,以便协调测试平台,使项目中的所有代码能在一起工作。三个基本的阶段是建立(build)、运行(run)和收尾(wrap-up)。每个阶段都可以再细分为更小的步骤。
**建立阶段**可以分为如下步骤。
&emsp;&emsp;**建立阶段**可以分为如下步骤。
1. **生成配置** (*Generate configuration*):把 DUT 的配置和周围的环境随机化。
2. **建立环境** (*Build environment*):基于配置来分配和连接 testbench 构件。Testbench 构件指的是存在于 testbench 中的部分,注意与设计中的物理构件区分开,后者是采用 RTL 代码描述的。例如,如果配置选择了三个总线驱动器,那么 testbench 应该在这个阶段对它们进行分配和初始化。
3. **对 DUT 进行复位** (*Reset the DUT.*)。
4. **配置 DUT** (*Configure the DUT*):基于第一步中生成的配置,载入 DUT 的命令寄存器。
1. **生成配置**(*Generate configuration*):把 DUT 的配置和周围的环境随机化。
**运行阶段**是指测试实际运行的阶段,可分为以下步骤。
2. **建立环境**(*Build environment*):基于配置来分配和连接测试平台构件。测试平台构件指的是存在于测试平台中的部分,注意与设计中的物理构件区分开,后者是采用 RTL 代码描述的。例如,如果配置选择了三个总线驱动器,那么测试平台应该在这个阶段对它们进行分配和初始化。
1. **启动环境** (*Start environment*):运行 testbench 构件,例如各种 BFM 和激励发生器。
2. **运行测试** (*Run the test*):启动测试然后等待测试完成。定向测试的完成很容易判断,但随机测试却比较困难。可以使用 testbench 的层作为引导。从顶层启动,等待一个层接收完来自上一层 (如果有的话) 的所有输入,接着等待当前层空闲下来,然后再等待下一层。应该同时使用超时检测以确保 DUT 或 testbench 不出现死锁 (lock up)。
3. **对 DUT 进行复位**(*Reset the DUT.*)。
收尾阶段包含如下两个步骤。
4. **配置 DUT**(*Configure the DUT*):基于第一步中生成的配置,载入 DUT 的命令寄存器。
1. **清空** (*Sweep*):在最下层完成以后,需要等待 DUT 清空最后的事务。
2. **报告** (*Report*):一旦 DUT 空闲下来,就可以清空遗留在 testbench 中的数据了。有时候保存在记分板里面的数据从来就没有送出来过,这些数据可能是被 DUT 丢弃掉的。可以根据这些信息创建最终报告,说明测试通过或者失败。如果测试失败,务必把相应的功能覆盖率结果删除,因为它们可能是不正确的。
&emsp;&emsp;**运行阶段**是指测试实际运行的阶段,可分为以下步骤。
如[图 1.12](#图1.12) 所示,测试启动环境以后,环境就会按上述步骤运行。
1. **启动环境**(*Start environment*):运行测试平台构件,例如各种 BFM 和激励发生器。
2. **运行测试**(*Run the test*):启动测试然后等待测试完成。定向测试的完成很容易判断,但随机测试却比较困难。可以使用测试平台的层作为引导。从顶层启动,等待一个层接收完来自上一层(如果有的话)的所有输入,接着等待当前层空闲下来,然后再等待下一层。应该同时使用超时检测以确保 DUT 或测试平台不出现死锁(lock up)。
&emsp;&emsp;收尾阶段包含如下两个步骤。
1. **清空**(*Sweep*):在最下层完成以后,需要等待 DUT 清空最后的事务。
2. **报告**(*Report*):一旦 DUT 空闲下来,就可以清空遗留在测试平台中的数据了。有时候保存在记分板里面的数据从来就没有送出来过,这些数据可能是被 DUT 丢弃掉的。可以根据这些信息创建最终报告,说明测试通过或者失败。如果测试失败,务必把相应的功能覆盖率结果删除,因为它们可能是不正确的。
&emsp;&emsp;如[图 12](#图12) 所示,测试启动环境以后,环境就会按上述步骤运行。
# 12. 最大限度的代码重用
为了验证一个带有数百个特性的复杂设备,必须编写数百个定向测试。如果使用约束下的随机激励,需要编写的测试就会少很多。与定向测试相比,随机测试的主要工作是构建 testbench,使它包含所有较低的层:场景、功能、命令以及信号。这个 testbench 代码要能够被所有的测试使用,所以它需要有很好的**通用性**。
&emsp;&emsp;为了验证一个带有数百个特性的复杂设备,必须编写数百个定向测试。如果使用受约束的随机激励,需要编写的测试就会少很多。与定向测试相比,随机测试的主要工作是构建测试平台,使它包含所有较低的层:场景、功能、命令以及信号。这个测试平台代码要能够被所有的测试使用,所以它需要有很好的**通用性**。
这些建议似乎是在推荐一个极度复杂的 testbench,但需要记住的是,在 testbench 中每输入一行,就等于给每个单独的测试都减少了一行,相当于在同时创建很多个测试,而这也正是建立一个复杂 testbench 所能获得的巨额回报。
&emsp;&emsp;这些建议似乎是在推荐一个极度复杂的测试平台,但需要记住的是,在测试平台中每输入一行,就等于给每个单独的测试都减少了一行,相当于在同时创建很多个测试,而这也正是建立一个复杂测试平台所能获得的巨额回报。
# 13. Testbench 的性能
# 13. 测试平台的性能
如果你是第一次接触这种方法学的话,可能还是会怀疑它工作起来是否会优于定向测试?一个普遍的质疑便是 testbench 的性能。一个定向测试通常可以在一秒之内运行完,但**约束下的随机测试却要花费数分钟甚至数小时去搜索整个状态空间**。这种论点的问题在于,它忽略了一个在验证上真实存在的瓶颈:创建一个测试所需要的时间。你可以在一天之内手动编写完一个定向测试,然后再花一两天的时间调试并手动验证结果。测试的实际运行时间比起你在其他方面花费的时间其实要少得多。
&emsp;&emsp;如果你是第一次接触这种方法学的话,可能还是会怀疑它工作起来是否会优于定向测试?一个普遍的质疑便是测试平台 的性能。一个定向测试通常可以在一秒之内运行完,但**受约束的随机测试却要花费数分钟甚至数小时去搜索整个状态空间**。这种论点的问题在于,它忽略了一个在验证上真实存在的瓶颈:创建一个测试所需要的时间。你可以在一天之内手动编写完一个定向测试,然后再花一两天的时间调试并手动验证结果。测试的实际运行时间比起你在其他方面花费的时间其实要少得多。
创建约束下的随机测试需要几个步骤。
&emsp;&emsp;创建受约束的随机测试需要几个步骤。
1. 最重要的一步是建立分层的 testbench,包括自检的部分。这项工作能给所有的测试带来好处,所以是非常值得的。
2. 按照验证计划中列举的目标创建激励。可以使用随机约束,也可以采用注入错误或协议违例等迂回的方式。以这其中的任何一种方式创建激励所花费的时间可能可以用于创建好儿个定向测试,但是它的回报也要高很多。一个约束下的随机测试能够尝试成千上万种不同的协议违例,而在同样的时间里创建的几个定向测试却只能尝试几种情形,显然前者要比后者好得多。
3. 功能覆盖率 (约束下的随机测试)。这项任务的开始是创建一个强有力的验证计划,这个计划必须带有清晰而且便于测植的目标。接下来你需要创建 System­Verilog 代码,在环境中添加工具用于收集数据。最后很重要的一点,你需要
4. 对结果进行分析,并据此判断是否满足目标要求,如果不满足,应如何修改测试。
1. 最重要的一步是建立分层的测试平台,包括自检的部分。这项工作能给所有的测试带来好处,所以是非常值得的。
2. 按照验证计划中列举的目标创建激励。可以使用随机约束,也可以采用注入错误或协议违例等迂回的方式。以这其中的任何一种方式创建激励所花费的时间可能可以用于创建好儿个定向测试,但是它的回报也要高很多。一个受约束的随机测试能够尝试成千上万种不同的协议违例,而在同样的时间里创建的几个定向测试却只能尝试几种情形,显然前者要比后者好得多。
3. 功能覆盖率(受约束的随机测试)。这项任务的开始是创建一个强有力的验证计划,这个计划必须带有清晰而且便于测植的目标。接下来你需要创建 System­Verilog 代码,在环境中添加工具用于收集数据。最后很重要的一点,你需要对结果进行分析,并据此判断是否满足目标要求,如果不满足,应如何修改测试。
# 14. 结束语
电子设计复杂度的持续增长要求以一种新颖的、系统的且自动化的方法来创建 testbench。从硬件规范到 RTL 编码、门级综合、芯片制造,以及最后到用户手里,项目每向前推进一步,修复单个 bug 所需要的代价就会增加数倍甚至数十倍。定向测试每次只能测试一个特性,而无法模拟设备在实际应用环境中所面对的复杂的激励和配置。为了得到稳健的设计,**必须使用约束下的随机激励加上功能覆盖率**,才能在可能的限度内创建出最广泛的激励。
&emsp;&emsp;电子设计复杂度的持续增长要求以一种新颖的、系统的且自动化的方法来创建测试平台。从硬件规范到 RTL 编码、门级综合、芯片制造,以及最后到用户手里,项目每向前推进一步,修复单个漏洞所需要的代价就会增加数倍甚至数十倍。定向测试每次只能测试一个特性,而无法模拟设备在实际应用环境中所面对的复杂的激励和配置。为了得到稳健的设计,**必须使用受约束的随机激励加上功能覆盖率**,才能在可能的限度内创建出最广泛的激励。
# 参考文献
1. 克里斯·斯皮尔, 斯皮尔, 张春,等. SystemVerilog验证:测试平台编写指南[M]. 科学出版社, 2009.
2. Spear C. SystemVerilog for verification: a guide to learning the testbench language features[M]. Springer Science & Business Media, 2008.
1. C. Spear. *SystemVerilog 验证: 测试平台编写指南 原书第二版*. 北京: 科学出版社, 2009.
2. C. Spear. *SystemVerilog for verification: a guide to learning the testbench language features*, 2nd ed. New York: Springer, 2008.
+197 -201
View File
@@ -1,5 +1,5 @@
---
title: "Josh's Notes: SystemVerilog 验证(Part 2 — 数据类型)"
title: "Josh's Note — SystemVerilog 验证<br>Part 2 数据类型"
mathjax: true
comments: true
copyright: true
@@ -25,12 +25,12 @@ categories:
date: 2022-05-31 10:18:34
---
和 Verilog 相比,SystemVerilog 提供了很多改进的数据结构。虽然其中的部分结构最初是为设计者创建的,但对测试者也同样有用。本文将介绍这些对验证很有用的数据结构。
和 Verilog 相比,SystemVerilog 提供了很多改进了的数据结构。虽然其中的部分结构最初是为设计人员创建的,但对测试人员也同样有用。本文将介绍这些对验证很有用的数据结构。
SystemVerilog 引进了一些新的数据类型,它们具有如下优点。
SystemVerilog 引进了一些新的数据类型,它们具有如下优点:
1. **双状态数据类型** (*Two-state*):更好的性能,更低的内存消耗。
2. **队列、动态数组和关联数组** (*Queues, dynamic and associative arrays*):减少内存消耗,自带搜索和分类功能。
1. **双状态数据类型** (*Two-state*):性能更好,内存消耗更低。
2. **队列、动态数组和关联数组** (*Queues, dynamic and associative arrays*):内存消耗减少,自带搜索和分类功能。
3. **类和结构** (*Classes and structures:*):支持抽象数据结构。
4. **联合和合并结构** (*Unions and packed structures*):允许对同一数据有多种视图 (view)。
5. **字符串** (*Strings*):支持内建的字符序列。
@@ -44,7 +44,7 @@ Verilog-1995 有两种基本的数据类型:变量 (variable) 和线网 (net)
- 单比特或多比特的无符号数 (unsigned single or multi-bit, `reg [7:0] m`);
- 32 比特的有符号数 (signed 32-bit variable, `integer`);
- 64 比特的无符号数 (unsigned 64-bit variable, `time`)
- 64 比特的无符号数 (unsigned 64-bit variable, `time`);
- 浮点数 (floating point number, `real`)。
若干变量可以被一起存放到定宽数组 (fixed-size array) 里。所有的存储都是静态 (static) 的,意味着所有的变量在整个仿真过程当中都是存活 (alive) 的,子程序 (routine) 不能通过堆栈来保存参数和局部变量。线网可以用来连接设计当中的不同部分,例如门原语和模块实例。尽管线网有很多种用法,但是大多数设计者还是使用标量或矢量 `wire` 来连接各个设计模块的端口。
@@ -55,22 +55,22 @@ SystemVerilog 增加了很多新的数据类型,对设计和验证工程师都
在 Verilog 中,初学者经常分不清 `reg` 和 `wire` 两者的区别。应该使用哪一个来驱动端口?连接不同模块时又该怎么做?SystemVerilog 对经典的 `reg` 数据类型进行了改进,使得它除了作为一个变量以外,还**可以被连续赋值、门单元和模块所驱动**。为了与寄存器类型相区别,这种改进的数据类型称为 `logic`。任何使用线网的地方均可使用 `logic`,但**要求 `logic` 不能有多个结构性的驱动**,例如在对双向总线建模的时候。此时,需要使用线网类型,例如 `wire`,SystemVerilog 会对多个数据来源进行解析以后确定最终值。
[例 2.1](#例2.1) 示范了在 SystemVerilog 中使用 `logic` 类型。
[例 1](#例1) 给出在 SystemVerilog 中使用 `logic` 类型的例子。
<span id="例2.1"></span>
<a id="例1"></a>
``` verilog 例 2.1 <code>logic</code> 类型的使用
``` verilog 例 1 <code>logic</code> 类型的使用
module logic_data_type(input logic rst_h);
parameter CYCLE = 20;
logic q, q_l, d, clk, rst_l;
initial begin
clk = 0; // 过程赋值
forever #(CYCLE/2) clk = ~clk;
end
parameter CYCLE = 20;
logic q, q_l, d, clk, rst_l;
initial begin
clk = 0; // 过程赋值
forever #(CYCLE/2) clk = ~clk;
end
assign rst_l = ~rst_h; // 连续赋值
not n1(q_l, q); // q_l 被门驱动
my_dff d1(q, d, clk, rst_l); // q 被模块驱动
assign rst_l = ~rst_h; // 连续赋值
not n1(q_l, q); // q_l 被门驱动
my_dff d1(q, d, clk, rst_l); // q 被模块驱动
endmodule
```
@@ -82,11 +82,11 @@ endmodule
## 1.2. 双状态数据类型
相比四状态数据类型,SystemVerilog 引入的双状态数据类型有利于提高仿真器的性能并减少内存的使用量。最简单的双状态数据类型是 `bit`,它是无符号的。另四种带符号的双状态数据类型是 `byte`,`shortint`,`int` 和 `longint`,如[例 2.2](#例2.2) 所示。
相比四状态数据类型,SystemVerilog 引入的双状态数据类型有利于提高仿真器的性能并减少内存的使用量。最简单的双状态数据类型是 `bit`,它是无符号的。另四种带符号的双状态数据类型是 `byte`,`shortint`,`int` 和 `longint`,如[例 2](#例2) 所示。
<span id="例2.2"></span>
<a id="例2"></a>
``` verilog 例 2.2 带符号的数据类型
``` verilog 例 2 带符号的数据类型
bit b; // 双状态,单比特
bit [31:0] b32; // 双状态,32 比特无符号整数
int unsigned ui; // 双状态,32 比特无符号整数
@@ -102,11 +102,11 @@ real r; // 双状态,双精度浮点数
> 虽然使用 `byte` 等数据类型来替代类似 `logic[7:0]` 进行声明可以让程序更简洁,但需要注意,这些新的数据类型都是**带符号**的,所以 `byte` 变量的最大值只有 127,而不是 255 (它的范围是 -128~127)。可以使用 `byte unsigned`,但这其实比使用 `byte [7:0]` 还要麻烦。在进行随机化时,带符号变量可能会造成意想不到的结果,这一点在后面会讨论到。
> 在把双状态变量连接到 DUT 务必要小心,尤其是连接到 DUT 的输出时,因为 DUT 产生的 `X` 或 `Z` 会被转换成双状态值,而测试代码可能永远也察觉不了。这些值被转换成了 `0` 还是 `1` 并不重要,重要的是要**随时检查未知值的传播**。使用 `$isunknown()` 操作符,可以在表达式的任意位出现 `X` 或 `Z` 时返回 `1`,如[例 2.3](#例2.3)。
> 在把双状态变量连接到 DUT 务必要小心,尤其是连接到 DUT 的输出时,因为 DUT 产生的 `X` 或 `Z` 会被转换成双状态值,而测试代码可能永远也察觉不了。这些值被转换成了 `0` 还是 `1` 并不重要,重要的是要**随时检查未知值的传播**。使用 `$isunknown()` 操作符,可以在表达式的任意位出现 `X` 或 `Z` 时返回 `1`,如[例 3](#例3)。
<span id="例2.3"></span>
<a id="例3"></a>
``` verilog 例 2.3 对四状态值的检查
``` verilog 例 3 对四状态值的检查
if ($isunknown(iport) == 1)
$display("@%0t: 4-state value detected on iport %b",
$time, iport);
@@ -122,18 +122,18 @@ if ($isunknown(iport) == 1)
Verilog 要求在声明中必须给出数组的上下界。因为几乎所有数组都使用 `0` 作为索引下界,所以 SystemVerilog **允许只给出数组宽度的便捷声明方式**,跟 C 语言类似。
<span id="例2.4"></span>
<a id="例4"></a>
``` verilog 例 2.4 定宽数组的声明
``` verilog 例 4 定宽数组的声明
int lo_hi[0:15]; // 16 个整数 [0]..[15]
int c_style[16]; // 16 个整数 [0]..[15]
```
可以通过在变量名后面指定维度的方式来创建**多维定宽数组** (*multidimensional fixed-size array*)。[例 2.5](#例2.5) 创建了几个二维的整数数组,大小都是 8 行 4 列,最后一个元素的值被设置为 1。多维数组在 Verilog-2001 中已经引入,但这种紧凑型声明方式却是新的。
可以通过在变量名后面指定维度的方式来创建**多维定宽数组** (*multidimensional fixed-size array*)。[例 5](#例5) 创建了几个二维的整数数组,大小都是 8 行 4 列,最后一个元素的值被设置为 1。多维数组在 Verilog-2001 中已经引入,但这种紧凑型声明方式却是新的。
<span id="例2.5"></span>
<a id="例5"></a>
``` verilog 例 2.5 声明并使用多维数组
``` verilog 例 5 声明并使用多维数组
int array2 [0:7][0:3]; // 完整的声明
int array3 [8][4]; // 紧凑的声明
@@ -147,28 +147,27 @@ array2[7][3] = 1; // 设置最后一个元素
这适用于所有数组类型,包括定宽数组、动态数组、关联数组和队列,也同时适用于地址中含有 `X` 或 `Z` 的情况。线网在没有驱动的时候输出是 `Z`。
很多 SystemVerilog 仿真器**在存放数组元素时使用 32 比特的字 (word) 边界**,所以 `byte`,`shortint` 和 `int` 都是存放在一个字中,`longint` 存放到两个字中。如[例 2.6](#例2.6) 所示,**在非合并数组中,字的低位用来存放数据,高位不使用**。[图 2.1](#图2.1) 所示的字节数组 `b_unpack` 被存放到三个字的空间里。
很多 SystemVerilog 仿真器**在存放数组元素时使用 32 比特的字 (word) 边界**,所以 `byte`,`shortint` 和 `int` 都是存放在一个字中,`longint` 存放到两个字中。如[例 6](#例6) 所示,**在非合并数组中,字的低位用来存放数据,高位不使用**。[图 1](#图1) 所示的字节数组 `b_unpack` 被存放到三个字的空间里。
<span id="例2.6"></span>
<a id="例6"></a>
``` verilog 例 2.6 非合并数组的声明
``` verilog 例 6 非合并数组的声明
bit [7:0] b_unpack[3]; // 非合并数组
```
<span id="图2.1"></span>
<div align="center">
<img src="../images/post/2022-05-31-josh-systemverilog-2/2022-05-31-josh-systemverilog-2-010-UnpackedArrayStorage.png" width=600px alt="图 2.1 非合并数组的存放"/>
</div>
<a id="图1"></a>
![图 1 非合并数组的存放](../images/post/2022-05-31-josh-systemverilog-2/2022-05-31-josh-systemverilog-2-010-UnpackedArrayStorage.png){width=600px}
仿真器通常使用两个或两个以上连续的字来存放 `logic` 和 `integer` 等四状态类型,这**比存放双状态变量多占用一倍的空间**。
## 2.2. 常量数组
[例 2.7](#例2.7) 示范了如何使用常量数组,即**用一个单引号加大括号来初始化数组** (注意这里的单引号并不同于编译器指引或宏定义中的单引号),可以一次性地为数组的部分或所有元素赋值。在大括号前标上重复次数可以对多个元素重复赋值,还可以为没有显式赋值的元素指定一个默认值。
[例 7](#例7) 示范了如何使用常量数组,即**用一个单引号加大括号来初始化数组** (注意这里的单引号并不同于编译器指引或宏定义中的单引号),可以一次性地为数组的部分或所有元素赋值。在大括号前标上重复次数可以对多个元素重复赋值,还可以为没有显式赋值的元素指定一个默认值。
<span id="例2.7"></span>
<a id="例7"></a>
``` verilog 例 2.7 初始化一个数组
``` verilog 例 7 初始化一个数组
int ascend[4] = '{0,1,2,3}; // 对 4 个元素进行初始化
int descend[5];
@@ -180,11 +179,11 @@ descend = '{9, 8, default:1}; // {9,8,1,1,1}
## 2.3. 基本的数组操作—— `for` 和 `foreach`
操作数组的最常见的方式是使用 `for` 或 `foreach` 循环。在[例 2.8](#例2.8) 中,`i` 被声明为 `for` 循环内的局部变量。SystemVerilog 的 `$size` 函数返回数组的宽度。在 `foreach` 循环中,只需要给出数组名并在后面的方括号中给出索引变量,SystemVerilog 便会自动遍历数组中的元素。索引变量将自动声明,并只在循环内有效。
操作数组的最常见的方式是使用 `for` 或 `foreach` 循环。在[例 8](#例8) 中,`i` 被声明为 `for` 循环内的局部变量。SystemVerilog 的 `$size` 函数返回数组的宽度。在 `foreach` 循环中,只需要给出数组名并在后面的方括号中给出索引变量,SystemVerilog 便会自动遍历数组中的元素。索引变量将自动声明,并只在循环内有效。
<span id="例2.8"></span>
<a id="例8"></a>
``` verilog 例 2.8 在数组操作中使用 <code>for</code> 和 <code>foreach</code> 循环
``` verilog 例 8 在数组操作中使用 <code>for</code> 和 <code>foreach</code> 循环
initial begin
bit [31:0] src[5], dst[5];
for (int i=0; i<$size(src); i++)
@@ -194,11 +193,11 @@ initial begin
end
```
注意在[例 2.9](#例2.9) 中,对多维数组使用 `foreach` 的语法可能会与设想的有所不同。使用时并不是像 `[i][j]` 这样把每个下标分别列在不同的方括号里,而是用逗号隔开后放在同一个方括号里,像 `[i,j]`。
注意在[例 9](#例9) 中,对多维数组使用 `foreach` 的语法可能会与设想的有所不同。使用时并不是像 `[i][j]` 这样把每个下标分别列在不同的方括号里,而是用逗号隔开后放在同一个方括号里,像 `[i,j]`。
<span id="例2.9"></span>
<a id="例9"></a>
``` verilog 例 2.9 初始化并遍历多维数组
``` verilog 例 9 初始化并遍历多维数组
int md[2][3] = '{'{0,1,2}, '{3,4,5}};
initial begin
@@ -214,11 +213,11 @@ initial begin
end
```
[例 2.9](#例2.9) 的输出结果如[例 2.10](#例2.10) 所示。
[例 9](#例9) 的输出结果如[例 10](#例10) 所示。
<span id="例2.10"></span>
<a id="例10"></a>
``` plaintext 例 2.10 多维数组元素值的打印输出结果
``` plaintext 例 10 多维数组元素值的打印输出结果
Initial value:
md[0][0] = 0
md[0][1] = 1
@@ -235,11 +234,11 @@ md[1][1] = 5
md[1][2] = 5
```
**如果不需要遍历数组中的所有维度,可以在 `foreach` 循环里忽略不需要的维度**。[例 2.11](#例2.11) 把一个二维数组打印成一个方形的阵列。它在外层循环中遍历第一个维度,然后在内层循环中遍历第二个维度。
**如果不需要遍历数组中的所有维度,可以在 `foreach` 循环里忽略不需要的维度**。[例 11](#例11) 把一个二维数组打印成一个方形的阵列。它在外层循环中遍历第一个维度,然后在内层循环中遍历第二个维度。
<span id="例2.11"></span>
<a id="例11"></a>
``` verilog 例 2.11 打印一个多维数组
``` verilog 例 11 打印一个多维数组
initial begin
byte twoD[4][6];
foreach(twoD[i,j])
@@ -254,11 +253,11 @@ initial begin
end
```
[例 2.11](#例2.11) 的输出结果如[例 2.12](#例2.12) 所示。
[例 11](#例11) 的输出结果如[例 12](#例12) 所示。
<span id="例2.12"></span>
<a id="例12"></a>
``` plaintext 例 2.12 打印多维数组的输出结果
``` plaintext 例 12 打印多维数组的输出结果
Initial value:
0: 0 1 2 3 4 5
1: 10 11 12 13 14 15
@@ -273,11 +272,11 @@ Initial value:
## 2.4. 基本的数组操作——复制和比较
可以在不使用循环的情况下对数组进行聚合比较和复制 (aggregate compare and copy, 聚合操作适用于整个数组而不是单个元素),其中比较**只限于等于比较或不等于比较**。[例 2.13](#例2.13) 列出了几个比较的例子。操作符 `? :` 是一个迷你型的 `if` 语句,在[例 2.13](#例2.13) 中用来对两个字符串进行选择。例子最后的比较语句使用了数组的一部分,`src[1:4]`,它实际上产生了一个有四个元素的临时数组。
可以在不使用循环的情况下对数组进行聚合比较和复制 (aggregate compare and copy, 聚合操作适用于整个数组而不是单个元素),其中比较**只限于等于比较或不等于比较**。[例 13](#例13) 列出了几个比较的例子。操作符 `? :` 是一个迷你型的 `if` 语句,在[例 13](#例13) 中用来对两个字符串进行选择。例子最后的比较语句使用了数组的一部分,`src[1:4]`,它实际上产生了一个有四个元素的临时数组。
<span id="例2.13"></span>
<a id="例13"></a>
``` verilog 例 2.13 数组的复制和比较操作
``` verilog 例 13 数组的复制和比较操作
initial begin
bit [31:0] src[5] = '{0,1,2,3,4},
dst[5] = '{5,4,3,2,1};
@@ -307,11 +306,11 @@ end
## 2.5. 同时使用位下标和数组下标
在 Verilog-1995 中一个很不方便的地方就是数组下标 (array subscript) 和位下标 (bit subscript) 不能同时使用。Verilog-2001 对定宽数组取消了这个限制。[例 2.14](#例2.14) 打印出数组的第一个元素 (二进制 101 )、它的最低位 (1) 以及紧接的高两位 (二进制 10)。
在 Verilog-1995 中一个很不方便的地方就是数组下标 (array subscript) 和位下标 (bit subscript) 不能同时使用。Verilog-2001 对定宽数组取消了这个限制。[例 14](#例14) 打印出数组的第一个元素 (二进制 101 )、它的最低位 (1) 以及紧接的高两位 (二进制 10)。
<span id="例2.14"></span>
<a id="例14"></a>
``` verilog 例 2.14 同时使用数组下标和位下标
``` verilog 例 14 同时使用数组下标和位下标
initial begin
bit [31:0] src[5] = '{5{5}};
$displayb(src[0],, // 'b101 或 'd5
@@ -328,11 +327,11 @@ end
## 2.7. 合并数组的例子
声明合并数组时,**合并的位和数组大小是数据类型的一部分,必须在变量名前面指定**。数组大小定义的格式必须是 `[msb:lsb]`,而不是 `[size]`。[例 2.15](#例2.15) 中的变量 `bytes` 是一个有 4 个字节的合并数组,使用单独的 32 比特的字来存放,如图 2.2 所示。
声明合并数组时,**合并的位和数组大小是数据类型的一部分,必须在变量名前面指定**。数组大小定义的格式必须是 `[msb:lsb]`,而不是 `[size]`。[例 15](#例15) 中的变量 `bytes` 是一个有 4 个字节的合并数组,使用单独的 32 比特的字来存放,如图 2 所示。
<span id="例2.15"></span>
<a id="例15"></a>
``` verilog 例 2.15 合并数组的声明和用法
``` verilog 例 15 合并数组的声明和用法
bit [3:0] [7:0] bytes; // 4 个 字节 组装成 32 比特
bytes = 32'hCafe_Dada;
$displayh(bytes,, // 显示所有的 32 比特
@@ -340,16 +339,15 @@ $displayh(bytes,, // 显示所有的 32 比特
bytes[3][7]); // 显示 MSB “1”
```
<span id="图2.2"></span>
<div align="center">
<img src="../images/post/2022-05-31-josh-systemverilog-2/2022-05-31-josh-systemverilog-2-020-PackedArrayLayout.png" width=600px alt="图 2.2 合井数组存放示意图"/>
</div>
<a id="图2"></a>
合并和非合并数组可以混合使用。可以使用数组来表示存储单元,这些单元可以按比特、字节或长字的方式进行存取。在[例 2.16](#例2.16) 中,`barray` 是一个具有 3 个合并元素的非合并数组。
![图 2 合井数组存放示意图](../images/post/2022-05-31-josh-systemverilog-2/2022-05-31-josh-systemverilog-2-020-PackedArrayLayout.png){width=600px}
<span id="例2.16"></span>
合并和非合并数组可以混合使用。可以使用数组来表示存储单元,这些单元可以按比特、字节或长字的方式进行存取。在[例 16](#例16) 中,`barray` 是一个具有 3 个合并元素的非合并数组。
``` verilog 例 2.16 合并数组的声明和用法
<a id="例16"></a>
``` verilog 例 16 合并数组的声明和用法
bit [3:0] [7:0] barray [3]; // 合并,3×32 比特
bit [31:0] lw = 32'h0123_4567; // 字
bit [7:0] [3:0] nibbles; // 合并数组
@@ -359,12 +357,11 @@ barray[0][1][6] = 1'b1;
nibbles = barray[0]; // 复制合并数组的元素值
```
[例 2.15](#例2.15) 中的变量 `bytes` 是一个具有 4 个字节的合并数组,以单字形式存放。`barray` 则是一个具有 3 个类似 `bytes` 元素的数组,其存放形式如图 2.3。
[例 15](#例15) 中的变量 `bytes` 是一个具有 4 个字节的合并数组,以单字形式存放。`barray` 则是一个具有 3 个类似 `bytes` 元素的数组,其存放形式如图 3。
<span id="图2.3"></span>
<div align="center">
<img src="../images/post/2022-05-31-josh-systemverilog-2/2022-05-31-josh-systemverilog-2-030-PackedArrayBitLayout.png" width=600px alt="图 2.3 合并数组存放示意图"/>
</div>
<a id="图3"></a>
![图 3 合并数组存放示意图](../images/post/2022-05-31-josh-systemverilog-2/2022-05-31-josh-systemverilog-2-030-PackedArrayBitLayout.png){width=600px}
- 使用一个下标,可以得到一个字的数据,如 `barray[2]`;
- 使用两个下标,可以得到一个字节的数据,如 `barray[0][3]`;
@@ -372,13 +369,13 @@ nibbles = barray[0]; // 复制合并数组的元素值
注意数组声明中在变量名后面指定了数组的大小,`barray[3]`,这个维度是非合并的,所以在使用该数组时至少要有一个下标。
[例 2.16](#例2.16) 中的最后一行在两个合并数组间实现复制。由于操作是以比特为单位进行的,所以即使数组维度不同也可以进行复制。
[例 16](#例16) 中的最后一行在两个合并数组间实现复制。由于操作是以比特为单位进行的,所以即使数组维度不同也可以进行复制。
## 2.8. 合井数组和非合并数组的选择
应该选择合并数组还是非合并数组呢?当需要和标量进行相互转换时,使用合并数组会非常方便。例如,以字节或字为单位对存储单元进行操作。[图 2.3](#图2.3) 中所示的 `barray` 可以满足这一要求。任何数组类型都可以合并,包括动态数组、队列和关联数组。
应该选择合并数组还是非合并数组呢?当需要和标量进行相互转换时,使用合并数组会非常方便。例如,以字节或字为单位对存储单元进行操作。[图 3](#图3) 中所示的 `barray` 可以满足这一要求。任何数组类型都可以合并,包括动态数组、队列和关联数组。
**如果需要等待数组中的变化,则必须使用合并数组**。当 testbench 需要通过存储器数据的变化来唤醒时,需要使用 `@` 操作符,但 **`@` 操作符只能用于标量或者合并数组**。在[例 2.16](#例2.16) 中,可以把 `lw` 和 `barray[0]` 用作敏感信号,但却不能用整个的 `barray` 数组,除非把它扩展成:`@(barray[0] or barray[1] or barray[2])`。
**如果需要等待数组中的变化,则必须使用合并数组**。当 testbench 需要通过存储器数据的变化来唤醒时,需要使用 `@` 操作符,但 **`@` 操作符只能用于标量或者合并数组**。在[例 16](#例16) 中,可以把 `lw` 和 `barray[0]` 用作敏感信号,但却不能用整个的 `barray` 数组,除非把它扩展成:`@(barray[0] or barray[1] or barray[2])`。
# 3. 动态数组
@@ -386,11 +383,11 @@ nibbles = barray[0]; // 复制合并数组的元素值
SystemVerilog 提供了动态数组类型,可以**在仿真时分配空间或调整宽度**,这样在仿真中就可以使用最小的存储星。
动态数组在声明时使用空的下标 `[]`,表示数组的宽度不在编译时给出,在程序运行时再指定。数组在最开始时是空的,所以必须调用 `new[]` 操作符来分配空间,同时在方括号中传递数组宽度。可以把数组名传给 `new[]` 构造符,并把已有数组的值复制到新数组里,如[例 2.17](#例2.17) 所示。
动态数组在声明时使用空的下标 `[]`,表示数组的宽度不在编译时给出,在程序运行时再指定。数组在最开始时是空的,所以必须调用 `new[]` 操作符来分配空间,同时在方括号中传递数组宽度。可以把数组名传给 `new[]` 构造符,并把已有数组的值复制到新数组里,如[例 17](#例17) 所示。
<span id="例2.17"></span>
<a id="例17"></a>
``` verilog 例 2.17 使用动态数组
``` verilog 例 17 使用动态数组
int dyn[], d2[]; // 声明动态数组
initial begin
@@ -406,7 +403,7 @@ initial begin
end
```
在[例 2.17](#例2.17) 中:
在[例 17](#例17) 中:
- A:调用 `new[5]` 为动态数组 `dyn` 分配了 5 个整型元素。
- B:把数组的索引值赋给相应的元素。
@@ -418,11 +415,11 @@ end
调用系统函数 `$size` 可以返回数组的宽度。动态数组有一些内建的子程序 (rou­tines),例如 `delete` 和 `size`。
如果想声明一个常数数组但又不想统计元素的个数,可以使用动态数组并使用常量数组进行赋值。在[例 2.18](#例2.18) 中声明的 `mask` 数组具有 9 个 8 比特元素,SystemVerilog 会自动统计元素的个数,这比声明一个定宽数组然后不小心把宽度错指为 8 要好。
如果想声明一个常数数组但又不想统计元素的个数,可以使用动态数组并使用常量数组进行赋值。在[例 18](#例18) 中声明的 `mask` 数组具有 9 个 8 比特元素,SystemVerilog 会自动统计元素的个数,这比声明一个定宽数组然后不小心把宽度错指为 8 要好。
<span id="例2.18"></span>
<a id="例18"></a>
``` verilog 例 2.18 使用动态数组来保存元素数量不定的列表
``` verilog 例 18 使用动态数组来保存元素数量不定的列表
bit [7:0] mask[] = '{8'b0000_0000, 8'b0000_0001,
8'b0000_0011, 8'b0000_0111,
8'b0000_1111, 8'b0001_1111,
@@ -438,13 +435,13 @@ bit [7:0] mask[] = '{8'b0000_0000, 8'b0000_0001,
SystemVerilog 引进了一种新的数据类型——队列 (queue),它结合了链表和数组的优点。队列与链表相似,**可以在一个队列中的任何地方增加或删除元素**,这类操作在性能上的损失比动态数组小得多,因为动态数组需要分配新的数组并复制所有元素的值。队列与数组相似,可以通过索引实现对任一元素的访问,而不需要像链表那样去遍历目标元素之前的所有元素。
队列的声明是使用带有美元符号的下标:`[$]`。队列元素的编号从 `0` 到 `$`。[例 2.19](#例2.19) 示范了如何使用方法 (method) 在队列中增加和删除元素。注意队列的常量 (literal) 只有大括号而没有数组常量中开头的单引号。
队列的声明是使用带有美元符号的下标:`[$]`。队列元素的编号从 `0` 到 `$`。[例 19](#例19) 示范了如何使用方法 (method) 在队列中增加和删除元素。注意队列的常量 (literal) 只有大括号而没有数组常量中开头的单引号。
SystemVerilog 的队列类似于标准模板库 (standard template library) 中的双端队列。通过增加元素来创建队列,SystemVerilog 会分配额外的空间以便新元素能够被快速插入。当元素增加到超过原有空间的容量时,SystemVerilog 会自动分配更多的空间。因此队列可以扩大或缩小,但不用像动态数组那样在性能上付出很大代价,System­Verilog 会随时记录闲置的空间。注意不要对队列使用构造函数 `new[]`。
<span id="例2.19"></span>
<a id="例19"></a>
``` verilog 例 2.19 队列的操作
``` verilog 例 19 队列的操作
int j = 1,
q2[$] = {3,4}, // 队列的常量不需要使用 “'”
q[$] = {0,2,5}; // {0,2,5}
@@ -465,11 +462,11 @@ initial begin
end
```
还可以使用字下标串联来替代方法。如果把 `$` 放在一个范围表达式的左边,那么 `$` 将代表最小值,例如 `[$:2]` 就代表 `[0:2]`。如果 `$` 放在表达式的右边,则代表最大值,如[例 2.20](#例2.20) 中初始化块的第一行里的 `[1:$]` 就表示 `[1:2]`。
还可以使用字下标串联来替代方法。如果把 `$` 放在一个范围表达式的左边,那么 `$` 将代表最小值,例如 `[$:2]` 就代表 `[0:2]`。如果 `$` 放在表达式的右边,则代表最大值,如[例 20](#例20) 中初始化块的第一行里的 `[1:$]` 就表示 `[1:2]`。
<span id="例2.20"></span>
<a id="例20"></a>
``` verilog 例 2.20 队列的操作
``` verilog 例 20 队列的操作
int j = 1,
q2[$] = {3,4}, // 队列的常量不需要使用 “'”
q[$] = {0,2,5}; // {0,2,5}
@@ -499,22 +496,21 @@ end
如果只是偶尔需要创建一个大容量的数组,那么动态数组已经足够好用了,但是如果需要超大容量的呢?假设正在对一个有着几个 G 字节寻址范围的处理器进行建模。在典型的测试中,这个处理器可能只访问了用来存放可执行代码和数据的几百或几千个字节,这种情况下对几 G 字节的存储空间进行分配和初始化显然是浪费的。
SystemVerilog 提供了关联数组 (associative array) 类型,用来保存稀疏矩阵 (sparse matrix) 的元素。这意味着当对一个非常大的地址空间进行寻址时,SystemVerilog 只为实际写入的元素分配空间。在[图 2.4](#图2.4) 中,关联数组只保留 0…3、42、1000、4521 和 200,000 等位置上的值。这样,用来存放这些值的空间比有 200,000 个条目的定宽或动态数组所占用的空间要小得多。
SystemVerilog 提供了关联数组 (associative array) 类型,用来保存稀疏矩阵 (sparse matrix) 的元素。这意味着当对一个非常大的地址空间进行寻址时,SystemVerilog 只为实际写入的元素分配空间。在[图 4](#图4) 中,关联数组只保留 0…3、42、1000、4521 和 200,000 等位置上的值。这样,用来存放这些值的空间比有 200,000 个条目的定宽或动态数组所占用的空间要小得多。
<span id="图2.4"></span>
<div align="center">
<img src="../images/post/2022-05-31-josh-systemverilog-2/2022-05-31-josh-systemverilog-2-040-AssociativeArray.png" width=600px alt="图 2.4 关联数组"/>
</div>
<a id="图4"></a>
![图 4 关联数组](../images/post/2022-05-31-josh-systemverilog-2/2022-05-31-josh-systemverilog-2-040-AssociativeArray.png){width=600px}
仿真器可以采用树或哈希表的形式来存放关联数组,但有一定的额外开销。当保存索引值比较分散的数组时,例如使用 32 位地址或 64 位数据作为索引的数据包,这种额外开销显然是可以接受的。
关联数组采用**在方括号中放置数据类型[^DataTypeNote]**的形式来进行声明,例如 `[int]` 或 `[Packet]`。[例 2.21](#例2.21) 示范了关联数组的声明、初始化和遍历过程。
关联数组采用**在方括号中放置数据类型[^DataTypeNote]**的形式来进行声明,例如 `[int]` 或 `[Packet]`。[例 21](#例21) 示范了关联数组的声明、初始化和遍历过程。
[^DataTypeNote]: 也可以采用通配符作为下标进行关联数组的声明,例如 `wild[*]`。但是不推荐使用这种风格,因为不明确指明数据类型会导致很多问题。一个典型的问题是在 `foreach` 循环中——在 `foreach(wild[j])` 中的变量 `j` 究竟是什么类型?
<span id="例2.21"></span>
<a id="例21"></a>
``` verilog 例 2.21 关联数组的声明、初始化和使用
``` verilog 例 21 关联数组的声明、初始化和使用
initial begin
bit [63:0] assoc[int], idx = 1;
@@ -543,13 +539,13 @@ initial begin
end
```
[例 2.21](#例2.21) 中的关联数组 `assoc` 具有稀疏分布的元素:1、2、4、8、16 等等。简单的 `for` 循环并不能遍历该数组,需要使用 `foreach` 循环来完成。如果想控制得更好,可以在 `do ... while` 循环中使用 `first` 和 `next` 函数。这些函数可以修改索引参数的值,然后根据数组是否为空返回 0 或 1。
[例 21](#例21) 中的关联数组 `assoc` 具有稀疏分布的元素:1、2、4、8、16 等等。简单的 `for` 循环并不能遍历该数组,需要使用 `foreach` 循环来完成。如果想控制得更好,可以在 `do ... while` 循环中使用 `first` 和 `next` 函数。这些函数可以修改索引参数的值,然后根据数组是否为空返回 0 或 1。
和 Perl 语言中的哈希数组类似,关联数组也可以使用字符串索引进行寻址。[例 2.22](#例2.22) 使用字符串索引读取文件,并建立关联数组 `switch`,以实现从字符串到数字的映射。如[例 2.22](#例2.22) 所示,可以使用函数 `exists()` 来检查元素是否存在。如果试图读取尚未被写入的元素,SystemVerilog 会返回数组类型的默认值,例如对于双状态类型是 `0`,对于四状态类型是 `X`。
和 Perl 语言中的哈希数组类似,关联数组也可以使用字符串索引进行寻址。[例 22](#例22) 使用字符串索引读取文件,并建立关联数组 `switch`,以实现从字符串到数字的映射。如[例 22](#例22) 所示,可以使用函数 `exists()` 来检查元素是否存在。如果试图读取尚未被写入的元素,SystemVerilog 会返回数组类型的默认值,例如对于双状态类型是 `0`,对于四状态类型是 `X`。
<span id="例2.22"></span>
<a id="例22"></a>
``` verilog 例 2.22 使用带字符串索引的关联数组
``` verilog 例 22 使用带字符串索引的关联数组
/*
输入文件的内容如下:
42 min_address
@@ -594,11 +590,11 @@ SystemVerilog 提供了很多数组的方法,可用于任何一种非合并的
## 7.1. 数组缩减方法
基本的数组缩减方法是把一个数组缩减成一个值,如[例 2.23](例2.23) 所示。最常用的缩减方法是 `sum`,它对数组中的所有元素求和。这里必须对 SystemVerilog 处理操作**位宽**的规则十分小心。默认情况下,如果把一个单比特数组的所有元素相加,其和也是单比特的。但如果使用 32 比特的表达式,把结果保存在 32 比特的变量里,与一个 32 比特的变量进行比较,或者使用适当的 `with` 表达式,SystemVerilog 都会在数组求和的过程中使用 32 比特位宽。
基本的数组缩减方法是把一个数组缩减成一个值,如[例 23](例23) 所示。最常用的缩减方法是 `sum`,它对数组中的所有元素求和。这里必须对 SystemVerilog 处理操作**位宽**的规则十分小心。默认情况下,如果把一个单比特数组的所有元素相加,其和也是单比特的。但如果使用 32 比特的表达式,把结果保存在 32 比特的变量里,与一个 32 比特的变量进行比较,或者使用适当的 `with` 表达式,SystemVerilog 都会在数组求和的过程中使用 32 比特位宽。
<span id="例2.23"></span>
<a id="例23"></a>
``` verilog 例 2.23 数组求和
``` verilog 例 23 数组求和
bit on[10]; // 单比特数组
int total;
@@ -627,11 +623,11 @@ end
其他的数组缩减方法还有 `product` (积),`and` (与),`or` (或) 和 `xor` (异或)。SystemVerilog 没有提供专门从数组里随机选取一个元素的方法。所以对于定宽数组队列、动态数组和关联数组可以使用 `$urandom_range($size (array)-1)`,而对于队列和动态数组还可以使用 `$urandom_ range(array.size()-1)`。
如果想从一个关联数组中随机选取一个元素,则需要逐个访问它之前的元素,因为无法直接访问到第 $N$ 个元素。[例 2.24](#例2.24) 示范了如何从一个以整数值作为索引的关联数组中随机选取一个元素。如果数组是以字符串作为索引,只需要将 `idx` 的类型改为 `string` 即可。
如果想从一个关联数组中随机选取一个元素,则需要逐个访问它之前的元素,因为无法直接访问到第 $N$ 个元素。[例 24](#例24) 示范了如何从一个以整数值作为索引的关联数组中随机选取一个元素。如果数组是以字符串作为索引,只需要将 `idx` 的类型改为 `string` 即可。
<span id="例2.24"></span>
<a id="例24"></a>
``` verilog 例 2.24 从一个关联数组中随机选取一个元素
``` verilog 例 24 从一个关联数组中随机选取一个元素
int aa[int], rand_idx, element, count;
element = $urandom_range(aa.size()-1);
@@ -649,11 +645,11 @@ $display("%0d element aa[%0d] = %0d",
数组中的最大值是什么?数组中有没有包含某个特定值?要想在非合并数组中查找数据,可以使用数组定位方法。**这些方法的返回值通常是一个队列**。
[例 2.25](#例2.25) 使用一个定宽数组 `f[6]`,一个动态数组 `d[]` 和一个队列 `q[$]`。`min` 和 `max` 函数能够找出数组中的最小值和最大值。注意,它们返回的是一个队列而非标量。这些方法也适用于关联数组。方法 `unique` 返回的是在数组中具有唯一值的队列,即排除掉重复的数值。
[例 25](#例25) 使用一个定宽数组 `f[6]`,一个动态数组 `d[]` 和一个队列 `q[$]`。`min` 和 `max` 函数能够找出数组中的最小值和最大值。注意,它们返回的是一个队列而非标量。这些方法也适用于关联数组。方法 `unique` 返回的是在数组中具有唯一值的队列,即排除掉重复的数值。
<span id="例2.25"></span>
<a id="例25"></a>
``` verilog 例 2.25 数组定位方法:<code>min</code>、<code>max</code>、<code>unique</code>
``` verilog 例 25 数组定位方法:<code>min</code>、<code>max</code>、<code>unique</code>
int aa[int], rand_idx, element, count;
element = $urandom_range(aa.size()-1);
@@ -667,11 +663,11 @@ $display("%0d element aa[%0d] = %0d",
element, rand_idx, aa[rand_idx]);
```
使用 `foreach` 循环固然可以实现数组的完全搜索,但是如果使用 SystemVerilog 的定位方法,则只需一个操作便可完成。表达式 `with` 可以指示 SystemVerilog 如何进行搜索,如[例 2.26](#例2.26) 所示。
使用 `foreach` 循环固然可以实现数组的完全搜索,但是如果使用 SystemVerilog 的定位方法,则只需一个操作便可完成。表达式 `with` 可以指示 SystemVerilog 如何进行搜索,如[例 26](#例26) 所示。
<span id="例2.26"></span>
<a id="例26"></a>
``` verilog 例 2.26 数组定位方法:<code>find</code>
``` verilog 例 26 数组定位方法:<code>find</code>
int d[] = '{9,1,8,3,4,4}, tq[$];
// 找出所有大于 3 的元素
@@ -689,22 +685,22 @@ tq = d.find_last with (item==4); // {4}
tq = d.find_last_index with (item==4); // {5} d[5]=4
```
在条件语句 `with` 中,`item` 被称为重复参数,它代表了数组中一个单独的元素。`item` 是默认的名字,也可以指定别的名字,只要在数组方法的参数列表中列出来就可以了,如[例 2.27](#例2.27) 所示。
在条件语句 `with` 中,`item` 被称为重复参数,它代表了数组中一个单独的元素。`item` 是默认的名字,也可以指定别的名字,只要在数组方法的参数列表中列出来就可以了,如[例 27](#例27) 所示。
<span id="例2.27"></span>
<a id="例27"></a>
``` verilog 例 2.27 重复参数的声明
``` verilog 例 27 重复参数的声明
tq = d.find_first with (item==4); // 本例的四个语句都是等价的
tq = d.find_first() with (item==4);
tq = d.find_first(item) with (item==4);
tq = d.find_first(x) with (x==4);
```
[例 2.28](#例2.28) 示范了几种对数组子集进行求和的方式。第一次求和 (`total`) 是先把元素值与 7 进行比较,比较表达式返回 1 (为真) 或 0 (为假),然后再把返回结果与对应元素相乘,所以 `{9, 0, 8, 0, 0, 0}` 的元素和是 17。第二次求和 (`total`) 则使用条件操作符 `? :` 进行计算。
[例 28](#例28) 示范了几种对数组子集进行求和的方式。第一次求和 (`total`) 是先把元素值与 7 进行比较,比较表达式返回 1 (为真) 或 0 (为假),然后再把返回结果与对应元素相乘,所以 `{9, 0, 8, 0, 0, 0}` 的元素和是 17。第二次求和 (`total`) 则使用条件操作符 `? :` 进行计算。
<span id="例2.28"></span>
<a id="例28"></a>
``` verilog 例 2.28 数组定位方法
``` verilog 例 28 数组定位方法
int count, total, d[] = '{9,1,8,3,4,4};
count = d.sum with (item > 7); // 2: {9, 8}
@@ -714,17 +710,17 @@ total = d.sum with (item < 8 ? item : 0); // 12=1+3+4+4
count = d.sum with (item == 4); // 2: {4, 4}
```
当把数组缩减方法与条件语句 `with` 结合使用时,会产生令人惊讶的结果,例如 `sum` 方法。在[例 2.28](#例2.28) 中,`sum` 操作符的结果是条件表达式为真的次数。对于[例 2.28](#例2.28) 的第一个运算语句来说,总共有两个数组元素大于 7 (9 和 8),所以 `count` 最后得 2。
当把数组缩减方法与条件语句 `with` 结合使用时,会产生令人惊讶的结果,例如 `sum` 方法。在[例 28](#例28) 中,`sum` 操作符的结果是条件表达式为真的次数。对于[例 28](#例28) 的第一个运算语句来说,总共有两个数组元素大于 7 (9 和 8),所以 `count` 最后得 2。
> 返回值为索引的数组定位方法,其返回的队列类型是 `int` 而非 `integer`,例如 `find_index` 方法。如果在这些语句中不小心用错了数据类型,那么代码有可能通不过编译。
## 7.3. 数组的排序
SystemVerilog 有几个可以改变数组中元素顺序的方法。可以对元素进行正排序、逆排序,或是打乱它们的顺序,如[例 2.29](#例2.29) 所示。注意,与前述数组定位方法不同的是,**排序方法改变了原始数组**,而**数组定位方法新建了一个队列来保存结果**。
SystemVerilog 有几个可以改变数组中元素顺序的方法。可以对元素进行正排序、逆排序,或是打乱它们的顺序,如[例 29](#例29) 所示。注意,与前述数组定位方法不同的是,**排序方法改变了原始数组**,而**数组定位方法新建了一个队列来保存结果**。
<span id="例2.29"></span>
<a id="例29"></a>
``` verilog 例 2.29 对数组排序
``` verilog 例 29 对数组排序
int d[] = '{9,1,8,3,4,4};
d.reverse(); // '{4,4,3,8,1,9}
d.sort(); // '{1,3,4,4,8,9}
@@ -732,11 +728,11 @@ d.rsort(); // '{9,8,4,4,3,1}
d.shuffle(); // '{9,4,3,8,1,4}
```
`reverse` 和 `shuffle` 方法不能带 `with` 条件语句,**它们的作用范围是整个数组**。[例 2.30](#例2.30) 示范了如何使用子域对一个结构进行排序。结构和合并结构后面会有解释。
`reverse` 和 `shuffle` 方法不能带 `with` 条件语句,**它们的作用范围是整个数组**。[例 30](#例30) 示范了如何使用子域对一个结构进行排序。结构和合并结构后面会有解释。
<span id="例2.30"></span>
<a id="例30"></a>
``` verilog 例 2.30 对结构数组进行排序
``` verilog 例 30 对结构数组进行排序
struct packed { byte red, green, blue; } c[];
initial begin
c = new[100]; // 分配 100 个像素
@@ -752,11 +748,11 @@ end
## 7.4. 使用数组定位方法建立记分板
数组定位方法可以用来建立记分板。[例 2.31](#例2.31) 定义了包结构 (`Packet`),然后建立了一个由包结构队列组成的记分板。后面会解释如何使用 `typedef` 创建结构。
数组定位方法可以用来建立记分板。[例 31](#例31) 定义了包结构 (`Packet`),然后建立了一个由包结构队列组成的记分板。后面会解释如何使用 `typedef` 创建结构。
<span id="例2.31"></span>
<a id="例31"></a>
``` verilog 例 2.31 带数组方法的记分板
``` verilog 例 31 带数组方法的记分板
typedef struct packed
{bit [7:0] addr;
bit [7:0] pr;
@@ -777,7 +773,7 @@ function void check_addr(bit [7:0] addr);
endfunction : check_addr
```
[例 2.31](#例2.31) 中的 `check_addr()` 函数在记分板里寻找和参数匹配的地址。`find_index()` 方法返回一个 `int` 队列。如果该队列为空 (`size==0`),则说明没有匹配值。如果该队列有一个成员 (`size==1`),则说明有一个匹配,该匹配元素随后被 `check_addr()` 函数删除掉。如果该队列有多个成员 (`size>1`),则说明记分板里有多个包地址和目标值匹配。
[例 31](#例31) 中的 `check_addr()` 函数在记分板里寻找和参数匹配的地址。`find_index()` 方法返回一个 `int` 队列。如果该队列为空 (`size==0`),则说明没有匹配值。如果该队列有一个成员 (`size==1`),则说明有一个匹配,该匹配元素随后被 `check_addr()` 函数删除掉。如果该队列有多个成员 (`size>1`),则说明记分板里有多个包地址和目标值匹配。
对于包信息的存储,更好的方式是采用类 (class),后续会有相关介绍。
@@ -843,11 +839,11 @@ endfunction : check_addr
# 9. 使用 `typedef` 创建新的类型
typedef 语句可以用来创建新的类型。例如,要求一个算术逻辑单元 (ALU) 在编译时可配置,以适应 8 比特、 16 比特、 24 比特或 32 比特等不同位宽的操作数。在 Verilog 中,可以为操作数的位宽和类型分别定义一个宏 (macro),如[例 2.32](#例2.32) 所示。
typedef 语句可以用来创建新的类型。例如,要求一个算术逻辑单元 (ALU) 在编译时可配置,以适应 8 比特、 16 比特、 24 比特或 32 比特等不同位宽的操作数。在 Verilog 中,可以为操作数的位宽和类型分别定义一个宏 (macro),如[例 32](#例32) 所示。
<span id="例2.32"></span>
<a id="例32"></a>
``` verilog 例 2.32 Verilog 中用户自定义的类型宏
``` verilog 例 32 Verilog 中用户自定义的类型宏
// 旧的 Verilog 风格
`define OPSIZE 8
`define OPREG reg [`OPSIZE-1:0]
@@ -857,9 +853,9 @@ typedef 语句可以用来创建新的类型。例如,要求一个算术逻辑
这种情况并没有创建新的类型,而只是在进行文本替换。在 SystemVerilog 中,采用下面的代码可以创建新的类型。本文约定,所有用户自定义类型都带后缀 “`_t`”。
<span id="例2.33"></span>
<a id="例33"></a>
``` verilog 例 2.33 SystemVerilog 中用户自定义类型
``` verilog 例 33 SystemVerilog 中用户自定义类型
// 新的 SystemVerilog 风格
parameter OPSIZE = 8;
typedef reg [OPSIZE-1:0] opreg_t;
@@ -873,18 +869,18 @@ opreg_t op_a, op_b;
> 用户自定义的最有用的类型是双状态的 32 比特的无符号整数。在 testbench 中,很多数值都是正整数,例如字段长度或事件次数,这种情况下如果定义有符号整数就会出问题。把对 `uint` 的定义放到通用定义程序包中,这样就可以在仿真程序的任何地方使用它。
<span id="例2.34"></span>
<a id="例34"></a>
``` verilog 例 2.34 <code>uint</code> 的定义
``` verilog 例 34 <code>uint</code> 的定义
typedef bit [31:0] uint; // 32 比特双状态无符号数
typedef int unsigned uint; // 等效定义
```
对新的数组类型的定义并不是很明显,需要把数组的下标放在新的数组名称中。[例 2.35](#例2.35) 创建了一种新的类型,`fixed_array5`,它是一个有着 5 个元素的定宽数组。[例 2.35](#例2.35) 接着声明了一个这种类型的数组并进行了初始化。
对新的数组类型的定义并不是很明显,需要把数组的下标放在新的数组名称中。[例 35](#例35) 创建了一种新的类型,`fixed_array5`,它是一个有着 5 个元素的定宽数组。[例 35](#例35) 接着声明了一个这种类型的数组并进行了初始化。
<span id="例2.35"></span>
<a id="例35"></a>
``` verilog 例 2.35 用户自定义数组类型
``` verilog 例 35 用户自定义数组类型
typedef int fixed_array5[5];
fixed_array5 f5;
@@ -902,19 +898,19 @@ Verilog 的最大缺陷之一是没有数据结构。在 SystemVerilog 中可以
## 10.1. 使用 `struct` 创建新类型
可以把若干变量组合到一个结构中。[例 2.36](#例2.36) 创建了一个名为 `pixel` 的结构,它有三个无符号的字节变量,分别代表红、绿和蓝。
可以把若干变量组合到一个结构中。[例 36](#例36) 创建了一个名为 `pixel` 的结构,它有三个无符号的字节变量,分别代表红、绿和蓝。
<span id="例2.36"></span>
<a id="例36"></a>
``` verilog 例 2.36 创建一个 <code>pixel</code> 类型
``` verilog 例 36 创建一个 <code>pixel</code> 类型
struct {bit [7:0] r, g, b;} pixel;
```
[例 2.36](#例2.36) 中的声明只是创建了一个 `pixel` 变量。要想在端口和程序中共享它,则必须创建一个新的类型,如[例 2.37](#例2.37) 所示。
[例 36](#例36) 中的声明只是创建了一个 `pixel` 变量。要想在端口和程序中共享它,则必须创建一个新的类型,如[例 37](#例37) 所示。
<span id="例2.37"></span>
<a id="例37"></a>
``` verilog 例 2.37 <code>pixel</code> 结构
``` verilog 例 37 <code>pixel</code> 结构
typedef struct {bit [7:0] r, g, b;} pixel_s;
pixel_s my_pixel;
```
@@ -923,11 +919,11 @@ pixel_s my_pixel;
## 10.2. 对结构进行初始化
可以在声明或者过程赋值语句中把多个值赋给一个结构体,就像数组那样。如[例 2.38](#例2.38) 所示,赋值时要把数值放到带单引号的大括号中。
可以在声明或者过程赋值语句中把多个值赋给一个结构体,就像数组那样。如[例 38](#例38) 所示,赋值时要把数值放到带单引号的大括号中。
<span id="例2.38"></span>
<a id="例38"></a>
``` verilog 例 2.38 对 <code>struct</code> 类型进行初始化
``` verilog 例 38 对 <code>struct</code> 类型进行初始化
initial begin
typedef struct {int a;
byte b;
@@ -944,11 +940,11 @@ end
## 10.3. 创建可容纳不同类型的联合
在硬件中,寄存器里的某些位的含义可能与其他位的值有关。例如,不同的操作码对应的处理器指令格式也不同。带立即操作数的指令,它在操作数位置上存放的是一个常量。整数指令对这个立即数的译码结果会与浮点指令大不相同。[例 2.39](#例2.39) 把整数 `i` 和实数 `f` 存放在同一位置上。
在硬件中,寄存器里的某些位的含义可能与其他位的值有关。例如,不同的操作码对应的处理器指令格式也不同。带立即操作数的指令,它在操作数位置上存放的是一个常量。整数指令对这个立即数的译码结果会与浮点指令大不相同。[例 39](#例39) 把整数 `i` 和实数 `f` 存放在同一位置上。
<span id="例2.39"></span>
<a id="例39"></a>
``` verilog 例 2.39 使用一个下标 <code>typedef</code> 创建联合
``` verilog 例 39 使用一个下标 <code>typedef</code> 创建联合
typedef union { int i; real f; } num_u;
num_u un;
un.f = 0.0; // 把数值设为浮点形式
@@ -960,11 +956,11 @@ un.f = 0.0; // 把数值设为浮点形式
## 10.4. 合并结构
SystemVerilog 提供的合并结构允许对数据在存储器中的排布方式有更多的控制。合并结构是以连续比特集的方式存放的,中间没有闲置的空间。[例 2.37](#例2.37) 中的 `pixel` 结构使用了三个数值,所以它占用了三个长字的存储空间,即使它实际只需要三个字节。可以指定把它合并到尽可能小的空间里。
SystemVerilog 提供的合并结构允许对数据在存储器中的排布方式有更多的控制。合并结构是以连续比特集的方式存放的,中间没有闲置的空间。[例 37](#例37) 中的 `pixel` 结构使用了三个数值,所以它占用了三个长字的存储空间,即使它实际只需要三个字节。可以指定把它合并到尽可能小的空间里。
<span id="例2.40"></span>
<a id="例40"></a>
``` verilog 例 2.40 合并结构
``` verilog 例 40 合并结构
typedef struct packed {bit [7:0] r, g, b;} pixel_p_s;
pixel_p_s my_pixel;
```
@@ -981,11 +977,11 @@ SystemVerilog 数据类型的多样性意味着可能需要在它们之间进行
## 11.1. 静态转换
静态转换操作不对转换值进行检查。如[例 2.41](#例2.41) 所示,转换时指定目标类型,并在需要转换的表达式前加上单引号即可。注意,Verilog 对整数和实数类型,或者不同位宽的向量之间进行隐式转换。
静态转换操作不对转换值进行检查。如[例 41](#例41) 所示,转换时指定目标类型,并在需要转换的表达式前加上单引号即可。注意,Verilog 对整数和实数类型,或者不同位宽的向量之间进行隐式转换。
<span id="例2.41"></span>
<a id="例41"></a>
``` verilog 例 2.41 在整型和实划之间进行静态转换
``` verilog 例 41 在整型和实划之间进行静态转换
int i;
real r;
@@ -999,11 +995,11 @@ r = real'(42); // 转换是非强制的
## 11.3. 流操作符
流操作符 `<<` 和 `>>` 用在赋值表达式的右边,后面带表达式、结构或数组。流操作符用于把其后的数据打包成一个比特流。操作符 `>>` 把数据从左至右变成流,而 `<<` 则把数据从右至左变成流,如[例 2.42](#例2.42) 所示。也可以指定一个片段宽度,把源数据按照这个宽度分段以后再转变成流。不能将比特流结果直接赋给非合并数组,而应该在赋值表达式的左边使用流操作符把比特流拆分到非合并数组中。
流操作符 `<<` 和 `>>` 用在赋值表达式的右边,后面带表达式、结构或数组。流操作符用于把其后的数据打包成一个比特流。操作符 `>>` 把数据从左至右变成流,而 `<<` 则把数据从右至左变成流,如[例 42](#例42) 所示。也可以指定一个片段宽度,把源数据按照这个宽度分段以后再转变成流。不能将比特流结果直接赋给非合并数组,而应该在赋值表达式的左边使用流操作符把比特流拆分到非合并数组中。
<span id="例2.42"></span>
<a id="例42"></a>
``` verilog 例 2.42 基本的流操作
``` verilog 例 42 基本的流操作
initial begin
int h;
bit [7:0] b, g[4], j[4] = '{8'ha, 8'hb, 8'hc, 8'hd};
@@ -1022,11 +1018,11 @@ end
也可以使用很多连接符 `{}` 来完成同样的操作,但是流操作符用起来会更简洁并且易于阅读。
如果需要打包或拆分数组,可以使用流操作符来完成具有不同尺寸元素的数组间的转换。例如,可以将字节数组转换成字数组。对于定宽数组、动态数组和队列都可以这样。[例 2.43](#例2.43) 示范了队列之间的转换,这种转换同时也适用于动态数组。数组元素会根据需要自动分配。
如果需要打包或拆分数组,可以使用流操作符来完成具有不同尺寸元素的数组间的转换。例如,可以将字节数组转换成字数组。对于定宽数组、动态数组和队列都可以这样。[例 43](#例43) 示范了队列之间的转换,这种转换同时也适用于动态数组。数组元素会根据需要自动分配。
<span id="例2.43"></span>
<a id="例43"></a>
``` verilog 例 2.43 使用流操作符进行队列间的转换
``` verilog 例 43 使用流操作符进行队列间的转换
initial begin
bit [15:0] wq[$] = {16'h1234, 16'h5678};
bit [7:0] bq[$];
@@ -1042,11 +1038,11 @@ end
> 数组下标失配是在数组间进行流操作时常见的错误。数组声明中的下标 `[256]` 等同于 `[0:255]` 而非 `[255:0]`。由于很多数组使用 `[high:low]` (由高到低) 的下标形式进行声明,使用流操作把它们的值赋给带 `[size]` 下标形式的数组,会造成元素倒序。同样,如果把声明形式为 `bit [7:0] src [255:0]` 的非合并数组使用流操作赋值给声明形式为 `bit [7:0] [255:0] dst` 的合并数组,则数值的顺序会被打乱。对于合并的字节数组,正确的声明形式应该是 `bit [255:0] [7:0] dst`。
流操作符也可用来将结构 (例如,ATM 信元) 打包或拆分到字节数组中。在[例 2.44](#例2.44) 中使用流操作把结构转换成动态的字节数组,然后字节数组又被反过来转换成结构。
流操作符也可用来将结构 (例如,ATM 信元) 打包或拆分到字节数组中。在[例 44](#例44) 中使用流操作把结构转换成动态的字节数组,然后字节数组又被反过来转换成结构。
<span id="例2.44"></span>
<a id="例44"></a>
``` verilog 例 2.44 使用流操作符在结构和数组间进行转换
``` verilog 例 44 使用流操作符在结构和数组间进行转换
initial begin
typedef struct {int a;
byte b;
@@ -1072,19 +1068,19 @@ end
在学会使用枚举类型之前,只能使用文本宏。宏的作用范围太大,而且大多数情况下对于调试者是可见的。枚举创建了一种强大的变量类型,它仅限于一些特定名称的集合,例如指令中的操作码或者状态机中的状态名。例如,使用 ADD、MOVE 或 ROTW 这些名称有利于编写和维护代码,它比直接使用 `8'h01` 这样的常量或者宏要好得多。定义常量的另一种方法是使用参数。但参数需要对每个数值进行单独的定义,而枚举类型却能够自动为列表中的每个名称分配不同的数值。
最简单的枚举类型声明包含了一个常量名称列表以及一个或多个变量,如[例 2.45](#例2.45) 所示。通过这种方式创建的是一个匿名的枚举类型,它只能用于这个例子中声明的变量。
最简单的枚举类型声明包含了一个常量名称列表以及一个或多个变量,如[例 45](#例45) 所示。通过这种方式创建的是一个匿名的枚举类型,它只能用于这个例子中声明的变量。
<span id="例2.45"></span>
<a id="例45"></a>
``` verilog 例 2.45 一个简单的枚举类型
``` verilog 例 45 一个简单的枚举类型
enum {RED, BLUE, GREEN} color;
```
创建一个署名的枚举类型有利于声明更多新变量,尤其是当这些变量被用作子程序参数或模块端口时。首先需要创建枚举类型,然后再创建相应的变量。使用内建的 `name()` 函数,可以得到枚举变量值对应的字符串,如[例 2.46](#例2.46) 所示。
创建一个署名的枚举类型有利于声明更多新变量,尤其是当这些变量被用作子程序参数或模块端口时。首先需要创建枚举类型,然后再创建相应的变量。使用内建的 `name()` 函数,可以得到枚举变量值对应的字符串,如[例 46](#例46) 所示。
<span id="例2.46"></span>
<a id="例46"></a>
``` verilog 例 2.46 枚举类型
``` verilog 例 46 枚举类型
// 创建代表 0,1,2 的数据类型
typedef enum {INIT, DECODE, IDLE} fsmstate_e;
fsmstate_e pstate, nstate; // 声明自定义类型变量
@@ -1104,28 +1100,28 @@ end
## 12.1. 定义枚举值
枚举值默认为从 0 开始递增的整数。可以定义自己的枚举值。[例 2.47](#例2.47) 中使用 `INIT` 代表默认值 0,`DECODE` 代表 2,`IDLE` 代表 3。
枚举值默认为从 0 开始递增的整数。可以定义自己的枚举值。[例 47](#例47) 中使用 `INIT` 代表默认值 0,`DECODE` 代表 2,`IDLE` 代表 3。
<span id="例2.47"></span>
<a id="例47"></a>
``` verilog 例 2.47 指定枚举值
``` verilog 例 47 指定枚举值
typedef enum {INIT, DECODE=2, IDLE} fsmtype_e;
```
枚举常量,如[例 2.47](#例2.47) 中的 `INIT`,它们的作用范围规则和变量是一样的。因此,如果在不同的枚举类型中用到了同一个枚举常量名,例如把 `INIT` 用于不同的状态机中,那么必须在不同的作用域里声明它们,例如模块、程序块、函数和类。
枚举常量,如[例 47](#例47) 中的 `INIT`,它们的作用范围规则和变量是一样的。因此,如果在不同的枚举类型中用到了同一个枚举常量名,例如把 `INIT` 用于不同的状态机中,那么必须在不同的作用域里声明它们,例如模块、程序块、函数和类。
> 如果没有特别指出,枚举类型会被当成 `int` 类型存储。由于 `int` 类型的默认值是 0,所以在给枚举常量赋值时务必小心。在[例 2.48](#例2.48) 中 `position` 会被初始化为 0,这并不是一个合法的 `ordinal_e` 变量。这种情况是语言本身所规定的,而非工具上的缺陷。因此把 0 指定给一个枚举常量可以避免这个错误,如[例 2.49](#例2.49) 所示。
> 如果没有特别指出,枚举类型会被当成 `int` 类型存储。由于 `int` 类型的默认值是 0,所以在给枚举常量赋值时务必小心。在[例 48](#例48) 中 `position` 会被初始化为 0,这并不是一个合法的 `ordinal_e` 变量。这种情况是语言本身所规定的,而非工具上的缺陷。因此把 0 指定给一个枚举常量可以避免这个错误,如[例 49](#例49) 所示。
<span id="例2.48"></span>
<a id="例48"></a>
``` verilog 例 2.48 指定枚举值:不正确
``` verilog 例 48 指定枚举值:不正确
typedef enum {FIRST=1, SECOND, THIRD} ordinal_e;
ordinal_e position;
```
<span id="例2.49"></span>
<a id="例49"></a>
``` verilog 例 2.49 指定枚举值:正确
``` verilog 例 49 指定枚举值:正确
typedef enum {BAD_O=0, FIRST=1, SECOND, THIRD} ordinal_e;
ordinal_e position;
```
@@ -1147,11 +1143,11 @@ SystemVerilog 提供了一些可以遍历枚举类型的函数:
件。如果使用 `current! =current.last`,则循环会在到达最后一个成员之前终止。如果
使用 `current<=current.last`,则会造成死循环,因为 `next` 给出的值永远也不会大于最后一个值。这类似于 `for` 循环的步长为 0.3,而循环变量定义为 `bit [1:0]`,所以循环永远不会退出。
实际上,可以使用 `do ... while` 循环来遍历所有值,如[例 2.50](#例2.50) 所示。
实际上,可以使用 `do ... while` 循环来遍历所有值,如[例 50](#例50) 所示。
<span id="例2.50"></span>
<a id="例50"></a>
``` verilog 例 2.50 遍历所有枚举成员
``` verilog 例 50 遍历所有枚举成员
typedef enum {RED, BLUE, GREEN} color_e;
color_e color;
color = color.first;
@@ -1167,9 +1163,9 @@ while (color != color.first); // 环形绕回时即完成
枚举类型的默认类型为双状态 `int`。可以使用简单的赋值表达式把枚举变量的值直接赋给非枚举变量如 `int`。但 SystemVerilog 不允许在没有进行显式类型转换的情况下把整型变量赋给枚举变量。SystemVerilog 要求显式类型转换的原因是**可能存在的数值越界情况**。
<span id="例2.51"></span>
<a id="例51"></a>
``` verilog 例 2.51 整型和枚举类型之间的相互赋值
``` verilog 例 51 整型和枚举类型之间的相互赋值
typedef enum {RED, BLUE, GREEN} COLOR_E;
COLOR_E color, c2;
int c;
@@ -1187,9 +1183,9 @@ initial begin
end
```
在[例 2.51](#例2.51) 中,`$cast` 被当成函数进行调用,目的在于把右边的值赋给左边的量。如果赋值成功,`$cast()` 返回 1。如果因为数值越界而导致赋值失败,则不进行任何赋值,函数返回 0。如果把 `cast` 当成任务使用并且操作失败,则 SystemVerilog 会打印错误信息。
在[例 51](#例51) 中,`$cast` 被当成函数进行调用,目的在于把右边的值赋给左边的量。如果赋值成功,`$cast()` 返回 1。如果因为数值越界而导致赋值失败,则不进行任何赋值,函数返回 0。如果把 `cast` 当成任务使用并且操作失败,则 SystemVerilog 会打印错误信息。
也可以像[例 2.51](#例2.51) 所示的那样使用 `type'(val)` 进行类型转换,但这种方式并不进行任何类型检查,所以转换结果可能会越界。例如,在[例 2.51](#例2.51) 中进行静态类型转换以后,赋给 `c2` 的值实际上已经越界,所以应该尽量避免使用这种方式。
也可以像[例 51](#例51) 所示的那样使用 `type'(val)` 进行类型转换,但这种方式并不进行任何类型检查,所以转换结果可能会越界。例如,在[例 51](#例51) 中进行静态类型转换以后,赋给 `c2` 的值实际上已经越界,所以应该尽量避免使用这种方式。
# 13. 常量
@@ -1199,26 +1195,26 @@ SystemVerilog 中有好几种类型的常量。Verilog 中创建常量的最典
SystemVerilog 也支持 `const` 修饰符,允许在变量声明时对其进行初始化,但不能在过程代码中改变其值。
<span id="例2.52"></span>
<a id="例52"></a>
``` verilog 例 2.52 <code>const</code> 变量的声明
``` verilog 例 52 <code>const</code> 变量的声明
initial begin
const byte colon = ":";
...
end
```
在[例 2.52](#例2.52) 中,`colon` 的值在 `initial` 块开头就被初始化。`const` 还可以作为子程序参数。
在[例 52](#例52) 中,`colon` 的值在 `initial` 块开头就被初始化。`const` 还可以作为子程序参数。
# 14. 字符串
Verilog 中使用 `reg` 变量来保存字符串,这一表达很不方便。SystemVerilog 中的 `string` 类型可以用来保存长度可变的字符串。单个字符是 `byte` 类型。长度为 $N$ 的字符串中,元素编号从 0 到 $N — 1$。注意,跟 C 语言 不一样的是,字符串的结尾并不带标识符 null,所有尝试使用字符 “\0” 的操作都会被忽略。字符串使用动态的存储方式,所以不用担心存储空间会全部用完。
[例 2.53](#例2.53) 示范了与字符串相关的几种操作。函数 `getc(N)` 返回位置 `N` 上的字节,`toup­per` 返回一个所有字符大写的字符串,`tolower` 返回一个小写的字符串。大括号 `{}` 用于串接字符串。任务 `putc(M,C)` 把字节 `c` 写到字符串的 `M` 位上。`M` 必须介于 0 和 `len` 所给出的长度之间。函数 `substr(start,end)` 提取出从位置 `start` 到 `end` 之间的所有字符。
[例 53](#例53) 示范了与字符串相关的几种操作。函数 `getc(N)` 返回位置 `N` 上的字节,`toup­per` 返回一个所有字符大写的字符串,`tolower` 返回一个小写的字符串。大括号 `{}` 用于串接字符串。任务 `putc(M,C)` 把字节 `c` 写到字符串的 `M` 位上。`M` 必须介于 0 和 `len` 所给出的长度之间。函数 `substr(start,end)` 提取出从位置 `start` 到 `end` 之间的所有字符。
<span id="例2.53"></span>
<a id="例53"></a>
``` verilog 例 2.53 字符串方法
``` verilog 例 53 字符串方法
string s;
initial begin
@@ -1241,20 +1237,20 @@ task my_log(string message);
endtask
```
稍加留意便可发现动态字符串的用处有多大。在别的语言如 C 里,必须不停地创建临时字符串来接收函数返回的结果。在[例 2.53](#例2.53) 中,函数 `psprintf()` 替代了 Verilog-2001 中的函数 `sformat()`。这个新函数返回一个格式化的临时字符串,并且可以直接传递给其他子程序。这样就可以不用定义新的临时字符串并在格式化语句与函数调用过程中传递这个字符串。
稍加留意便可发现动态字符串的用处有多大。在别的语言如 C 里,必须不停地创建临时字符串来接收函数返回的结果。在[例 53](#例53) 中,函数 `psprintf()` 替代了 Verilog-2001 中的函数 `sformat()`。这个新函数返回一个格式化的临时字符串,并且可以直接传递给其他子程序。这样就可以不用定义新的临时字符串并在格式化语句与函数调用过程中传递这个字符串。
# 15. 表达式的位宽
在 Verilog 中,表达式的位宽是造成行为不可预知的主要原因之一。[例 2.54](#例2.54) 使用四种不同方式实现 `1+1`:
在 Verilog 中,表达式的位宽是造成行为不可预知的主要原因之一。[例 54](#例54) 使用四种不同方式实现 `1+1`:
- 方式 A 使用两个单比特变量,在这种精度下得到 `1+1=0`。
- 方式 B 由于赋值表达式的左边有一个 8 比特的变量,所以其精度是 8 比特,得到的结果是 `1+1=2`。
- 方式 C 采用一个哑元常数强迫 SystemVerilog 使用 2 比特精度。
- 方式 D 中,第一个值在转换符的作用下被指定为 2 比特的值,所以结果是 `1+1=2`。
<span id="例2.54"></span>
<a id="例54"></a>
``` verilog 例 2.54 表达式位宽依赖于上下文
``` verilog 例 54 表达式位宽依赖于上下文
bit [7:0] b8;
bit one = 1'b1; // 单比特
$displayb(one + one); // A: 1+1 = 0
@@ -1,5 +1,5 @@
---
title: "Josh's Notes: SystemVerilog 验证(Part 3 — 过程语句和子程序)"
title: "Josh's Note — SystemVerilog 验证<br>Part 3 过程语句和子程序"
mathjax: true
comments: true
copyright: true
@@ -1,194 +0,0 @@
---
title: 高等数学常用公式
mathjax: true
comments: true
copyright: true
toc:
enable: true
number: false
wrap: true
expand_all: true
max_depth: 4
abbrlink: 1823c9d1
date: 2023-04-14 16:25:59
tags:
- 等价无穷小
- 导数公式
- Maclaurin 公式
- 曲率
- 积分公式
- 三角函数
categories:
- [数学, 微积分]
---
# 1. 常见等价无穷小
||||
| :--: | :--: | :--: |
| $\sin x \sim x$ | $\tan x \sim x$ | $\arcsin x \sim x$ |
| $\arctan x \sim x$ | $\displaystyle\left( 1 - \cos x \right) \sim \frac{x^2}{2}$ | $\ln (1+x) \sim x$ |
| $\left( e^x -1 \right) \sim x$ | $\left( a^x - 1 \right) \sim x \ln a$ | $\left( \left( 1+x \right) ^\alpha -1 \right) \sim \alpha x$ |
<!-- more -->
# 2. 导数基本公式
| 一般函数 | 三角函数 | 反三角函数 | 双曲函数<br>(圆函数) |
| :--: | :--: | :--: | :----: |
| $\left( C \right)' = 0$ | $\left( \sin x \right)' = \cos x$ | $\displaystyle\left( \arcsin x \right)' = \frac{1}{\sqrt{1-x^2}}$ | $\displaystyle\left( \sinh x \right)' = \left(\frac{e^x-e^{-x}}{2}\right)' = \cosh x$ |
| $\left( x^\alpha \right)'=\alpha x^{\alpha-1} \left( \alpha \in \mathbf{Z} \right)$ | $\left( \cos x \right)' = -\sin x$ | $\displaystyle\left( \arccos x \right)' = -\frac{1}{\sqrt{1-x^2}}$ | $\displaystyle\left( \cosh x \right)' = \left( \frac{e^x+e^{-x}}{2} \right)'=\sinh x$ |
| $\displaystyle\left( \log_ax\right)'=\frac{1}{x\ln a}$ | $\displaystyle\left( \tan x \right)' = \frac{1}{\cos^2 x}=\sec^2 x$ | $\displaystyle\left( \arctan x \right)' = \frac{1}{1+x^2}$ | $\displaystyle\left( \mathrm{arsinh} \, x \right)' = \left(\ln \left( x+\sqrt{x^2 + 1} \right) \right)' = \frac{1}{x^2+1}$ |
| $( \ln$\| $x$ \|$)'=\displaystyle\frac{1}{x}$ | $\displaystyle\left( \cot x \right)' = -\frac{1}{\sin^2 x} = -\csc^2 x$ | $\displaystyle\left( \mathrm{arccot} \, x \right)' = -\frac{1}{1+x^2}$ | $\displaystyle\left( \mathrm{arcosh} \, x \right)' = \left( \ln \left( x + \sqrt{x^2 - 1} \right) \right)' = \frac{1}{\sqrt{x^2-1}}$
| | $\left( \sec x \right)' = \sec x \cdot \tan x$ |
| | $\left( \csc x \right)' = \csc x \cdot \cot x$ |
- Newton-Leibniz 公式:
$$
\begin{aligned}
\left( u \cdot v \right)^{\left( n \right)} &= u^{\left( n \right)}v + nu^{\left( n-1 \right)}v' + \frac{n \left( n-1 \right)}{2!}u^{\left( n-2 \right)}v'' + \cdots + \frac{n\left( n-1 \right)\cdots\left(n-k+1\right)}{k!}u^{\left( n-k \right)}v^{(k)} + \cdots + uv^{\left( n \right)} \\
&= \sum_{k=0}^{n}C_n^k u^{\left( u-k \right)}v^k
\end{aligned}
$$
可以注意到 Newton-Leibniz 公式具有类似二项式定理展开的形式。
# 3. 几个初等函数的 Maclaurin 公式
## 3.1 Taylor 公式的一般形式
$$
f(x)=f(x_0) + f'(x_0)(x-x_0) + \frac{f''(x_0)}{2!}(x-x_0)^2 + \cdots + \frac{f^{(n)}(x_0)}{n!}(x-x_0)^n + R_n
$$
其中
$$
R_n = \frac{f^{(n+1)}(\xi)}{(n+1)!}(x-x_0)^{n+1} \, (\xi\,在\,x\,和\,x_0\,之间) = o\left( \left( x - x_0 \right)^n \right)(x\to x_0)
$$
## 3.2 Maclaurin 公式的一般形式
$$
f(x)=f(0)+f'(0)\,x + \frac{f''(0)}{2!}x^2 + \cdots + \frac{f^{(n)}(0)}{n!}x^n + R_n
$$
其中
$$
R_n = \frac{f^{(n+1)}(\xi)}{(n+1)!}x^{n+1} \, (\xi\,在\,0\,和\,x\,之间) = \frac{f^{(n+1)}(\theta x)}{(n+1)!} x^{n+1}(0<\theta<1) = o\left( \left( x - x_0 \right)^n \right)(x\to x_0)
$$
## 3.3 指数函数的 Maclaurin 展开式
$$
e^x=1+x+\frac{x^2}{2} + \frac{x^3}{3} + \cdots +\frac{x^n}{n!} + \frac{e^{\theta x}}{(n+1)!}(0<\theta<1)
$$
## 3.4 正弦函数的 Maclaurin 展开式
$$
\sin x = x - \frac{x^3}{3!} + \frac{x^5}{5!} + \cdots + (-1)^{m-1}\frac{x^{2m-1}}{(2m-1)!} + R_{2m}
$$
其中
$$
R_{2m}=\frac{\sin\left( \theta x + \frac{(2m-1)\pi}{2}\right)}{(2m+1)!}x^{2m+1} = o(x^{2m})(0<\theta <1)
$$
## 3.5 余弦函数的 Maclaurin 展开式
$$
\cos x = 1 - \frac{x^2}{2!} + \frac{x^4}{4!} + \cdots + (-1)^m\frac{x^{2m}}{2m!} + R_{2m+1}
$$
其中
$$
R_{2m+1}=\frac{\cos(\theta x + (m+1)\pi)}{(2m+2)!} x^{2m+2}=o(x^{2m+2}) (0<\theta <1)
$$
## 3.6 $\ln (1+x)$ 的 Maclaurin 展开式
$$
\ln(1+x) = x - \frac{x^2}{2} + \frac{x^3}{3} -\frac{x^4}{4} + \cdots + \frac{(-1)^{n-1}x^n}{n} + R_n(x)
$$
其中
$$
R_n(x) = \frac{(-1)^n}{(n+1)(1+\theta x)^{n+1}}x^{n+1} = o(x^n)(0<\theta <1)
$$
## 3.7 $(1+x)^\alpha$ 的 Maclaurin 展开式
$$
(1+x)^\alpha = 1 + \alpha x + \frac{\alpha(\alpha-1)}{2!}x^2 + \cdots + \frac{\alpha(\alpha - 1)\cdots (\alpha-n+1)}{n!}x^n + R_n(x)
$$
其中
$$
R_n(x) = \frac{\alpha(\alpha -1)\cdots(\alpha-n)}{(n+1)!}(1+\theta x)^{\alpha-n-1}x^{n+1} = o(x)(0<\theta <1)
$$
## 3.8 $\frac{1}{1-x}$ 的 Maclaurin 展开式
$$
\frac{1}{1-x} = 1+x+x^2+\cdots+x^n +o(x^n)
$$
# 4. 曲率及曲率半径
| 曲率 | 曲率半径 |
| :--: | :--: |
| $K=\left\| \dfrac{\mathrm{d}\alpha}{\mathrm{d}s}\right\| \xlongequal{\tan \alpha = y' \Rightarrow \alpha = \arctan y'} \dfrac{\left\| \frac{y''}{1+y'^2}\mathrm{d}x \right\|}{\sqrt{1+y'^2}}\mathrm{d}x = \dfrac{\left\| y'' \right\|}{\left( 1 + y' \right)^\frac{3}{2}}$ | $R = \frac{1}{K}$ |
# 5. 积分常用公式
| 序 | 描述 | 公式 |
| :--: | :----: | :----------------------------------------------:|
| 1 | 定积分的定义 | $\displaystyle\int^1_0f(x)\mathrm{d}x=I=\lim_{\lambda \to 0}\sum_{i=1}^{n}f(\xi_i)\Delta x_i$,其中 $\lambda = \max \left\{ \Delta x_1,\Delta x_2, \cdots, \Delta x_n \right\}$ |
| 2 | 变上限积分 | $考察定积分\displaystyle\int^x_af(x)\mathrm{d}x=\int^x_af(t)\mathrm{d}t$,对 $\displaystyle\Phi(x)=\int_a^xf(t)\mathrm{d}t$,有 $\displaystyle\Phi'(x)=\frac{\mathrm{d}}{\mathrm{d}x}\int_a^xf(t)\mathrm{d}t = f(x)$ |
| 3. | — | $\displaystyle\frac{\mathrm{d}}{\mathrm{d}x}\int^{\beta(x)}_{\alpha(x)}f'(t)\mathrm{d}t = f\left[ \beta\left(x\right)\right]\beta'(x)-f[\alpha(x)]\alpha'(x)$ |
| 4 | 上下限对称的积分 | 若 $f(x)$ 为偶函数,则 $\displaystyle\int_{-a}^af(x)\mathrm{d}x=2\int_0^af(x)\mathrm{d}x$;若 $f(x)$ 为奇函数,则 $\displaystyle\int_{-a}^af(x)\mathrm{d}x=0$ |
| 5 | 周期函数的积分 | $\displaystyle f(x+T)=f(x)\Rightarrow\int_0^{nT}f(x)\mathrm{d}x=n\int^T_0f(x)\mathrm{d}x$ |
| 6 | 分部积分法 | $\displaystyle\int uv'\mathrm{d}x=uv - \int u'v\mathrm{d}x \Leftrightarrow \int u\mathrm{d}v = uv - \int v\mathrm{d}u$ |
# 6. 基本积分表
| 序 | 积分式 |
| :--: | :-------------------------: |
| 1 | $\displaystyle\int k\mathrm{d}x=kx+C$,特别地 $\displaystyle\int\mathrm{d}x=x+C$ |
| 2 | $\displaystyle\int x^\mu\mathrm{d}x=\frac{x^{\mu+1}}{\mu+1}+C(\mu\ne-1)$,特别地 $\displaystyle\int \frac{\mathrm{d}x}{x^2}=-\frac{1}{x}+C,\int\frac{\mathrm{d}x}{\sqrt{x}}=2\sqrt{x}+C$ |
| 3 | $\displaystyle\int\frac{\mathrm{d}x}{x}=\ln \|x\|+C$ |
| 4 | $\displaystyle\int\frac{\mathrm{d}x}{1+x^2} = \arctan x +C$ |
| 5 | $\displaystyle\int\frac{\mathrm{d}x}{\sqrt{1-x^2}}=\arcsin x+C$ |
| 6 | $\displaystyle\int\sin x\mathrm{d}x = -\cos x+C, \int\cos x\mathrm{d}x = \sin x +C$ |
| 7 | $\displaystyle\int\frac{\mathrm{d}x}{\cos^2x} = \int\sec^2x\mathrm{d}x = \tan x +C, \int\frac{\mathrm{d}x}{\sin^2x}=\int\csc^2x\mathrm{d}x = -\cot x +C$ |
| 8 | $\displaystyle\int a^x\mathrm{d}x = \frac{a^x}{\ln a} + C$,特别地 $\displaystyle\int e^x\mathrm{d}x = e^x +C$
| 9 | $\displaystyle\int \sinh x\mathrm{d}x = \cosh x + C,\int \cosh x \mathrm{d}x=\sinh x +C$ |
# 7. 三角函数相关公式
| 序 | 公式 |
| :--: | :-------------------------: |
| 1 | $\sin^2x+\cos^2x=1, \tan^2x+1=\sec^2x,\cot^2x+1=\csc^2x$ |
| 2 | $\begin{aligned}&\cosh^2x-\sinh^2x=1,\\ &\sinh(x\pm y)=\sinh x\cdot\cosh y \pm \sinh y\cdot\cosh x, \cosh(x\pm y) = \cosh x\cdot\cosh y,\\ &\sinh2x = 2\sinh x\cdot \cosh x, \cosh 2x = \cosh^2x+\sinh^2x = 2\cosh^2x - 1\end{aligned}$ |
| 3<br>积化和差公式 | $\sin\alpha\cos\beta=\frac12[\sin(\alpha+\beta)+\sin(\alpha-\beta)],\cos\alpha\sin\beta = \frac12[\sin(\alpha+\beta) - \sin(\alpha-\beta)]$ <br> $\cos\alpha\cos\beta = \frac12[cos(\alpha+\beta) + cos(\alpha - \beta)], \sin\alpha\sin\beta=-\frac12[\cos(\alpha+\beta) - \cos(\alpha-\beta)]$ |
| 4<br>和差化积公式 | $\displaystyle\sin\alpha + \sin\beta = 2\sin\left(\frac{\alpha+\beta}{2}\right) \cos\left(\frac{\alpha-\beta}{2}\right), \sin\alpha - \sin\beta = 2\sin\left(\frac{\alpha-\beta}{2}\right) \cos\left(\frac{\alpha+\beta}{2}\right)$ <br> $\displaystyle\cos\alpha + \cos\beta = 2\cos\left(\frac{\alpha+\beta}{2}\right) \cos\left(\frac{\alpha-\beta}{2}\right), \cos\alpha - \cos\beta = -2\sin\left(\frac{\alpha+\beta}{2}\right) \sin\left(\frac{\alpha-\beta}{2}\right)$ |
| 5<br>三角代换 | $\displaystyle\sqrt{a^2-x^2}\xrightarrow{x=a\sin t}a\cos t, \sqrt{a^2+x^2} \xrightarrow{x=a\tan t}a\sec t, \sqrt{x^2-a^2}\xrightarrow{x=a\sec t}a\tan t \left( a>0,t\in\left( -\frac{\pi}{2} , \frac{\pi}{2} \right) \right)$ |
| 6 | $\displaystyle\int\sqrt{a^2-x^2}\mathrm{d}x = \frac{a^2}{2}\arcsin\frac xa + \frac12x\sqrt{a^2-x^2} + C(a>0)$ |
| 7 | $\displaystyle\int\sqrt{x^2+a^2}\mathrm{d}x = \frac x2\sqrt{x^2+a^2} + \frac{a^2}2\ln \left\| x+\sqrt{x^2+a^2} \right\|+C(a>0)$ |
| 8 | $\displaystyle\int\frac{1}{\sqrt{x^2+a^2}}\mathrm{d}x = \ln\left\| x+ \sqrt{x^2+a^2} \right\| +C$, $\displaystyle\int\frac{1}{\sqrt{x^2-a^2}}\mathrm{d}x = \ln\left\| x + \sqrt{x^2+a^2}\right\|(a>0)$,特别地,$\displaystyle\int\frac{1}{\sqrt{x^2+1}}\mathrm{d}x=\left(x+\sqrt{x^2+1}\right) = \mathrm{arsinh}\, x$, $\displaystyle\int\frac{1}{\sqrt{x^2-1}}\mathrm{d}x = \ln\left( x+\sqrt{x^2-1}\right) = \mathrm{arcosh}\, x$ |
| 9 | $\displaystyle\int\sec x\mathrm{d}x = \int\frac{1}{\cos x}\mathrm{d}x = \int\frac{\sec^2x+\sec x \tan x}{\sec x + \tan x}\mathrm{d}x = \int\frac{1}{\sec x + \tan x}\mathrm{d}(\sec x + \tan x) = \ln \left\| \sec x + \tan x \right\| + C$ |
| 10 | $\displaystyle\int\csc x\mathrm{d}x = \int\frac{1}{\sin x}\mathrm{d}x = \ln\left\| \tan\frac x2 \right\| + C = \frac 12 \ln \left\| \frac{1-\cos x}{1 + \cos x}\right\| + C$ |
| 11 | $\displaystyle\int\tan x\mathrm{d}x = \int\frac{\sin x}{\cos x}\mathrm{d}x = -\int\frac{1}{\cos x}\mathrm{d}(\cos x) = -\ln \left\| \cos x\right\| +C$ |
| 12 | $\displaystyle\int\frac{1}{\tan x}\mathrm{d}x = \int\frac{\cos x}{\sin x}\mathrm{d}x = \int\frac{1}{\sin x}\mathrm{d}(\sin x) = \ln\left\| \sin x \right\| + C$ |
| 13 | $\displaystyle\int\arctan x\mathrm{d}x = x\arctan x - \ln \left\| 1+x^2 \right\| +C$ |
| 14<br>Wallis 公式 | $\displaystyle\int^{\frac{\pi}{2}}_{0}\sin^nx\mathrm{d}x = \int^{\frac{\pi}{2}}_{0}\cos^nx\mathrm{d}x = \begin{cases} \displaystyle\frac{n-1}{n}\cdot\frac{n-3}{n-2}\cdot\cdots\cdot\frac12\cdot\frac\pi2,&n为偶数 \\ \displaystyle\frac{n-1}{n}\cdot\frac{n-3}{n-2}\cdot\cdots\cdot\frac23\cdot1,&n为奇数 \end{cases} \\ = \begin{cases} \displaystyle\frac{(n-1)!!}{n!!}\cdot\frac\pi2,&n为偶数 \\ \displaystyle\frac{(n-1)!!}{n!!},&n为奇数 \end{cases}$ |
| 15 | $\displaystyle\int_0^\pi\sin^nx\mathrm{d}x = 2\int^\frac\pi2_0\sin^nx\mathrm{d}x,\int_0^\pi\cos^nx\mathrm{d}x = \begin{cases} 2\displaystyle\int^\frac\pi2_0\cos^nx\mathrm{d}x,&n为偶数 \\ 0,&n为奇数 \end{cases}$ <br> $\displaystyle\int_0^{2\pi}\sin^nx = \int_0^{2\pi}\cos^nx\mathrm{d}x = \begin{cases} 4\displaystyle\int^\frac\pi2_0\sin^nx\mathrm{d}x,&n为偶数 \\ 0,&n为奇数 \end{cases}$ <br> $\displaystyle\int_0^\frac\pi2f(\sin x)\mathrm{d}x = \int_0^\frac\pi2f(\cos x)\mathrm{d}x$, $\displaystyle\int_0^\pi f(\sin x)\mathrm{d}x \ne \int_0^\pi f(\cos x)\mathrm{d}x$ <br> $\displaystyle\int_0^\pi\pi f(\sin x)\mathrm{d}x = \frac\pi2\int_0^\pi f(\sin x)\mathrm{d}x = \pi\int_0^\frac\pi2 f(\sin x)\mathrm{d}x$ |
| 16<br>万能公式 | 令 $u=\displaystyle\tan\frac x2,x=2\arctan u$,则 $\displaystyle\sin x = \frac{2u}{1+u^2},\cos x=\frac{1-u^2}{1+u^2}, \mathrm{d}x = \frac{2}{1+u^2}\mathrm{d}u$ |
| 17 | $\displaystyle\int \frac{a\cos x+ b\sin x}{c\cos x + d \sin x} = A\int\mathrm{d}x+B\int\frac{\mathrm{d}(c\cos x+d \sin x)}{c \cos x + d \sin x}$ <br> (设 $a\cos x + b\sin x = A(c \cos x + d \sin x) + B(c \cos x + d \sin x)'$,由待定系数法求出A、B)$ |
@@ -0,0 +1,285 @@
---
title: Josh's Summary — 工科数学分析<br>Part 1.1 基本微分与积分
mathjax: true
comments: true
copyright: true
toc:
enable: true
number: false
wrap: true
expand_all: true
max_depth: 4
abbrlink: 1823c9d1
date: 2023-04-14 16:25:59
tags:
- 等价无穷小
- 导数公式
- Maclaurin 公式
- 曲率
- 积分公式
- 三角函数
categories:
- - Josh 的学习笔记
- 微积分
- - 数学
- 微积分
---
$\newcommand\diff{\mathop{}\!\mathrm{d}}$
# 1. 常见等价无穷小
||||
| :--: | :--: | :--: |
| $\sin x \sim x$ | $\tan x \sim x$ | $\arcsin x \sim x$ |
| $\arctan x \sim x$ | $\displaystyle\left( 1 - \cos x \right) \sim \dfrac{x^2}{2}$ | $\ln (1+x) \sim x$ |
| $\left( e^x -1 \right) \sim x$ | $\left( a^x - 1 \right) \sim x \ln a$ | $\left( \left( 1+x \right) ^\alpha -1 \right) \sim \alpha x$ |
<!-- more -->
# 2. 导数基本公式
| 一般函数 | 三角函数 | 反三角函数 | 双曲函数<br>(圆函数) |
| :--: | :--: | :--: | :----: |
| $\left( C \right)' = 0$ | $\left( \sin x \right)' = \cos x$ | $\displaystyle\left( \arcsin x \right)' = \dfrac{1}{\sqrt{1-x^2}}$ | $\displaystyle\left( \sinh x \right)' = \left(\dfrac{e^x-e^{-x}}{2}\right)' = \cosh x$ |
| $\left( x^\alpha \right)'=\alpha x^{\alpha-1} \left( \alpha \in \mathbb{Z} \right)$ | $\left( \cos x \right)' = -\sin x$ | $\displaystyle\left( \arccos x \right)' = -\dfrac{1}{\sqrt{1-x^2}}$ | $\displaystyle\left( \cosh x \right)' = \left( \dfrac{e^x+e^{-x}}{2} \right)'=\sinh x$ |
| $\displaystyle\left( \log_ax\right)'=\dfrac{1}{x\ln a}$ | $\displaystyle\left( \tan x \right)' = \dfrac{1}{\cos^2 x}=\sec^2 x$ | $\displaystyle\left( \arctan x \right)' = \dfrac{1}{1+x^2}$ | $\displaystyle\left( \mathrm{arsinh} \, x \right)' = \left(\ln \left( x+\sqrt{x^2 + 1} \right) \right)' = \dfrac{1}{x^2+1}$ |
| $( \ln$\| $x$ \|$)'=\displaystyle\dfrac{1}{x}$ | $\displaystyle\left( \cot x \right)' = -\dfrac{1}{\sin^2 x} = -\csc^2 x$ | $\displaystyle\left( \mathrm{arccot} \, x \right)' = -\dfrac{1}{1+x^2}$ | $\displaystyle\left( \mathrm{arcosh} \, x \right)' = \left( \ln \left( x + \sqrt{x^2 - 1} \right) \right)' = \dfrac{1}{\sqrt{x^2-1}}$
| | $\left( \sec x \right)' = \sec x \cdot \tan x$ |
| | $\left( \csc x \right)' = \csc x \cdot \cot x$ |
- Newton-Leibniz 公式:
$$
\begin{aligned}
\left( u \cdot v \right)^{\left( n \right)} &= u^{\left( n \right)}v + nu^{\left( n-1 \right)}v' + \dfrac{n \left( n-1 \right)}{2!}u^{\left( n-2 \right)}v'' + \cdots + \dfrac{n\left( n-1 \right)\cdots\left(n-k+1\right)}{k!}u^{\left( n-k \right)}v^{(k)} + \cdots + uv^{\left( n \right)} \\
&= \sum_{k=0}^{n}C_n^k u^{\left( u-k \right)}v^k
\end{aligned}
$$
可以注意到 Newton-Leibniz 公式具有类似二项式定理展开的形式。
# 3. 几个初等函数的 Maclaurin 公式
## 3.1 Taylor 公式的一般形式
$$\begin{aligned}
f(x)&=f(x_0) + f'(x_0)(x-x_0) + \dfrac{f''(x_0)}{2!}(x-x_0)^2 + \cdots + \dfrac{f^{(n)}(x_0)}{n!}(x-x_0)^n + R_n
\\
&= \sum_{k=0}^n \dfrac{f^{(n)}(x_0)}{n!}(x - x_0)^n + R_n
\end{aligned}$$
其中
$$
R_n = \dfrac{f^{(n+1)}(\xi)}{(n+1)!}(x-x_0)^{n+1} \xlongequal{x\to x_0} o\left( \left( x - x_0 \right)^n \right), \quad \xi\,在\,x\,和\,x_0\,之间
$$
## 3.2 Maclaurin 公式的一般形式
$$\begin{aligned}
f(x) &= f(0)+f'(0)\,x + \dfrac{f''(0)}{2!}x^2 + \cdots + \dfrac{f^{(n)}(0)}{n!}x^n + R_n
\\
&= \sum_{k=0}^n \dfrac{f^{(n)}(0)}{n!}x^n + R_n
\end{aligned}$$
其中
$$
R_n = \dfrac{f^{(n+1)}(\xi)}{(n+1)!}x^{n+1} = \dfrac{f^{(n+1)}(\theta x)}{(n+1)!} x^{n+1} \xlongequal{x\to x_0} o\left( \left( x - x_0 \right)^n \right), \quad \xi\,在\,0\,和\,x\,之间, 0<\theta<1
$$
## 3.3 指数函数的 Maclaurin 展开式
$$
e^x=1+x+\dfrac{x^2}{2} + \dfrac{x^3}{3} + \cdots +\dfrac{x^n}{n!} + \dfrac{e^{\theta x}}{(n+1)!}, \quad 0<\theta<1
$$
## 3.4 正弦函数的 Maclaurin 展开式
$$
\sin x = x - \dfrac{x^3}{3!} + \dfrac{x^5}{5!} + \cdots + (-1)^{m-1}\dfrac{x^{2m-1}}{(2m-1)!} + R_{2m}
$$
其中
$$
R_{2m}=\dfrac{\sin\left( \theta x + \dfrac{(2m-1)\pi}{2}\right)}{(2m+1)!}x^{2m+1} = o(x^{2m}), \quad 0<\theta<1
$$
## 3.5 余弦函数的 Maclaurin 展开式
$$
\cos x = 1 - \dfrac{x^2}{2!} + \dfrac{x^4}{4!} + \cdots + (-1)^m\dfrac{x^{2m}}{2m!} + R_{2m+1}
$$
其中
$$
R_{2m+1}=\dfrac{\cos(\theta x + (m+1)\pi)}{(2m+2)!} x^{2m+2}=o(x^{2m+2}), \quad 0<\theta<1
$$
## 3.6 $\ln (1+x)$ 的 Maclaurin 展开式
$$
\ln(1+x) = x - \dfrac{x^2}{2} + \dfrac{x^3}{3} -\dfrac{x^4}{4} + \cdots + \dfrac{(-1)^{n-1}x^n}{n} + R_n(x)
$$
其中
$$
R_n(x) = \dfrac{(-1)^n}{(n+1)(1+\theta x)^{n+1}}x^{n+1} = o(x^n), \quad 0<\theta<1
$$
## 3.7 $(1+x)^\alpha$ 的 Maclaurin 展开式
$$
(1+x)^\alpha = 1 + \alpha x + \dfrac{\alpha(\alpha-1)}{2!}x^2 + \cdots + \dfrac{\alpha(\alpha - 1)\cdots (\alpha-n+1)}{n!}x^n + R_n(x)
$$
其中
$$
R_n(x) = \dfrac{\alpha(\alpha -1)\cdots(\alpha-n)}{(n+1)!}(1+\theta x)^{\alpha-n-1}x^{n+1} = o(x), \quad 0<\theta<1
$$
## 3.8 $\dfrac{1}{1-x}$ 的 Maclaurin 展开式
$$
\dfrac{1}{1-x} = 1+x+x^2+\cdots+x^n +o(x^n)
$$
# 4. 曲率及曲率半径
| 曲率 | 曲率半径 |
| :--: | :--: |
| $K=\left\| \dfrac{\diff \alpha}{\diff s}\right\| \xlongequal{令\ \tan \alpha = y', 则\ \alpha = \arctan y'} \dfrac{\left\| \dfrac{y''}{1+y'^2}\diff x \right\|}{\sqrt{1+y'^2}}\diff x = \dfrac{\left\| y'' \right\|}{\left( 1 + y' \right)^{3/2}}$ | $R = \dfrac{1}{K}$ |
# 5. 积分常用公式
| 序 | 描述 | 公式 |
| :--: | :----: | :----------------------------------------------:|
| 1 | 定积分的定义 | $\displaystyle\int^1_0f(x)\diff x=I=\lim_{\lambda \to 0}\sum_{i=1}^{n}f(\xi_i)\Delta x_i$,其中 $\lambda = \max \left\{ \Delta x_1,\Delta x_2, \cdots, \Delta x_n \right\}$ |
| 2 | 变上限积分 | $考察定积分\displaystyle\int^x_af(x)\diff x=\int^x_af(t)\diff t$,对 $\displaystyle\Phi(x)=\int_a^xf(t)\diff t$,有 $\displaystyle\Phi'(x)=\dfrac{\diff }{\diff x}\int_a^xf(t)\diff t = f(x)$ |
| 3 | 变上限积分的扩展 | $\displaystyle\dfrac{\diff }{\diff x}\int^{\beta(x)}_{\alpha(x)}f'(t)\diff t = f\left[ \beta\left(x\right)\right]\beta'(x)-f[\alpha(x)]\alpha'(x)$ |
| 4 | 上下限对称的积分 | 若 $f(x)$ 为偶函数,则 $\displaystyle\int_{-a}^af(x)\diff x=2\int_0^af(x)\diff x$;若 $f(x)$ 为奇函数,则 $\displaystyle\int_{-a}^af(x)\diff x=0$ |
| 5 | 周期函数的积分 | $\displaystyle f(x+T)=f(x)\Rightarrow\int_0^{nT}f(x)\diff x=n\int^T_0f(x)\diff x$ |
| 6 | 分部积分法 | $\displaystyle\int uv'\diff x=uv - \int u'v\diff x \Leftrightarrow \int u\diff v = uv - \int v\diff u$ |
# 6. 基本积分表
| 序 | 积分式 |
| :--: | :-------------------------: |
| 1 | $\displaystyle\int k\diff x=kx+C$,特别地 $\displaystyle\int\diff x=x+C$ |
| 2 | $\displaystyle\int x^\mu\diff x=\dfrac{x^{\mu+1}}{\mu+1}+C(\mu\ne-1)$,特别地 $\displaystyle\int \dfrac{1}{x^2}\diff x=-\dfrac{1}{x}+C,\int\dfrac{1}{\sqrt{x}}\diff x=2\sqrt{x}+C$ |
| 3 | $\displaystyle\int\dfrac{1}{x}\diff x=\ln \|x\|+C$ |
| 4 | $\displaystyle\int\dfrac{1}{1+x^2}\diff x = \arctan x +C$ |
| 5 | $\displaystyle\int\dfrac{1}{\sqrt{1-x^2}}\diff x=\arcsin x+C$ |
| 6 | $\displaystyle\int\sin x\diff x = -\cos x+C, \int\cos x\diff x = \sin x +C$ |
| 7 | $\displaystyle\int\dfrac{\diff x}{\cos^2x} = \int\sec^2x\diff x = \tan x +C, \int\dfrac{\diff x}{\sin^2x}=\int\csc^2x\diff x = -\cot x +C$ |
| 8 | $\displaystyle\int a^x\diff x = \dfrac{a^x}{\ln a} + C$,特别地 $\displaystyle\int e^x\diff x = e^x +C$
| 9 | $\displaystyle\int \sinh x\diff x = \cosh x + C,\int \cosh x \diff x=\sinh x +C$ |
# 7. 三角函数相关公式
| 序 | 公式 |
| :--: | :-------------------------: |
| 1 | $\sin^2x+\cos^2x=1, \tan^2x+1=\sec^2x,\cot^2x+1=\csc^2x$ |
| 2 | $\begin{aligned}&\cosh^2x-\sinh^2x=1,\\ &\sinh(x\pm y)=\sinh x\cdot\cosh y \pm \sinh y\cdot\cosh x, \cosh(x\pm y) = \cosh x\cdot\cosh y,\\ &\sinh2x = 2\sinh x\cdot \cosh x, \cosh 2x = \cosh^2x+\sinh^2x = 2\cosh^2x - 1\end{aligned}$ |
| 3<br>积化和差公式 | $\sin\alpha\cos\beta=\dfrac12[\sin(\alpha+\beta)+\sin(\alpha-\beta)],\cos\alpha\sin\beta = \dfrac12[\sin(\alpha+\beta) - \sin(\alpha-\beta)]$ <br> $\cos\alpha\cos\beta = \dfrac12[cos(\alpha+\beta) + cos(\alpha - \beta)], \sin\alpha\sin\beta=-\dfrac12[\cos(\alpha+\beta) - \cos(\alpha-\beta)]$ |
| 4<br>和差化积公式 | $\displaystyle\sin\alpha + \sin\beta = 2\sin\left(\dfrac{\alpha+\beta}{2}\right) \cos\left(\dfrac{\alpha-\beta}{2}\right), \sin\alpha - \sin\beta = 2\sin\left(\dfrac{\alpha-\beta}{2}\right) \cos\left(\dfrac{\alpha+\beta}{2}\right)$ <br> $\displaystyle\cos\alpha + \cos\beta = 2\cos\left(\dfrac{\alpha+\beta}{2}\right) \cos\left(\dfrac{\alpha-\beta}{2}\right), \cos\alpha - \cos\beta = -2\sin\left(\dfrac{\alpha+\beta}{2}\right) \sin\left(\dfrac{\alpha-\beta}{2}\right)$ |
| 5<br>三角代换 | $\displaystyle\sqrt{a^2-x^2}\xrightarrow{x=a\sin t}a\cos t, \sqrt{a^2+x^2} \xrightarrow{x=a\tan t}a\sec t, \sqrt{x^2-a^2}\xrightarrow{x=a\sec t}a\tan t \left( a>0,t\in\left( -\dfrac{\pi}{2} , \dfrac{\pi}{2} \right) \right)$ |
| 6 | $\displaystyle\int\sqrt{a^2-x^2}\diff x = \dfrac{a^2}{2}\arcsin\dfrac xa + \dfrac12x\sqrt{a^2-x^2} + C(a>0)$ |
| 7 | $\displaystyle\int\sqrt{x^2+a^2}\diff x = \dfrac x2\sqrt{x^2+a^2} + \dfrac{a^2}2\ln \left\| x+\sqrt{x^2+a^2} \right\|+C(a>0)$ |
| 8 | $\displaystyle\int\dfrac{1}{\sqrt{x^2+a^2}}\diff x = \ln\left\| x+ \sqrt{x^2+a^2} \right\| +C$, $\displaystyle\int\dfrac{1}{\sqrt{x^2-a^2}}\diff x = \ln\left\| x + \sqrt{x^2-a^2}\right\|(a>0)$<br>特别地,$\displaystyle\int\dfrac{1}{\sqrt{x^2+1}}\diff x=\ln\left(x+\sqrt{x^2+1}\right) = \mathrm{arsinh}\, x$, $\displaystyle\int\dfrac{1}{\sqrt{x^2-1}}\diff x = \ln\left( x+\sqrt{x^2-1}\right) = \mathrm{arcosh}\, x$ |
| 9 | $\displaystyle\int\sec x\diff x = \int\dfrac{1}{\cos x}\diff x = \int\dfrac{\sec^2x+\sec x \tan x}{\sec x + \tan x}\diff x = \int\dfrac{1}{\sec x + \tan x}\diff (\sec x + \tan x) = \ln \left\| \sec x + \tan x \right\| + C$ |
| 10 | $\displaystyle\int\csc x\diff x = \int\dfrac{1}{\sin x}\diff x = \ln\left\| \tan\dfrac x2 \right\| + C = \dfrac 12 \ln \left\| \dfrac{1-\cos x}{1 + \cos x}\right\| + C$ |
| 11 | $\displaystyle\int\tan x\diff x = \int\dfrac{\sin x}{\cos x}\diff x = -\int\dfrac{1}{\cos x}\diff (\cos x) = -\ln \left\| \cos x\right\| +C$ |
| 12 | $\displaystyle\int\dfrac{1}{\tan x}\diff x = \int\dfrac{\cos x}{\sin x}\diff x = \int\dfrac{1}{\sin x}\diff (\sin x) = \ln\left\| \sin x \right\| + C$ |
| 13 | $\displaystyle\int\arctan x\diff x = x\arctan x - \ln \left\| 1+x^2 \right\| +C$ |
| 14<br>Wallis 公式 | $\displaystyle\int^{\pi/2}_{0}\sin^nx\diff x = \int^{\pi/2}_{0}\cos^nx\diff x = \begin{cases} \displaystyle\dfrac{n-1}{n}\cdot\dfrac{n-3}{n-2}\cdot\cdots\cdot\dfrac12\cdot\dfrac\pi2,&n为偶数 \\ \displaystyle\dfrac{n-1}{n}\cdot\dfrac{n-3}{n-2}\cdot\cdots\cdot\dfrac23\cdot1,&n为奇数 \end{cases} \\ = \begin{cases} \displaystyle\dfrac{(n-1)!!}{n!!}\cdot\dfrac\pi2,&n为偶数 \\ \displaystyle\dfrac{(n-1)!!}{n!!},&n为奇数 \end{cases}$ |
| 15 | $\displaystyle\int_0^\pi\sin^nx\diff x = 2\int^{\pi/2}_0\sin^nx\diff x,\int_0^\pi\cos^nx\diff x = \begin{cases} 2\displaystyle\int^{\pi/2}_0\cos^nx\diff x,&n为偶数 \\ 0,&n为奇数 \end{cases}$ <br> $\displaystyle\int_0^{2\pi}\sin^nx = \int_0^{2\pi}\cos^nx\diff x = \begin{cases} 4\displaystyle\int^{\pi/2}_0\sin^nx\diff x,&n为偶数 \\ 0,&n为奇数 \end{cases}$ <br> $\displaystyle\int_0^{\pi/2}f(\sin x)\diff x = \int_0^{\pi/2}f(\cos x)\diff x$, $\displaystyle\int_0^\pi f(\sin x)\diff x \ne \int_0^\pi f(\cos x)\diff x$ <br> $\displaystyle\int_0^\pi\pi f(\sin x)\diff x = \dfrac\pi2\int_0^\pi f(\sin x)\diff x = \pi\int_0^{\pi/2} f(\sin x)\diff x$ |
| 16<br>万能公式 | 令\ $u=\displaystyle\tan\dfrac x2,x=2\arctan u$,则\ $\displaystyle\sin x = \dfrac{2u}{1+u^2},\cos x=\dfrac{1-u^2}{1+u^2}, \diff x = \dfrac{2}{1+u^2}\diff u$ |
| 17 | $\displaystyle\int \dfrac{a\cos x+ b\sin x}{c\cos x + d \sin x} = A\int\diff x+B\int\dfrac{\diff (c\cos x+d \sin x)}{c \cos x + d \sin x}$ <br> (设 $a\cos x + b\sin x = A(c \cos x + d \sin x) + B(c \cos x + d \sin x)'$,由待定系数法求出 $A, B$) |
# 8. 定积分的几何应用
## 8.1 平面
### 8.1.1 直角坐标
1. 直角梯形的面积
$$\begin{equation*}
A = \int_a^b [f(x_1) - f(x_2)] \diff x
\end{equation*}$$
2. 曲边梯形的面积:对于参数方程 $\begin{cases}
x = \varphi(x) \\ y = {\psi(x)}
\end{cases}$,曲边梯形的面积(变换上下限)
$$\begin{equation*}
A = \int_a^b y\diff x = \int_{t_1}^{t_2} \psi(t) \diff \varphi(t) = \int_{t_1}^{t_2} \psi(t)\varphi'(t) \diff t
\end{equation*}$$
3. 椭圆的面积:椭圆 $\begin{cases}
x = a \cos t \\ y = b \sin t
\end{cases}$,即 $\dfrac{x^2}{a^2} + \dfrac{y^2}{b^2} = 1$ 的面积
$$\begin{equation*}
A = 4 \int_0^a y \diff x = 4ab \int_0^{\pi/2} (1-\cos t)^2 \diff t = 3\pi a^2
\end{equation*}$$
4. 摆线的面积:摆线 $\begin{cases}
x = a (t - \sin t) \\ y = a (1 - \cos t)
\end{cases}$ 的一拱与 $x$ 轴所围图形的面积
$$\begin{equation*}
A = \int_0^2\pi a y \diff x = a^2 \int_0^{2\pi} (1 - \cos t)^2 \diff t = 3\pi a^2
\end{equation*}$$
### 8.1.2 极坐标
1. 扇形的面积:由 $\rho = \rho(\theta)$ 及射线 $\theta = \alpha$ 和 $\theta = \beta$ 所围曲边扇形的面积
$$\begin{equation*}
A = \int_\alpha^\beta \frac{1}{2} \rho^2(\theta) \diff \theta = \frac{1}{2} \int_\alpha^\beta \rho^2 \diff \theta
\end{equation*}$$
2. 阿基米德螺线:阿基米德螺线 $\rho = a \theta (a > 0)$ 对应 $\theta$ 从 $0$ 变换到 $2\pi$ 所围图形的面积
$$\begin{equation*}
A = \int_0^{2\pi} \frac{1}{2} (a\theta)^2\diff \theta = \frac{4}{3} \pi^3 a^2
\end{equation*}$$
3. 双纽线:双纽线 $\rho^2 = a^2 \cos 2\theta$ 所围平面图形的面积
$$\begin{equation*}
A = 4 \int_0^{\pi/4} a^2 \cos 2\theta \diff \theta = a^2
\end{equation*}$$
4. 心形线:心形线 $\rho = a(a+\cos\theta), a>0$ 所围平面图形的面积
$$\begin{equation*}
A = 2 \cdot \frac{1}{2} \int_0^\pi a^2 (1+ \cos \theta)^2 \diff \theta = \frac{3}{2}\pi a^2
\end{equation*}$$
5. 曲线的弧长
| 弧微分 | 直角坐标 | 参数方程 | 极坐标 |
| :--: | :--: | :--: | :--: |
| $\diff s = \sqrt{(\diff x)^2 + (\diff y)^2}$ | $s = \displaystyle\int_a^b \sqrt{1 + y'^2}\diff x$ | $s = \displaystyle\int_a^b \sqrt{\varphi'^2(t) + \psi'^2(t)}\diff t$ | $s = \displaystyle\int_\alpha^\beta \sqrt{\rho^2{\theta} + \rho'^2(\theta)} \diff\theta$
## 8.2 空间
1. 已知平行截面面积求立体体积:令 $A(x)$ 为截面面积,则立体体积
$$\begin{equation*}
V = \int_a^b A(x) \diff x
\end{equation*}$$
2. 旋转体体积
| 薄片法 | 柱壳法 |
| :--: | :--: |
| $V = \displaystyle\int_a^b \pi f^2(x) \diff x$ | $V = \displaystyle\int_a^b 2\pi x \left| f(x) \right|\diff x$ |
+1 -1
View File
@@ -1,5 +1,5 @@
---
title: "Josh's Review: 数字信号处理(Part 1 — 离散时间信号和系统分析基础)"
title: "Josh's Review — 数字信号处理<br>Part 1 离散时间信号和系统分析基础"
mathjax: true
comments: true
copyright: true
+1 -1
View File
@@ -1,5 +1,5 @@
---
title: "Josh's Review: 数字信号处理(Part 2 — 离散傅里叶级数 DFS)"
title: "Josh's Review — 数字信号处理<br>Part 2 离散傅里叶级数 DFS"
mathjax: true
comments: true
copyright: true
+1 -1
View File
@@ -1,5 +1,5 @@
---
title: "Josh's Review: 数字信号处理(Part 3 — 离散傅里叶变换 DFT)"
title: "Josh's Review — 数字信号处理<br>Part 3 离散傅里叶变换 DFT"
mathjax: true
comments: true
copyright: true
+1 -1
View File
@@ -1,5 +1,5 @@
---
title: "Josh's Review: 数字信号处理(Part 4 — 快速傅里叶变换 FFT)"
title: "Josh's Review — 数字信号处理<br>Part 4 快速傅里叶变换 FFT"
mathjax: true
comments: true
copyright: true
+1 -1
View File
@@ -1,5 +1,5 @@
---
title: "Josh's Review: 数字信号处理(Part 5 — 部分 FFT 蝶形图)"
title: "Josh's Review — 数字信号处理<br>Part 5 部分 FFT 蝶形图"
mathjax: true
comments: true
copyright: true
+1 -1
View File
@@ -1,5 +1,5 @@
---
title: "Josh's Review: 数字信号处理(Part 6 — 数字滤波器的基本结构)"
title: "Josh's Review — 数字信号处理<br>Part 6 数字滤波器的基本结构"
mathjax: true
comments: true
copyright: true
+1 -1
View File
@@ -1,5 +1,5 @@
---
title: "Josh's Review: 数字信号处理(Part 7 — 数字滤波器设计)"
title: "Josh's Review — 数字信号处理<br>Part 7 数字滤波器设计"
mathjax: true
comments: true
copyright: true
@@ -1,5 +1,5 @@
---
title: "Josh's Notes: Verilog(Part 6 —— 如何写好状态机)"
title: "Josh's Note — Verilog<br>Part 6 如何写好状态机"
mathjax: false
comments: true
copyright: true
@@ -1,5 +1,5 @@
---
title: "Josh's Notes: Verilog(Part 7 —— 逻辑验证与 testbench 编写)"
title: "Josh's Note — Verilog<br>Part 7 逻辑验证与 testbench 编写"
mathjax: false
comments: true
copyright: true
@@ -1,5 +1,5 @@
---
title: 'Josh''s Notes: 最优阵列处理(Part 1.1 —— 频率-波数响应和波束方向图)'
title: "Josh's Note — 最优阵列处理<br>Part 1.1 频率-波数响应和波束方向图"
mathjax: true
comments: true
copyright: true
@@ -423,5 +423,5 @@ $$\begin{equation}
# 参考文献
1. Van Trees, Harry L. *Optimum array processing: Part IV of detection, estimation, and modulation theory.* John Wiley & Sons, 2002.
2. Van Trees, Harry L, 汤俊. *最优阵列处理技术.* 清华大学出版社. 2008.
1. Harry L. Van Trees. *Optimum array processing: Part IV of detection, estimation, and modulation theory.* New York, NY, USA: John Wiley & Sons, 2002.
2. Harry L. Van Trees, 汤俊. *最优阵列处理技术.* 北京:清华大学出版社. 2008.
@@ -1,5 +1,5 @@
---
title: 'Josh''s Notes: 最优阵列处理(Part 1.2 —— 均匀线阵模型)'
title: "Josh's Note — 最优阵列处理<br>Part 1.2 均匀线阵模型"
mathjax: true
comments: true
copyright: true
@@ -329,8 +329,8 @@ $$\begin{equation} \label{WeightVecCalculationWithAllZeroExceptMainAxis}
# 参考文献
1. Van Trees, Harry L. *Optimum array processing: Part IV of detection, estimation, and modulation theory.* John Wiley & Sons, 2002.
2. Van Trees, Harry L, 汤俊. *最优阵列处理技术.* 清华大学出版社. 2008.
1. Harry L. Van Trees. *Optimum array processing: Part IV of detection, estimation, and modulation theory.* New York, NY, USA: John Wiley & Sons, 2002.
2. Harry L. Van Trees, 汤俊. *最优阵列处理技术.* 北京:清华大学出版社. 2008.
[阵列流形矢量的定义]: https://josh-gao.top/posts/8b61f5a7.html#DefinitionOfArrayManifoldVector
[复权矢量]: https://josh-gao.top/posts/8b61f5a7.html#ComplexWeightVector
@@ -1,5 +1,5 @@
---
title: 'Josh''s Notes: 最优阵列处理(Part 1.3 —— 均匀加权线阵)'
title: "Josh's Note — 最优阵列处理<br>Part 1.3 均匀加权线阵"
mathjax: true
comments: true
copyright: true
@@ -629,5 +629,5 @@ $$\begin{equation}
# 参考文献
1. Van Trees, Harry L. *Optimum array processing: Part IV of detection, estimation, and modulation theory.* John Wiley & Sons, 2002.
2. Van Trees, Harry L, 汤俊. *最优阵列处理技术.* 清华大学出版社. 2008.
1. Harry L. Van Trees. *Optimum array processing: Part IV of detection, estimation, and modulation theory.* New York, NY, USA: John Wiley & Sons, 2002.
2. Harry L. Van Trees, 汤俊. *最优阵列处理技术.* 北京:清华大学出版社. 2008.
@@ -1,5 +1,5 @@
---
title: 'Josh''s Notes: 最优阵列处理(Part 1.4 —— 阵列调向)'
title: "Josh's Note — 最优阵列处理<br>Part 1.4 阵列调向"
mathjax: true
comments: true
copyright: true
@@ -411,8 +411,8 @@ $$\begin{equation}
# 参考文献
1. Van Trees, Harry L. *Optimum array processing: Part IV of detection, estimation, and modulation theory.* John Wiley & Sons, 2002.
2. Van Trees, Harry L, 汤俊. *最优阵列处理技术.* 清华大学出版社. 2008.
1. Harry L. Van Trees. *Optimum array processing: Part IV of detection, estimation, and modulation theory.* New York, NY, USA: John Wiley & Sons, 2002.
2. Harry L. Van Trees, 汤俊. *最优阵列处理技术.* 北京:清华大学出版社. 2008.
[1.1 节]: https://josh-gao.top/posts/8b61f5a7.html
[1.2 节]: https://josh-gao.top/posts/de20fd09.html
@@ -1,5 +1,5 @@
---
title: 'Josh''s Notes: 最优阵列处理(Part 1.5 —— 阵列性能度量指标)'
title: "Josh's Note — 最优阵列处理<br>Part 1.5 阵列性能度量指标"
mathjax: true
comments: true
copyright: true
@@ -1,5 +1,5 @@
---
title: 'Josh''s Notes: 最优阵列处理(Part 2.1 —— 谱加权)'
title: "Josh's Note — 最优阵列处理<br>Part 2.1 谱加权"
mathjax: true
comments: true
copyright: true
@@ -792,8 +792,8 @@ ylabel('Beam pattern (dB)')
# 参考文献
1. Van Trees, Harry L. _Optimum array processing: Part IV of detection, estimation, and modulation theory._ John Wiley & Sons, 2002.
2. Van Trees, Harry L, 汤俊. _最优阵列处理技术._ 清华大学出版社. 2008.
1. Harry L. Van Trees. *Optimum array processing: Part IV of detection, estimation, and modulation theory.* New York, NY, USA: John Wiley & Sons, 2002.
2. Harry L. Van Trees, 汤俊. *最优阵列处理技术.* 北京:清华大学出版社. 2008.
[^1]: 参数 $D_N$ 是阵列的归一化方向性。它是相对于一个均匀加权阵列的方向性进行归一化的。对于标准线阵, $D_N$ 也是归一化的白噪声增益。
+371
View File
@@ -0,0 +1,371 @@
---
title: Josh's Note — 凸优化<br>Part 1.2 凸集—一些重要的凸集
mathjax: true
comments: true
copyright: true
toc:
enable: true
number: false
wrap: true
expand_all: true
max_depth: 4
categories:
- - Josh 的学习笔记
- 凸优化
- 凸集
- - 数学
- 凸优化
tags:
- 凸优化
- 凸集
- 射线
- 超平面
- 半空间
- Euclid球
- 椭球
- 范数球
- 范数锥
- 二阶锥
- 多面体
- 单纯形
- 半正定锥
abbrlink: 9293b739
date: 2024-06-08 14:57:52
---
$\newcommand{\bfR}{\mathbf{R}}
\newcommand{\bfS}{\mathbf{S}}
\newcommand{\TT}{\mathrm{T}}
\newcommand{\E}{\mathcal{E}}
\newcommand{\P}{\mathcal{P}}
\def\conv{\mathop{\bf conv}}$&emsp;&emsp;本文将描述一些重要的凸集。首先介绍一些简单的例子。
- 空集 $\emptyset$、任意一个点(即单点集(singleton))$\{x_0\}$ 、全空间 $\bfR^n$ 都是 $\bfR^n$ 的仿射(自然也是凸的)子集。
- 任意直线是仿射的。如果直线通过零点,则是子空间,因此,也是凸锥。
- 一条线段是凸的,但不是仿射的(除非退化为一个点)。
- 一条**射线**(*ray*),即具有形式 $\left\{x_0 + \theta v\mid \theta \geqslant 0 \right\}, v \ne 0$ 的集合,是凸的,但不是仿射的。如果射线的基点 $x_0$ 是 $0$,则它是凸锥。
- 任意子空间是仿射的、凸锥(自然是凸的)。
<!-- more -->
# 1. 超平面与半空间
&emsp;&emsp;**超平面**(*hyperplane*)是具有如下形式的集合
$$
\left\{ x\mid a^\TT x = b \right\}
$$
其中 $a \in \bfR^n, a \ne 0$ 且 $b \in \bfR$。解析地来看,超平面是关于 $x$ 的非平凡线性方程的解空间(因此是一个仿射集合)。几何上,超平面 $\left\{ x\mid a^\TT x = b \right\}$ 可以理解为与给定向量 $a$ 的内积为常数的点的集合;也可以看成法线方向为 $a$ 的超平面,而常数 $b \in \bfR$ 决定了这个平面从原点的偏移。为更好地理解几何含义,可以将超平面表示成
$$
\left\{ x\mid a^\TT (x - x_0) = 0 \right\}
$$
其中 $x_0$ 是超平面上的任意一点(即任意满足 $a^\TT x_0 = b$ 的点)。进一步,可以表示为
$$
\left\{ x\mid a^\TT (x - x_0) = 0 \right\} = x_0 + a^\perp
$$
其中 $a^\perp$ 表示 $a$ 的正交补,即与 $a$ 正交的向量的集合:
$$
a^\perp = \left\{ v\mid a^\TT v = 0 \right\}
$$
从中可以看出,超平面由偏移 $x_0$ 加上所有正交于(法)向量 $a$ 的向量构成,具体可见[图 6](#图6) 。
<a id="图6"></a>
![图 6. $\bfR^2$ 中由法向量 $a$ 和超平面上一点 $x_0$ 确定的超平面。对于超平面上任意一点 $x$,$x - x_0$(如深色箭头所示)都垂直于 $a$。](../images/post/2024-06-08-josh-cvx-1-2/2024-06-08-josh-cvx-1-2-060-HyperplaneInR2.png){width=400px}
&emsp;&emsp;一个超平面将 $\bfR^n$ 划分为两个**半空间**(*halfspaces*)。(闭的)半空间是具有下列形式的集合,
$$\begin{equation}\label{HalfSpace}
\left\{x\mid a^\TT x \leqslant b \right\}
\end{equation}
$$
即(非平凡的)线性不等式的解空间,其中 $a\ne 0$。半空间是凸的,但不是仿射的,如[图 7](#图7) 所示。
<a id="图7"></a>
![图 7. $\bfR^2$ 上由 $a^\TT x = b$ 定义的超平面决定了两个半空间。由 a^\TT x \geqslant b 决定的半空间(无阴影)是向 $a$ 扩展的半空间。由 a^\TT x \leqslant b 确定的半空间(阴影所示)向 $-a$ 方向扩展。向量 $a$ 是这个半空间向外的法向量。](../images/post/2024-06-08-josh-cvx-1-2/2024-06-08-josh-cvx-1-2-070-AHyperplaneAndTwoHalfspaces.png){width=400px}
&emsp;&emsp;半空间 $\eqref{HalfSpace}$ 也可以表示为
$$
\left\{x\mid a^\TT (x - x_0) \leqslant 0 \right\}
$$
其中 $x_0$ 是相应超平面上的任意一点,即 $x_0$ 满足 $a^\TT x_0 = b$。上式有一个简单的几何解释:半空间由 $x_0$ 加上任意与(向外的法)向量 $a$ 呈钝角(或直角)的向量组成,如[图 8](#图8) 所示。
<a id="图8"></a>
![图 8. 阴影所示集合是由 $a^\TT (x - x_0) \leqslant 0$ 决定的半空间。向量 $x_1 - x_0$ 与 $a$ 的夹角为锐角,所以 $x_1$不在这个半空间中。向量 $x_2 - x_1$ 与 $a$ 的夹角为钝角,所以 $x_2$ 在半空间中。](../images/post/2024-06-08-josh-cvx-1-2/2024-06-08-josh-cvx-1-2-080-VectorsAndHalfspaces.png){width=400px}
&emsp;&emsp;半空间 $\eqref{HalfSpace}$ 的边界是超平面 $\left\{x\mid a^\TT x = b \right\}$。集合 $\left\{x\mid a^\TT x < b \right\}$ 是半空间 $\left\{x\mid a^\TT x \leqslant b \right\}$ 的内部,称为**开半空间**(*open halfspace*)。
# 2. Euclid球和椭球
&emsp;&emsp;$\bfR^n$ 中的空间 **Euclid 球**(*Euclidean ball*)(或简称为球)具有下面的形式:
$$
B(x_c,r) = \left\{x\mid \left\| x - x_c \right\|_2 \leqslant r \right\} = \left\{ x\mid (x-x_c)^\TT(x-x_c) \leqslant r^2 \right\}
$$
其中 $r > 0$,$\| \cdot \|_2$ 表示 Euclid 范数,即 $\|u\|_2 = (u^\TT u)^{1/2}$。向量 $x_r$ 是**球心**(*center*),标量 $r$ 为**半径**(*radius*)。$B (x_c, r)$ 由距离球心 $x_r$ 距离不超过 $r$ 的所有点组成。 Euclid 球的另一个常见的表达式为:
$$
B(x_c,r) = \left\{ x_c + ru\mid \|u\|_2 \leqslant 1 \right\}
$$
&emsp;&emsp;Euclid 球是凸集,即如果 $\|x_1-x_2\|\leqslant r$,$\|x_2-x_c\|\leqslant r$,并且 $0 \leqslant \theta \leqslant 1$,那么
$$\begin{aligned}
\left\| \theta x_1 + (1- \theta)x_2 - x_c\right\|_2 &= \left\| \theta(x_1 - x_c) + (1-\theta)(x_2 - x_c)\right\|_2
\\
&\leqslant \theta \left\|x_1 - x_c\right\|_2 + (1-\theta) \left\| x_2 - x_c \right\|_2
\\
& \leqslant r
\end{aligned}$$
(这里利用了 $\| \cdot \|_2$ 的齐次性和三角不等式。)
&emsp;&emsp;一类相关的凸集是**椭球**(*ellipsoid*),它们具有如下的形式:
$$\begin{equation}\label{ellipsoid-1}
\E = \left\{ x\mid (x-x_c)^\TT P^{-1}(x-x_c) \leqslant 1 \right\}
\end{equation}$$
其中 $P = P^\TT \succ 0$,即 $P$ 是对称正定矩阵。向量 $x_c \in \bfR^n$ 为椭球的中心。矩阵 $P$ 决定了椭球从 $x_c$ 向各个方向扩展的幅度。$\E$ 的半轴长度由 $\sqrt{\lambda_i}$ 给出,这里 $\lambda_i$ 为 $P$ 的特征值。球可以看成 $P = r^2I$ 的椭球。[图 9](#图9) 给出了 $\bfR^2$ 上的一个椭球。
<a id="图9"></a>
![图 9. 阴影所示为 $\bfR^2$ 中的一个椭球。中心 $x_c$ 由点显示,两个半轴由线段显示](../images/post/2024-06-08-josh-cvx-1-2/2024-06-08-josh-cvx-1-2-090-EllipsoidInR2.png){width=300px}
&emsp;&emsp;椭球另一个常用的表示形式是
$$\begin{equation}\label{ellipsoid-2}
\E = \left\{ x_c + Au\mid \|u\|_2 \leqslant 1 \right\}
\end{equation}$$
其中 $A$ 是非奇异的方阵。在此类表示形式中,可以不失一般性地假设 $A$ 对称正定。取 $A=P^{1/2}$,这个表达式给出了由式 $\eqref{ellipsoid-1}$ 定义的椭球。当式 $\eqref{ellipsoid-2}$ 中的矩阵 $A$ 为对称半正定矩阵,但奇异时,集合 $\eqref{ellipsoid-2}$ 称为**退化的椭球**(*degenerate ellipsoid*),其仿射维数等于 $A$ 的秩。退化的椭球也是凸的。
# 3. 范数球和范数锥
&emsp;&emsp;设 $\| \cdot \|$ 是 $\bfR^n$ 中的范数。由范数的一般性质可知,以 $r$ 为半径,$x_c$ 为球心的**范数球**(*norm ball*) $\left\{ x\mid \|x-x_c\| \leqslant r \right\}$ 是凸的。关于范数 $\| \cdot \|$ 的**范数锥**(*norm cone*)是集合
$$
C = \left\{ (x,t)\mid \|x\| \leqslant t \right\} \subseteq \bfR^{n+1}
$$
顾名思义,它是一个凸锥。
> **举例**&emsp;**二阶锥**(*second-order cone*)是由 Euclid 范数定义的范数锥,即
>
> $$\begin{aligned}
> C &= \left\{ (x,t) \in \bfR^{n+1}\mid \|x\|_2 \leqslant t\right\}
> \\
> &= \left\{ \left[\begin{array}{c}
> x \\ t
> \end{array} \right]\middle| \left[\begin{array}{c}
> x \\ t
> \end{array} \right]^\TT\left[\begin{array}{c}
> I & 0 \\ 0 & -1
> \end{array} \right] \left[\begin{array}{c}
> x \\ t
> \end{array} \right] \leqslant 0,\ t\geqslant 0 \right\}
> \end{aligned}$$
>
> 二阶锥的其他名字也常常被使用。它由二次不等式定义,因此也被称为**二次锥**(*quadratic cone*)。同时,也称其为 **Lorentz 锥**(*Lorentz cone*)或**冰激凌锥**(*ice-cream cone*)。[图 10](#图10) 显示了 $\bfR^3$ 上一个的二阶锥。
>
> <a id="图10"></a>
>
> ![图 10. $\bfR^3$ 中二阶锥 $\left\{(x_1,x_2,t)\mid (x_1^2 + x_2^2)^{1/2} \leqslant t\right\}$ 的边界](../images/post/2024-06-08-josh-cvx-1-2/2024-06-08-josh-cvx-1-2-100-BoundaryOfSecondOrderCone.png){width=500px}
# 4. 多面体
&emsp;&emsp;**多面体**(*polyhedron*)被定义为有限个线性等式和不等式的解集:
$$\begin{equation}\label{polyhedron-1}
\P = \left\{ x\mid a_j^\TT x \leqslant b_j,\ j = 1,\cdots,m,\ c_j^\TT x = d_j,\ j = 1,\cdots,p\right\}
\end{equation}$$
因此,多面体是有限个半空间和超平面的交集。仿射集合(例如子空间、超平面、直线)、射线、线段和半空间都是多面体。显而易见,多面体是凸集。有界的多面体有时也称为**多胞形**(*polytope*),但也有一些作者反过来使用这两个概念(即用多胞形表示具有 $\eqref{polyhedron-1}$ 形式的集合,而当其有界时称为多面体)。[图 11](#图11) 显示了一个由五个半空间的交集定义的多面体。
<a id="图11"></a>
![图 11. 多面体 $\P$(阴影所示)是外法向量为 $a_1,\cdots,a_5$ 的五个半空间的交集。](../images/post/2024-06-08-josh-cvx-1-2/2024-06-08-josh-cvx-1-2-110-Polyhydron.png){width=400px}
&emsp;&emsp;可以方便地使用紧凑表达式
$$\begin{equation}\label{polyhedron-2}
\P = \left\{ x\mid Ax \preceq b,\ Cx = d \right\}
\end{equation}$$
来表示 $\eqref{polyhedron-1}$,其中
$$
A = \left[\begin{array}{c}
a_1^\TT \\ \vdots \\ a_m^\TT
\end{array}\right],\qquad C = \left[\begin{array}{c}
c_1^\TT \\ \vdots \\ c_p^\TT
\end{array}\right]
$$
此处的 $\preceq$ 代表 $\bfR^m$ 上的**向量不等式**(*vector inequality*)或**分量不等式**(*componentwise inequality*):$u \preceq v$ 表示 $u_i \leqslant v_i, i = 1,\cdots, m$。
> **举例**&emsp;**非负象限**(*nonnegative orthant*)是具有非负分量的点的集合,即
>
> $$
> \bfR_+^n = \left\{ x\in\bfR^n\mid x_i \geqslant 0,\ i = 1,\cdots,n \right\} = \left\{ x\in \bfR^n\mid x \succeq 0 \right\}
> $$
>
> (此处 $\bfR_+$ 表示非负实数的集合,即 $\bfR_+ = \left\{ x\in\bfR\mid x \geqslant 0 \right\}$。)非负象限既是多面体也是锥(因此称为**多面体锥**(*polyhedral cone*))。
## 4.1 单纯形
&emsp;&emsp;**单纯形**(*simplex*)是一类重要的多面体。设 $k+1$ 个点 $v_0,\cdots,v_k \in \bfR^n$ 仿射独立,即 $v_1 - v_0, \cdots, v_k-v_0$ 线性独立,那么,这些点决定了一个单纯形:
$$\begin{equation}\label{simplex}
C = \conv{\{v_0,\cdots,v_k\}} = \left\{ \theta_0v_0 + \cdots + \theta_k v_k\mid \theta \succeq 0,\ \mathbf{1}^\TT\theta = 1 \right\}
\end{equation}$$
其中 $\mathbf{1}$ 表示所有分量均为 $1$ 的向量。这个单纯形的仿射维数为 $k$,因此也称为 $\bfR^n$ 空间的 $k$ 维单纯形。
> **举例**&emsp;**一些常见的单纯形**。1 维单纯形是一条线段;2 维单纯形是一个三角形(包含其内部); 3 维单纯形是一个四面体。
>
> **单位单纯形**(*unit simplex*)是由零向量和单位向量 $\mathbf{0}, e_1,\cdots, e_n \in \bfR^n$ 决定的 $n$ 维单纯形。它可以表示为满足下列条件的向量的集合:
>
> $$
> x \succeq 0,\qquad \mathbf{1}^\TT x\leqslant 1
> $$
>
> **概率单纯形**(*probability simplex*)是由单位向量 $e_1,\cdots, e_n \in \bfR^n$ 决定的 $n - 1$ 维单纯形。它是满足下列条件的向量的集合:
>
> $$
> x \succeq 0,\qquad \mathbf{1}^\TT x= 1
> $$
>
> 概率单纯形中的向量对应于含有 $n$ 个元素的集合的概率分布,$x_i$ 可理解为第 $i$ 个元素的概率。
&emsp;&emsp;为了用多面体来描述单纯形 $\eqref{simplex}$,采用以下步骤将其变换为 $\eqref{polyhedron-2}$ 的形式。由定义可知,$x\in C$ 的充要条件是,对于某些 $\theta\succeq 0, \mathbf{1}^\TT\theta=1$, 有 $x = \theta_0 v_0 + \theta_1 v_1 + \cdots + \theta_k v_k$。等价地,如果定义 $y = (\theta_1,\cdots,\theta_k)$ 和
$$
B = \left[ \begin{array}{c}
v_1-v_0 & \cdots & v_k-v_0
\end{array} \right] \in \bfR ^{n\times k}
$$
则 $x\in C$ 的充要条件是
$$\begin{equation}\label{IFFCondition}
x = v_0 + By
\end{equation}
$$
对于 $y \succeq 0$,$\mathbf{1}^\TT y \leqslant 1$ 成立。注意到 $v_0,\cdots,v_k$ 仿射独立意味着矩阵 $B$ 的秩为 $k$。因此,存在非奇异矩阵 $A=(A_1,A_2)\in\bfR^{n\times n}$ 使得
$$
AB = \left[ \begin{array}{c}
A_1 \\ A_2
\end{array} \right] B = \left[ \begin{array}{c}
I \\ 0
\end{array} \right]
$$
用 $A$ 左乘 $\eqref{IFFCondition}$,得到
$$
A_1 x = A_1 v_0 + y,\qquad A_2 x = A_2 v_0
$$
从中可以看出,$x\in C$ 当且仅当 $A_2 x = A_2 v_0$ 并且向量 $y = A_1 x - A_1 v_0$ 满足 $y\succeq 0$ 和 $\mathbf{1}^\TT y \leqslant 1$。换言之得到了 $x\in C$ 的充要条件,
$$
A_2 x = A_2 v_0, \qquad A_1 x \succeq A_1 v_0, \qquad \mathbf{1}^\TT A_1 x \leqslant 1 + \mathbf{1}^\TT A_1 v_0
$$
这些是 $x$ 的线性等式和不等式,因此,描述了一个多面体。
## 4.2 多面体的凸包描述
&emsp;&emsp;有限集合 $\{v_1,\cdots,v_k\}$ 的凸包是
$$
\conv\{v_1,\cdots,v_k\} = \left\{ \theta_1 v_1 + \cdots + \theta_k v_k\mid \theta \succeq 0, \ \mathbf{1}^\TT \theta = 1 \right\}
$$
它是一个有界的多面体,但是(除非是例如单纯形这样的特殊情况)无法简单地用形如 $\eqref{polyhedron-1}$ 的式子,即用线性等式和不等式的集合将其表示。
&emsp;&emsp;凸包表达式的一个扩展表示是,
$$\begin{equation}\label{ExtendedHull}
\left\{ \theta_1 v_1 + \cdots + \theta_k v_k\mid \theta_1 + \cdots + \theta_m = 1,\ \theta_i\geqslant 0, \ i=1,\cdots,k \right\}
\end{equation}$$
其中 $m\leqslant k$。此处我们考虑 $v_i$ 的非负线性组合,但是仅仅要求前 $m$ 个系数之和为一。此外,我们可以将 $\eqref{ExtendedHull}$ 解释为点 $v_1,\cdots,v_m$ 的凸包加上点 $v_{m+1},\cdots,v_k$ 的锥包。集合 $\eqref{ExtendedHull}$ 定义了一个多面体,反之亦然,每个多面体都可以表示为此类形式(虽然这一点此处并未证明)。
&emsp;&emsp;“如何表示多面体”这一问题的求解是十分巧妙的,并且有一些非常实用的结果。一个简单的例子是定义在 $\ell_\infty$-范数空间的 $\bfR^n$ 上的单位球,
$$
C = \left\{x\mid |x_i| \leqslant 1, \ i = 1,\cdots n\right\}
$$
$C$ 可以由 $2n$ 个线性不等式 $\pm e_i^\TT x \leqslant 1$ 表示为 $\eqref{polyhedron-1}$ 的形式,其中 $e_i$ 表示第 $i$ 维的单位向量。为了将其描述为形如 $\eqref{ExtendedHull}$ 的凸包,需要至少 $2^n$ 个点:
$$
C = \conv\{v_1,\cdots,v_{2^n}\}
$$
其中 $v_1,\cdots,v_{2^n}$ 是以 $1$ 和 $-1$ 为分量的全部向量,共 $2^n$ 个。可见,当 $n$ 很大时,这两种描述方式的规模相差极大。
# 5. 半正定锥
&emsp;&emsp;用 $\bfS^n$ 表示对称 $n\times n$ 矩阵的集合,即
$$
\bfS^n = \left\{ X \in \bfR ^{n\times n}\mid X = X^\TT \right\}
$$
这是一个维数为 $n(n + 1)/2$ 的向量空间。用 $\bfS^n_+$ 表示对称半正定矩阵的集合:
$$
\bfS^n_+ = \left\{ X \in \bfS^n\mid X \succeq 0 \right\}
$$
用 $\bfS^n_{++}$ 表示对称正定矩阵的集合:
$$
\bfS^n_{++} = \left\{ X \in \bfS^n\mid X \succ 0 \right\}
$$
(这些符号与 $\bfR_+$ 相对应:$\bfR_+$ 表示非负实数,而 $\bfR_{++}$ 表示正实数。)
&emsp;&emsp;集合 $\bfS^n_+$ 是一个凸锥:如果 $\theta_1,\theta_2 \geqslant 0$ 并且 $A,B\in\bfS^n_+$,那么 $\theta_1 A + \theta_2 B\in\bfS^n_+$。从半正定矩阵的定义可以直接得到:对于任意 $x \in \bfR^n$,如果 $A\succeq 0$,$B\succeq 0$ 并且 $\theta_1,\theta_2 \geqslant 0$,那么有
$$
x^\TT (\theta_1 A + \theta_2 B)x = \theta_1 x^\TT A x + \theta_2 x^\TT Bx \geqslant 0
$$
> **举例**&emsp;$\bfS^2$ 上的**半正定锥**(*Positive semidefinite cone*)。我们有
>
> $$
> X = \left[\begin{array}{c}
x & y \\ y & z
\end{array}\right] \in \bfS^2_+ \quad \Longleftrightarrow \quad x\geqslant 0, \quad z \geqslant 0, \quad xz\geqslant y^2
> $$
>
> [图 12](#图12) 给出了这个锥的边界,按 $(x,y,z)$ 表示在 $\bfR^3$ 中。
>
> <a id="图12"></a>
>
> ![图 12. $\bfS^2$ 中半正定锥的边界。](../images/post/2024-06-08-josh-cvx-1-2/2024-06-08-josh-cvx-1-2-120-BoundaryOfPostiveSemidefiniteCone.png){width=500px}
# 参考文献
1. Stephen P. Boyd and Lieven Vandenberghe, *Convex optimization*. Cambridge, UK: Cambridge University Press, 2004.
2. Stephen P. Boyd and Lieven Vandenberghe, *凸优化*. 北京: 清华大学出版社, 2013.
+322
View File
@@ -0,0 +1,322 @@
---
title: Josh's Note — 凸优化<br>Part 1.3 凸集—保凸运算
mathjax: true
comments: true
copyright: true
toc:
enable: true
number: false
wrap: true
expand_all: true
max_depth: 4
categories:
- - Josh 的学习笔记
- 凸优化
- 凸集
- - 数学
- 凸优化
tags:
- 凸优化
- 凸集
- 保凸运算
- 交集
- 仿射函数
- 伸缩
- 平移
- 线性分式
- 透视函数
abbrlink: a4a69a4f
date: 2024-06-08 23:27:19
---
$
\newcommand{\bfR}{\mathbf{R}}
\newcommand{\bfS}{\mathbf{S}}
\newcommand{\TT}{\mathrm{T}}
\newcommand{\H}{\mathcal{H}}
\newcommand{\E}{\mathcal{E}}
\newcommand{\P}{\mathcal{P}}
\def\dom{\mathop{\bf dom}}
\def\prob{\mathop{\bf prob}}
$&emsp;&emsp;本文将描述一些保凸运算,利用保凸运算可以使用凸集构造出其他凸集。这些运算与[*Part 1.2 凸集—一些重要的凸集*](https://josh-gao.top/posts/9293b739.html)中描述的凸集的简单例子一起构成了凸集的演算,可以用来确定或构建集合的凸性。
# 1. 交集
&emsp;&emsp;交集运算是保凸的:如果 $S_1$ 和 $S_2$ 是凸集,那么 $S_1 \cap S_2$ 也是凸集。这个性质可以扩展到无穷个集合的交:如果对于任意 $\alpha\in A$,$S_\alpha$ 都是凸的,那么 $\displaystyle \bigcap_{\alpha \in A} S_\alpha$ 也是凸集。(子空间、仿射集合和凸锥对与任意交运算也是封闭的。)举一个简单的例子,多面体是半空间和超平面(它们都是凸集)的交集,因而是凸的。
> **举例**&emsp;半正定锥 $\bfS^n_+$ 可以表示为
>
> $$
> \bigcap_{z\ne 0} \left\{ X \in \bfS^n\mid z^\TT Xz \geqslant 0 \right\}
> $$
>
> 对于任意 $z\ne 0$,$z^\TT Xz$ 是关于 $X$ 的(不恒等于零的)线性函数,因此集合
>
> $$
> \left\{ X \in \bfS^n\mid z^\TT Xz \geqslant 0 \right\}
> $$
>
> 实际上就是 $\bfS^n$ 的半空间。由此,半正定锥是无穷个半空间的交集,因此是凸的。
<!-- more -->
> **举例** &emsp;考虑集合
>
> $$\begin{equation}\label{example2.8}
> S = \left\{ x \in \bfR^m\mid |p(t)|\leqslant 1\ 对于\ |t| \leqslant \pi/3 \right\}
> \end{equation}$$
>
> 其中 $p(t) = \displaystyle\sum_{k=1}^m x_k \cos kt$。集合 $S$ 可以表示为无穷个**平板**(*slab*)的交集:$S = \displaystyle \bigcap_{|t|\leqslant\pi/3} S_t$,其中
>
> $$
> S_t = \left\{x\mid -1\leqslant (\cos t,\cdots, \cos mt)^\TT x \leqslant 1\right\}
> $$
>
> 因此,$S$ 是凸的。对于 $m=2$ 的情况,它的定义和集合可见[图 13](#图13) 和[图 14](#图14)。
>
> <a id="图13"></a>
>
> ![图 13. $\eqref{example2.8}$ 定义的集合 ($m=2$) 中的点的三角多项式。虚线所示的三角多项式是另外两个的平均。](../images/post/2024-06-08-josh-cvx-1-3/2024-06-08-josh-cvx-1-3-130-ThreeTrigonometricPolynomials.png){width=500px}
>
> <a id="图14"></a>
>
> ![图 14. 图中央的白色区域显示了 $m=2$ 情况下 $\eqref{example2.8}$ 定义的集合 $S$。这个集合是无限多个(图中显示了其中 20 个)平板的交集,所以是凸的。](../images/post/2024-06-08-josh-cvx-1-3/2024-06-08-josh-cvx-1-3-140-TheSetS.png){width=470px}
&emsp;&emsp;在上面这些例子中,我们通过将集合表示为(可能无穷多个)半空间的交集来表明集合的凸性。反过来我们也将看到:每一个闭的凸集 $S$ 是(通常为无限多个)半空间的交集。事实上,一个闭集 $S$ 是包含它的所有半空间的交集:
$$
S = \bigcap \left\{ \H\mid \H\ 是半空间,\ S\subseteq \H \right\}
$$
# 2. 仿射函数
&emsp;&emsp;函数 $f: \bfR^n \to \bfR^m$ 是**仿射**(*affine*)的,如果它是一个线性函数和一个常数的和,即具有 $f(x) = Ax+ b$ 的形式,其中 $A \in \bfR^{m\times n}$,$b \in \bfR^m$。假设 $S \subseteq \bfR^n$ 是凸的,并且 $f: \bfR^n \to \bfR^m$ 是仿射函数。那么,$S$ 在 $f$ 下的象
$$
f(S) = \left\{ f(x)\mid x\in S \right\}
$$
是凸的。类似地,如果 $f:\bfR^k\to\bfR^n$ 是仿射函数,那么 $S$ 在 $f$ 下的原象
$$
f^{-1}(S) = \left\{ x\mid f(x)\in S \right\}
$$
是凸的。
&emsp;&emsp;两个简单的例子是**伸缩**(*scaling*)和**平移**(*translation*)。如果 $S \subseteq \bfR^n$ 是凸集,$\alpha \in \bfR$ 并且 $a \in \bfR^n$,那么,集合 $\alpha S$ 和 $S+a$ 是凸的,其中
$$
\alpha S = \left\{ \alpha x\mid x \in S \right\},\qquad S + a = \left\{ x + a\mid x \in S \right\}
$$
一个凸集向它的某几个坐标的**投影**(*projection*)是凸的,即:如果 $S \subseteq \bfR^m \times \bfR^n$ 是凸集,那么
$$
T = \left\{ x_1\in \bfR^m\mid (x_1,x_2)\in S\ 对于某些\ x_2 \in \bfR^n \right\}
$$
是凸集。
&emsp;&emsp;两个集合的**和**(*sum*)可以定义为:
$$
S_1 + S_2 = \left\{ x + y\mid x \in S_1, y \in S_2\right\}
$$
如果 $S_1$ 和 $S_2$ 是凸集,那么,$S_1 + S_2$ 是凸的。可以看出,如果 $S_1$ 和 $S_2$ 是凸的,那么其直积或 Cartesian 乘积
$$
S_1 \times S_2 = \left\{ (x_1,x_2)\mid x_1\in S_1, x_2\in S_2 \right\}
$$
也是凸集。这个集合在线性函数 $f(x_1,x_2) = x_1+x_2$ 下的象是和 $S_1 + S_2$。
&emsp;&emsp;也可以考虑 $S_1,S_2 \in \bfR^m \times \bfR^n$ 的**部分和**(*partial sum*),定义为
$$
S = \left\{ (x,y_1 + y_2)\mid (x,y_1)\in S_1,\ (x,y_2)\in S_2 \right\}
$$
其中 $x\in\bfR^n$,$y_i \in \bfR^m$。$m=0$ 时,部分和给出了 $S_1$ 和 $S_2$的交集;$n=0$ 时,部分和等于集合之和。凸集的部分和是凸集。
> **举例**&emsp;**多面体**。$\{ x\mid Ax \preceq b, Cx = d \}$ 可以表示为非负象限和原点的 Cartesian 乘积在仿射函数 $f(x) = (b -Ax, d - Cx)$ 下的原象:
>
> $$
> \{x\mid Ax\preceq b, Cx = d\} = \{ x\mid f(x) \in \bfR^m_+ \times \{0\}\}
> $$
>
> {% note info %}这里可以这样理解:函数 $f(x) = (b -Ax, d - Cx)$ 在条件 $Ax \preceq b, Cx = d$ 下的值域为 $\mathbf{R}^m_+ \times \{0\}$。{% endnote %}
> **举例**&emsp;**线性矩阵不等式的解**。条件
>
> $$\begin{equation}
> A(x) = x_1 A_1 + \cdots + x_nA_n \preceq B
> \end{equation}$$
>
> 称为关于 $x$ 的**线性矩阵不等式**(*Linear Matrix Inequality, LMI*),其中 $B,A_i \in \bfS^m$(注意它与有序线性不等式
>
> $$
> a^\TT x = x_1a_1+\cdots x_na_n \leqslant b
> $$
>
> 的相似性,其中 $b,a_i\in \bfR$。)
>
> 线性矩阵不等式的解 $\{ x\mid A(x) \preceq B\}$ 是凸集。事实上,它是半正定锥在由 $f(x) = B-A(x)$ 给定的仿射映射 $f: \bfR^n \to \bfS^m$ 下的原象。
> **举例**&emsp;**双曲锥**。集合
>
> $$
> \{ x\mid x^\TT Px \leqslant (c^\TT x) ^2, c^\TT x \geqslant 0 \}
> $$
>
> 是凸集,其中 $P\in\bfS^n_+$,$c\in\bfR$。这是因为它是二阶锥
>
> $$
> \{ (z,t)\mid z^\TT z \leqslant t ^2 , t \geqslant 0 \}
> $$
>
> 在仿射函数 $f(x) = (P^{1/2}x,c^\TT x)$ 下的原象。
> **举例**&emsp;**椭球**。椭球
>
> $$
> \E = \{ x\mid (x-x_c)^\TT P^{-1} (x-x_c) \leqslant 1 \}
> $$
>
> 是单位 Euclid 球 $\{ u\mid \|u\|_2 \leqslant 1 \}$ 在仿射映射 $f(u) = P^{1/2}u + x_c$ 下的象, 其中 $P \in \bfS^n_{++}$。(同时也是单位球在仿射映射 $g(x) = P^{-1/2}(x — x_c)$ 下的原象。)
# 3. 线性分式及透视函数
&emsp;&emsp;本节将讨论一类称为**线性分式**(*linear-fractional*)的函数,它比仿射函数更普遍,并且仍然保凸。
## 3.1 透视函数
&emsp;&emsp;定义 $P:\bfR^{n+1}\to\bfR^n$,$P(z,t) = z/t$ 为**透视函数**(*perspective function*),其定义域为 $\dom P = \bfR^n \times \bfR_{++}$。(此处的 $\bfR_{++}$ 表示正实数集合,即 $\bfR_{++} = \{ x\in\bfR\mid x > 0 \}$。)透视函数对向量进行伸缩(scale),或称为规范化(normalize),使得最后一维分量为1 并舍弃之。
> **注释**&emsp;我们用小孔成象来解释透视函数。($\bfR^3$ 中的)小孔照相机由一个不透明的水平面 $x_3 = 0$ 和一个在原点的小孔组成,光线通过这个小孔在 $x_3 = -1$ 呈现出一个水平图像。在相机上方 $x$($x_3 > 0$)处的一个物体,在相平面的点 $-(x_1/x_3,x_2/x_3,1)$ 处形成一个图像。忽略象点的最后一维分量(因为它恒等于 $-1$),$x$ 处的点的象在象平面上呈现于 $y=-(x_1/x_3,x_2/x_3)$ 处。[图 15](#图15)显示了这个过程。
>
> <a id="图15"></a>
>
> ![图 15. 透视函数的小孔成象解释。深色的水平直线表示 $\bfR^3$ 中的平面 $x_3 = 0$,除了在原点处有一个小孔外,它是不透光的。平面之上的物体或光源呈现在浅色水平直线所示的象平面 $x_3 = -1$ 上。源位置向其象位置的映射对应于透视函数。](../images/post/2024-06-08-josh-cvx-1-3/2024-06-08-josh-cvx-1-3-150-PinHoleCameraInterpretationOfPerspectiveFuncation.png){width=500px}
&emsp;&emsp;如果 $C \subseteq \dom P$ 是凸集,那么它的象
$$
P(C) = \{ P(x)\mid x\in C \}
$$
也是凸集。这个结论很直观:通过小孔观察一个凸的物体,可以得到凸的象。为解释这个事实,我们将说明在透视函数作用下,线段将被映射成线段。(也可以这样理解,通过小孔,一条线段的象是一条线段。)
> **解释**&emsp;假设 $x = (\tilde{x},x_{n+1})$,$y = (\tilde{y}, y_{n+1}) \in \bfR^{n+1}$,并且 $x_{n+1}>0$,$y_{n+1}>0$ 。那么,对于 $0 \leqslant \theta \leqslant 1$
>
> $$
> P(\theta x + (1-\theta)y) = \frac{\theta\tilde{x}+ (1-\theta)\tilde{y}}{\theta x_{n+1} + (1-\theta)y_{n+1}} = \mu P(x) + (1-\mu) P(y)
$$
>
> 其中
>
> $$
> \mu = \frac{\theta x_{n+1}}{\theta x_{n+1} + (1-\theta) y_{n+1}}\in[0,1]
> $$
>
> $\theta$ 和 $\mu$ 之间的关系是单调的:当 $\theta$ 在 $0$、$1$ 间变化时(形成线段 $[x,y]$),$\mu$ 也在 $0$、$1$ 间变化(形成线段 $[P(x),P(y)]$。这说明 $P([x,y]) = [P(x),P(y)]$。
&emsp;&emsp;现在假设 $C$ 是凸的,并且有 $C \subseteq \dom P$(即对于所有 $x\in C$,$x_{n+1} > 0$)及 $x,y\in C$。为显示 $P(C)$ 的凸性,需要说明线段 $[P(x), P(y)]$ 在 $P(C)$ 中。这条线段是线段 $[x,y]$ 在 $P$ 的象,因而属于 $P(C)$。
&emsp;&emsp;一个凸集在透视函数下的原象也是凸的:如果 $C\subseteq \bfR^n$ 为凸集,那么
$$
P^{-1}(C) = \{ (x,t)\in\bfR^{n+1}\mid x/t\in C, t > 0 \}
$$
是凸集。为证明这点,假设 $(x,t)\in P^{-1}(C)$,$(y,s)\in P^{-1}(C)$,$0 \leqslant \theta \leqslant 1$。我们需要说明
$$
\theta(x,t) + (1-\theta)(y,s) \in P^{-1} (C)
$$
即
$$
\frac{\theta x + (1-\theta)y}{\theta t + (1-\theta)s} \in C
$$
(显然,$\theta t+(1-\theta)s>0$)。这可从下式看出,
$$
\frac{\theta x+(1-\theta)y}{\theta t+(1-\theta)s}=\mu(x/t)+(1-\mu)(y/s)
$$
其中
$$
\mu=\frac{\theta t}{\theta t+(1-\theta)s}\in[0,1]
$$
## 3.2 线性分式函数
&emsp;&emsp;**线性分式函数**(*linear-fractional function*)由透视函数和仿射函数复合而成。设 $g:\bfR^n \to \bfR^{m+1}$ 是仿射的,即
$$\begin{equation}\label{AffineFunction}
g(x) = \left[\begin{array}{c}
A \\ c^\TT
\end{array}\right]x + \left[\begin{array}{c}
b \\ d
\end{array}\right]
\end{equation}$$
其中 $A \in \bfR ^{m\times n}$,$b \in \bfR^m$,$c \in \bfR^n$ 并且 $d\in\bfR^n$。则由 $f =P\circ g$ 给出的函数 $f:\bfR^n \to \bfR^m$
$$\begin{equation}\label{LinearFractionalFunction}
f(x) = (Ax+b)/(c^\TT x + d),\qquad \dom f = \{x\mid c^\TT x + d > 0\}
\end{equation}$$
称为**线性分式**(*linear-fractional*)(或**投射**(*projective*))函数。如果 $c = 0$,$d > 0$,则 $f$ 的定义域为 $\bfR^n$ 并且 $f$ 是仿射函数。因此,我们可以将仿射和线性函数视为特殊的线性分式函数。
> **注释**&emsp;**投射解释**。可以很方便地将一个线性分式函数表示为:将矩阵
>
> $$\begin{equation}
> Q = \left[\begin{array}{c}
> A & b \\ c^\TT & d
> \end{array}\right] \in \bfR^{(m+1)\times (n+1)}
> \end{equation}$$
>
> 作用于(即左乘)点 $(x,1)$,得到 $(Ax + b,c^\TT x + d)$;然后将所得结果做伸缩变换或归一化,以使得其最后一个分量为一,得到 $(f(x), 1)$。
>
> 也可以从儿何上进行解释,即这个表达式将 $\bfR^n$ 与 $\bfR^{n+1}$ 空间上的一组射线联系了起来。也就是说,对于 $\bfR^n$ 空间的一个点 $z$,我们可以构造一个 $\bfR^{n+1}$ 空间的(开)射线 $\P(z) = \{t(z,1)\mid t > 0\}$。这条射线上每个点的最后一个分量均是正值。反之, $\bfR^{n+1}$ 空间中每条以原点为顶点并且最后一个分量为正值的射线均可以由一些 $v\in\bfR^n$ 表示为 $\P(v) = \{t(v, 1)\mid t \geqslant 0\}$。$\P$ 表示了 $\bfR^n$ 与最后一个分量为正的射线之间的(投射)关系,这种关系是一一对应和满的。
>
> 线性分式函数 $\eqref{LinearFractionalFunction}$ 可以表示为
>
> $$
> f(x) = \P^{-1}(Q\P(x))
> $$
>
> 因此,从 $x\in\dom f$ 出发,即由一个满足 $c^\TT x +d > 0$ 的点,可以得到 $\bfR^{n+1}$ 空间的一条射线 $\P(x)$。将线性变换矩阵 $Q$ 作用于这条射线,就可以得到另一条射线 $Q\P(x)$。因为 $x \in \dom f$,这条射线的最后一个分量为正。最后,我们也可以通过逆投射变换恢复出 $f(x)$。
&emsp;&emsp;类似于透视函数,线性分式函数也是保凸的。如果 $C$ 是凸集并且在 $f$ 的定义域中(即任意 $x\in C$ 满足 $c^\TT x+d > 0$),那么 $C$ 的象 $f(C)$ 也是凸集。根据前述的结果可以直接得到这个结论: $C$ 在仿射映射 $\eqref{AffineFunction}$ 下的象是凸的,并且在透视函数 $P$ 下的映射(即 $f(C)$)是凸的。类似地,如果 $C \subseteq \bfR^m$ 是凸集,那么其原象 $f^{-1}(C)$ 也是凸的。
> **举例**&emsp;**条件概率**。设 $u$ 和 $v$ 是分别在 $\{1, \cdots, n\}$ 和 $\{1, \cdots, m\}$ 中取值的随机变量,并且 $p_{ij}$ 表示概率 $\prob(u = i,v = j)$。那么条件概率 $f_{ij} = \prob(u = i\mid v = j)$ 由下式给出
>
> $$
> f_{ij} = \frac{p_{ij}}{\displaystyle\sum_{k=1}^n p_{kj}}
> $$
>
> 因此,$f$ 可以通过一个线性分式映射从 $p$ 得到。
>
> 可以知道,如果 $C$ 是一个关于 $(u,v)$ 的联合密度的凸集,那么相应的 $u$ 的条件密度(给定 $v$)的集合也是凸集。
&emsp;&emsp;[图 16](#图16) 表示了集合 $C\subseteq \bfR^2$ 及其在下面的线性分式函数下的象
$$
f(x) = \frac{1}{x_1 + x_2 + 1} x,\qquad \dom f = \{(x_1,x_2)\mid x_1+x_2+1>0\}
$$
<a id="图15"></a>
![图 16. **左**:集合 $C\subseteq \bfR^2$。虚线显示了线性分式函数 $f(x) = x/(x_1 + x_2 + 1)$ 的定义域的边界,其中 $\dom f = \{(x_1,x_2)\mid x_1+x_2+1>0\}$。**右**:$C$ 在 $f$ 下的象。虚线显示了 $f^{-1}$ 的定义域的边界。](../images/post/2024-06-08-josh-cvx-1-3/2024-06-08-josh-cvx-1-3-160-ASetAndItsImageUnderLFF.png){width=800px}
# 参考文献
1. Stephen P. Boyd and Lieven Vandenberghe, *Convex optimization*. Cambridge, UK: Cambridge University Press, 2004.
2. Stephen P. Boyd and Lieven Vandenberghe, *凸优化*. 北京: 清华大学出版社, 2013.
+160
View File
@@ -0,0 +1,160 @@
---
title: Josh's Note — 凸优化<br>Part 1.4 凸集—广义不等式
mathjax: true
comments: true
copyright: true
toc:
enable: true
number: false
wrap: true
expand_all: true
max_depth: 4
categories:
- - Josh 的学习笔记
- 凸优化
- 凸集
- - 数学
- 凸优化
tags:
- 凸优化
- 凸集
- 广义不等式
- 正常锥
- 最小元
- 极小元
- 最大元
- 极大元
abbrlink: aff3a091
date: 2024-06-12 16:49:26
---
# 1. 正常锥与广义不等式
$
\newcommand{\bfR}{\mathbf{R}}
\newcommand{\bfS}{\mathbf{S}}
\newcommand{\E}{\mathcal{E}}
\newcommand{\TT}{\mathrm{T}}
\def\iint{\mathop{\bf int}}
$&emsp;&emsp;称锥 $K \subseteq \bfR^n$ 即为**正常锥**(*proper cone*),如果它满足下列条件
- K 是凸的。
- K 是闭的。
- K 是**实**(*solid*)的,即具有非空内部。
- K 是**尖**(*pointed*)的,即不包含直线(或者等价地,$x\in K, -x \in K \Longrightarrow x = 0$)。
正常锥 $K$ 可以用来定义**广义不等式**(*generalized inequality*),即 $\bfR^n$ 上的偏序关系。这种偏序关系和 $\bfR$ 上的标准序有很多相同的性质。用正常锥 $K$ 可以定义 $\bfR^n$ 上的偏序关系如下
$$
x \preceq_K y \Longleftrightarrow y - x \in K
$$
$y \preceq_K x$ 也可以写为 $x \succeq_K y$。类似地,定义相应的严格偏序关系为
$$
x \prec_K y \Longleftrightarrow y - x \in \iint K
$$
并且可以同样地定义 $x \succ_K y$。(为将广义不等式 $\preceq_K$ 与严格的广义不等式区分开,有时也称 $\preceq_K$ 为不严格的广义不等式)。
<!-- more -->
&emsp;&emsp;当 $K = \bfR_+$ 时,偏序关系 $\preceq_K$ 就是通常意义上 $\bfR$ 中的序 $\leqslant$;相应地,严格偏序关系 $\prec_K$ 与 $\bfR$ 上的严格序 $<$ 相同。因此,广义不等式包含了 $\bfR$ 上的(不严格和严格)不等式,它是广义不等式的一种特殊情况。
> **举例**&emsp;**非负象限及分量不等式**。非负象限 $K = \bfR^n_+$ 是一个正常锥。相应的广义不等式 $\preceq_K$ 对应于向量间的分量不等式,即 $x \preceq_K y$ 等价于 $x_i \leqslant y_i, i = 1,\cdots,n$。相应地,其严格不等式对应于严格的分量不等式,即 $x \prec_K y$ 等价于 $x_i < y_i, i = 1,\cdots,n$。
>
> 我们会经常使用对应于非负象限的不严格和严格的偏序关系,因此省略下标 $K$。当 $\preceq$ 或 $\prec$ 出现在向量间的时候,该符号应被理解为分量不等式。
> **举例**&emsp;**半正定锥和矩阵不等式**。半正定锥是 $\bfS^n$ 空间中的正常锥,相应的广义不等式 $\preceq_K$ 就是通常的矩阵不等式,即 $X \preceq_K Y$ 等价于 $Y - X$ 为半正定矩阵。(在 $\bfS^n$ 中)$\bfS^n_+$ 的内部由正定矩阵组成,因此严格广义不等式也等同于通常的对称矩阵的严格不等式,即 $X \prec_K Y$ 等价于 $Y - X$ 为正定矩阵。
>
> 这里,也是由于经常使用这种偏序关系,因此省略其下标,即对于对称矩阵,我们将广义不等式简写为 $X \preceq Y$ 或 $X \prec Y$, 它们表示关于半正定锥的广义不等式。
> **举例**&emsp;**$[0, 1]$ 上非负的多项式锥**。$K$ 定义如下
>
> $$\begin{equation}
> K = \{ c\in\bfR^n\mid c_1 + c_2 t + \cdots + c_n t^{n-1} \geqslant 0\ 对于\ t \in [0,1]\}
> \end{equation}$$
>
> 即 $K$ 是 $[0, 1]$ 上最高 $n - 1$ 阶的非负多项式(系数)锥。可以看出 $K$ 是一个正常锥,其内部是 $[0, 1]$ 上为正的多项式的系数集合。
>
> 两个向量 $c, d \in \bfR^n$ 满足 $c \preceq_K d$ 的充要条件是,对于所有 $t \in [0, 1]$ 有
>
> $$
> c_1 + c_2 t + \cdots + c_n t^{n-1} \leqslant d_1 + d_2 t + \cdots + d_n t^{n-1}
> $$
## 1.1 广义不等式的性质
&emsp;&emsp;广义不等式 $\preceq_K$ 满足许多性质,例如
- **$\preceq_K$ 对于加法是保序的**:如果 $x \preceq_K y$ 并且 $u \preceq_K v$,那么 $x + u \preceq_K y + v$。
- **$\preceq_K$ 具有传递性**:如果 $x \preceq_K y$ 并且 $y \preceq_K z$,那么 $x \preceq_K z$。
- **$\preceq_K$ 对于非负数乘是保序的**:如果 $x \preceq_K y$ 并且 $\alpha \geqslant 0$,那么 $\alpha x \preceq_K \alpha y$。
- **$\preceq_K$ 是自反的**:$x \preceq_K x$。
- **$\preceq_K$ 是反对称的**:如果 $x \preceq_K y$ 并且 $y \preceq_K x$,那么 $x = y$。
- **$\preceq_K$ 对于极限运算是保序的**:如果对于 $i = 1,2,\dots$ 均有 $x_i \preceq_K y_i$,当 $i \to \infty$ 时,有 $x_i \to x$ 和 $y_i \to y$,那么 $x \preceq_K y$。
相应的广义不等式 $\prec_K$ 也满足一些性质,例如
- 如果 $x \prec_K y$,那么 $x \preceq_K y$。
- 如果 $x \prec_K y$ 并且 $u \prec_K v$, 那么 $x + u \prec_K y + v$。
- 如果 $x \prec_K y$ 并且 $\alpha > 0$,那么 $\alpha x \prec_K \alpha y$。
- $x \nprec_K x$。
- 如果 $x \prec_K y$,那么对于足够小的 $u$ 和 $v$ 有 $x + u \prec_K y + v$。
这些性质可以从 $\preceq_K$ 和 $\prec_K$ 的定义以及正常锥的性质中直接得到。
# 2. 最小与极小元
&emsp;&emsp;广义不等式的符号($\preceq_K$,$\prec_K$)似乎表明它们与 $\bfR$ 上的普通不等式($\leqslant$,$<$)有着相同的性质。虽然普通不等式的许多性质对于广义不等式确实成立,但很多重要的性质并不如此。最明显的区别在于,$\bfR$ 上的 $\leqslant$ 是一个**线性序**(*linear ordering*),即任意两点都是**可比的**(*comparable*),也就是说 $x\leqslant y$ 和 $y \leqslant x$ 二者必居其一。这个性质对于其他广义不等式并不成立。这导致了最小、最大这些概念在广义不等式环境下变得更加复杂。本节将对此进行简要的讨论。
&emsp;&emsp;如果对于每个 $y \in S$,均有 $x \preceq_K y$,称 $x\in S$ 是 $S$(关于广义不等式 $\preceq_K$)的**最小元**(*minimum element*)。类似地,我们可以定义关于广义不等式的**最大元**(**maximum element**)。如果一个集合有最小(或最大)元,那么它们是唯一的。
&emsp;&emsp;相对应的概念是**极小元**(*minimal element*)。如果 $y \in S$,$y \preceq_K x$ 可以推得 $y=x$,那么称 $x\in S$ 是 $S$ 上(关于广义不等式 $\preceq_K$)的**极小元**(*minimal element*)。同样地,可以定义**极大元**(*maximal element*)。一个集合可以有多个极小(或极大)元。
&emsp;&emsp;可以用简单的集合符号对最小元和极小元进行描述。元素 $x\in S$ 是 $S$ 中的一个最小元,当且仅当
$$
S \subseteq x + K
$$
这里 $x+K$ 表示可以与 $x$ 相比并且大于或等于(根据 $\preceq_K$)$x$ 的所有元素。元素 $x\in S$ 是极小元,当且仅当
$$
(x - K) \cap S = \{x\}
$$
这里 $x-K$ 表示可以与 $x$ 相比并且小于或等于(根据立$\preceq_K$)$x$ 的所有元素,它与 $S$ 的唯一共同点即是 $x$。
&emsp;&emsp;$K=\bfR^n$ 导出的实际上就是 $\bfR$ 上一般的序。此时,极小和最小的概念是一致的,也符合集合最小元素的通常定义。
> **举例**&emsp;考虑锥 $\bfR^2_+$,它导出的是 $\bfR^2$ 上的关于分量的不等式。对此,可以给出一些关于极小元和最小元的简单的几何描述。不等式 $x \preceq y$ 的含义是 $y$ 在 $x$ 之上、之右。$x \in S$是集合 $S$ 的最小元,表明 $S$ 的其他所有点都在它之上、之右。而 $x$ 为集合 $S$ 的极小元,是指 $S$ 中没有任何一个点在 $x$ 之下、之左,其区别可见[图 17](#图17)。
>
> <a id="图17"></a>
>
> ![图 17. **左**:集合出关于 $\bfR^2$ 上的分量不等式有最小元 $x_1$。集合 $x_1+K$ 由浅色阴影所示;$x_1$ 是 $S_1$ 的最小元,因为 $S_1 \subseteq x_1 + K$。**右**:点 $x_2$ 是 $S_2$ 的极小元。集合 $x_2-K$ 由浅色阴影所示。点 $x_2$ 是极小的,因为 $x_2-K$ 和 $S_2$ 只相交于 $x_2$](../images/post/2024-06-12-josh-cvx-1-4/2024-06-12-josh-cvx-1-4-170-MinimalAndMinimum.png){width=700px}
> **举例**&emsp;**对称矩阵集合中的最小元和极小元**。用 $A \in \bfS^n_{++}$ 表示一个圆心在原点的椭圆,即
>
> $$
> \E_A = \{ x\mid x^\TT A^{-1} x \leqslant 1 \}
> $$
>
> 我们知道 $A \preceq B$ 等价于 $\E_A \subseteq \E_B$。
>
> 给定 $v_1,\cdots,v_k \in \bfR^n$ 并定义
>
> $$
> S = \{ P \in \bfS ^n_{++}\mid v_i^\TT P^{-1} v_i \leqslant 1,\ i = 1,\dots k \}
> $$
>
> 它对应于包含了点 $v_1,\cdots,v_k$ 的椭圆的集合。集合 $S$ 没有最小元:对于任意包含点$v_1,\cdots,v_k$ 的椭圆,总可以找到另一个包含这些点但不可比的椭圆。一个椭圆是极小的,如果它包含这些点但没有更小的椭圆也包含这些点。[图 18](#图18)显示了 $\bfR^2$ 上 $k = 2$ 时的一个例子。
>
> <a id="图18"></a>
>
> ![图 18. $\bfR^2$ 中的三个椭球,它们均以原点(图中较低的点所示)为中心,并且包含较高处的点。椭球 $\E_1$ 不是极小的,因为存在包含这些点并且更小的椭球(例如,$\E_3$)。由于同样的原因,$\E_3$ 也不是极小的。椭球 $\E_2$ 是极小的,因为没有其他(以原点为中心)包含这些点并被 $\E_2$ 包含的椭球。](../images/post/2024-06-12-josh-cvx-1-4/2024-06-12-josh-cvx-1-4-180-ThreeEllipsoids.png){width=300px}
# 参考文献
1. Stephen P. Boyd and Lieven Vandenberghe, *Convex optimization*. Cambridge, UK: Cambridge University Press, 2004.
2. Stephen P. Boyd and Lieven Vandenberghe, *凸优化*. 北京: 清华大学出版社, 2013.
+190
View File
@@ -0,0 +1,190 @@
---
title: Josh's Note — 凸优化<br>Part 1.5 凸集—分离与支撑超平面
mathjax: true
comments: true
copyright: true
toc:
enable: true
number: false
wrap: true
expand_all: true
max_depth: 4
categories:
- - Josh 的学习笔记
- 凸优化
- 凸集
- - 数学
- 凸优化
tags:
- 凸优化
- 凸集
abbrlink: bc5bb04
date: 2024-06-12 18:29:40
---
# 1. 超平面分离定理
$
\newcommand{\bfR}{\mathbf{R}}
\newcommand{\TT}{\mathrm{T}}
\newcommand{\d}{\mathrm{d}}
\def\dist{\mathop{\bf dist}}
\def\iint{\mathop{\bf int}}
\def\bd{\mathop{\bf bd}}
\def\cl{\mathop{\bf cl}}
$&emsp;&emsp;本节将阐述一个在之后非常重要的想法:用超平面或仿射函数将两个不相交的凸集分离开来。其基本结果就是**超平面分离定理**(*separating hyperplane theorem*):假设 $C$ 和 $D$ 是两个不相交的凸集,即 $C \cap D = \emptyset$,那么存在 $a \ne 0$ 和 $b$ 使得对于所有 $x\in C$ 有 $a^\TT x \leqslant b$,对于所有 $x\in D$ 有 $a^\TT x \geqslant b$。换言之,仿射函数 $a^\TT x-b$ 在 $C$ 中非正,而在 $D$ 中非负。超平面 $\{ x\mid a^\TT x = b \}$ 称为集合 $C$ 和 $D$ 的**分离超平面**(*separating hyperplane*),或称超平面**分离**(*separate*)了集合 $C$ 和 $D$,如[图 19](#图19)。
<a id="图19"></a>
![图 19. 超平面 $\{ x\mid a^\TT x = b \}$ 分离了两个不相交的凸集 $C$ 和 $D$。仿射函数 $a^\TT x-b$ 在 $C$ 上非正而在 $D$ 上非负。](../images/post/2024-06-12-josh-cvx-1-5/2024-06-12-josh-cvx-1-5-190-Hyperplane.png){width=400px}
<!-- more -->
## 1.1 超平面分离定理的证明
&emsp;&emsp;这里我们考虑一个特殊的情况下的证明。假设 $C$ 和 $D$ 的(Euclid)**距离**(*distance*)为正,这里的距离定义为
$$
\dist(C,D) = \inf\{ \|u,v\|_2\mid u \in C,\ v \in D\}
$$
并且存在 $c\in C$ 和 $d\in D$ 达到这个最小距离,即 $\|c-d\|_2=\dist(C,D)$。(这些条件是可以被满足的,例如当 $C$ 和 $D$ 是闭的并且其中之一是有界的。)
&emsp;&emsp;定义
$$
a = d - c,\qquad b = \frac{\|d\|_2^2 - \|c\|_2^2}{2}
$$
我们将显示仿射函数
$$
f(a) = a^\TT x - b = (d-c)^\TT(x - (1/2)(d+c))
$$
在 $C$ 中非正而在 $D$ 中非负,即超平面 $\{ x\mid a^\TT x = b \}$ 分离了 $C$ 和 $D$。这个超平面与连接 $c$ 和 $d$ 之间的线段相垂直并且穿过其中点,如[图 20](#图20) 所示。
<a id="图20"></a>
![图 20. 两个凸集间分离超平面的构造。$c \in C$ 和 $d\in D$ 是两个集合中最靠近彼此的一个点对。分离超平面垂直并且等分 $c$ 和 $d$ 之间的线段。](../images/post/2024-06-12-josh-cvx-1-5/2024-06-12-josh-cvx-1-5-200-SeparateHyperplane.png){width=400px}
&emsp;&emsp;首先证明 $f$ 在 $D$ 中非负。关于 $f$ 在 $C$ 中非正的证明是相似的(只需将 $C$ 和 $D$ 交换并考虑 $-f$ 即可)。
> **证明**&emsp;假设存在一个点 $u\in D$,并且
>
> $$\begin{equation}\label{ufunction}
> f(u) = (d-c)^\TT (u - (1/2)(d+c)) < 0
> \end{equation}$$
>
> 可以将 $f(u)$ 表示为
>
> $$
> f(u) = (d-c)^\TT (u - d + (1/2)(d-c)) = (d-c)^\TT(u-d) + (1/2) \| d-c \|_2^2
> $$
>
> 可以看出式 $\eqref{ufunction}$ 意味着 $(d-c)^\TT(u-d) < 0$。于是,观察到
>
> $$
> \left. \frac{\d}{\d t} \|d + t(u-d) - c\|_2^2 \right|_{t=0} = 2(d-c)^\TT(u-d) < 0
> $$
>
> 因此,对于足够小的 $t>0$ 及 $t\leqslant 1$,有
>
> $$
> \| d + t(u-d) - c \|_2 < \| d -c \|_2
> $$
>
> 即点 $d+t(u-d)$ 比 $d$ 更靠近 $c$。因为 $D$ 是包含 $d$ 和 $u$ 的凸集,我们有 $d+t(u-d) \in D$。但这是不可能的,因为根据假设,$d$ 应当是 $D$ 中离 $C$ 最近的点。
> **举例**&emsp;**仿射集与凸集的分离**。设 $C$ 是凸集,而 $D$ 是仿射的,即 $D = \{ Fu + g\mid u \in \bfR^m\}$,其中 $F \in \bfR^{n\times m}$。设 $C$ 和 $D$ 不相交,那么根据超平面分离定理,存在 $a \ne 0$ 和 $b$ 使得对于所有 $x \in C$ 有 $a^\TT x \leqslant b$,对于所有 $x \in D$ 有 $a^\TT x \geqslant b$。
>
> 这里 $a^\TT x \geqslant b$ 对于所有 $x \in D$ 均成立,表明对于任意 $u \in \bfR^m$ 均有 $a^\TT Fu \geqslant b - a^\TT g$。但是在 $\bfR^m$ 上,只有当一个线性函数为零时,它才是有界的。因此,可以推知 $a^\TT F=0$ (并且因此有 $b \leqslant a^\TT g$)。
>
> 所以可知,存在 $a \ne 0$ 使得 $F^\TT a =0$ 和 $a^\TT x \leqslant a^\TT g$ 对于所有 $x\in C$ 均成立。
## 1.2 严格分离
&emsp;&emsp;如果之前构造的分离超平面满足更强的条件,即对于任意 $x\in C$ 有 $a^\TT x < b$ 并且对于任意 $x\in D$ 有 $a^\TT x > b$, 则称其为集合 $C$ 和 $D$ 的**严格分离**(*strict separation*)。简单的例子就可以看出,对于一般的情况,不相交的凸集并不一定能够被超平面严格分离(即使集合是闭集)。但是,在很多特殊的情况下,可以构造严格分离。
> **举例**&emsp;**点和闭凸集的严格分离**。令 $C$ 为闭凸集,而 $x_0 \notin C$,那么存在将 $x_0$ 与 $C$ 严格分离的超平面。
>
> 为说明这一点,需要注意,对于足够小的 $\epsilon > 0$,存在两个不相交的集合 $C$ 和 $B(x_0, \epsilon)$。根据超平面分离定理,存在 $a \ne 0$ 和 $b$,使得对于任意 $x\in C$ 有 $a^\TT x \leqslant b$;对于任意 $x \in B(x_0, \epsilon)$ 有 $a^\TT x \geqslant b$。
>
> 利用 $B(x_0, \epsilon) = \{ x_0 + u\mid \|u\|_2 \leqslant \epsilon \}$,可以将前述第二个条件表示为
>
> $$
> a^\TT (x_0 + u) \geqslant b\ 对于所有\ \|u\|_2 \leqslant \epsilon
> $$
>
> $u = -\epsilon a / \|a\|_2$ 极小化了上式的左端,代入可得
>
> $$
> a^\TT x_0 - \epsilon \| a \|_2 \geqslant b
> $$
>
> 所以,仿射函数
>
> $$
> f(x) = a^\TT x - b - \epsilon \|a\|_2/2
> $$
>
> 在 $C$ 上是负的,而在 $x_0$ 点是正的。
>
> 由此可以得到前面已提及的事实:一个闭凸集是包含它的所有半空间的交集。事实上,令 $C$ 为闭和凸的,$S$ 为所有包含 $C$ 的半空间。显然,$x\in C \Rightarrow x \in S$。为证明反方向,假设存在 $x\in S$ 并且 $x \notin C$。根据严格分离的结果,存在一个将 $x$ 与 $C$ 严格分离的超平面,即存在一个包含 $C$ 但不包含 $x$ 的半空间。也就是说,$x \notin S$。
## 1.3 超平面分离定理的逆定理
&emsp;&emsp;超平面分离定理的逆定理(即分离超平面的存在表明 $C$ 和 $D$ 不相交)是不成立的,除非在凸性之外再给 $C$ 或 $D$ 附加其他约束。
> **反例**&emsp;考虑 $C = D = \{0\} \subseteq \bfR$,超平面 $x=0$ 可以分离 $C$ 和 $D$。
&emsp;&emsp;通过给 $C$ 和 $D$ 增加一些条件,可以得到超平面分离定理的多种逆定理。
> **举例**&emsp;设 $C$ 和 $D$ 是凸集,$C$ 是开集,如果存在一个仿射函数 $f$,它在 $C$ 中非正而在 $D$ 中非负,那么 $C$ 和 $D$ 不相交。(为说明此结论,首先可知 $f$ 在 $C$ 上是负的。否则,如果 $f$ 在 $C$ 中的某一点为零,那么 $f$ 在这个点附近会取得正值,这与前述矛盾。因此 $C$ 和 $D$ 一定是不相交的,因为 $f$ 在 $C$ 中为负,而在 $D$ 中非负。)将逆定理与超平面分离定理相结合,我们可以得到下面的结论:任何两个凸集 $C$ 和 $D$,如果其中至少有一个是开集,那么当且仅当存在分离超平面时,它们不相交。
> **举例**&emsp;**严格线性不等式的择一定理**。我们导出严格线性不等式
>
> $$\begin{equation}\label{StrictLinearInequality}
> Ax \prec b
> \end{equation}$$
>
> 有解的充要条件。该不等式不可行的充要条件是(凸)集
>
> $$
> C = \{ b = Ax\mid x \in \bfR^n\},\qquad D = \bfR^m_{++} = \{ y \in \bfR^m\mid y \succ 0 \}
> $$
>
> 不相交。集合 $D$ 是开集,而 $C$ 是仿射集合。根据前述的结论,$C$ 和 $D$ 不相交的充要条件是,存在分离超平面,即存在非零的 $\lambda \in \bfR^m$ 和 $\mu \in \bfR$ 使得 $C$ 中 $\lambda^\TT y \leqslant \mu$ 而 $D$ 中 $\lambda^\TT y \geqslant \mu$。
>
> 这些条件可以被简化。第一个条件意味着对于所有 $x$ 都有 $\lambda^TT (b - Ax) \leqslant \mu$。这表明 $A^\TT \lambda = 0$,$\lambda^\TT b \leqslant \mu$。第二个不等式意味着 $\lambda^\TT y \geqslant \mu$ 对于所有 $y \succ 0$ 均成立。这表明 $\mu \leqslant 0$ 且 $\lambda \preceq 0$,$\lambda\ne 0$。
>
> 将这些结果放在一起,我们可以得知严格不等式组 $\eqref{StrictLinearInequality}$ 无解的充要条件是存在 $\lambda \in \bfR^m$ 使得
>
> $$\begin{equation}\label{IFFCondition}
> \lambda = 0,\qquad \lambda\succeq 0,\qquad A^\TT \lambda = 0,\qquad \lambda^\TT b \leqslant 0
> \end{equation}$$
>
> 这些不等式和等式关于 $\lambda\in\bfR^m$ 也是线性的。我们称式 $\eqref{StrictLinearInequality}$ 和式 $\eqref{IFFCondition}$ 构成一对**择一选择**(alternatives):对于任意的 $A$ 和 $b$,两者中仅有一组有解。
# 2. 支撑超平面
&emsp;&emsp;设 $C \subseteq \bfR^n$ 而 $x_0$ 是其边界 $\bd C$ 上的一点,即
$$
x_0 \in \bd C = \cl C\ \backslash\ \iint C
$$
如果 $a \ne 0$,并且对任意 $x \in C$ 满足 $a^\TT x \leqslant a^\TT x_0$,那么称超平面 $\{ x\mid a^\TT x = a^\TT x_0 \}$ 为集合 $C$ 在点 $x_0$ 处的**支撑超平面**(*supporting hyperplane*)。这等于说点 $x_0$ 与集合 $C$ 被超平面 $\{ x\mid a^\TT x = a^\TT x_0 \}$ 所分离。其几何解释是超平面 $\{ x\mid a^\TT x = a^\TT x_0 \}$ 与 $C$ 相切于点 $x_0$,而且半空间 $\{ x\mid a^\TT x \leqslant a^\TT x_0 \}$ 包含 $C$,如[图 21](#图21)。
<a id="图21"></a>
![图 21. 超平面 $\{ x\mid a^\TT x = a^\TT x_0 \}$ 在 $x_0$ 处支撑 $C$。](../images/post/2024-06-12-josh-cvx-1-5/2024-06-12-josh-cvx-1-5-210-SupportingHyperplane.png){width=400px}
&emsp;&emsp;一个基本的结论,称为**支撑超平面定理**(*supporting hyperplane theorem*),表明对于任意非空的凸集 $C$ 和任意 $x_0 \in \bd C$,在 $x_0$ 处存在 $C$ 的支撑超平面。支撑超平面定理从超平面分离定理很容易得到证明。需要区分两种情况。如果 $C$ 的内部非空,对于 $\{x_0\}$ 和 $\iint C$ 应用超平面分离定理可以直接得到所需的结论。如果 $C$ 的内部是空集,则 $C$ 必处于小于 $n$ 维的一个仿射集合中,并且任意包含这个仿射集合的超平面一定包含 $C$ 和 $x_0$,这是一个(平凡的)支撑超平面。
&emsp;&emsp;支撑超平面定理也有一个不完全的逆定理:如果一个集合是闭的,具有非空内部,并且其边界上每个点均存在支撑超平面,那么它是凸的。
# 参考文献
1. Stephen P. Boyd and Lieven Vandenberghe, *Convex optimization*. Cambridge, UK: Cambridge University Press, 2004.
2. Stephen P. Boyd and Lieven Vandenberghe, *凸优化*. 北京: 清华大学出版社, 2013.
+199
View File
@@ -0,0 +1,199 @@
---
title: Josh's Note — 凸优化<br>Part 1.6 凸集—对偶锥与广义不等式
mathjax: true
comments: true
copyright: true
toc:
enable: true
number: true
wrap: true
expand_all: true
max_depth: 4
categories:
- - Josh 的学习笔记
- 凸优化
- 凸集
- - 数学
- 凸优化
tags:
- 凸优化
- 凸集
abbrlink: b2aac0f7
date: 2024-06-13 10:57:38
---
# 1. 对偶锥
$
\newcommand{\bfR}{\mathbf{R}}
\newcommand{\bfS}{\mathbf{S}}
\newcommand{\TT}{\mathrm{T}}
\def\tr{\mathop{\bf tr}}
\def\iint{\mathop{\bf int}}
$&emsp;&emsp;令 $K$ 为一个锥。集合
$$\begin{equation}
K^\ast = \{ y\mid x^\TT y \geqslant 0,\ \forall x \in K \}
\end{equation}$$
称为 K 的**对偶锥**(*dual cone*)。顾名思义,$K^\ast$ 是一个锥,并且它总是凸的,即使 $K$ 不是凸锥。
&emsp;&emsp;从几何上看,$y \in K^\ast$ 当且仅当 $-y$ 是 $K$ 在原点的一个支撑超平面的法线,如[图 22](#图22) 所示。
<a id="图22"></a>
![图 22. **左**:以 $y$ 为内法向量的半空间包含锥 $K$,因此,$y \in K^\ast$。**右**:以 $z$ 为内法向量的半空间不包含 $K$,因此,$z \notin K^\ast$。](../images/post/2024-06-13-josh-cvx-1-6/2024-06-13-josh-cvx-1-6-220-DualCone.png){width=600px}
> **举例**&emsp;**子空间**。子空间 $V \subseteq \bfR^n$(这是一个锥)的对偶锥是其正交补 $V^\perp = \{y\mid y^\TT v = 0,\ \forall v \in V\}$。
<!-- more -->
> **举例**&emsp;**非负象限**。锥 $\bfR^n_+$ 的对偶是它本身:
>
> $$
> y^\TT x \geqslant 0,\ \forall x \succeq 0 \Longleftrightarrow y \succeq 0
> $$
>
> 称这种锥**自对偶**(*self-dual*)。
> **举例**&emsp;**半正定锥**。在 $n \times n$ 对称矩阵的集合 $\bfS^n$ 上,其标准内积 $\tr(XY) = \displaystyle\sum_{i,j=1}^{n} X_{ij}Y_{ij}$。半正定锥 $\bfS^n_+$ 是自对偶的,即对于任意的 $X,Y\in\bfS^n$
>
> $$
> \tr (XY) \geqslant 0,\ \forall X \succeq 0 \Longleftrightarrow Y \succeq 0
> $$
>
> 下面说明这一结论。
>
> > **证明**&emsp;假设 $Y \notin \bfS^n_+$,那么存在 $q \in \bfR^n$ 并且
> >
> > $$
> > q^\TT Yq = \tr (qq^\TT Y) < 0
> > $$
> >
> > 于是半正定矩阵 $X = qq^\TT$ 满足 $\tr(XY) < 0$,由此可知 $Y \notin (\bfS^n_+)^\ast$。
> >
> > 假设 $X,Y\in\bfS^n_+$,可以利用特征值分解将 $X$ 表述为 $X = \displaystyle\sum_{i=1}^n \lambda_i q_i q_i^\TT$,其中(特征值)$\lambda_i \geqslant 0,\ i = 1,\cdots,n$。于是有
> >
> > $$
> > \tr (XY) = \tr \left( Y \sum_{i=1}^n \lambda_i q_i q_i^\TT \right) = \sum_{i=1}^n \lambda_i q^\TT Y q_i \geqslant 0
> > $$
> >
> > 以上表明 $Y \in (\bfS^n_+)^\ast$。
> **举例**&emsp;**范数锥的对偶**。令 $\|\cdot\|$ 为定义在 $\bfR^n$ 上的范数。与之相关的锥 $K = \{ (x,t) \in \bfR^{n+1}\mid \|x\|\leqslant t \}$ 的对偶锥由其对偶范数定义,
>
> $$
> K^\ast = \{(u,v) \in \bfR^{n+1}\mid \|u\|_\ast \leqslant v\}
> $$
>
> 这里的对偶范数由 $\|u\|_\ast = \sup\{u^\TT x\mid \| x \|\leqslant 1\}$ 给出。
>
> 为证明这个结论,我们需要说明
>
> $$\begin{equation}\label{DualOfNormCone}
> x^\TT u + tv \geqslant 0\ 只要\ \|x\|\leqslant t \Longleftrightarrow \|u\|_\ast \leqslant v
> \end{equation}$$
>
> > **证明**&emsp;首先,证明由右端关于 $(u,v)$ 的条件可以得出左端的条件。设 $\|u\|_\ast \leqslant v$,并且对于一些 $t>0$ 有 $\|x\| \leqslant t$。(如果 $t = 0$,$x$ 必须是零,因此显然有 $u^\TT x + vt \geqslant 0$。)根据对偶锥的定义以及 $\|-x/t\|\leqslant 1$,我们有
> >
> > $$
> > u^\TT (-x/t) \leqslant \|u\|_\ast \leqslant v
> > $$
> >
> > 因此,$u^\TT x + vt \geqslant 0$。
> >
> > 其次,我们证明 $\eqref{DualOfNormCone}$ 左端的条件可以导出 $\eqref{DualOfNormCone}$ 右端的条件。假设 $\|u\|_\ast> v$,即右端不成立。那么,根据对偶锥的定义,存在 $x$ 满足 $\|x\|\leqslant 1$ 及 $x^\TT u > v$。取 $t=1$,我们有
> >
> > $$
> > u^\TT (-x) + v < 0
> > $$
> >
> > 这与 $\eqref{DualOfNormCone}$ 的左端相矛盾。
&emsp;&emsp;对偶锥满足一些性质,例如
- $K^\ast$ 是闭凸锥。
- $K_1 \subseteq K_2$ 可导出 $K_2^\ast \subseteq K_1^\ast$。
- 如果 $K$ 有非空内部,那么 $K^\ast$ 是尖的。
- 如果 $K$ 的闭包是尖的,那么 $K^\ast$ 有非空内部。
- $K^{\ast\ast}$ 是 $K$ 的凸包的闭包。(因此,如果 $K$ 是凸和闭的,则 $K^{\ast\ast} = K$。)这些性质表明如果 $K$ 是一个正常锥,那么它的对偶 $K^\ast$ 也是,进一步地,有 $K^{\ast\ast} = K$。
# 2. 广义不等式的对偶
&emsp;&emsp;现在假设凸锥 $K$ 是正常锥,因此它可以导出一个广义不等式 $\preceq_K$。其对偶锥 $K^\ast$ 也是正常的,所以也能导出一个广义不等式。我们称广义不等式立 $\preceq_{K^\ast}$ 为广义不等式 $\preceq_K$ 的**对偶**(*dual*)。
&emsp;&emsp;关于广义不等式及其对偶有一些重要的性质
- $x \preceq_K y$ 当且仅当对于任意 $\lambda \succeq_{K^\ast}$,有 $\lambda^\TT x \leqslant \lambda^\TT y$。
- $x \prec_K y$ 当且仅当对于任意 $\lambda \succeq_{K^\ast}$ 和 $\lambda\ne 0$,有 $\lambda^\TT T x < \lambda^\TT y$。
&emsp;&emsp;因为 $K = K^{\ast\ast}$,与 $\preceq_{K^\ast}$ 相关的对偶广义不等式为 $\preceq_{K}$,因此交换广义不等式及其对偶后,这些性质依然成立。作为一个具体的例子,我们可知 $\lambda\preceq_{K^\ast} \mu$ 的充要条件是对于所有 $x \succeq_K 0$ 有 $\lambda^\TT x \leqslant \mu^\TT x$。
> **举例**&emsp;**线性严格广义不等式的择一定理**。设 $K \subseteq \bfR^m$ 为正常锥。考虑严格广义不等式
>
> $$\begin{equation}\label{StrictGeneralInequality}
> Ax \prec_K b
> \end{equation}$$
>
> 其中 $x \in \bfR^n$
>
> 下面推导对于这个不等式的择一定理。假设它是不可行的,即仿射集合 $\{b-Ax\mid x\in\bfR^n\}$ 与开凸集 $\iint K$ 不相交。那么存在一个分离超平面,即非零的 $\lambda\in\bfR^m$ 和 $\mu\in \bfR$ 使得对于任意 $x$ 有灯 $\lambda^\TT(b-Ax) \leqslant \mu$,对于任意 $y \in \iint K$ 有 $\lambda^\TT y \geqslant \mu$。第一个条件表明 $A^\TT \lambda = 0$ 及 $\lambda^\TT b \leqslant \mu$。第二个条件表明对于任意 $y\in K$ 有 $\lambda^\TT y \geqslant \mu$,这种情况仅当 $\lambda \in K^\ast$ 和 $\mu \leqslant 0$ 时才可能发生。
>
> 综上,我们可知当 $\eqref{StrictGeneralInequality}$ 不可行时,存在 $\lambda$ 使得
>
> $$\begin{equation}\label{StrictGeneralInequalityInfeasible}
> \lambda \ne 0,\qquad \lambda \preceq_{K^\ast} 0,\qquad A^\TT \lambda = 0,\qquad \lambda^\TT b \leqslant 0
> \end{equation}$$
>
> 现在我们证明反方向,即如果 $\eqref{StrictGeneralInequalityInfeasible}$ 成立,那么,不等式组 $\eqref{StrictGeneralInequality}$ 不可能可行。假设不等式均成立,因为 $\lambda\ne 0$,$\lambda \succeq_{K^\ast}$ 及 $b - Ax \succ_K 0$,我们有 $\lambda^\TT (b-Ax)>0$。但是根据 $A^\TT \lambda = 0$,我们可以找到 $\lambda^\TT (b-Ax) = \lambda^\TT b \leqslant 0$,而这是一个矛盾。
>
> 因此,不等式组 $\eqref{StrictGeneralInequality}$ 和 $\eqref{StrictGeneralInequalityInfeasible}$ 构成一对择一:对于任意 $A, b$,它们中仅有一个是可行的。(这是严格线性不等式的择一定理的推广;严格线性不等式的择一定理是 $K = \bfR^m_+$ 时的特殊情况。)
# 3. 对偶不等式定义的最小元和极小元
&emsp;&emsp;可以利用对偶广义不等式来刻画集合 $S\subseteq\mathbf{R}^m$(可能非凸)关于正常锥 $K$ 导出的广义不等式的最小元和极小元。
## 3.1 最小元的对偶性质
&emsp;&emsp;首先考虑**最小**(*minimum*)元的性质。$x$ 是 $S$ 上关于广义不等式 $\preceq _K$ 的最小元的充要条件是,对于所有 $\lambda\succ_{K^*}0$,$x$ 是在 $z\in S$ 上极小化 $\lambda^\TT z$ 的唯一最优解。几何上看,这意味着对于任意 $\lambda\succ_{K^*}0$,超平面
$$
\{z\mid \lambda^\TT (z-x)=0\}
$$
是在 $x$ 处对 $S$ 的一个严格支撑超平面。(用严格支撑超平面表明这个超平面与 $S$ 只相交于 $x$。)注意此处并不要求 $S$ 是凸集。这可由[图 23](#图23)来表示。
<a id="图23"></a>
![图 23. 最小元的对偶性质。点 $x$ 是集合 $S$ 中关于 $\mathbf{R}_+^2$ 的极小元。这等价于:对于任意 $\lambda\succ0$,超平面 $\{z\mid\lambda^\TT (z-x)=0\}$ 在 $x$ 处对 $S$ 严格支撑,即在超平面的一边包含了 $S$,并只在 $x$ 处与 $S$ 接触。](../images/post/2024-06-13-josh-cvx-1-6/2024-06-13-josh-cvx-1-6-230-DualCharacterizationOfMinimumElement.png){width=400px}
&emsp;&emsp;为说明这个结论,设 $x$ 是 $S$ 的最小元,即对于任意 $z\in S$ 有 $x\preceq_Kz$,同时,令 $\lambda\succ_{K^*} 0$,而$z\in S$,$z\neq x$。因为 $x$ 是 $S$ 上的最小元,所以有 $z-x\succeq_K0$。根据 $\lambda\succ_{K^*}0$ 及 $z-x\succeq_K0$,$z-x\neq0$,可以得到 $\lambda^\TT (z-x)>0$。因为 $z$ 是 $S$ 上任意一个不等于 $x$ 的元素,所以 $x$ 是在 $z\in S$ 上极小化 $\lambda^\TT z$ 的唯一解。反之,假设对于所有 $\lambda\succ_{K^*}0$,$x$ 是 $z\in S$ 上极小化 $\lambda^\TT z$ 的唯一解,但 $x$ 不是 $S$ 的最小元。那么存在 $z\in S$ 满足 $z\nsucceq_Kx$。因为 $z-x\nsucceq_K0$,存在 $\tilde{\lambda}\succeq_{K^*} 0$ 并且 $\tilde{\lambda}^\TT(z-x)<0$。因此,对于 $\lambda\succ_{K^*} 0$,在 $\tilde{\lambda}$ 的邻域内有 $\lambda^\TT (z-x)<0$。这与 $x$ 是 $S$ 上极小化 $\lambda^\TT z$ 的唯一解相矛盾。
## 3.2 极小元的对偶性质
&emsp;&emsp;现在讨论**极小**(*minimal*)元的类似性质。此时,在必要和充分条件间存在一定的间隙。如果 $\lambda\succ_{K^*} 0$ 并且 $x$ 在 $z\in S$ 上极小化 $\lambda^\TT z$,那么 $x$ 是极小的,如[图 24](#图24)所示。
<a id="图24"></a>
![图 24. 集合 $S\subseteq\mathbf{R}^2$。其关于 $\mathbf{R}_+^2$ 的极小点集合由其边界的(左下)深色部分所示。$S$ 上极小化 $\lambda_1^\TT z$ 的解为 $x_1$,因为 $\lambda_1\succ0$,所以 $x_1$ 是极小的。$S$ 上极小化 $\lambda_2^\TT z$ 的解为 $x_2$,因为 $\lambda_2\succ0$,所以它是 $S$ 的另一个极小点。](../images/post/2024-06-13-josh-cvx-1-6/2024-06-13-josh-cvx-1-6-240-ASetAndItsSetOfMinimalPoints.png){width=400px}
> **证明**&emsp;假设 $\lambda\succ_{K^*} 0$ 并且 $x$ 在 $S$ 上极小化 $\lambda^\TT z$,但 $x$ 不是极小元,即存在 $z\in S$ 满足 $z\neq x$,$z\preceq_Kx$。那么 $\lambda^\TT (x-z)>0$,这与我们的假设,即 $x$ 在 $S$ 上极小化了 $\lambda^\TT z$,相矛盾。
&emsp;&emsp;其逆命题在一般情况下不成立:$S$ 上的极小元 $x$ 可以对于任何 $\lambda$ 都不是 $z\in S$ 上极小化 $\lambda^\TT z$ 的解,如[图 25](#图25)所示。此图表明了凸性在这个逆定理中的重要作用,当凸性成立时,逆定理是成立的。假设集合 $S$ 是凸集,可以说对于任意极小元 $x$,存在非零的 $\lambda\succeq_{K^*} 0$ 使得 $x$ 在 $z\in S$ 上极小化 $\lambda^\TT z$。
<a id="图25"></a>
![图 25. 点 $x$ 是 $S\subseteq\mathbf{R}^2$ 关于 $\mathbf{R}_+^2$ 的极小元。但是,不存在 $\lambda$,使得 $x$ 在 $z\in S$ 上极小化 $\lambda^\TT z$](../images/post/2024-06-13-josh-cvx-1-6/2024-06-13-josh-cvx-1-6-250-MinimalElement.png){width=350px}
> **证明**&emsp;假设 $x$ 是极小的,也就是说 $((x-K)\setminus\{x\})\cap S=\emptyset$。对凸集 $(x-K)\setminus\{x\}$ 和 $S$ 应用超平面分离定理,可以得出:存在 $\lambda\neq0$ 和 $\mu$,使得对于所有 $y\in K$ 有 $\lambda^\TT (x-y)\leqslant\mu$,对于所有 $z\in S$ 有 $\lambda^\TT z\geqslant\mu$。根据第一个不等式,可知 $\lambda\succeq_{K^*} 0$。由于 $x\in S$ 和 $x\in x-K$,所以有 $\lambda^\TT x=\mu$,所以第二个不等式表明 $\mu$ 是 $S$ 上 $\lambda^\TT z$ 的最小值。因此,$x$ 是 $S$ 上极小化 $\lambda^\TT z$ 的一个解,这里 $\lambda\neq0$,$\lambda\succeq_{K^*}0$。
&emsp;&emsp;这个逆定理无法加强为 $\lambda\succ_{K^*} 0$。反例表明,凸集 $S$ 上的极小元 $x$,可以对于任意 $\lambda\succ_{K^*}0$,都不是 $z\in S$ 中极小化 $\lambda ^\TT z$ 的解(参见[图 26,左图](#图26))。同时,并不是对于任意 $\lambda\succeq_{K^*} 0$,在 $z\in S$ 上极小化 $\lambda^\TT z$ 的解都一定是极小的(参见[图 26,左图](#右26))。
<a id="图26"></a>
![图 26. **左**:点 $x_1\in S_1$ 是极小的,但对于任意 $\lambda\succ0$,它都没有在 $S_1$ 上极小化 $\lambda^\TT z$。(但是,对于 $\lambda=(1,0)$,它确实在所有 $z\in S_1$中极小化了$\lambda^\TT z$。)**右**:点 $x_2\in S_2$ 不是极小的,但对于 $\lambda=(0,1)\succeq0$,它确实在所有 $z\in S_2$ 中极小化了$\lambda^\TT z$。](../images/post/2024-06-13-josh-cvx-1-6/2024-06-13-josh-cvx-1-6-260-MinimalAndMinimizer.png){width=700px}
# 参考文献
1. Stephen P. Boyd and Lieven Vandenberghe, *Convex optimization*. Cambridge, UK: Cambridge University Press, 2004.
2. Stephen P. Boyd and Lieven Vandenberghe, *凸优化*. 北京: 清华大学出版社, 2013.
+569
View File
@@ -0,0 +1,569 @@
---
title: Josh's Note — 凸优化<br>Part 2.1 凸函数—基本性质和例子
mathjax: true
comments: true
copyright: true
toc:
enable: true
number: false
wrap: true
expand_all: true
max_depth: 4
categories:
- - Josh 的学习笔记
- 凸优化
- 凸函数
- - 数学
- 凸优化
tags:
- 凸优化
- 凸函数
abbrlink: 320f661c
date: 2024-06-14 20:29:26
---
# 1. 定义
$
\newcommand{\TT}{\mathrm{T}}
\newcommand{\dd}{\mathrm{d}}
\def\dom{\mathop{\bf dom}}
\def\diag{\mathop{\bf diag}}
\def\epi{\mathop{\bf epi}}
\def\hypo{\mathop{\bf hypo}}
\def\prob{\mathop{\bf prob}}
$&emsp;&emsp;函数 $f:\mathbf{R}^n\to\mathbf{R}$ 是**凸**(*Convex*)的,若 $\dom f$ 是凸集,且对于任意 $x,y\in\dom f$ 和任意 $0\leqslant\theta\leqslant1$,有
$$\begin{equation}\label{DefinitionOfConvexFunction}
f(\theta x+(1-\theta)y)\leqslant\theta f(x)+(1-\theta)f(y)
\end{equation}$$
&emsp;&emsp;从几何意义上看,上述不等式意味着点 $(x,f(x))$ 和 $(y,f(y))$ 之间的线段,即从 $x$ 到 $y$ 的**弦**(*chord*),在函数 $f$ 的图像上方(如[图 1](#图1)所示)。称函数 $f$ 是**严格凸**(*strictly convex*)的,若式 $\eqref{DefinitionOfConvexFunction}$ 中的不等式当 $x\neq y$ 以及 $0<\theta<1$ 时严格成立。称函数 $f$ 是**凹**(*concave*)的,若函数 $-f$ 是凸的;称函数 $f$ 是**严格凹**(*strictly concave*)的,若 $-f$ 严格凸。
<a id="图1"></a>
![图 1. 凸函数示意图。图上任意两点之间的弦(即线段)都在函数图像之上。](../images/post/2024-06-14-josh-cvx-2-1/2024-06-14-josh-cvx-2-1-010-ConvexFunction.png){width=400px}
<!-- more -->
&emsp;&emsp;对于仿射函数,式 $\eqref{DefinitionOfConvexFunction}$ 始终可以取等号,因此所有的[仿射函数][](包括线性函数)是既凸且凹的。反之,若某个函数是既凸又凹的,则其是仿射函数。
&emsp;&emsp;函数是凸的,当且仅当其在与其定义域相交的任何直线上都是凸的。换言之,函数 $f$ 是凸的,当且仅当对于任意 $x\in\dom f$ 和任意向量 $v$,函数 $g(t)=f(x+tv)$ 是凸的(其定义域为 $\{t\mid x+tv\in\dom f\}$)。这个性质非常有用,因为它让我们可以通过将函数限制在直线上来判断其是否是凸函数。
{% note info 注解 %}
这里可能是由于翻译问题导致不是很好理解,我们先看原文:
> A function is convex if and only if it is convex when restricted to any line that
intersects its domain. In other words $f$ is convex if and only if for all $x\in\mathbf{dom}\, f$ and all $v$, the function $g(t) = f(x + tv)$ is convex (on its domain, $\{t\mid x+tv\in\mathbf{dom}\, f\}$). This property is very useful, since it allows us to check whether a function is convex by restricting it to a line.
仍然不是很好理解。因此询问 ChatGPT 得到如下解释:
- 限制在直线上:考虑一个函数 $f$ 和其定义域内的任意一点 $x$。再选择一个任意方向向量 $v$。我们沿着这个方向 $v$ 从点 $x$ 出发,得到一条直线。任何点 $x+tv$(其中 $t$ 是一个实数)都在这条直线上。这就叫做将函数限制在直线上。
- 直线上的函数:我们定义一个新的函数 $g(t)=f(x+tv)$。这个新的函数 $g(t)$ 表示原函数 $f$ 在直线 $x+tv$ 上的值。
- 检查凸性:若对于任意 $x$ 和 $v$,新的函数 $g(t)$ 是凸的,则我们就说原函数 $f$ 是凸的。也就是说,若 $f$ 在所有限制的直线上都是凸的,则 $f$ 本身就是凸的。
通过限制在直线上,我们将原来的多变量问题简化为单变量问题。对于单变量函数,判断凸性要比多变量情况简单得多。这使得我们可以用更简单的方法来判断一个函数是否是凸的。
> **举例**&emsp;假设我们有一个二次函数 $f(x)=x_1^2+x_2^2$。我们选一个点 $x=(a,b)$ 和一个方向 $v=(c,d)$,沿着这个方向得到直线 $(a,b)+t(c,d)$,然后我们可以定义一个新函数:
>
> $$
> g(t)=f((a,b)+t(c,d))=f(a+tc,b+td)=(a+tc)^2+(b+td)^2
> $$
>
> 我们需要检查这个新函数 $g(t)$ 是否是凸的。若对所有 $x$ 和 $v$ 新函数 $g(t)$ 都是凸的,则原函数 $f$ 就是凸的。在这个例子中,显然 $g(t)=(a+tc)^2+(b+td)^2$ 是一个关于 $t$ 的二次函数,它是凸的。因此,原函数 $f(x)=x_1^2+x_2^2$ 是凸的。
总的来说,"将函数限制在直线上"意味着通过沿着任意方向取直线来简化判断多变量函数的凸性,从而可以更方便地确定函数的整体凸性。
{% endnote %}
&emsp;&emsp;对凸函数的**分析**(*analysis*)已经相当地透彻,这里不再继续深入。例如有这样一个简单的结论,凸函数在其定义域相对内部是连续的;它只可能在相对边界上不连续。
# 2. 扩展值延伸
&emsp;&emsp;通常可以定义凸函数在定义域外的值为 $\infty$,从而将这个凸函数延伸至全空间 $\mathbf{R}^n$。若 $f$ 是凸函数,我们定义它的**扩展值延伸**(*extended-value extension*)$\tilde{f}:\mathbf{R}^n\to\mathbf{R}\cup\{\infty\}$ 如下
$$
\tilde{f}(x)=\begin{cases}
f(x)&x\in\textbf{dom}f\\\infty&x\not\in\textbf{dom}f
\end{cases}
$$
延伸函数 $\tilde{f}$ 是定义在全空间 $\mathbf{R}^n$ 上的,取值集合为 $\mathbf{R}\cup\{\infty\}$。我们也可以从延伸函数 $\tilde{f}$ 的定义中确定原函数 $f$ 的定义域,即 $\dom f=\{x\mid\tilde{f}(x)<\infty\}$。
&emsp;&emsp;这种延伸可以简化符号描述,此时我们就不需要明确描述定义域或者每次提到 $f(x)$ 时都限定“对于所有的 $x\in\dom f$”。以基本不等式 $\eqref{DefinitionOfConvexFunction}$ 为例,对于延伸函数 $\tilde{f}$,可以描述为:对于**任意**(*any*)$x$ 和 $y$,以及 $0<\theta<1$,有
$$
\tilde{f}(\theta x+(1-\theta)y)\leqslant\theta\tilde{f}(x)+(1-\theta)\tilde{f}(y)
$$
(当 $\theta=0$ 或 $\theta=1$ 时不等式总成立。)当然此时应当利用扩展运算和扩展序来理解这个不等式。
- 若 $x$ 和 $y$ 在 $\dom f$ 内,上述不等式即为不等式 $\eqref{DefinitionOfConvexFunction}$;
- 若 $x$ 或 $y$ 在 $\dom f$ 外,上述不等式的右端为 $\infty$,不等式仍然成立。
> **举例**&emsp;设 $f_1$ 和 $f_2$ 是 $\mathbf{R}^n$ 上的两个凸函数。逐点和函数 $f=f_1+f_2$ 的定义域为 $\dom f=\dom f_1\cap\dom f_2$,对于任意 $x\in\dom f$,有 $f(x)=f_1(x)+f_2(x)$。利用扩展值延伸我们可以简单地描述为,对于任意 $x$,$\tilde{f}(x)=\tilde{f}_1(x)+\tilde{f}_2(x)$。在这个方程里,函数 $f$ 的定义域被自动定义为 $\dom f=\dom f_1\cap\dom f_2$,因为当 $x\not\in\dom f_1$ 或者 $x\not\in\dom f_2$ 时,$\tilde{f}(x)=\infty$。在此例中,我们就可以利用扩展运算来自动定义定义域。
&emsp;&emsp;在不会造成歧义的情况下,可以用同样的符号来表示一个凸函数及其延伸函数。即假设所有的凸函数都隐含地被延伸了,也就是在定义域外都被定义为 $\infty$。
> **举例**&emsp;**凸集的示性函数**。设 $C\subseteq\mathbf{R}^n$ 是一个凸集,考虑(凸)函数 $I_C$,其定义域为 $C$,对于所有的 $x\in C$,有 $I_C(x)=0$。换言之,此函数在集合 $C$ 上一直为零。其扩展值延伸可以描述如下
>
> $$
> \tilde{I}_C(x)=\begin{cases}0&x\in C\\\infty&x\not\in C.\end{cases}
> $$
>
> 凸函数 $\tilde{I}_C$ 被称作集合 $C$ 的**示性函数**(*indicator function*)。
>
> 利用示性函数 $\tilde{I}_C$,可以更加灵活地定义符号描述。例如,对于在集合 $C$ 上极小化函数 $f$ 的问题(假设 $f$ 定义在整个 $\mathbf{R}^n$ 空间),可以给出等价的问题,即在 $\mathbf{R}^n$ 上极小化函数 $f+\tilde{I}_C$。事实上,按照不会造成歧义的约定,函数 $f+\tilde{I}_C$ 等价于定义在集合 $C$ 上的函数 $f$。
&emsp;&emsp;类似地,可以通过定义凹函数在定义域外都为 $-\infty$ 对其进行延伸。
# 3. 一阶条件
&emsp;&emsp;假设 $f$ 可微(即其梯度 $\nabla f$ 在开集 $\dom f$ 内处处存在),则函数 $f$ 是凸函数的充要条件是 $\dom f$ 是凸集且对于任意 $x,y\in\dom f$,下式成立
$$\begin{equation}\label{FirstOrderCondition}
f(y)\geqslant f(x)+\nabla f(x)^\TT (y-x)
\end{equation}$$
[图 2](#图2) 描述了上述不等式,也即沿函数上任意一点作切线,函数始终位于切线上方。
<a id="图2"></a>
![图 2. 若函数 $f$ 是凸的且可微,则对于任意 $x,y\in\dom f$,有 $f(x)+\nabla f(x)^\TT(y-x)\leqslant f( y)$。](../images/post/2024-06-14-josh-cvx-2-1/2024-06-14-josh-cvx-2-1-020-FirstOrderCondition.png){width=500px}
&emsp;&emsp;由 $f(x)+\nabla f(x)^\TT (y-x)$ 得出的仿射函数 $y$ 即为函数 $f$ 在点 $x$ 附近的 Taylor 近似。不等式 $\eqref{FirstOrderCondition}$ 表明,对于一个凸函数,其一阶 Taylor 近似实质上是原函数的一个**全局下估计**(*global underestimator*)。反之,若某个函数的一阶 Taylor 近似总是其全局下估计,则这个函数是凸的。
&emsp;&emsp;不等式 $\eqref{FirstOrderCondition}$ 说明从一个凸函数的**局部信息**(*local information*)(即它在某点的函数值及导数),可以得到一些**全局信息**(*global information*)(如它的全局下估计)。这也许是凸函数的最重要的信息,由此可以解释凸函数以及凸优化问题的一些非常重要的性质。
> **举例**&emsp;由不等式 $\eqref{FirstOrderCondition}$ 可以知道,若 $\nabla f(x)=0$,则对于所有的 $y\in\dom f$,存在 $f(y)\geqslant f(x)$,即 $x$ 是函数 $f$ 的全局极小点。
&emsp;&emsp;严格凸性同样可以由一阶条件刻画:函数 $f$ 严格凸的充要条件是 $\dom f$ 是凸集且对于任意 $x,y\in\dom f$,$x\neq y$,有
$$\begin{equation}\label{StrictFirstOrderCondition}
f(y)>f(x)+\nabla f(x)^\TT (y-x)
\end{equation}$$
&emsp;&emsp;对于凹函数,亦存在与之对应的一阶条件:函数 $f$ 是凹函数的充要条件是 $\dom f$ 是凸集且对于任意 $x,y\in\dom f$,下式成立
$$
f(y)\leqslant f(x)+\nabla f(x)^\TT (y-x)
$$
## 3.1 一阶凸性条件的证明
&emsp;&emsp;为了证明式 $\eqref{FirstOrderCondition}$,先考虑 $n=1$ 的情况:我们证明可微函数 $f:\mathbf{R}\to\mathbf{R}$ 是凸函数的充要条件是对于 $\dom f$ 内的任意 $x$ 和 $y$,有
$$\begin{equation}\label{FirstOrderConditionWhenNEquals1}
f(y)\geqslant f(x)+f'(x)(y-x)
\end{equation}$$
&emsp;&emsp;首先证明必要性。假设 $f$ 是凸函数,且 $x,y\in\dom f$。因为 $\dom f$ 是凸集(某个区间),对于任意 $0<t\leqslant1$,我们有 $x+t(y-x)\in\dom f$,由函数 $f$ 的凸性可得
$$
f(x+t(y-x))\leqslant(1-t)f(x)+tf(y)
$$
将上式两端同除 $t$ 可得
$$
f(y)\geqslant f(x)+\frac{f(x+t(y-x))-f(x)}{t}
$$
令 $t\to 0$,可以得到不等式 $\eqref{FirstOrderConditionWhenNEquals1}$。
&emsp;&emsp;为了证明充分性,假设对 $\dom f$(某个区间)内的任意 $x$ 和 $y$,函数满足不等式 $\eqref{FirstOrderConditionWhenNEquals1}$。选择任意 $x\neq y$,$0\leqslant\theta\leqslant1$,令 $z=\theta x+(1-\theta)y$。两次应用不等式 $\eqref{FirstOrderConditionWhenNEquals1}$ 可得
$$
f(x)\geqslant f(z)+f'(z)(x-z),\quad f(y)\geqslant f(z)+f'(z)(y-z)
$$
将第一个不等式乘以 $\theta$,第二个不等式乘以 $1-\theta$,并将二者相加可得
$$
\theta f(x)+(1-\theta)f(y)\geqslant f(z)
$$
从而说明了函数 $f$ 是凸的。
&emsp;&emsp;现在来证明一般情况,即 $f:\mathbf{R}^n\to\mathbf{R}$。设 $x,y\in\mathbf{R}^n$,考虑过这两点的直线上的函数 $f$,即函数 $g(t)=f(ty+(1-t)x)$,此函数对 $t$ 求导可得 $g'(t)=\nabla f(ty+(1-t)x)^\TT(y-x)$。
&emsp;&emsp;首先假设函数 $f$ 是凸的,则函数 $g$ 是凸的,由前面的讨论可得 $g(1)\geqslant g(0)+g'(0)$,即
$$
f(y)\geqslant f(x)+\nabla f(x)^\TT (y-x)
$$
再假设此不等式对于任意 $x$ 和 $y$ 均成立,因此若 $ty+(1-t)x\in\dom f$ 以及 $\tilde{t}y+(1-\tilde{t})x\in\dom f$,有
$$
f(ty+(1-t)x)\geqslant f(\tilde{t}y+(1-\tilde{t})x)+\nabla f(\tilde{t}y+(1-\tilde{t})x)^\TT (y-x)(t-\tilde{t})
$$
即 $g(t)\geqslant g(\tilde{t})+g'(\tilde{t})(t-\tilde{t})$,说明了函数 $g$ 是凸的。
# 4 二阶条件
&emsp;&emsp;现在假设函数 $f$ 二阶可微,即对于开集 $\dom f$ 内的任意一点,它的 **Hessian 矩阵**或者二阶导数 $\nabla^2f$ 存在,则函数 $f$ 是凸函数的充要条件是,其 Hessian 矩阵是半正定阵:即对于所有的 $x\in\dom f$,有
$$
\nabla^2f(x)\succeq0
$$
对于 $\mathbf{R}$ 上的函数,上式可以简化为一个简单的条件 $f''(x)\geqslant0$($\dom f$ 是凸的,即一个区间),此条件说明函数 $f$ 的导数是非减的。条件 $\nabla^2f(x)\succeq0$ 从几何上可以理解为函数图像在点 $x$ 处具有正(向上)的曲率。
&emsp;&emsp;类似地,函数 $f$ 是凹函数的充要条件是,$\dom f$ 是凸集且对于任意 $x\in$ $\dom f$,$\nabla ^{2}f( x)$ $\preceq$ 0。严格凸的条件可以部分由二阶条件刻画。若对于任意的 $x\in\dom f$ 有 $\nabla^2f(x)\succ0$,则函数 $f$ 严格凸。反过来则不一定成立:例如,函数 $f:\mathbf{R}\to\mathbf{R}$,其表达式为 $f(x)=x^4$,它是严格凸的,但是在 $x=0$ 处,二阶导数为零。
> **举例**&emsp;**二次函数**。考虑二次函数 $f:\mathbf{R}^n\to\mathbf{R}$,其定义域为 $\dom f=\mathbf{R}^n$,其表达式为
>
> $$
> f(x)=(1/2)x^\TT Px+q^\TT x+r
> $$
>
> 其中 $P\in\mathbf{S}^{n}$,$q\in\mathbf{R}^{n}$,$r\in\mathbf{R}$。因为对于任意 $x$,$\nabla^2f(x)=P$,所以函数 $f$ 是凸的,当且仅当 $P\succeq0$($f$ 是凹的当且仅当 $P\preceq0$)。
>
> 对于二次函数,严格凸比较容易表达:函数 $f$ 是严格凸的,当且仅当 $P\succ0$(函数是严格凹的当且仅当 $P\prec0$)。
> **注释**&emsp;在判断函数的凸性和凹性时,不管是一阶条件还是二阶条件,$\dom f$ 必须是凸集这个前提条件必须满足。例如,考虑函数 $f(x)=1/x^2$,其定义域为 $\dom f=\{x\in$ $\mathbf{R}\mid x\neq0\}$,对于所有 $x\in\dom f$ 均满足 $f''(x)>0$,但是函数 $f(x)$ 并不是凸函数。
# 5. 例子
&emsp;&emsp;前文已经提到所有的线性函数和仿射函数均为凸函数(同时也是凹函数),并描述了凸和凹的二次函数。本节绘出更多的凸函数和凹函数的例子。
## $\mathbf{R}$ 上的例子
&emsp;&emsp;首先考虑 $\mathbf{R}$ 上的一些函数,其自变量为 $x$。
- **指数函数**(*Exponential*)。对任意 $a\in\mathbf{R}$,函数 $e^{ax}$ 在 $\mathbf{R}$ 上是凸的。
- **幂函数**(*Power*)。当 $a\geqslant1$ 或 $a\leqslant0$ 时,$x^a$ 在 $\mathbf{R}_{++}$ 上是凸函数;当 $0\leqslant a\leqslant1$ 时,$x^a$ 在 $\mathbf{R}_{++}$ 上是凹函数。
- **绝对值幂函数**(*Power of absolute value*)。当 $p\geqslant1$ 时,函数 $|x|^p$ 在 $\mathbf{R}$ 上是凸函数。
- **对数函数**(*Logarithm*)。函数 $\log x$ 在 $\mathbf{R}_{++}$ 上是凹函数。
- **负熵**(*Negative entropy*)。函数 $x\log x$ 在其定义域上是凸函数。(定义域为 $\mathbf{R}_{++}$ 或者 $\mathbf{R}_+$,当 $x=0$ 时定义函数值为 0。)
&emsp;&emsp;我们可以通过基本不等式 $\eqref{DefinitionOfConvexFunction}$ 或者二阶导数半正定或半负定来判断上述函数是凸的或是凹的。以函数 $f(x)=x\log x$ 为例,其导数和二阶导数为
$$
f'(x)=\log x+1,\quad f''(x)=1/x
$$
即对于 $x>0$,有 $f''(x)>0$。所以负熵函数是(严格)凸的。
## $\mathbf{R}^n$ 上的例子
&emsp;&emsp;下面给出 $\mathbf{R}^n$ 上的一些例子。
**范数**(*Norm*)。 $\mathbf{R}^n$ 上的任意范数均为凸函数。
**最大值函数**(*Max function*)。函数 $f(x)=\max\{x_1,\cdots,x_n\}$ 在 $\mathbf{R}^n$ 上是凸的。
**二次-线性分式函数**(*Quadratic-over-linear function*)。函数 $f(x,y)=x^2/y$,其定义域为
$$
\dom f= \mathbf{R} \times \mathbf{R} _{+ + }= \{ ( x, y) \in \mathbf{R} ^{2}\mid y> 0\}
$$
是凸函数(如[图 3](#图3)所示)。
<a id="图3"></a>
![图 3. 函数 $f(x, y) = x^2/y$ 的图像。](../images/post/2024-06-14-josh-cvx-2-1/2024-06-14-josh-cvx-2-1-030-QuadraticOverLinearFunction.png){width=400px}
**指数和的对数**(*Log-sum-exp*)。函数 $f(x)=\log\left(e^{x_1}+\cdots+e^{x_n}\right)$ 在 $\mathbf{R}^n$上是凸函数。这个函数可以看成最大值函数的可微(实际上是解析)近似,因为对任意 $x$,下面的不等式成立
$$
\max\{x_{1},\cdots,x_{n}\}\leqslant f(x)\leqslant\max\{x_{1},\cdots,x_{n}\}+\log n
$$
(第二个不等式当 $x$ 的所有分量都相等时是紧的。)[图 4](#图4) 描述了当 $n=2$ 时 $f$ 的图像。
<a id="图4"></a>
![图 4. 函数 $f(x, y) = log(e^x + e^y)$ 的图像。](../images/post/2024-06-14-josh-cvx-2-1/2024-06-14-josh-cvx-2-1-040-LogSumExo.png){width=400px}
**几何平均**(*Geometric mean*)。几何平均函数$f(x)=\left(\displaystyle\prod_{i=1}^n x_i\right)^{1/n}$在定义域 $\dom f=\mathbf{R}_{++}^n$ 上是凹函数。
**对数-行列式**(*Log-determinant*)。函数 $f(X)=\log\det X$ 在定义域 $\dom f=\mathbf{S}_{++}^n$ 上是凹函数。
&emsp;&emsp;判断上述函数的凸性(或者凹性)可以有多种途径,可以直接验证不等式 $\eqref{DefinitionOfConvexFunction}$ 是否成立,亦可以验证其 Hessian 矩阵是否半正定,或者可以将函数转换到与其定义域相交的任意直线上,通过得到的单变量函数判断原函数的凸性。
**范数**。若函数 $f:\mathbf{R}^n\to\mathbf{R}$ 是范数,任取 $0\leqslant\theta\leqslant1$,有
$$
f(\theta x+(1-\theta)y)\leqslant f(\theta x)+f((1-\theta)y)=\theta f(x)+(1-\theta)f(y)
$$
上述不等式可以由三角不等式得到,当范数满足齐次性时,上述不等式取等号。
**最大值函数**。对任意 $0\leqslant\theta\leqslant1$,函数 $f(x)=\displaystyle\max_i x_i$ 满足
$$\begin{aligned}
f(\theta x+(1-\theta)y)&=\max_{i}(\theta x_{i}+(1-\theta)y_{i})
\\
&\leqslant\theta\max_{i}x_{i}+(1-\theta)\max_{i}y_{i}
\\
&=\theta f(x)+(1-\theta)f(y)
\end{aligned}$$
**二次线性分式函数**。为了说明二次-线性分式函数 $f( x, y) = x^2/ y$ 是凸的,我们注意到,对于 $y>0$,有
$$
\nabla^2f(x,y)=\dfrac{2}{y^3}\left[\begin{array}{cc}
y^2&-xy\\-xy&x^2
\end{array}\right]=\dfrac{2}{y^3}\left[\begin{array}{c}
y\\-x
\end{array}\right]\left[\begin{array}{c}
y\\-x
\end{array}\right]^\TT \succeq0
$$
**指数和的对数**。指数和的对数函数的 Hessian 矩阵为
$$
\nabla^{2}f(x)=\frac{1}{(\mathbf{1}^\TT z)^{2}}\left((\mathbf{1}^\TT z)\diag(z)-zz^\TT\right)
$$
其中 $z=(e^{x_1},\cdots,e^{x_n})$。为了说明 $\nabla^2f(x)\succeq0$,我们证明对任意 $v$,有 $v^\TT \nabla^2f(x)v\geqslant0$,即
$$
v^\TT \nabla^{2}f(x)v=\frac{1}{(\mathbf{1}^\TT z)^{2}}\left(\left(\sum_{i=1}^{n}z_{i}\right)\left(\sum_{i=1}^{n}v_{i}^{2}z_{i}\right)-\left(\sum_{i=1}^{n}v_{i}z_{i}\right)^{2}\right)\geqslant0
$$
上述不等式可以应用 Cauchy-Schwarz 不等式 $(a^\TT a)(b^\TT b)\geqslant(a^\TT b)^2$ 得到,此时向量 $a$ 和 $b$ 的分量为 $a_i= v_i\sqrt {z_i}$,$b_i= \sqrt {z_i}$。
**几何平均**。类似地,我们说明,几何平均函数 $f(x)=\left(\displaystyle\prod_{i=1}^nx_i\right)^{1/n}$ 在定义域 $\dom f=\mathbf{R}_{++}^{n}$上是凹的。其 Hessian 矩阵 $\nabla^2f(x)$ 可以通过下面两个式子给出
$$
\frac{\partial^{2}f(x)}{\partial x_{k}^{2}}=-(n-1)\frac{\left(\displaystyle\prod_{i=1}^{n}x_{i}\right)^{1/n}}{n^{2}x_{k}^{2}},\quad\frac{\partial^{2}f(x)}{\partial x_{k}\partial x_{l}}=\frac{\left(\displaystyle\prod_{i=1}^{n}x_{i}\right)^{1/n}}{n^{2}x_{k}x_{l}}\quad\forall\:k\neq l
$$
因此 $\nabla^2f(x)$ 具有如下表达式
$$\nabla^{2}f(x)=-\frac{\displaystyle\prod_{i=1}^{n}x_{i}^{1/n}}{n^{2}}\left(n \diag(1/x_{1}^{2},\cdots,1/x_{n}^{2})-qq^\TT\right)
$$
其中,$q_i=1/x_i$。我们需要证明 $\nabla^2f(x)\preceq0$,即对于任意向量 $v$,有
$$
v^\TT \nabla^2f(x)v=-\frac{\displaystyle\prod_{i=1}^nx_i^{1/n}}{n^2}\left(n\sum_{i=1}^nv_i^2/x_i^2-\left(\sum_{i=1}^nv_i/x_i\right)^2\right)\leqslant0
$$
这同样可以应用 Cauchy-Schwarz 不等式 $(a^\TT a)(b^\TT b)\geqslant(a^\TT b)^2$ 得到,只需令向量 $a=\mathbf{1}$,向量 $b$ 的分量 $b_i=v_i/x_i$。
**对数-行列式**。对于函数 $f(X)=\log\det X$,我们可以将其转化为任意直线上的单变量函数来验证它是凹的。令 $X=Z+tV$,其中 $Z,V\in\mathbf{S}^n$,定义 $g(t)=f(Z+tV)$,自变量 $t$ 满足 $Z+tV\succ0$。不失一般性,假设 $t=0$ 满足条件,即 $Z\succ0$。我们有
$$\begin{aligned}
g(t)&=\log\det(Z+tV)
\\
&=\log\det(Z^{1/2}(I+tZ^{-1/2}VZ^{-1/2})Z^{1/2})
\\
&=\sum_{i=1}^{n}\log(1+t\lambda_{i})+\log\det Z
\end{aligned}$$
其中 $\lambda_1,\cdots,\lambda_n$ 是矩阵 $Z^{-1/2}VZ^{-1/2}$ 的特征值。因此下式成立
$$
g'(t)=\sum_{i=1}^{n}\frac{\lambda_{i}}{1+t\lambda_{i}},\qquad g''(t)=-\sum_{i=1}^{n}\frac{\lambda_{i}^{2}}{(1+t\lambda_{i})^{2}}
$$
因为 $g''(t)\leqslant0$,函数 $f$ 是凹的。
# 6. 下水平集
&emsp;&emsp;函数 $f: \mathbf{R} ^{n}\to \mathbf{R}$ 的 **$\alpha$-下水平集**(*$\alpha$-sublevel set*)定义为
$$
C_{\alpha}=\{x\in\dom f\mid f(x)\leqslant\alpha\}
$$
对于任意 $\alpha$ 值,凸函数的下水平集仍然是凸集。证明可以由凸集的定义直接得到:若 $x,y\in C_{\alpha }$,则有 $f( x) \leqslant \alpha$,$f( y) \leqslant \alpha$,因此对于任意$0\leqslant\theta\leqslant1$,$f(\theta x+(1-\theta)y)\leqslant\alpha$,即 $\theta x+(1-\theta)y\in C_{\alpha}$。
&emsp;&emsp;反过来不一定正确:某个函数的所有下水平集都是凸集,但这个函数可能不是凸函数。例如,函数 $f(x)=-e^x$ 在 $\mathbf{R}$ 上不是凸函数(实质上,它是严格凹函数),但是其所有下水平集均为凸集。
&emsp;&emsp;若 $f$ 是凹函数,则由 $\{x\in\dom f\mid f(x)\geqslant\alpha\}$ 定义的 **$\alpha$-上水平集**(*$\alpha$-superlevel set*)也是凸集。下水平集的性质可以用来判断集合的凸性,若某个集合可以描述为一个凸函数的下水平集,或者一个凹函数的上水平集,则其是凸集。
> **举例**&emsp;对于 $x\in\mathbf{R}_+^n$,其几何平均和算术平均分别为
>
> $$
> G(x)=\left(\prod_{i=1}^{n}x_{i}\right)^{1/n},\qquad A(x)=\frac{1}{n}\sum_{i=1}^{n}x_{i}
> $$
>
> (在 $G$ 中,定义 $0^{1/n}=0$)。算术几何平均不等式为 $G(x)\leqslant A(x)$。
>
> 设 $0\leqslant\alpha\leqslant1$,考虑集合
>
> $$
> \{x\in\mathbf{R}_{+}^{n}\mid G(x)\geqslant\alpha A(x)\}
> $$
>
> 即使得几何平均至少大于等于算术平均的 $\alpha$ 倍的集合。此集合是凸集,因为它是凹函数 $G(x)=\alpha A(x)$ 的 $0$-上水平集。事实上,这个每合是正齐次的,因此它是凸锥
# 7. 上境图
&emsp;&emsp;函数 $f:\mathbf{R}^{n}\to\mathbf{R}$ 的图像定义为
$$
\{(x,f(x))\mid x\in\dom f\}
$$
它是 $\mathbf{R}^{n+1}$ 空间的子集。函数 $f:\mathbf{R}^n\to\mathbf{R}$ 的**上境图**(*epigraph*)定义为
$$
\epi f=\{(x,t)\mid x\in\dom f,f(x)\leqslant t\}
$$
它也是 $\mathbf{R}^{n+1}$ 空间的子集。(“Epi”是之上的意思,所以上境图的英文 epigraph 是“在函数图像之上”的意思。)[图 5](#图5)说明了上境图的定义。
<a id="图5"></a>
![图 5. 函数 $f$ 的上境图,见阴影部分。深颜色的下边界是函数 $f$ 的图像。](../images/post/2024-06-14-josh-cvx-2-1/2024-06-14-josh-cvx-2-1-050-EpigraphOfF.png){width=400px}
&emsp;&emsp;凸集和凸函数的联系可以通过上境图来建立:一个函数是凸函数,当且仅当其上境图是凸集。一个函数是凹函数,当且仅当其**亚图**(*hypograph*)
$$
\hypo f=\{(x,t)\mid t\leqslant f(x)\},
$$
是凸集。
> **举例**&emsp;**矩阵分式函数**。矩阵分式函数 $f:\mathbf{R}^n\times\mathbf{S}^n\to\mathbf{R}$
>
> $$
> f(x,Y)=x^\TT Y^{-1}x
> $$
>
> 在定义域 $\dom f=\mathbf{R}^n\times\mathbf{S}_{++}^n$ 上是凸的。(这实质上是定义域为 $\dom f=\mathbf{R}\times\mathbf{R}_{++}$ 的二次-线性分式函数 $f(x,y)=x^2/y$ 的一个扩展。)
>
> 一个简单的方式来验证矩阵分式函数 $f$ 的凸性是通过其上境图
>
> $$\begin{aligned}
> \epi f &= \left\{(x,Y,t)\mid Y\succ0,\ x^\TT Y^{-1}x\leqslant t\right\}
> \\
> &=\left\{(x,Y,t)\:\middle|\left[\begin{array}{cc}
> Y&x
> \\
> x^\TT&t
> \end{array}\right]\succeq0,\:Y\succ0\right\}
> \end{aligned}$$
>
> 并应用 Schur 补条件判断分块矩阵的半正定性。最后一个条件是关于 $(x,Y,t)$ 的线性矩阵不等式,因此 $\epi f$ 是凸集。
>
> 对于 $n=1$ 的特殊情况,矩阵分式函数简化为二次-线性分式函数 $x^2/y$,相应的线性矩阵不等式表示为
> $$
> \left[\begin{array}{cc}y&x\\x&t\end{array}\right]\succeq0,\quad y>0
> $$
>
> (函数图像如[图 3](#图3) 所示)。
&emsp;&emsp;关于凸函数的很多结果可以从几何的角度利用上境图并结合凸集的一些结论来证明(或理解),例如,考虑凸函数的一阶条件
$$
f(y)\geqslant f(x)+\nabla f(x)^\TT (y-x)
$$
其中函数 $f$ 是凸的,$x,y\in\dom f$。我们可以利用 $\epi f$ 从几何角度理解上述基本不等式。若 $(y,t)\in\epi f$,有
$$
t\geqslant f(y)\geqslant f(x)+\nabla f(x)^\TT (y-x)
$$
上式可以描述为
$$
(y,t)\in\epi f\implies\left[\begin{array}{c}\nabla f(x)\\-1\end{array}\right]^\TT \left(\left[\begin{array}{c}y\\t\end{array}\right]-\left[\begin{array}{c}x\\f(x)\end{array}\right]\right)\leqslant0
$$
这意味着法向量为 $(\nabla f(x),-1)$ 的超平面在边界点 $(x,f(x))$ 支撑着 $\epi f$,如[图 6](#图6) 所示。
<a id="图6"></a>
![图 6. 对于可微凸函数 $f$,向量 $(\nabla f(x),-1)$ 定义了函数 $f$ 在点 $x$ 处的上境图的一个支撑超平面。](../images/post/2024-06-14-josh-cvx-2-1/2024-06-14-josh-cvx-2-1-060-EpigraphAndSupportingHyperplane.png){width=400px}
# 8. Jensen 不等式及其扩展
&emsp;&emsp;基本不等式
$$
f(\theta x+(1-\theta)y)\leqslant\theta f(x)+(1-\theta)f(y)
$$
有时也称作 **Jensen 不等式**(*Jensen’s inequality*)。此不等式可以很方便地扩展至更多点的凸组合:若函数 $f$ 是凸函数,$x_1,\cdots,x_k\in\dom f$,$\theta_1,\cdots,\theta_k\geqslant0$ 且 $\theta_1+\cdots+\theta_k=1$,则下式成立
$$
f(\theta_1x_1+\cdots+\theta_kx_k)\leqslant\theta_1f(x_1)+\cdots+\theta_kf(x_k)
$$
考虑凸集时,此不等式可以扩展至无穷项和、积分以及期望。例如,若在 $S\subseteq\dom f$ 上 $p(x)\geqslant0$ 且 $\displaystyle\int_Sp(x) \dd x = 1$,则当相应的积分存在时,下式成立
$$
f\left(\int_Sp(x)x\dd x\right)\leqslant\int_Sf(x)p(x)\dd x
$$
扩展到更一般的情况,我们可以采用其支撑属于 $\dom f$ 的任意概率测度。若 $x$ 是随机变量,事件 $x\in\dom f$ 发生的概率为 1,函数 $f$ 是凸函数,当相应的期望存在时,我们有
$$\begin{equation}\label{GeneralJensenInequality}
f(\mathbb{E}x)\leqslant\mathbb{E}f(x)
\end{equation}$$
设随机变量 $x$ 的可能取值为 $\{ x_1, x_2\}$ 相应地取值概率为 $\prob ( x= x_1) = \theta$,$\prob( x=x_2)=1-\theta$,则由一般形式 $\eqref{GeneralJensenInequality}$ 可以得到基本不等式 $\eqref{DefinitionOfConvexFunction}$。所以不等式 $\eqref{GeneralJensenInequality}$ 可以刻画凸性:若函数 $f$ 不是凸函数,则存在随机变量 $x$,$x\in\dom f$ 以概率 $1$ 发生,使得 $f(\mathbb{E}x)>\mathbb{E}f(x)$。
&emsp;&emsp;上述所有不等式均被称为 **Jensen 不等式**(*Jensen’s inequality*),而实际上最初由 Jensen 提出的不等式相当简单
$$
f\left(\frac{x+y}2\right)\leqslant\frac{f(x)+f(y)}2
$$
> **注释**&emsp;我们可以这样理解式 $\eqref{GeneralJensenInequality}$。假设 $x\in\dom f\subseteq\mathbf{R}^n$,$z$ 是 $\mathbf{R}^n$ 中的随机变量,其均值为零,则有
>
> $$
> \mathbb{E}f(x+z)\geqslant f(x)
> $$
>
> 因此,随机化或者扰动(即在自变量上增加一个零均值的随机变量)从平均效果上不会减小凸函数的值。
# 9. 不等式
&emsp;&emsp;很多著名的不等式都可以通过将 Jensen 不等式应用于合适的凸函数得到。(事实上,凸性和 Jensen 不等式可以构成不等式理论的基础。)
> **举例**&emsp;考虑算术-几何平均不等式
>
> $$\begin{equation}\label{ArithmeticGeometricMeanInequality}
> \sqrt{a b} \leqslant( a+b ) / 2
> \end{equation}$$
>
> 其中 $a, b \geqslant0$。我们可以利用凸性和 Jensen 不等式得到此不等式。函数 $-\log x$ 是凸函数:利用 Jensen 不等式,令 $\theta=1 / 2$ ,可得
>
> $$
> -\log \left( \frac{a+b} {2} \right) \leqslant\frac{-\log a-\log b} {2}
> $$
>
> 等式两边取指数即可得到式 $\eqref{ArithmeticGeometricMeanInequality}$。
> **举例**&emsp;证明 Hölder 不等式:对 $p > 1$,$1 / p+1 / q=1$,以及 $x,y \in\mathbf{R}^{n}$ 有
>
> $$
> \sum_{i=1}^{n} x_{i} y_{i} \leqslant\left( \sum_{i=1}^{n} | x_{i} |^{p} \right)^{1 / p} \left( \sum_{i=1}^{n} | y_{i} |^{q} \right)^{1 / q}
> $$
>
> 由 $-\log x$ 的凸性以及 Jensen 不等式,可以得到更为一般的算术-几何平均不等式
>
> $$
> a^{\theta} b^{1-\theta} \leqslant\theta a+( 1-\theta) b,
> $$
>
> 其中 $a,b \geqslant0$,$0 \leqslant\theta\leqslant1$。令
>
> $$
> a=\frac{| x_{i} |^{p}} {\displaystyle\sum_{j=1}^{n} | x_{j} |^{p}}, \qquad b=\frac{| y_{i} |^{q}} {\displaystyle\sum_{j=1}^{n} | y_{j} |^{q}}, \qquad\theta=1 / p,
> $$
>
> 可以得到如下不等式
>
> $$
> \left( \frac{| x_{i} |^{p}} {\displaystyle\sum_{j=1}^{n} | x_{j} |^{p}} \right)^{1 / p} \left( \frac{| y_{i} |^{q}} {\displaystyle\sum_{j=1}^{n} | y_{j} |^{q}} \right)^{1 / q} \leqslant\frac{| x_{i} |^{p}} {p \displaystyle\sum_{j=1}^{n} | x_{j} |^{p}}+\frac{| y_{i} |^{q}} {q \displaystyle\sum_{j=1}^{n} | y_{j} |^{q}}.
> $$
>
> 对 $i$ 进行求和可以得到 Hölder 不等式。
# 参考文献
1. Stephen P. Boyd and Lieven Vandenberghe, *Convex optimization*. Cambridge, UK: Cambridge University Press, 2004.
2. Stephen P. Boyd and Lieven Vandenberghe, *凸优化*. 北京: 清华大学出版社, 2013.
[仿射函数]: https://josh-gao.top/posts/a4a69a4f.html?#%E4%BB%BF%E5%B0%84%E5%87%BD%E6%95%B0
@@ -0,0 +1,479 @@
---
title: Zynq MPSoC / RFSoC 动态配置 DIMM DDR
mathjax: true
comments: true
copyright: true
toc:
enable: true
number: true
wrap: true
expand_all: true
max_depth: 4
tags:
- 调试记录
- DDR
- MPSoC
- RFSoC
- SPD
- Zynq
categories:
- 调试记录
abbrlink: 11cd1dc
date: 2024-06-27 20:06:13
---
对于 DIMM 拓扑的 DDR,通常可以使用 I2C 对搭载在 DIMM 上的 SPD EEPROM 进行读取后获得配置参数,然后对 DDR 控制器进行配置。
AMD Xilinx UG1085 的 [Dynamic DDR Configuration](https://docs.amd.com/r/en-US/ug1085-zynq-ultrascale-trm/Dynamic-DDR-Configuration) 一节指出,当 DDR 控制器处于复位状态时,可以在运行时通过 FSBL 获取 DDR 参数并对 DDR 控制器进行初始化。
本文基于 Zynq RFSoC,对 PS 端的 SO-DIMM DDR 进行动态配置。
<!-- more -->
# 名词释义
- [BSP](https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842276/Standalone+Board+Support+Package+BSP):Board Support Package,板级支持包
- [EEPROM](https://en.wikipedia.org/wiki/EEPROM):Electrically-Erasable Programmable Read-Only Memory,电子擦除式可复写只读存储器
- [FSBL](https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842019/Zynq+UltraScale+FSBL#ZynqUltraScale+FSBL-WhatisFSBL?):First Stage Bootloader,第一阶段引导加载程序
- [DDR DRAM](https://en.wikipedia.org/wiki/DDR_SDRAM):Double Data Rate Synchronous Dynamic Random-Access Memory,双倍数据率同步动态随机存取存储器
- [DIMM](https://en.wikipedia.org/wiki/DIMM):Dual In-line Memory Modules,双列直插式存储模块
- PCW:Processing System Configuration Wizard,处理系统配置向导
- [SO-DIMM](https://en.wikipedia.org/wiki/DIMM#SO-DIMM):Small Outline Dual In-line Memory Modules,小外形双列直插式内存模块
- [SPD](https://en.wikipedia.org/wiki/Serial_presence_detect):Serial Presence Detect,串行存在检测
# 硬软件版本
| 硬软件 | 型号/版本 |
| :--: | :-------: |
| FPGA | Zynq RFSoC XCZU48DR-2-FSVG1517-I |
| DDR4 | Micron MTA4ATF51264HZ-2G6E1 |
| I2C Mux | TI TCA9548APWR |
| Vivado | 2024.1 |
| Vitis Classic | 2024.1 |
# Zynq MPSoC / RFSoC 动态 DDR 配置简介
Zynq MPSoC / RFSoC 动态 DDR 配置具有如下特性:
- 无需在 Vivado 中进行改动即可更换 DIMM,并使用动态 DDR 配置初始化 DDR;
- 支持 DDR3 和 DDR4 DIMM;
- 单一的 PetaLinux BSP 即可支持任何可安装的 DIMM 器件。
{% note warning %}
动态 DDR 配置功能仅可用于 PS DIMM DDR,不支持颗粒 DDR。
{% endnote %}
# 具体操作方法
## PCW GUI 配置
在使用动态 DDR 配置之前,需要在如[图 1](#图1) 的 Vivado 的 PCW GUI 中启用 DDR 控制器,且将“DDR Controller Options”部分设置为:
- Memory Type:DDR4 或 DDR3
- Components:UDIMM 或 RDIMM
- ECC:Enabled 或 Disabled
- Effective DRAM Bus Width:64 Bit
<a id="图1"></a>
![图 1. Zynq UltraScale+ MPSoC 配置 GUI](../images/post/2024-06-27-zynq-mpsoc-ddr-spd/2024-06-27-zynq-mpsoc-ddr-spd-010-ZynqGui.png)
动态 DDR 配置将自动读取 SPD 表,并设置“DDR Memory Option”部分的所有参数,如下表。
| Option | Value Example | Option | Value Example |
| -------------- | --------- | -------------- | --------- |
| Speed Bin (Use Tooltip) | DDR42133P | DRAM IC Bus Width (per die) | 8 Bits |
| Cas Latency | 15 | DRAM Device Capacity(per die) | 4096 MBits |
| RAS to CAS Delay (Cycles) | 15 | Bank Group Address Count (Bits) | 2 |
| Pre-charge Time (Cycles) | 15 | Bank Address Count (Bits) | 2 |
| Cas Write Latency (Cycles) | 14 | Row Address Count (Bits) | 15 |
| tRC (ns) | 46.5 | Column Address Count | 10 |
| tRASmin (ns) | 33 | Dual Rank | |
| tFAW (ns) | 21 | DDR Size (in hexa) | 0XFFFFFFFF (4GB) |
| Additive Latency (Cycles) | 0 | | |
而“Other Options”部分的所有值都需要用户根据需要设置,无法从 SPD 表中获得,如下表。
| Option | Value Example | Option | Value Example |
| -------------- | --------- | -------------- | --------- |
| Memory Address Map | ROW BANK COL | Power Mode Settings | Power Down Enable |
| Data Mask and DBI | DM NO DBI | Clock Stop |
| Address Mirroring | | **Refresh Mode Settings** |
| 2nd Clock | | Lower-Power Auto Self-Refresh | Manual Normal |
| Parity | | Temp Controlled Refresh | |
| 2Tck Command Timing (2T) | | Max. Operating Temperature | Normal (0-85) |
| | | Fine Granularity Refresh Mode | 1x |
| | | Self-Refresh Abort | |
## 启用动态 DDR 配置功能
要启用动态 DDR 配置功能,需要在 Vivado 中使用 TCL 命令将参数 `CONFIG.PSU_DYNAMIC_DDR_CONFIG_EN` 置为 1:
``` tcl
set_property CONFIG.PSU_DYNAMIC_DDR_CONFIG_EN 1 [get_bd_cells /zynq_ultra_ps_e]
```
这里的 `zynq_ultra_ps_e` 需要替换为实际 Block Design 中 Zynq UltraScale+ MPSoC IP 核的名称,如[图 2](#图2)。
<a id="图2"></a>
![图 2. Block Design 整体](../images/post/2024-06-27-zynq-mpsoc-ddr-spd/2024-06-27-zynq-mpsoc-ddr-spd-020-BlockDesign.png)
然后重新生成 Output Products 即可(若除 PS 处理器外还有其他逻辑,则需要重新生成比特流)。FSBL 将会在启动过程中使用该参数,并执行动态 DDR 配置。
{% note info %}
如果设置了上述参数却出现了如下警告,是因为 GUI 中 DDR 类型必须为 UDIMM 或 RDIMM,不能为 Component。
``` plain
WARNING: [BD 41-721] Attempt to set value '1' on disabled parameter 'PSU_DYNAMIC_DDR_CONFIG_EN' of cell '/zynq_ultra_ps_e_0' is ignored
```
{% endnote %}
## I2C 硬件要求
由于动态 DDR 配置需要在 FSBL 中使用 I2C 读取 DDR SPD EEPROM 中的数据,而在 Xilinx 自动生成 FSBL 中,I2C 读取 DDR SPD EEPROM 的方式是固定的,因此**若不想对生成的 FSBL 进行修改,则需要在硬件上适配 FSBL**。
Xilinx FSBL 使用 I2C1(1 号 I2C 控制器),借助一个 I2C Mux 与 SPD EEPROM 进行通信,使用的地址为:
- I2C Mux 地址: 0x75
- I2C Slave 地址: 0b1010001 (0x51)
- SODIMM SA[2:0]: 0b001
{% note info %}
从 Vivado 2019.1 开始,动态 DDR 配置对于所有使用 DIMM DDR 的 Zynq MPSoC / RFSoC 评估板均启用,在使用预置硬件配置时无需额外用户操作。
{% endnote %}
## 根据硬件修改 FSBL
若 I2C 硬件连接不满足上述要求,还可以按照实际连接关系修改 FSBL。FSBL 中使用 I2C 读取 DDR SPD EEPROM 的函数为 `u32 XFsbl_IicReadSpdEeprom(u8 *SpdData)`。
``` c xfsbl_ddr_init.c
u32 XFsbl_DdrInit(void)
{
// ...
/* Get the Model Part Number from the SPD stored in EEPROM */
Status = XFsbl_IicReadSpdEeprom(SpdData);
if (Status != XFSBL_SUCCESS) {
Status = XFSBL_FAILURE;
goto END;
}
// ...
}
```
下面对函数进行拆解,结合注释可以更好理解操作的过程。
### 初始化 I2C 控制器
首先对 I2C 控制器 I2C1 进行初始化。值得一提的是,从 Vivado / Vitis 2023.2 版本开始,对设备进行寻址时,不再依赖于设备的 Device ID,而是直接使用基地址 Base Address,少了从 Device ID 到 Base Address 这一步操作,从开发的角度来看更为合理了。
{% note info %}
若设计使用了 I2C 控制器 I2C0,则可以改为使用基地址 `XPAR_I2C0_BASEADDR` 或 Device ID `XPAR_PSU_I2C_0_DEVICE_ID` 来寻找设备。
{% endnote %}
``` c xfsbl_ddr_init.c
static u32 XFsbl_IicReadSpdEeprom(u8 *SpdData)
{
// ...
/* Lookup for I2C-1U device */
#ifdef SDT
ConfigIic = XIicPs_LookupConfig(XPAR_I2C1_BASEADDR);
#else
ConfigIic = XIicPs_LookupConfig(XPAR_PSU_I2C_1_DEVICE_ID);
#endif
if (!ConfigIic) {
UStatus = XFSBL_FAILURE;
goto END;
}
/* Initialize the I2C device */
Status = XIicPs_CfgInitialize(&IicInstance, ConfigIic,
ConfigIic->BaseAddress);
if (Status != XST_SUCCESS) {
UStatus = XFSBL_FAILURE;
goto END;
}
/* Set the Serial Clock for I2C */
Status = XIicPs_SetSClk(&IicInstance, XFSBL_IIC_SCLK_RATE);
if (Status != XST_SUCCESS) {
UStatus = XFSBL_FAILURE;
goto END;
}
// ...
}
```
### 选择 I2C Mux 的 Slave
由于开发板搭载了较多 I2C 外设,而 Zynq MPSoC / RFSoC 的 I2C 控制器数量有限,因此需要通过 I2C Mux 来扩展所连 I2C Slave 的数量。
本板卡 I2C1 原理图如[图 3](#图3),所用 I2C Mux 的型号为 TCA9548A,其地址配置方式如[图 4](#图4),Slave 选择方式如[图 5](#图5),这里均和评估板保持一致,因此可以与自动生成的 FSBL 兼容。
结合[图 3](#图3) 和[图 4](#图4) 可知 I2C Mux 的地址为 `0x75`,从[图 3](#图3) 中可知 PS DDR4 SODIMM 的 I2C 连接在了第 3 号 Slave 的位置,因此按照[图 5](#图5) 需要将 B3 置 1,也即需要向地址为 `0x75` 的 I2C Mux TCA9548A 的控制寄存器中写入 `0x08`。
<a id="图3"></a>
![图 3. I2C Mux 原理图](../images/post/2024-06-27-zynq-mpsoc-ddr-spd/2024-06-27-zynq-mpsoc-ddr-spd-030-I2C1Schematic.png)
<a id="图4"></a>
![图 4. TCA9548A 地址配置](../images/post/2024-06-27-zynq-mpsoc-ddr-spd/2024-06-27-zynq-mpsoc-ddr-spd-040-tca9548aAddress.png){width=600px}
<a id="图5"></a>
![图 5. TCA9548A Slave选择](../images/post/2024-06-27-zynq-mpsoc-ddr-spd/2024-06-27-zynq-mpsoc-ddr-spd-050-tca9548aConfig.png){width=1000px}
按照上述分析,下面的代码就不难理解了,首先向地址为 `XFSBL_MUX_ADDR`(默认为 `0x75`)的 I2C Mux 写入选通配置 `0x08`,然后从同样的地址回读,验证配置是否正确。
{% note info %}
- 若设计中没有使用到 I2C Mux,而是直接将 I2C 控制器连接到了 DIMM,则可以删去这部分代码;
- 若设计中 I2C Mux 地址不同,则可以修改 `XFSBL_MUX_ADDR` 的宏定义;
- 若设计中 I2C Mux 连接的 Slave 不同,可以修改 I2C 发送的 `TxArray`。
{% endnote %}
``` c xfsbl_ddr_init.c
static u32 XFsbl_IicReadSpdEeprom(u8 *SpdData)
{
// ...
/*
* Configure I2C Mux to select DDR4 SODIMM Slave
* 0x08U - Enable DDR4 SODIMM module
*/
TxArray = 0x08U;
XIicPs_MasterSendPolled(&IicInstance, &TxArray, 1U, XFSBL_MUX_ADDR);
/*
* Wait until bus is idle to start another transfer.
*/
Status = Xil_WaitForEvent(IicInstance.Config.BaseAddress +
XIICPS_SR_OFFSET, XIICPS_SR_BA_MASK, 0U, XFSBL_IIC_BUS_TIMEOUT);
if (Status != XST_SUCCESS) {
UStatus = XFSBL_FAILURE;
goto END;
}
/*
* Get Configuration to confirm the selection of the slave
* device.
*/
Status = XIicPs_MasterRecvPolled(&IicInstance, SpdData, 1U,
XFSBL_MUX_ADDR);
if (Status != XST_SUCCESS) {
UStatus = XFSBL_FAILURE;
goto END;
}
/*
* Wait until bus is idle to start another transfer.
*/
Status = Xil_WaitForEvent(IicInstance.Config.BaseAddress +
XIICPS_SR_OFFSET, XIICPS_SR_BA_MASK, 0U, XFSBL_IIC_BUS_TIMEOUT);
if (Status != XST_SUCCESS) {
UStatus = XFSBL_FAILURE;
goto END;
}
// ...
}
```
### 读取 EEPROM 的第一页
配置完 I2C Mux 后,即可开始读取 SPD EEPROM 中的内容了。[图 6](#图6) 给出了 EEPROM 支持的指令表,由于 EEPROM 一次读的最大长度为一页,也即一个 Page,因此需要分两次对其中的两个 Page 进行读取。
<a id="图6"></a>
![图 6. DDR4 SPD EEPROM 指令表](../images/post/2024-06-27-zynq-mpsoc-ddr-spd/2024-06-27-zynq-mpsoc-ddr-spd-060-DDR4SPDAddress.png){width=800px}
首先设置 Page Address 为 0,也即向地址 `0x36` 中写入 `0x00`,表示从 Page 0 中进行读取,一次读取 256 Byte。
{% note info %}
通常 SPD EEPROM 的 Page 选择地址是固定的,如果 Page Address 0 的地址有变更,修改 `XFSBL_SODIMM_CONTROL_ADDR_LOW` 的宏定义即可。
{% endnote %}
``` c xfsbl_ddr_init.c
static u32 XFsbl_IicReadSpdEeprom(u8 *SpdData)
{
// ...
/*
* Set SODIMM control address to enable access to lower
* EEPROM page (0U to 255U Bytes).
* 0x00U - Enable Read of Lower Page from EEPROM
*/
TxArray = 0x00U;
XIicPs_MasterSendPolled(&IicInstance, &TxArray, 1U,
XFSBL_SODIMM_CONTROL_ADDR_LOW);
/*
* Wait until bus is idle to start another transfer.
*/
Status = Xil_WaitForEvent(IicInstance.Config.BaseAddress +
XIICPS_SR_OFFSET, XIICPS_SR_BA_MASK, 0U, XFSBL_IIC_BUS_TIMEOUT);
if (Status != XST_SUCCESS) {
UStatus = XFSBL_FAILURE;
goto END;
}
/*
* Configure SODIMM Slave address to select starting address of the
* read bytes.
* 0x00U - Set starting byte address of read Lowe Page from EEPROM
* This will result in to starting address of 0x149U (0x100U + 0x49U) in
* the EEPROM.
*/
TxArray = 0x00U;
XIicPs_MasterSendPolled(&IicInstance, &TxArray, 1U,
XFSBL_SODIMM_SLAVE_ADDR);
/*
* Wait until bus is idle to start another transfer.
*/
Status = Xil_WaitForEvent(IicInstance.Config.BaseAddress +
XIICPS_SR_OFFSET, XIICPS_SR_BA_MASK, 0U, XFSBL_IIC_BUS_TIMEOUT);
if (Status != XST_SUCCESS) {
UStatus = XFSBL_FAILURE;
goto END;
}
/*
* Receive the Data of 256U Bytes from SPD EEPROM via I2C.
*/
Status = XIicPs_MasterRecvPolled(&IicInstance, SpdData, 256U,
XFSBL_SODIMM_SLAVE_ADDR);
if (Status != XST_SUCCESS) {
UStatus = XFSBL_FAILURE;
goto END;
}
/*
* Wait until bus is idle.
*/
Status = Xil_WaitForEvent(IicInstance.Config.BaseAddress +
XIICPS_SR_OFFSET, XIICPS_SR_BA_MASK, 0U, XFSBL_IIC_BUS_TIMEOUT);
if (Status != XST_SUCCESS) {
UStatus = XFSBL_FAILURE;
goto END;
}
// ...
}
```
### 读取 EEPROM 的第二页
然后设置 Page Address 为 1,也即向地址 `0x37` 中写入 `0x00`,表示从 Page 0 中进行读取,一次读取 256 Byte。
{% note info %}
通常 SPD EEPROM 的 Page 选择地址是固定的,如果 Page Address 1 的地址有变更,修改 `XFSBL_SODIMM_CONTROL_ADDR_HIGH` 的宏定义即可。
{% endnote %}
``` c xfsbl_ddr_init.c
static u32 XFsbl_IicReadSpdEeprom(u8 *SpdData)
{
// ...
/*
* Set SODIMM control address to enable access to upper
* EEPROM page (256U to 511U Bytes).
* 0x01U - Enable Read of Upper Page from EEPROM
*/
TxArray = 0x01U;
XIicPs_MasterSendPolled(&IicInstance, &TxArray, 1U,
XFSBL_SODIMM_CONTROL_ADDR_HIGH);
/*
* Wait until bus is idle to start another transfer.
*/
Status = Xil_WaitForEvent(IicInstance.Config.BaseAddress +
XIICPS_SR_OFFSET, XIICPS_SR_BA_MASK, 0U, XFSBL_IIC_BUS_TIMEOUT);
if (Status != XST_SUCCESS) {
UStatus = XFSBL_FAILURE;
goto END;
}
/*
* Configure SODIMM Slave address to select starting address of the
* read bytes.
* 0x00U - Set starting byte address of read Upper Page from EEPROM
* This will result in to starting address of 0x149U (0x100U + 0x49U) in
* the EEPROM.
*/
TxArray = 0x00U;
XIicPs_MasterSendPolled(&IicInstance, &TxArray, 1U,
XFSBL_SODIMM_SLAVE_ADDR);
/*
* Wait until bus is idle to start another transfer.
*/
Status = Xil_WaitForEvent(IicInstance.Config.BaseAddress +
XIICPS_SR_OFFSET, XIICPS_SR_BA_MASK, 0U, XFSBL_IIC_BUS_TIMEOUT);
if (Status != XST_SUCCESS) {
UStatus = XFSBL_FAILURE;
goto END;
}
/*
* Receive the Data of 256U Bytes from SPD EEPROM via I2C.
*/
Status = XIicPs_MasterRecvPolled(&IicInstance, &SpdData[256U], 256U,
XFSBL_SODIMM_SLAVE_ADDR);
if (Status != XST_SUCCESS) {
UStatus = XFSBL_FAILURE;
goto END;
}
/*
* Wait until bus is idle.
*/
Status = Xil_WaitForEvent(IicInstance.Config.BaseAddress +
XIICPS_SR_OFFSET, XIICPS_SR_BA_MASK, 0U, XFSBL_IIC_BUS_TIMEOUT);
if (Status != XST_SUCCESS) {
UStatus = XFSBL_FAILURE;
goto END;
}
// ...
}
```
# 调试
配置完成后可以实测了,这里对 FSBL 进行 Debug,观察整个读写的过程。在单独调试 FSBL 的时候,可以不勾选“Program FPGA”和“Initialize using FSBL”,如[图 7](#图7)。
<a id="图7"></a>
![图 7. Debug 配置](../images/post/2024-06-27-zynq-mpsoc-ddr-spd/2024-06-27-zynq-mpsoc-ddr-spd-070-DebugConfig.png)
将断点设置在函数 `XFsbl_IicReadSpdEeprom()` 被调用的地方。
<a id="图8"></a>
![图 8. `XFsbl_IicReadSpdEeprom()` 函数断点](../images/post/2024-06-27-zynq-mpsoc-ddr-spd/2024-06-27-zynq-mpsoc-ddr-spd-080-Breakpoint.png)
观察 I2C Mux 回读的数据。回读的数据存储在 `SpdData` 数组中,可以观察到数组的第 0 个字节为 `0x08`,与写入的数据一致。
<a id="图9"></a>
![图 9. I2C Mux 回读](../images/post/2024-06-27-zynq-mpsoc-ddr-spd/2024-06-27-zynq-mpsoc-ddr-spd-090-IICMuxRead.png)
然后观察 I2C EEPROM 回读的数据,并与 Micron 给出的 [MTA4ATF51264HZ-2G6E1 的 SPD 数据][]进行对比,可以观察到数据是一致的。
<a id="图10"></a>
![图 10. I2C EEPROM 回读](../images/post/2024-06-27-zynq-mpsoc-ddr-spd/2024-06-27-zynq-mpsoc-ddr-spd-100-IICEEPROMRead.png)
最后,`XFsbl_DdrInit()` 函数的剩余部分会完成 DDR 参数的解析与 DDR 控制器的初始化。
# 参考文档
[75768 - Zynq MPSoC Dynamic DDR Configuration Support for DIMM Devices](https://support.xilinx.com/s/article/75768)
[SPD I2c Address for DDR4 SODIMM](https://electronics.stackexchange.com/questions/554703/spd-i2c-address-for-ddr4-sodimm)
[MTA4ATF51264HZ-2G6E1 的 SPD 数据]: https://www.micron.com/products/memory/dram-modules/sodimm/part-catalog/part-detail/spd-data/mta4atf51264hz-2g6e1
+653
View File
@@ -0,0 +1,653 @@
---
title: Josh's Note — 凸优化<br>Part 2.2 凸函数—保凸运算
mathjax: true
comments: true
copyright: true
toc:
enable: true
number: false
wrap: true
expand_all: true
max_depth: 4
categories:
- - Josh 的学习笔记
- 凸优化
- 凸函数
- - 数学
- 凸优化
tags:
- 凸优化
- 凸函数
- 保凸运算
abbrlink: c3476904
date: 2024-07-03 23:04:33
---
$
\newcommand{\dd}{\mathrm{d}}
\newcommand{\TT}{\mathrm{T}}
\def\diag{\mathop{\bf diag}}
\def\dist{\mathop{\bf dist}}
\def\dom{\mathop{\bf dom}}
\def\epi{\mathop{\bf epi}}
$&emsp;&emsp;本文讨论几种保持函数凸性或者凹性的运算,这样可以构造新的凸函数或者凹函数。首先从一些简单的运算开始,如求和、伸缩以及逐点上确界,之后再介绍一些更为复杂的运算(其中一些运算的特例即为简单运算)。
# 1. 非负加权求和
&emsp;&emsp;显然,若函数 $f$ 是凸函数且 $\alpha\geqslant0$,则函数 $\alpha f$ 也是凸函数。若函数 $f_1$ 和 $f_2$ 都是凸函数,则它们的和 $f_1+f_2$ 也是凸函数。将非负伸缩以及求和运算结合起来,可以看出,凸函数的集合本身是一个凸锥:凸函数的非负加权求和仍然是凸函数,即函数
$$
f=w_1f_1+\cdots+w_mf_m
$$
是凸函数。类似地,凹函数的非负加权求和仍然是凹函数。严格凸(凹)函数的非负,非零加权求和是严格凸(凹)函数。
&emsp;&emsp;这个性质可以扩展至无限项的求和以及积分的情形。例如,若对于每一个 $y\in\mathcal{A}$,函数 $f(x,y)$ 关于 $x$ 都是凸函数,且 $w(y)\geqslant 0$,则函数
$$
g(x)=\int_{\mathcal{A}}w(y)f(x,y)\dd y
$$
关于 $x$是凸函数(若此积分存在)。
<!-- more -->
&emsp;&emsp;容易验证非负伸缩以及求和运算是保凸运算,或者可以根据相关的上境图得到此结论。例如,若 $w\geqslant 0$ 且 $f$ 是凸函数,则有
$$
\epi (wf)=\left[\begin{array}{cc}
I&0\\
0&w
\end{array}\right]\epi f
$$
因为凸集通过线性变换得到的像仍然是凸集,所以 $\epi(wf)$ 是凸集。
{% note info 注解 %}
这里对上镜图的相关结论进行解释。函数 $f:\mathbf{R}^{n}\to\mathbf{R}$ 的上镜图定义为
$$
\epi f=\{(x,t)\mid f(x)\leqslant t\}
$$
则有
$$\begin{aligned}
\left[\begin{array}{cc}
I&0\\
0&w
\end{array}\right]\epi f&=\left\{\left[\begin{array}{cc}
I&0\\
0&w
\end{array}\right](x,t)\:\middle|\: f(x)\leqslant t\right\}
\\
&= \{(x,wt)\mid f(x)\leqslant t\}
\\
&= \{(x,t)\mid wf(x)\leqslant t\}
\\
&= \epi (wf)
\end{aligned}
$$
{% endnote %}
# 2. 复合仿射映射
&emsp;&emsp;假设函数 $f:\mathbf{R}^n\to\mathbf{R}$,$A\in\mathbf{R}^{n\times m}$,$b\in\mathbf{R}^n$,定义**复合仿射映射**(*composition with an affine mapping*)$ g:\mathbf{R}^m\to\mathbf{R}$ 为
$$
g(x)=f(Ax+b)
$$
其中 $\dom g=\{x\mid Ax+b\in\dom f\}$。若函数 $f$ 是凸函数,则函数 $g$ 是凸函数;若函数 $f$ 是凹函数,则函数 $g$ 是凹函数。
# 3. 逐点最大和逐点上确界
## 3.1 逐点最大
&emsp;&emsp;若函数 $f_{1}$ 和 $f_{2}$ 均为凸函数,则二者的**逐点最大**(*pointwise maximum*)函数
$$
f(x)=\max\{f_1(x),f_2(x)\}
$$
其定义域为 $\dom f=\dom f_1\cap\dom f_2$,仍然是凸函数。这个性质很容易验证:任取 $0\leqslant \theta \leqslant 1$ 以及 $x,y\in\dom f$,有
$$\begin{aligned}
f(\theta x+(1-\theta)y)&=\max\{f_1(\theta x+(1-\theta)y),f_2(\theta x+(1-\theta)y)\}
\\
&\leqslant\max\{\theta f_1(x)+(1-\theta)f_1(y),\theta f_2(x)+(1-\theta)f_2(y)\}
\\
&\leqslant\theta\max\{f_1(x),f_2(x)\}+(1-\theta)\max\{f_1(y),f_2(y)\}
\\
&=\theta f(x)+(1-\theta)f(y)
\end{aligned}$$
从而得到了函数 $f$ 的凸性。同样很容易证明,若函数 $f_1,\cdots,f_m$ 为凸函数,则它们的逐点最大函数
$$
f(x)=\max\{f_1(x),\cdots,f_m(x)\}
$$
仍然是凸函数。
> **举例**&emsp;**分段线性函数**(*Piecewise-linear functions*)。函数
>
> $$
> f(x)=\max\left\{a_1^\TT x+b_1,\cdots,a_L^\TT x+b_L\right\}
> $$
>
> 定义了一个(具有不大于 $L$ 个子区域的)分段线性函数(实际上是仿射函数)。因为它是一系列仿射函数的逐点最大函数,所以它是凸函数。反之亦成立:任意具有不大于 $L$ 个子区域的分段线性凸函数都可以表述成上述形式。
>
> {% note info 注解 %}
> 参考 Wikipedia,[分段线性函数词条](https://en.wikipedia.org/wiki/Piecewise_linear_function)即为我们通常理解的分段函数,但是这里的分段线性函数有所不同,定义为多个分段函数的逐点最大,因此数凸的。
>
> 关于子区域数量,可以这样理解:若 $L$ 个仿射函数相邻两段各不相同,则每一段仿射函数均对应着一个子区域,因此最多共有 $L$ 个子区域。
> {% endnote %}
> **举例**&emsp;**最大 $r$ 个分量之和**。对于任意 $x\in\mathbf{R}^n$,用 $x_{[i]}$ 表示 $x$ 中第 $i$ 大的分量,将 $x$ 的分量按照非升序进行排列
>
> $$
> x_{[1]}\geqslant x_{[2]}\geqslant\cdots\geqslant x_{[n]}
> $$
>
> 则对 $x$ 的最大 $r$ 个分量进行求和所得到的函数
>
> $$
> f(x)=\sum_{i=1}^rx_{[i]}
> $$
>
> 是凸函数。事实上,此函数可以表述为
>
> $$
> f(x)=\sum_{i=1}^rx_{[i]}=\max\{x_{i_1}+\cdots+x_{i_r}\mid1\leqslant i_1<i_2<\cdots<i_r\leqslant n\}
> $$
>
> 即从 $x$ 的分量中选取 $r$ 个不同分量进行求和的所有可能组合的最大值。因为函数 $f$ 是 $\displaystyle\frac{n!}{r!(n-r)!}$ 个线性函数的逐点最大,所以是凸函数。
>
> 进一步可以证明,当 $w_1\geqslant w_2\geqslant\cdots\geqslant w_r\geqslant 0$ 时,函数 $\displaystyle\sum_{i=1}^rw_ix_{[i]}$ 是凸函数。
## 3.2 逐点上确界
&emsp;&emsp;逐点最大的性质可以扩展至无限个凸函数的**逐点上确界**(*pointwise supremum*)。
{% note info 上确界和下确界 %}
&emsp;&emsp;假定 $C\subseteq\mathbf{R}$。若对每个 $x\in C$ 均有 $x\leqslant a$,则称 $a$ 是 $C$ 的**上界**(*upper bound*)。$C$ 的上界组成的集合或是空集(此时称 $C$ 无上界),或等于 $\mathbf{R}$(仅当 $C=\emptyset$ 时),或是闭的无限区间 $[b,\infty)$。称 $b$ 为 $C$ 的**最小上界**(*least upper bound*)或**上确界**(*supremum*),用 $\sup C$ 表示。规定 $\sup\emptyset=-\infty$,当 $C$ 无上界时取 $\sup C=\infty$。当 $\sup C\in C$ 时,称 $C$ 的上确界是可达的。
&emsp;&emsp;当 $C$ 是有限集时,$\sup C$ 是它所有元素的最大值。一些作者用符号 $\max C$ 表示可达的上确界,但我们采用标准的数学习惯,只在 $C$ 是有限集时用 $\max C$。
&emsp;&emsp;类似地,可以定义下界和下确界。若对每个 $x\in C$ 均有 $a\leqslant x$,则称 $a$ 是 $C\subseteq\mathbf{R}$ 的下界。$C\subseteq\mathbf{R}$ 的**下确界**(*infimum*)或**最大下界**(*greatest lower bound*)定义为 $\inf C=-\sup(-C)$。当 $C$ 是有限集时,下确界是它所有元素的最小值。规定 $\inf\emptyset=\infty$,并在 $C$ 无下界时,取 $\inf C=-\infty$。
{% endnote %}
&emsp;&emsp;若对于任意 $y\in\mathcal{A}$,函数 $f(x,y)$ 关于 $x$ 都是凸的,则函数
$$\begin{equation}\label{PointwiseMaximum}
g(x)=\sup_{y\in\mathcal{A}}f(x,y)
\end{equation}$$
关于 $x$ 亦是凸的。此时,函数 $g$ 的定义域为
$$
\dom g=\{x\mid(x,y)\in\dom f\:\forall y\in\mathcal{A},\sup_{y\in\mathcal{A}}f(x,y)<\infty\}
$$
类似地,一系列凹函数的逐点下确界仍然是凹函数。
&emsp;&emsp;从上境图的角度理解,一系列函数的逐点上确界函数对应着这些函数上境图的交集:对于函数 $f$,$g$ 以及式 $\eqref{PointwiseMaximum}$ 定义的 $\mathcal{A}$,有
$$
\epi g=\bigcap_{y\in\mathcal{A}}\epi f(\:\cdot\:,y)
$$
因此,函数 $g$ 的凸性可由一系列凸集的交集仍然是凸集得到。
> **举例**&emsp;**集合的支撑函数**。令集合 $C\subseteq\mathbf{R}^n$,且 $C\neq\emptyset$,定义集合 $C$ 的**支撑函数**(*support function*)$S_C$ 为
>
> $$
> S_C(x)=\sup\{x^\TT y\mid y\in C\}
> $$
>
> (自然地,函数 $S_C$ 的定义域为 $\dom S_{C}=\left\{x\mid\sup_{y\in C}x^\TT y<\infty\right\}$)。
>
> 对于任意 $y\in C$,$x^\TT y$ 是 $x$ 的线性函数,所以 $S_{C}$ 是一系列线性函数的逐点上确界函数,因此是凸函数。
> **举例**&emsp;**到集合中最远点的距离**。令集合 $C\subseteq\mathbf{R}^n$,定义点 $x$ 与集合中最远点的距离(范数)为
>
> $$
> f(x)=\sup_{y\in C}\|x-y\|
> $$
>
> 此函数是凸函数。为了说明这一点,我们注意到,对于任意 $y$,函数 $\|x-y\|$ 关于 $x$ 是凸函数。因为函数 $f$ 是一族凸函数(对应不同的 $y\in C$)的逐点上确界,所以是凸函数。
> **举例**&emsp;**以权为变量的最小二乘代价函数**。令 $a_1,\cdots,a_n\in\mathbf{R}^m$,在加权最小二乘问题中我们对所有的 $x\in\mathbf{R}^m$ 极小化目标函数 $\displaystyle\sum_{i=1}^nw_i(a_i^\TT x-b_i)^2$。我们称 $w_i$ 为**权**(*weight*),并允许 $w_i$ 为负(则目标函数有可能无下界)。
>
> 定义(最优)**加权最小二乘代价**(*weighted least-squares cost*)函数为
>
> $$
> g(w)=\inf_{x}\sum_{i=1}^{n}w_{i}(a_{i}^{\TT}x-b_{i})^{2}
> $$
>
> 其定义域为
>
> $$\dom g=\left\{w\,\middle|\,\inf_{x}\sum_{i=1}^{n}w_{i}(a_{i}^{\TT}x-b_{i})^{2}>-\infty\right\}$$
>
> 因为函数 $g$ 是一族关于 $w$ 的线性函数的下确界(对应于不同的 $x\in\mathbf{R}^m$),它是 $w$ 的凹函数。
>
> 至少在部分定义域上,我们可以得到函数 $g$ 的一个显式表达式。令 $W=\diag(w)$ 是一对角阵,其对角线元素为 $w_1,\cdots,w_n$,令 $A\in\mathbf{R}^{n\times m}$,其行向量为 $a_i^\TT$,有
>
> $$
> g(w)=\inf_{x}(Ax-b)^{\TT}W(Ax-b)=\inf_{x}(x^{\TT}A^{\TT}WAx-2b^{\TT}WAx+b^{\TT}Wb)
> $$
>
> 从上式可以看出,若 $A^{\TT}WA\not\succeq0$,括号里的二次函数关于 $x$ 无下界,故 $g(w)=-\infty$,即 $w\not\in\dom g$。当 $A^\TT WA\succ0$ 时(即定义了一个严格的线性矩阵不等式),通过解析求解二次函数的极小值,可以得到函数 $g$ 的一个简单的表达式
>
> $$\begin{aligned}
> g(w)&=b^{\TT}Wb-b^{\TT}WA(A^{\TT}WA)^{-1}A^{\TT}Wb
> \\
> &=\sum_{i=1}^{n}w_{i}b_{i}^{2}-\sum_{i=1}^{n}w_{i}^{2}b_{i}^{2}a_{i}^{\TT}\left(\sum_{j=1}^{n}w_{j}a_{j}a_{j}^{\TT}\right)^{-1}a_{i}
> \end{aligned}$$
>
> 从上述表达式并不能立即得到函数 $g$ 的凹性(不过可以从矩阵分式函数的凸性来推导函数 $g$ 的凹性)。
> **举例**&emsp;**对称矩阵的最大特征值**。 定义函数 $f(X)=\lambda_{\max}(X)$,其定义域为 $\dom f=\mathbf{S}^m$,它是凸函数。为了说明这一点,我们将 $f$ 表述为
>
> $$
> f(X)=\sup\{y^\TT Xy\mid\|y\|_2=1\}
> $$
>
> 即针对不同的 $y\in\mathbf{R}^m$ 关于 $X$ 的一族线性函数(即$y^\TT Xy$)的逐点上确界。
> **举例**&emsp;**矩阵范数**。考虑函数 $f(X)=\|X\|_2$,其定义域为 $\dom f=\mathbf{R}^{p\times q}$,其中 $\|\cdot\|_2$ 表示谱范数或者最大奇异值。函数 $f$ 可以表述为
>
> $$
> f(X)=\sup\{u^{\TT}Xv\mid\|u\|_{2}=1,\|v\|_{2}=1\}
> $$
>
> 由于它是 $X$ 的一族线性函数的逐点上确界,所以是凸函数。
>
> 作为一个推广,假设 $\|\cdot\|_a$和$\|\cdot\|_b$ 分别是 $\mathbf{R}^p$ 和 $\mathbf{R}^q$ 上的范数,定义矩阵 $X\in\mathbf{R}^{p\times q}$ 的诱导范数为
>
> $$
> \|X\|_{a,b}=\sup_{v\neq0}\frac{\|Xv\|_{a}}{\|v\|_{b}}
> $$
## 3.3 表示成一族仿射函数的逐点上确界
&emsp;&emsp;上述例子描述了一个建立函数凸性的好方法:将函数表示为一族仿射函数的逐点上确界。除了一个技术条件,反过来也是成立的:几乎所有的凸函数都可以表示成一族仿射函数的逐点上确界。例如,若函数 $f:\mathbf{R}^n\to\mathbf{R}$ 是凸函数,其定义域为 $\dom f=\mathbf{R}^n$,我们有
$$
f(x)=\sup\{g(x)\mid g\:\text{仿射},\:g(z)\leqslant f(z)\:\forall z\}
$$
换言之,函数 $f$ 是它所有的仿射全局下估计的逐点上确界。下面我们将证明这个结论。
&emsp;&emsp;设函数 $f$ 是凸函数,定义域为 $\dom f=\mathbf{R}^{n}$ ,显然下面的不等式成立
$$
f ( x ) \geqslant \sup \{g ( x ) \mid g\:\text{仿射}, \ g ( z ) \leqslant f ( z ) \ \forall z \},
$$
因为函数 $g$ 是函数 $f$ 的任意仿射下估计,我们有 $g ( x ) \leqslant f ( x )$。为了建立等式,我们说明,对于任意 $x \in\mathbf{R}^{n}$,存在仿射函数 $g$ 是函数 $f$ 的全局下估计,并且满足 $g ( x )=f ( x )$。
&emsp;&emsp;毫无疑问,函数 $f$ 的上境图是凸集,因此我们在点 $( x, f ( x ) )$ 处可以找到此凸集的支撑超平面,即存在 $a \in\mathbf{R}^{n}$,$\; b \in\mathbf{R}$ 且 $( a, b ) \neq0$,使得对任意 $( z, t ) \in\epi f$,有
$$
\left[ \begin{array} {c} a \\ b \\ \end{array} \right]^{\TT} \left[ \begin{array} {c} {x-z} \\ {f ( x )-t} \\ \end{array} \right] \leqslant0.
$$
即对任意 $z\in\dom f=\mathbf{R}^n$ 以及所有 $s\geqslant0$($(z,t)\in\epi f$ 等价于存在 $s\geqslant0$ 使得 $t=f(z)+s$),下式成立
$$\begin{equation}\label{ProofOfAffineFunctionRepresentation}
a^\TT(x-z)+b(f(x)-f(z)-s)\leqslant0
\end{equation}
$$
为了保证不等式 $\eqref{ProofOfAffineFunctionRepresentation}$ 对所有的 $s\geqslant0$ 均成立,必须有 $b\geqslant0$。若 $b=0$,对所有的$z\in\mathbf{R}^n$,不等式 $\eqref{ProofOfAffineFunctionRepresentation}$ 可以简化为 $a^\TT(x-z)\leqslant0$,这意味着 $a=0$,于是和假设 $(a,b)\neq0$ 矛盾。因此 $b>0$,即支撑超平面不是竖直的。
&emsp;&emsp;我们知道 $b>0$,因此,对任意 $z$,令 $s=0$,式 $\eqref{ProofOfAffineFunctionRepresentation}$ 可以重新表述为
$$
g(z)=f(x)+(a/b)^{\TT}(x-z)\leqslant f(z)
$$
由此说明函数 $g$ 是函数 $f$ 的一个仿射下估计,并且满足 $g(x)=f(x)$。
# 4. 复合
&emsp;&emsp;本节给定函数 $h:\mathbf{R}^k\to\mathbf{R}$ 以及 $g:\mathbf{R}^n\to\mathbf{R}^k$,定义复合函数 $f=h\circ g:\mathbf{R}^n\to\mathbf{R}$ 为
$$
f(x)=h(g(x)),\quad\dom f=\{x\in\dom g\mid g(x)\in\dom h\}
$$
我们考虑当函数 $f$ 保凸或者保凹时,函数 $h$ 和 $g$ 必须满足的条件。
## 4.1 标量复合
&emsp;&emsp;首先考虑 $k=1$ 的情况,即 $h:\mathbf{R}\to\mathbf{R}$,$g:\mathbf{R}^n\to\mathbf{R}$。仅考虑 $n=1$ 的情况(事实上,将函数限定在与其定义域相交的任意直线上得到的函数决定了原函数的凸性)。
&emsp;&emsp;为了找出复合规律,首先假设函数 $h$ 和 $g$ 是二次可微的,且 $\dom g= \dom h= \mathbf{R}$。在上述假设下,函数 $f$ 是凸的等价于 $f^{\prime\prime}\geqslant 0$(即对所有的 $x\in\mathbf{R}$,$f^{\prime\prime}(x)\geqslant 0$)。
&emsp;&emsp;复合函数 $f=h\circ g$ 的二阶导数为
$$\begin{equation}\label{SecondDerivativeOfScalarCompositionFunction}
f''(x)=h''(g(x))g'(x)^2+h'(g(x))g''(x)
\end{equation}$$
假设函数 $g$ 是凸函数($g^{\prime\prime}\geqslant 0$),函数 $h$ 是凸函数且非减(即$h^{\prime\prime}\geqslant0$ 且 $h^{\prime}\geqslant0$),从式 $\eqref{SecondDerivativeOfScalarCompositionFunction}$ 可以得出 $f^{\prime\prime}\geqslant 0$,即函数 $f$ 是凸函数。类似地,由式 $\eqref{SecondDerivativeOfScalarCompositionFunction}$ 可以得出如下结论
$$\begin{equation}\label{Conclusion1}\begin{aligned}
若\,h\,是凸函数且非减,g\,是凸函数,则\,f\,是凸函数,\\
若\,h\,是凸函数且非增,g\,是凹函数,则\,f\,是凸函数,\\
若\,h\,是凹函数且非减,g\,是凹函数,则\,f\,是凹函数,\\
若\,h\,是凹函数且非增,g\,是凸函数,则\,f\,是凹函数。
\end{aligned}\end{equation}$$
上述结论在函数 $g$ 和 $h$ 二次可微且定义域均为 $\mathbf{R}$ 时成立。事实上,对于更一般的情况,如 $n>1$,不再假设函数 $h$ 和 $g$ 可微或者 $\dom g=\mathbf{R}^n$,$\dom h=\mathbf{R}$,一些相似的复合规则仍然成立
$$\begin{equation}\label{Conclusion2}\begin{aligned}
若\,h\,是凸函数且\,\tilde{h}\,非减,\,g\,是凸函数,则\,f\,是凸函数,\\
若\,h\,是凸函数且\,\tilde{h}\,非增,\,g\,是凹函数,则\,f\,是凸函数,\\
若\,h\,是凹函数且\,\tilde{h}\,非减,\,g\,是凹函数,则\,f\,是凹函数,\\
若\,h\,是凹函数且\,\tilde{h}\,非增,\,g\,是凸函数,则\,f\,是凹函数。
\end{aligned}\end{equation}$$
其中,$\tilde{h}$ 表示函数 $h$ 的扩展值延伸,若点不在 $\dom h$ 内,对其赋值 $\infty$(若 $h$ 是凸函数)或者$-\infty$(若 $h$ 是凹函数)。这些结论和式 $\eqref{Conclusion1}$ 中的结论的唯一不同是我们要求**扩展值延伸**(*extended-value extension*)$\tilde{h}$ 在整个 $\mathbf{R}$ 上非增或者非减。
&emsp;&emsp;为了更好地理解式 $\eqref{Conclusion2}$ 中的结论,假设 $h$ 是凸函数,所以 $\tilde{h}$ 在定义域 $\dom h$ 外取值为 $\infty$。$\tilde{h}$ 非减意味着对于任意 $x,y\in\mathbf{R}$,$x<y$,有 $\tilde{h}(x)\leqslant\tilde{h}(y)$。特别地,若 $y\in\dom h$,则 $x\in\dom h$。换言之,我们可以认为 $h$ 的定义域在负方向上无限延伸。它或者是 $\mathbf{R}$ 或者是形如 $(-\infty,a)$ 或 $\left(-\infty,a\right]$ 的区间。类似地,若 $h$ 是凸函数且 $\tilde{h}$ 非增,我们可以理解为 $h$ 是非增的且 $\dom h$ 在正方向上趋于无穷。[图 7](#图7) 描述了不同的扩展值延伸的情况。
<a id="图7"></a>
![图 7. **左**:函数 $x^2$,其定义域为 $\mathbf{R}_+$,在其定义域内是凸且非减的,但是其扩展值延伸不是非减的。**右**:函数 $\max\{x,0\}^2$,其定义域为 $\mathbf{R}$,函数是凸函数,且其扩展值延伸是非减的。](../images/post/2024-07-03-josh-cvx-2-2/2024-07-03-josh-cvx-2-2-070-ExtendedValueExtension.png){width=700px}
> **举例**&emsp;通过一些简单例子,我们可以更好地理解复合定理中函数 $h$ 需要满足的条件。
>
> - 函数 $h(x)=\log x$:定义域为 $\dom h=\mathbf{R}_{++}$,为凹函数且 $\tilde{h}$ 非减。
> - 函数 $h(x)=x^1/2$:定义域为 $\dom h=\mathbf{R}_+$,为凹函数且 $\tilde{h}$ 非减。
> - 函数 $h(x)=x^{3/2}$:定义域为 $\dom h=\mathbf{R}_+$,为凸函数,但是**不**满足 $\tilde{h}$ 非减的条件。例如,$\tilde{h}(-1)=\infty$ 但 $\tilde{h}(1)=1$。
> - 当 $x\geqslant 0$ 时,$h(x)=x^3/2$,当 $x<0$ 时,$h(x)=0$:定义域为 $\dom h=\mathbf{R}$,$h$ 是凸函数且满足 $\tilde{h}$ 非减的条件。
&emsp;&emsp;即使不假设可微并运用表达式 $\eqref{SecondDerivativeOfScalarCompositionFunction}$,也可以直接证明复合函数结论式 $\eqref{Conclusion2}$。举例来说,我们证明如下结论:若 $g$ 是凸函数,$h$ 是凸函数且 $\tilde{h}$ 非减,则 $f=h\circ g$ 是凸函数。
> **证明**&emsp;假设 $x,y\in\dom f$,$0\leqslant\theta\leqslant1$。由 $x,y\in\dom f$,有 $x,y\in\dom g$ 且 $g( x)$, $g( y) \in \dom h$。因为 $\dom g$ 是凸集,有 $\theta x+(1-\theta)y\in\dom g$,由函数 $g$ 的凸性可得
>
> $$\begin{equation}\label{ConvexityOfFunctionG}
> g(\theta x+(1-\theta)y)\leqslant\theta g(x)+(1-\theta)g(y)
> \end{equation}
> $$
>
> 由 $g(x),g(y)\in\dom h$ 可得 $\theta g(x)+(1-\theta)g(y)\in\dom h$,即式 $\eqref{ConvexityOfFunctionG}$ 的右端在 $\dom h$ 内。根据假设 $\tilde{h}$ 是非减的,可以理解为其定义域在负方向上无限延伸。由式 $\eqref{ConvexityOfFunctionG}$ 的右端在 $\dom h$ 内,我们知道其左侧仍在定义域内,即 $g(\theta x+(1-\theta)y)\in\dom h$,因此 $\dom f$ 是凸集。
>
> 根据前提条件,$\tilde{h}$ 非减,利用不等式 $\eqref{ConvexityOfFunctionG}$,有
>
> $$\begin{equation}\label{NondecreasingOfFunctionH}
> h(g(\theta x+(1-\theta)y))\leqslant h(\theta g(x)+(1-\theta)g(y))
> \end{equation}
> $$
>
> 由函数 $h$ 的凸性可得
>
> $$\begin{equation}\label{ConvexityOfFunctionH}
> h(\theta g(x)+(1-\theta)g(y))\leqslant\theta h(g(x))+(1-\theta)h(g(y))
> \end{equation}
> $$
>
> 综合式 $\eqref{NondecreasingOfFunctionH}$ 和式 $\eqref{ConvexityOfFunctionH}$ 可得
>
> $$
> h(g(\theta x+(1-\theta)y))\leqslant\theta h(g(x))+(1-\theta)h(g(y))
> $$
>
> 复合定理得证。
> **举例**&emsp;**简单的复合结论**。
>
> - 若 $g$ 是凸函数,则 $\exp g(x)$ 是凸函数。
> - 若 $g$ 是凹函数且大于零,则 $\log g(x)$ 是凹函数。
> - 若 $g$ 是凹函数且大于零,则 $1/g(x)$是凸函数。
> - 若 $g$ 是凸函数且不小于零,$p\geqslant1$,则 $g(x)^p$ 是凸函数。
> - 若 $g$ 是凸函数,则 $-\log(-g(x))$ 在 $\{x\mid g(x)<0\}$ 上是凸函数。
> **注释**&emsp;扩展值延伸 $\tilde{h}$ 的单调性要求必须满足,注意到是 $\tilde{h}$,而不仅仅是 $h$。例如,考虑 $g( x) = x^2$,$\dom g = \mathbf{R}$,$h( x) = 0$,$\dom h= [ 1, 2]$ 复合的情形。此时 $g$ 是凸函数,$h$ 是凸函数且非减,但是函数 $f=h\circ g$
>
> $$
> f(x)=0,\quad\dom f=[-\sqrt{2},-1]\:\cup\:[1,\sqrt{2}]
> $$
>
> 不是凸函数,因为其定义域非凸。当然,此时函数 $\tilde{h}$ 不是非减的。
## 4.2 矢量复合
&emsp;&emsp;下面考虑 $k\geqslant1$ 的情况,此时更复杂一些。设
$$
f(x)=h(g(x))=h(g_1(x),\cdots,g_k(x))
$$
其中 $h: \mathbf{R} ^k\to \mathbf{R}$,$g_i: \mathbf{R} ^n\to \mathbf{R}$。和上一节一样,不失一般性,假设 $n=1$。和 $k=1$ 的情形类似,为了得到复合规则,假设函数二次可微,且 $\dom g=$ $\mathbf{R}$,$\dom h= \mathbf{R} ^{k}$。此时,对函数 $f$ 进行二次微分可得
$$\begin{equation}\label{SecondDerivativeOfVectorCompositionFunction}
f''(x)=g'(x)^{\TT}\nabla^2h(g(x))g'(x)+\nabla h(g(x))^{\TT}g''(x)
\end{equation}
$$
上式可以看成式 $\eqref{SecondDerivativeOfScalarCompositionFunction}$ 对应的向量形式。同样我们需要判断在什么条件下对所有 $x$ 有 $f(x)^{\prime\prime}\geqslant0$(或者对所有 $x$ 有 $f(x)^\prime\prime\leqslant 0$,此时 $f$ 是凹函数)。利用式 $\eqref{SecondDerivativeOfVectorCompositionFunction}$,我们可以得到很多规则,例如:
$$\begin{aligned}
若\:h\:是凸函数且在每维分量上\:h\:非减,g_i\:是凸函数,则\:f\:是凸函数;\\
若\:h\:是凸函数且在每维分量上\:h\:非增,g_i\:是凹函数,则\:f\:是凸函数;\\
若\:h\:是凹函数且在每维分量上\:h\:非减,g_i\:是凹函数,则\:f\:是凹函数。
\end{aligned}$$
和标量的情形类似,对于更一般的情况:$n>1$,不假设 $h$ 或 $g$ 可微以及一般的定义域类似的复合结论仍然成立。对于一般的结论,不仅 $h$ 需要满足单调性条件,其扩展值延伸 $\tilde{h}$ 同样必须满足。
&emsp;&emsp;为了更好地理解扩展值延伸 $\tilde{h}$ 必须满足单调性条件的含义,我们考虑凸函数 $h:\mathbf{R}^{k}\to\mathbf{R}$,且 $\tilde{h}$ 非减,即对任意 $u\preceq v$,有 $\tilde{h}(u)\leqslant\tilde{h}(v)$。这说明了若 $v\in\dom h$ 则 $u\in\dom h$,也即 $h$ 的定义域在方向 $-\mathbf{R}_+^k$ 上必须无限延伸。这个条件可以紧凑地描述为 $\dom h-\mathbf{R}_{+}^{k}=\dom h$。
> **举例**&emsp;矢量复合的例子。
>
> - 令 $h(z)=z_[1]+\cdots+z_{[r]}$,即对 $z\in\mathbf{R}^k$ 的前 $r$ 大分量进行求和。则 $h$ 是凸函数且在每一维分量上非减。假设 $g_1,\cdots,g_k$ 是 $\mathbf{R}^n$ 上的凸函数,则复合函数 $f=h\circ g$,即最大 $r\uparrow g_i$ 函数的逐点和,是凸函数。
>
> - 函数 $h(z)=\log\left(\displaystyle\sum_{i=1}^k\mathrm{e}^{z_i}\right)$ 是凸函数且在每一维分量上非减,因此只要 $g_i$ 是凸函数,$\log\left(\displaystyle\sum_{i=1}^{k}\mathrm{e}^{g_{i}}\right)$ 就是凸函数。
>
> - 对 $0<p\leqslant 1$,定义在 $\mathbf{R}_+^k$ 上的函数 $h(z)=\left(\displaystyle\sum_{i=1}^kz_i^p\right)^{1/p}$ 是凹的,且其扩展值延伸(当 $z\not\succeq0$ 时为 $-\infty$)在每维分量上非减,则若 $g_i$ 是凹函数且非负,$f(x)=\left(\displaystyle\sum_{i=1}^kg_i(x)^p\right)^{1/p}$ 是凸函数。
>
> - 设 $p\geqslant 1$, $g_{1}, \cdots , g_{k}$ 是凸函数且非负。则函数 $\left(\displaystyle\sum_{i=1}^ng_i(x)^p\right)^{1/p}$
>
> 为了说明这一点,考虑函数 $h:\mathbf{R}^k\to\mathbf{R}$
>
> $$
> h(z)=\left(\sum_{i=1}^{k}\max\{z_{i},0\}^{p}\right)^{1/p}
> $$
>
> 其中 $\dom h=\mathbf{R}^{k}$,因此 $h=\tilde{h}$。由函数 $h$ 是凸函数且非减可知 $h(g(x))$ 关于 $x$ 是凸函数。对 $z\succeq0$,我们有 $h(z)=\left(\displaystyle\sum_{i=1}^kz_i^p\right)^{1/p}$,所以 $\left(\displaystyle\sum_{i=1}^kg_i(x)^p\right)^{1/p}$ 是凸函数。
>
> - 几何平均函数 $h(z)=\left(\displaystyle\prod_{i=1}^kz_i\right)^{1/k}$,定义域为 $\mathbf{R}_+^k$,它是凹函数,且其扩展值延伸在每维分量上非减。因此若 $g_1,\cdots,g_k$ 是非负凹函数,它们的几何平均 $\left(\displaystyle\prod_{i=1}^kg_i\right)^{1/k}$ 也是非负凸函数。
# 5. 最小化
&emsp;&emsp;我们已经得到,任意个凸函数的逐点最大或者上确界仍然是凸函数。事实上,一些特殊形式的最小化同样可以得到凸函数。若函数 $f$ 关于 $(x,y)$ 是凸函数,集合 $C$ 是非空凸集,定义函数
$$\begin{equation}\label{DefinitionOfMinimization}
g(x)=\inf_{y\in C}f(x,y)
\end{equation}
$$
若存在某个 $x$ 使得 $g(x)>-\infty$(该条件隐含着对所有 $x,g(x)>-\infty$),则函数 $g$ 关于 $x$ 是凸函数。函数 $g$ 的定义域是 $\dom f$ 在 $x$ 方向上的投影,即
$$
\dom g=\{x\mid 对某些\:y\in C\:有\: (x,y)\in\dom f\}
$$
&emsp;&emsp;任取 $x_1$, $x_2\in \dom g$,利用 Jensen 不等式来证明上述结论。
> **证明**&emsp;令 $\epsilon>0$,则存在 $y_{1}$, $y_{2}\in C$,使 $f( x_{i}, y_{i}) \leqslant g( x_{i}) + \epsilon ( i= 1$, 2)。设 $\theta\in[0,1]$,有
>
> $$\begin{aligned}
> g(\theta x_{1}+(1-\theta)x_{2})&=\inf_{y\in C}f(\theta x_{1}+(1-\theta)x_{2},y)
> \\
> &\leqslant f(\theta x_1+(1-\theta)x_2,\theta y_1+(1-\theta)y_2)
> \\
> &\leqslant\theta f(x_1,y_1)+(1-\theta)f(x_2,y_2)
> \\
> &\leqslant\theta g(x_1)+(1-\theta)g(x_2)+\epsilon
> \end{aligned}$$
>
> 因为上式对任意$\epsilon>0$均成立,所以下式成立
> $$
> g(\theta x_1+(1-\theta)x_2)\leqslant\theta g(x_1)+(1-\theta)g(x_2)
> $$
&emsp;&emsp;此结论亦可通过上境图来说明。对式 $\eqref{DefinitionOfMinimization}$ 中定义的 $f$,$g$ 和 $C$,设对每个 $x$,在集合 $y\in C$ 上求下确界均可达到,则有
$$
\epi g=\{(x,t)\mid$对某个$y\in C$成立$(x,y,t)\in\epi f\}
$$
由于 $\epi g$是凸集在其中一些分量上的投影,所以它仍然是凸集。
> **举例**&emsp;**Schur 补**。设二次函数
>
> $$
> f(x,y)=x^{\TT}Ax+2x^{\TT}By+y^{\TT}Cy
> $$
>
> (其中$A$和$C$是对称矩阵)关于 $(x,y)$ 是凸函数,即
>
> $$
> \left[\begin{array}{cc}A&B\\B^{\TT}&C\end{array}\right]\succeq0
> $$
>
> 我们可以将$g(x)=\inf_yf(x,y)$表述为
>
> $$
> g(x)=x^{\TT}(A-BC^\dagger B^{\TT})x
> $$
>
> 其中 $C^\dagger$ 是矩阵 $C$ 的伪逆。根据极小化的性质,$g$ 是凸函数,因此 $A-BC^\dagger B^{\TT}\succeq 0$。
>
> 如果矩阵$C$可逆,即$C\succ0$,则矩阵$A-BC^{-1}B^{\TT}$称为$C$在矩阵
>
> $$
> \left[\begin{array}{cc}A&B\\B^{\TT}&C\end{array}\right]
> $$
>
> 中的 Schur 补。
> **举例**&emsp;**到某一集合的距离**。采用范数 $\|\cdot\|$,某点$x$到集合 $S\subseteq\mathbb{R}^n$ 的距离定义为
>
> $$
> \dist (x,S)=\inf_{y\in S}\|x-y\|
> $$
>
> 函数 $\|x-y\|$关于$(x,y)$ 是凸的,所以若集合 $S$ 是凸集,距离函数 $\dist (x,S)$ 是 $x$ 的凸函数。
> **举例**&emsp;设 $h$ 是凸函数。则函数 $g$
>
> $$
> g(x)=\inf\{h(y)\mid Ay=x\}
> $$
>
> 是凸函数。为了说明这一点,定义函数 $f$
>
> $$
> f(x,y)=\left\{\begin{array}{ll}h(y)&\text{如果}Ay=x\\\infty&\text{其他情况,}\end{array}\right.
> $$
>
> 此函数关于$(x,y)$是凸的。以$y$为自变量,极小化函数$f$即可得到函数$g$,因此函数$g$是凸函数。(直接证明$g$是凸函数亦不复杂。)
# 6. 透视函数
&emsp;&emsp;给定函数 $f:\mathbf{R}^n\to\mathbf{R}$,则 $f$ 的透视函数 $g:\mathbf{R}^n+1\to\mathbf{R}$ 定义为
$$
g(x,t)=tf(x/t)
$$
其定义域为
$$
\mathbf{dom}g=\{(x,t)\mid x/t\in\mathbf{dom}f,t>0\}
$$
透视运算是保凸运算:如果函数 $f$ 是凸函数,则其透视函数 $g$ 也是凸函数。类似地,若
$f$ 是凹函数,则 $g$ 亦是凹函数。
&emsp;&emsp;可以从多个角度来证明此结论,例如,我们可以直接验证定义凸性的不等式。这里应用上境图和[透视函数][]一节所描述的 $\mathbf{R}^{n+1}$ 上的透视映射给出一个简短的证明(同时也可以说明“透视”一词的由来)。当 $t>0$ 时,我们有
$$\begin{array}{lll}
(x,t,s)\in\epi g&\iff&tf(x/t)\leqslant s
\\
&\iff&f(x/t)\leqslant s/t
\\
&\iff&(x/t,s/t)\in\epi f
\end{array}$$
因此,$\epi g$是透视映射下 $\epi f$ 的原像,此透视映射将 $(u,v,w)$ 映射为 $(u,w)/v$。根据[透视函数][]一节中的结论,$\epi g$ 是凸集,所以函数 $g$ 是凸函数。
> **举例**&emsp;**Euclid 范数的平方**。$\mathbb{R}^n$ 上的凸函数 $f(x)=x^{\TT}x$ 的透视函数由下式给出
>
> $$
> g(x,t)=t(x/t)^{\TT}(x/t)=\frac{x^{\TT}x}{t}
> $$
>
> 当 $t>0$ 时它关于 $(x,t)$ 是凸函数。
>
> 我们可以利用其他方法导出$g$的凸性。首先,将 $g$ 表示为一系列二次-线性分式函数 $x_i^2/t$ 的和。在[凸函数举例][]部分,我们已经知道,每一项 $x_i^2/t$ 是凸函数,因此和亦为凸函数。另一方面。我们可以将 $g$ 表述为一种特殊的矩阵分式函数 $x^{\TT}(tI)^{-1}x$,由此导出凸性。
> **举例**&emsp;**负对数**。考虑 $\mathbf{R}_{++}$ 上的凸函数 $f(x)=-\log x$,其透视函数为
>
> $$
> g(x,t)=-t\log(x/t)=t\log(t/x)=t\log t-t\log x
> $$
>
> 在 $\mathbf{R}_{++}^{2}$ 上它是凸函数。函数 $g$ 称为关于 $t$ 和 $x$ 的**相对熵**(*relative entropy*)。当 $x=1$ 时,$g$ 即为负熵函数。
>
> 基于函数 $g$ 的凸性,我们可以得出一些有趣的相关函数的凸性或凹性。首先,定义两个向量 $u, v\in \mathbf{R} _{+ + }^{n}$ 的相对熵
>
> $$
> \sum_{i=1}^nu_i\log(u_i/v_i)
> $$
>
> 由于它是一系列 $u_i,v_i$ 的相对熵的和,因此关于 $(u,v)$ 是凸函数。
>
> 另一个密切相关的函数是向量 $u,v\in\mathbf{R}_{++}^{n}$ 之间的 **Kullback-Leibler 散度**(Kullback-Leibler divergence),其形式为
>
> $$\begin{equation}\label{KLDivergence}
> D_{\mathrm{kl}}(u,v)=\sum_{i=1}^{n}\left(u_{i}\log(u_{i}/v_{i})-u_{i}+v_{i}\right)
> \end{equation}
> $$
>
> 因为它是 $(u,v)$ 的相对熵和线性函数的和,所以它也是凸函数。Kullback-Leibler 散度总是满足 $D_{\mathrm{kl}}(u,v)\geqslant0$,当且仅当 $u=v$ 时,$D_\mathrm{kl}(u,v)=0$,因此 Kullback-Leibler 散度可以用来衡量两个正向量之间的偏差。(注意到当 $u$ 和 $v$ 都是概率向量,即 $\mathbf{1}^{\TT}u=\mathbf{1}^{\TT}v=1$ 时,相对熵和 Kullback-Leibler 散度是等价的。)
>
> 如果在相对熵函数中选择 $v_i=\mathbf{1}^{\TT}u$,我们可以得到定义在 $u\in\mathbb{R}_+^n$ 上的凹函数(也是齐次函数)
>
> $$
> \sum_{i=1}^{n}u_{i}\log(\mathbf{1}^{\TT}u/u_{i})=(\mathbf{1}^{\TT}u)\sum_{i=1}^{n}z_{i}\log(1/z_{i})
> $$
>
> 其中 $z=u/(\mathbf{1}^{\TT}u)$。此函数称为**归一化熵**(*normalized entropy*)函数。向量 $z=u/\mathbf{1}^{\TT}u$ 的分量和为 1,称为归一化向量或者概率分布;$u$ 的归一化熵是 $\mathbf{1}^{\TT}u$和归一化概率分布 $z$ 的熵的乘积。
> **举例**&emsp;设 $f:\mathbf{R}^m\to\mathbf{R}$ 是凸函数,$A\in\mathbf{R}^m\times n,b\in\mathbf{R}^m,c\in\mathbf{R}^n,d\in\mathbf{R}$。定义
>
> $$
> g(x)=(c^Tx+d)f\left((Ax+b)/(c^Tx+d)\right)
> $$
>
> 其定义域为
>
> $$
> \mathbf{dom}g=\{x\mid c^Tx+d>0,(Ax+b)/(c^Tx+d)\in\mathbf{dom}f\}
> $$
>
> 则$g$是凸函数。
# 参考文献
1. Stephen P. Boyd and Lieven Vandenberghe, *Convex optimization*. Cambridge, UK: Cambridge University Press, 2004.
2. Stephen P. Boyd and Lieven Vandenberghe, *凸优化*. 北京: 清华大学出版社, 2013.
[透视函数]: https://josh-gao.top/posts/a4a69a4f.html#%E9%80%8F%E8%A7%86%E5%87%BD%E6%95%B0
[凸函数举例]: https://josh-gao.top/posts/320f661c.html#%E4%BE%8B%E5%AD%90
@@ -0,0 +1,279 @@
---
title: 信息论角度推导高斯分布的概率密度函数
mathjax: true
comments: true
copyright: true
toc:
enable: true
number: true
wrap: true
expand_all: true
max_depth: 4
abbrlink: '741621e3'
date: 2025-07-02 09:20:07
tags:
- 高斯分布
- 信息论
categories:
- [数学, 概率论]
---
$\newcommand\diff{\mathop{}\!\mathrm{d}}$
# 背景与目标
在统计建模中,我们常常面临这样一个问题:**已知某个连续随机变量的期望和方差,如何合理地确定它的概率分布?** 最大熵原理(Maximum Entropy Principle)提供了一个具有信息论意义的答案:
> 在已知约束(如期望与方差)下,熵最大的概率密度函数是最“中立”或最“无偏”的选择。
熵在此表示不确定性或信息量。连续型随机变量的微分熵定义为:
$$
\begin{equation*}
H[p] = -\int_{-\infty}^{\infty} p(x) \ln p(x) \, \diff x
\end{equation*}
$$
我们的目标是:**在已知期望和方差的约束下,最大化熵 $H[p]$,求出最优概率密度函数 $p(x)$**。
<!-- more -->
# 约束条件
我们假设随机变量 $X$ 满足:
- 归一化约束:
$$
\begin{equation*}
\int_{-\infty}^{\infty} p(x) \, \diff x = 1
\end{equation*}
$$
- 期望约束:
$$
\begin{equation*}
\int_{-\infty}^{\infty} x \, p(x) \, \diff x = \mu
\end{equation*}
$$
- 方差约束:
$$
\begin{equation*}
\int_{-\infty}^{\infty} (x - \mu)^2 \, p(x) \, \diff x = \sigma^2
\end{equation*}
$$
# 构造拉格朗日泛函
引入拉格朗日乘子 $\lambda_0, \lambda_1, \lambda_2$,构造带约束的目标泛函:
$$
\begin{equation*}
\mathcal{L}[p] = -\int p(x) \ln p(x) \diff x
+ \lambda_0 \left( \int p(x) \diff x - 1 \right)
+ \lambda_1 \left( \int x p(x) \diff x - \mu \right)
+ \lambda_2 \left( \int (x - \mu)^2 p(x) \diff x - \sigma^2 \right)
\end{equation*}
$$
将所有积分项合并为:
$$
\begin{equation*}
\mathcal{L}[p] = \int \left[
- p(x) \ln p(x)
+ \lambda_0 p(x)
+ \lambda_1 x p(x)
+ \lambda_2 (x - \mu)^2 p(x)
\right] \diff x
\end{equation*}
$$
# 变分法求极值
我们考虑一个扰动:
$$
\begin{equation*}
p(x) \rightarrow p(x) + \epsilon \eta(x)
\end{equation*}
$$
其中 $\epsilon$ 是足够小的实数,$\eta(x)$ 是任意光滑、在积分区间内有界且满足边界条件的函数(可理解为“任意小的扰动”)。为了求出 $\dfrac{\delta \mathcal{L}}{\delta p(x)}$,我们代入扰动项进行展开:
$$
\begin{equation*}
\mathcal{L}[p + \epsilon \eta]
= -\int (p(x) + \epsilon \eta(x)) \ln (p(x) + \epsilon \eta(x)) \, \diff x + \text{其余约束项}
\end{equation*}
$$
> 注意:这里只展开了主熵项 $-\displaystyle\int p \ln p$,约束项形式类似,将在后面统一处理。
---
对主项使用泰勒展开(忽略高阶小量):
> **泰勒展开回顾:**
>
> 设 $f(p) = p \ln p$,我们对 $p(x) + \epsilon \eta(x)$ 展开,有:
> $$
> f(p + \epsilon \eta) = p \ln p + \epsilon \eta (1 + \ln p) + o(\epsilon)
> $$
> 其中:
> $$
> \frac{\diff }{\diff p}(p \ln p) = \ln p + 1
> $$
将其代入:
$$
\begin{align*}
\mathcal{L}[p + \epsilon \eta]
&= -\int \left[ p(x) \ln p(x) + \epsilon \eta(x)(1 + \ln p(x)) \right] \diff x + o(\epsilon) + \text{约束项} \\
&= \mathcal{L}[p] - \epsilon \int \eta(x) (1 + \ln p(x)) \diff x + o(\epsilon) + \text{约束项}
\end{align*}
$$
对约束项也类似展开:
- 对归一化项:
$$
\begin{equation*}
\lambda_0 \left( \int (p + \epsilon \eta) \diff x - 1 \right)
= \lambda_0 \left( \int p \, \diff x - 1 + \epsilon \int \eta \, \diff x \right)
\end{equation*}
$$
- 对期望项:
$$
\begin{equation*}
\lambda_1 \left( \int x (p + \epsilon \eta) \diff x - \mu \right)
= \lambda_1 \left( \int x p \, \diff x - \mu + \epsilon \int x \eta \, \diff x \right)
\end{equation*}
$$
- 对方差项:
$$
\begin{equation*}
\lambda_2 \left( \int (x - \mu)^2 (p + \epsilon \eta) \diff x - \sigma^2 \right)
= \lambda_2 \left( \int (x - \mu)^2 p \, \diff x - \sigma^2 + \epsilon \int (x - \mu)^2 \eta(x) \diff x \right)
\end{equation*}
$$
---
将所有一阶 $\epsilon$ 项收集起来:
$$
\begin{equation*}
\mathcal{L}[p + \epsilon \eta] = \mathcal{L}[p]
+ \epsilon \int \eta(x) \left[ - (1 + \ln p(x)) + \lambda_0 + \lambda_1 x + \lambda_2 (x - \mu)^2 \right] \diff x + o(\epsilon)
\end{equation*}
$$
对 $\epsilon$ 求导并令其在 $\epsilon = 0$ 处为零:
$$
\begin{equation*}
\left. \frac{\diff}{\diff \epsilon} \mathcal{L}[p + \epsilon \eta] \right|_{\epsilon=0}
= \int \eta(x) \left[ -\ln p(x) - 1 + \lambda_0 + \lambda_1 x + \lambda_2 (x - \mu)^2 \right] \diff x = 0
\end{equation*}
$$
根据变分法基本引理,这个积分当且仅当括号内为 $0$ 时对所有扰动函数 $\eta(x)$ 为零:
> 变分法基本引理:
>
> 若函数 $F(x)$ 满足
> $$
> \int_{a}^{b} F(x) \cdot \eta(x) dx = 0
> $$
> 对所有合适扰动 $\eta(x)$ 成立,则必有
> $$
> F(x) = 0 \quad \forall x \in (a, b)
> $$
>
> 这是因为若 $F(x_0) \ne 0$,则可构造在 $x_0$ 附近支持的 $\eta(x)$ 使得积分不为零,导致矛盾。
$$
\begin{equation*}
\frac{\delta \mathcal{L}}{\delta p(x)} = -\ln p(x) - 1 + \lambda_0 + \lambda_1 x + \lambda_2 (x - \mu)^2 = 0
\end{equation*}
$$
也即求得了变分导数。移项得:
$$
\begin{equation*}
\ln p(x) = \lambda_0' + \lambda_1 x + \lambda_2 (x - \mu)^2
\end{equation*}
$$
两边取指数:
$$
\begin{equation*}
p(x) = \exp\left( \lambda_0' + \lambda_1 x + \lambda_2 (x - \mu)^2 \right)
\end{equation*}
$$
要满足可积性,需 $\lambda_2 < 0$。设
$$
\begin{equation*}
p(x) = A \cdot \exp\left( -\alpha (x - \mu)^2 \right)
\end{equation*}
$$
# 归一化与确定参数
根据归一化条件:
$$
\begin{equation*}
A \cdot \int_{-\infty}^{\infty} \exp\left( -\alpha (x - \mu)^2 \right) \diff x = 1
\end{equation*}
$$
已知高斯积分结果:
$$
\begin{equation*}
\int_{-\infty}^{\infty} \exp\left( -\alpha (x - \mu)^2 \right) \diff x = \sqrt{\frac{\pi}{\alpha}}
\end{equation*}
$$
得到:
$$
\begin{equation*}
A = \sqrt{\frac{\alpha}{\pi}}
\end{equation*}
$$
若令 $\alpha = \dfrac{1}{2\sigma^2}$,则最终得:
$$
\begin{equation*}
p(x) = \frac{1}{\sqrt{2\pi\sigma^2}} \exp\left( -\frac{(x - \mu)^2}{2\sigma^2} \right)
\end{equation*}
$$
# 总结
从最大熵原理出发,在已知均值与方差的约束下,最“无偏”或熵最大的概率密度函数是:
$$
\begin{equation*}
p(x) = \frac{1}{\sqrt{2\pi\sigma^2}} \exp\left( -\frac{(x - \mu)^2}{2\sigma^2} \right)
\end{equation*}
$$
这正是**高斯分布**的标准形式,说明它不仅数学上方便,**信息论上也是最合理的选择**。
Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 810 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 496 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB