qbqp
This commit is contained in:
commit
36985b42e9
|
@ -0,0 +1 @@
|
||||||
|
/target
|
|
@ -0,0 +1,7 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pbqp"
|
||||||
|
version = "0.1.0"
|
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "pbqp"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
|
@ -0,0 +1,82 @@
|
||||||
|
# QBQP 算法
|
||||||
|
|
||||||
|
寄存器分配算法。
|
||||||
|
|
||||||
|
## 约束方程的含义
|
||||||
|
|
||||||
|
主要就是约束方程了:
|
||||||
|
|
||||||
|
$$
|
||||||
|
min\{ \sum_{i \le i \lt j \le n} X_i^T C_{ij} X_j + \sum_{i=1}^n s_i X_i \}
|
||||||
|
$$
|
||||||
|
|
||||||
|
- $X_i = (x_{i, sp}, x_{i, r_1}, x_{i, r_2}, ..., x_{i, r_K})^T$
|
||||||
|
- 这里 $x_{i, sp}$ 表示将 $t_i$ spill -> stack 的代价。
|
||||||
|
- $X_i = (x, xxx, ..., x)^T$ 只有一个 分量=1,其他都是 0
|
||||||
|
- K 表示 $t_i$ 有 K 个可选的寄存器(不一定是所有的 physical reg,这是显然的,比方说不想要破坏到 callee-saved 寄存器)。
|
||||||
|
- $C_{ij}$ 量化了 $t_i$ 和 $t_j$ 之间的相互影响
|
||||||
|
- i === j? (不一定,比方说在传参的时候,i 可以放到 a0, 但是 j 是不能放到 a0 的)
|
||||||
|
- 但是我有一种想法: 就是我认为还是要把 32 个寄存器全部摆上台面的,如果不能用,我认为可以相应的可以设置为 $\infin$ ,这显然可能会变成一个 稀疏矩阵,然后是不是可以进行 凸优化啥的。如果 i!=j 并且有: $R_i$ ^ $R_j \ne \phi$ 那这可能需要对齐,可能有点麻烦
|
||||||
|
- 如果 i === j,那么可以做一件事情:将 $c_{ij}$ 的对角线设置为 负数。对角线意味着: virtual reg $t_i$ 和 $t_j$ 是可接合的,可以分配到 同一个 physical reg 的,负数的 语义 是:鼓励接合(代价总是越小越好)
|
||||||
|
- $s_i = (\vec{cost(i)}, \vec0, ..., \vec0)$
|
||||||
|
- $\vec{cost(t_i)}$ : $t_i$(virtual reg) 溢出的代价。如果每个 $t_i$ 都选择了 spill ,那么相当于是: $\forall t_i, X_i = (1, 0, ..., 0)$,那么 $\sum_{i=1}^n s_i X_i = \sum_{i=1}^n cost(t_i)$
|
||||||
|
|
||||||
|
## 伪代码
|
||||||
|
|
||||||
|
伪代码 ( from 华保健 ) 如下:
|
||||||
|
|
||||||
|
```pseudocode
|
||||||
|
void reduce_1(vertex x) {
|
||||||
|
y = adj(x);
|
||||||
|
for (i = 1; i < len(E_y); i++) {
|
||||||
|
delta(i) = min(C_xy(i, :) + E_x);
|
||||||
|
}
|
||||||
|
E_y += delta;
|
||||||
|
remote_vertex(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reduce_2(vertex x) {
|
||||||
|
y, z = adj(x);
|
||||||
|
for (i = 1; i < len(E_y); i++) {
|
||||||
|
for (j = 1; j < len(E_z); j++) {
|
||||||
|
delta(i) = min(C_xy(i, :) + C_xz(j, :) + E_x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
C_yz += delta;
|
||||||
|
remote_vertex(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reduce_N(vertex x) {
|
||||||
|
y, z = adj(x);
|
||||||
|
for (i = 1; i < len(E_y); i++) {
|
||||||
|
delta(i) = 0;
|
||||||
|
for (j = 1; j < len(E_z); j++) {
|
||||||
|
delta(i) = min(C_xy(i, :) + E_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
min_index = get_min_index(delta);
|
||||||
|
for y : vertex in adj(x) {
|
||||||
|
E_y += C_xy(min_index, :);
|
||||||
|
}
|
||||||
|
remote_vertex(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void solve_PBQP(graph pbqp_model) {
|
||||||
|
while (pbqp_model still has edges) {
|
||||||
|
simplify(pbqp_model);
|
||||||
|
while (there exists any vertex x of degree 1) {
|
||||||
|
reduce_1(x);
|
||||||
|
}
|
||||||
|
while (there exists any vertex x of degree 2) {
|
||||||
|
reduce_2(x);
|
||||||
|
}
|
||||||
|
while (there exists any vertex x of degree >= 2) {
|
||||||
|
reduce_N(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### rust
|
||||||
|
|
||||||
|
看 src/main.rs (from gpt)
|
|
@ -0,0 +1,125 @@
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
struct Vertex {
|
||||||
|
cost_vector: Vec<i32>, // 代价向量
|
||||||
|
neighbors: HashSet<usize>, // 邻接点索引集
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Edge {
|
||||||
|
cost_matrix: Vec<Vec<i32>>, // 代价矩阵
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Graph {
|
||||||
|
vertices: Vec<Vertex>,
|
||||||
|
edges: HashMap<(usize, usize), Edge>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Graph {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
vertices: vec![],
|
||||||
|
edges: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_vertex(&mut self, cost_vector: Vec<i32>) -> usize {
|
||||||
|
let index = self.vertices.len();
|
||||||
|
self.vertices.push(Vertex {
|
||||||
|
cost_vector,
|
||||||
|
neighbors: HashSet::new(),
|
||||||
|
});
|
||||||
|
index
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_edge(&mut self, v1: usize, v2: usize, cost_matrix: Vec<Vec<i32>>) {
|
||||||
|
self.vertices[v1].neighbors.insert(v2);
|
||||||
|
self.vertices[v2].neighbors.insert(v1);
|
||||||
|
self.edges.insert(
|
||||||
|
(v1, v2),
|
||||||
|
Edge {
|
||||||
|
cost_matrix: cost_matrix.clone(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
self.edges.insert((v2, v1), Edge { cost_matrix });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_vertex(&mut self, index: usize) {
|
||||||
|
if let Some(vertex) = self.vertices.get(index) {
|
||||||
|
for &neighbor in &vertex.neighbors {
|
||||||
|
self.vertices[neighbor].neighbors.remove(&index);
|
||||||
|
self.edges.remove(&(index, neighbor));
|
||||||
|
self.edges.remove(&(neighbor, index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.vertices.remove(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to simplify the graph based on degree of vertices
|
||||||
|
fn simplify(&mut self) {
|
||||||
|
while !self.edges.is_empty() {
|
||||||
|
for i in 0..self.vertices.len() {
|
||||||
|
match self.vertices[i].neighbors.len() {
|
||||||
|
1 => self.reduce_1(i),
|
||||||
|
2 => self.reduce_2(i),
|
||||||
|
_ => self.reduce_n(i),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reduce_1(&mut self, x: usize) {
|
||||||
|
let y = *self.vertices[x].neighbors.iter().next().unwrap();
|
||||||
|
let edge = self.edges.get(&(x, y)).unwrap();
|
||||||
|
let mut delta = Vec::new();
|
||||||
|
|
||||||
|
for i in 0..self.vertices[y].cost_vector.len() {
|
||||||
|
let min_cost = edge.cost_matrix[i].iter().min().unwrap();
|
||||||
|
delta.push(min_cost + self.vertices[x].cost_vector[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..self.vertices[y].cost_vector.len() {
|
||||||
|
self.vertices[y].cost_vector[i] += delta[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
self.remove_vertex(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reduce_2(&mut self, x: usize) {
|
||||||
|
let mut iter = self.vertices[x].neighbors.iter();
|
||||||
|
let y = *iter.next().unwrap();
|
||||||
|
let z = *iter.next().unwrap();
|
||||||
|
let mut delta = Vec::new();
|
||||||
|
|
||||||
|
for i in 0..self.vertices[y].cost_vector.len() {
|
||||||
|
for j in 0..self.vertices[z].cost_vector.len() {
|
||||||
|
let cost_y = self.edges.get(&(x, y)).unwrap().cost_matrix[i][j];
|
||||||
|
let cost_z = self.edges.get(&(x, z)).unwrap().cost_matrix[i][j];
|
||||||
|
delta.push(std::cmp::min(cost_y, cost_z) + self.vertices[x].cost_vector[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..self.vertices[y].cost_vector.len() {
|
||||||
|
self.vertices[y].cost_vector[i] += delta[i];
|
||||||
|
self.vertices[z].cost_vector[i] += delta[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
self.remove_vertex(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reduce_n(&mut self, x: usize) {
|
||||||
|
// This function needs to be implemented based on specific problem constraints and conditions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut graph = Graph::new();
|
||||||
|
// Example usage
|
||||||
|
let v0 = graph.add_vertex(vec![1, 2, 3]);
|
||||||
|
let v1 = graph.add_vertex(vec![4, 5, 6]);
|
||||||
|
let v2 = graph.add_vertex(vec![7, 8, 9]);
|
||||||
|
|
||||||
|
graph.add_edge(v0, v1, vec![vec![10, 20], vec![30, 40]]);
|
||||||
|
graph.add_edge(v1, v2, vec![vec![50, 60], vec![70, 80]]);
|
||||||
|
|
||||||
|
graph.simplify();
|
||||||
|
}
|
Loading…
Reference in New Issue