Kl算法
KL 算法是 Kernighan 与 Lin 两个人在 1970 年设计一个图划分算法,是在寻找图 G 的一个极小成本的可许划分。KL 算法也是一种基于贪心算法的划分算法,通过交换两模块中的元素实现两模块间通信代价极小化。由于贪心算法会导致局部最优解,KL 算法在交换模块中元素时把所有可能交换后产生的代价增益都计算出来,从中选择一个最好的交换元素进行交换。这样在某种程度上降低了局部最优的风险,但会造成算法的时间复杂性。不过,KL 算法在很大程度上会给出全局最优解。实验表明 KL 算法给出的划分通信代价极小化是最好的。
【异构分布式嵌入式系统的优化设计方法,许巾一,陈仪香,李凯旋,2020 年 1 月】
λ-优化与 2 式划分
λ 优化:两个集合间的λ点互换是指交换这两个集合的λ元素。1-互换是将一个集合的单点与另一个集合的单点进行互换。一个配置称为 1-优化,若不再存在 1-互换导致划分成本的下降。
2 式划分:最简单划分问题是:给一个 2n 节点的图 G,其中每
个节点都拥有相同的尺寸,寻找一个极小成本划分将 2n 节点划分成都含有 n
个节点的两个集合。
题目
实现效果
Cpp实现
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
using namespace std;
const int task_num = 8;
vector<vector<double>> init(double data[][task_num]); //初始化函数
//计算D
vector<double> countD(vector<vector<double>> &data, vector<int> tempA,vector<int> tempB);
//计算外代价
vector<double> countE(vector<vector<double>> data,vector<int> A,vector<int> B);
//计算内代价
vector<double> countI(vector<vector<double>> data,vector<int> A);
//计算总代价
double calculateDistance(vector<vector<double>> data, vector<int> tempA, vector<int> tempB);
template <typename T>
void res_print(vector<T> A,vector<T> B, int type);
// #define CountD
// #define CountE
#define CountI
int main()
{
vector<int> A,B;
double matrix[task_num][task_num] =
{
{0, 1, 0.5, 0, 0.5, 1, 0, 0.5},
{1, 0, 0.5, 0, 0, 0, 0, 0},
{0.5, 0.5, 0, 0.5, 1, 0.5, 0, 0},
{0, 0, 0.5, 0, 0, 1, 0, 0.5},
{0.5, 0, 1, 0, 0, 0.5, 1, 0},
{1, 0, 0.5, 1, 0.5, 0, 0.5, 0.5},
{0, 0, 0, 0, 1, 0.5, 0, 0.5},
{0.5, 0, 0, 0.5, 0, 0.5, 0.5, 0},
};//导入通信代价矩阵
// // 4
// char charA[4] = {'a','d','g','h'};
// char charB[4] = {'b','c','e','f'};
// //4
// char charA[4] = {'a','c','e','h'};
// char charB[4] = {'b','d','g','f'};
// // 4
// char charA[4] = {'a','c','e','f'};
// char charB[4] = {'b','d','g','h'};
// 4
char charA[4] = {'a','b','c','d'};
char charB[4] = {'e','f','g','h'};
//4.5
// char charA[4] = {'a','d','e','h'};
// char charB[4] = {'b','c','g','f'};
// char charA[4] = {'a','e','f','h'};
// char charB[4] = {'b','c','d','g'};
for(int i = 0; i < task_num / 2; i++)
{
A.push_back(charA[i]-'a');
B.push_back(charB[i]-'a');
}
cout<<"初始划分集为:"<<endl;
res_print(A,B,0);
vector<vector<double>> data = init(matrix);
vector<vector<double>> tempMatrix = data;
for(int i = 0; i< tempMatrix.size(); i++)
{
for(int j = 0; j< tempMatrix.size(); j++)
{
cout<<tempMatrix[i][j]<<"\t";
}
cout<<endl;
}
vector<int> tempA, resA; //resA 存放结果
vector<int> tempB, resB; //res
vector<double> G; //G 存放每一次的g
vector<double> D_A, D_B;
int p = 0;
double Gain=1;
while(Gain > 0)
{
G.clear(); //清空之前G
D_A.clear();
D_B.clear();
resA.clear();
resB.clear();
tempA = A;
tempB = B;
p = 0;
while(p != 4)
{
D_A = countD(data,tempA,tempB);
D_B = countD(data,tempB,tempA);
cout<<"p="<<p+1<<endl;
cout<<"外部与内部成本之差"<<endl;
for(int i = 0; i < D_A.size(); i++)
{
cout<<char(tempA[i]+'a')<<": "<<D_A[i];
cout<<endl;
}
for(int i = 0; i < D_B.size(); i++)
{
cout<<char(tempB[i]+'a')<<": "<<D_B[i];
cout<<endl;
}
int max_g = -100;
int max_index_A, max_index_B;
cout<<"交换对(x,y)"<<"\tDx\tDy\tCxy\t收益gp"<<endl;
for(int i = 0; i < tempA.size(); i++)
{
for(int j = 0; j < tempB.size(); j++)
{
int g_temp = D_A[i] + D_B[j] - 2*data[tempA[i]][tempB[j]];
cout<<"("<< char(tempA[i]+'a')<<","<<char(tempB[j]+'a')<<")\t\t"<<D_A[i]<<"\t"<<D_B[j]<<"\t"<<data[tempA[i]][tempB[j]]<<"\t"<<g_temp<<endl;
if(g_temp > max_g)
{
max_index_A = i;
max_index_B = j;
max_g = g_temp;
}
}
}
// 已经选过的放到结果中
resA.push_back(tempA[max_index_A]);
resB.push_back(tempB[max_index_B]);
tempA.erase(tempA.begin() + max_index_A);
D_A.erase(D_A.begin() + max_index_A);
tempB.erase(tempB.begin() + max_index_B);
D_B.erase(D_B.begin() + max_index_B);
G.push_back(max_g);
p++;
}
int res = 0;
int max_G = -10000;
int res_max_index = 0;
for(int i = 0; i < G.size(); i++)
{
res += G[i];
if(res > max_G)
{
res_max_index = i;
max_G = res;
}
}
Gain = max_G;
cout<<"k =" <<res_max_index<<endl;
if(Gain != 0 || res_max_index != 0)
{
// if(Gain > 0)
// {
// 交换
A.clear();
B.clear();
for(int i = 0; i < task_num/2; i++)
{
if(i <= res_max_index)
{
A.push_back(resB[i]);
B.push_back(resA[i]);
}
else
{
A.push_back(resA[i]);
B.push_back(resB[i]);
}
}
//res_print(A,B);
sort(A.begin(), A.begin()+A.size());
sort(B.begin(), B.begin()+B.size());
cout<<"交换"<<endl;
res_print(A,B,0);
}
cout<<"Gain = "<< Gain<<endl;
}
cout<<"划分结果:"<<endl<<endl;
res_print(A, B, 0);
double totalDistance = calculateDistance(data, A, B);
cout<<"通信代价="<<totalDistance<<endl;
return 0;
}
vector<double> countD(vector<vector<double>> &data, vector<int> tempA,vector<int> tempB)
{
vector<double> res;
vector<double> EA=countE(data, tempA, tempB); // 计算外部代价
vector<double> IA=countI(data, tempA); // 计算内部代价
#ifdef CountD
cout<<"countD"<<endl;
res_print(tempA,tempB);
res_print(EA, IA);
#endif
for(int i=0;i<tempA.size();i++)
{
res.push_back(EA[i]-IA[i]);
}
return res;
}
template <typename T>
void res_print(vector<T> A,vector<T> B, int type)
{
for(int i = 0; i < A.size(); i++)
{
if(!type)
cout<<char(A[i]+'a')<<" ";
else
cout<<A[i]<<" ";
}
cout<<endl;
for(int i = 0; i < B.size(); i++)
{
if(!type)
cout<<char(B[i]+'a')<<" ";
else
cout<<B[i]<<" ";
}
cout<<endl;
}
vector<double> countE(vector<vector<double>> data,vector<int> A,vector<int> B)//计算外代价
{
vector<double> E;
for(int i=0;i < A.size();i++)
{
E.push_back(0);
for(int j = 0; j < B.size(); j++)
{
E[i]+=data[A[i]][B[j]];
}
}
#ifdef CountE
cout<<"countE"<<endl;
res_print(A,B);
res_print(E, E);
#endif
return E;
}
vector<double> countI(vector<vector<double>> data,vector<int> A)//计算内代价
{
vector<double> I;
for(int i = 0; i < A.size(); i++)
{
I.push_back(0);
for(int j = 0;j < A.size();j++)
{
I[i] += data[A[i]][A[j]];
}
}
return I;
}
vector<vector<double>> init(double data[][task_num])
{
vector<vector<double>> res;
for(int i = 0; i < task_num; i++)
{
vector<double> temp;
for(int j = 0; j < task_num; j++)
{
temp.push_back(data[i][j]);
}
res.push_back(temp);
}
return res;
}
double calculateDistance(vector<vector<double>> data, vector<int> tempA, vector<int> tempB)
{
double totalDistance=0;
//先找到两个相邻的簇,然后匹配簇中的元素
for (int i = 0; i < tempA.size(); i++)
{
//vector<int> last= list[i];//得到相邻的簇
for (int j=0; j < tempB.size();j++)
{
double sum = 0;
//vector<int> next=list[j];//得到相邻的簇
if( data[tempA[i]][tempB[j]])
{//若两元素间有链路相链接
sum += data[tempA[i]][tempB[j]];
totalDistance+=data[tempA[i]][tempB[j]];
}
// cout<< "模块"<< i + 1 <<"与模块"<< j + 1<<"通信代价:"<<sum<<endl;
}
}
return totalDistance;
}