class TSP_DATA:
'''用于读取数据、存放图的数据结构
类内变量:
必有:
self.NAME 测试样例名称
self.TYPE 测试样例类型 TSP ATSP
self.DIMENSION. 维度
self.EDGE_WEIGHT_TYPE 边权值计算方式 决定读取方式
self.matrix 矩阵形式数据
self.table . 邻接表形式数据
可能有:
self.EDGE_WEIGHT_FORMAT
self.EDGE_DATA_FORMAT
self.NODE_COORD_TYPE required if EDGE_WEIGHT_TYPE is not WeightKind::Explicit
'''
def __init__(self, path):
"""传入单个数据地址,读取并且加载数据的表头
path:
单个测试样例的数据地址
"""
self.debug = True
raw_data, name = self.read_any_file(path)
self.get_headline(raw_data)
assert self.NAME == name
assert 'TSP' in self.TYPE
self.rawnum = self.get_data_list(raw_data)
if self.debug:
print("原始数据:",self.rawnum)
if self.EDGE_WEIGHT_TYPE == "EXPLICIT":
self.matrix = self.get_adjacency_matrix()
if self.debug:
print("矩阵",self.matrix)
def get_data_list(self, data_all):
""" 返回数字数据,被关键字和EOF包裹。不做其他处理
EXPLICIT EDGE_WEIGHT_SECTION
DGE_WEIGHT_SECTION
0 273 0 1272 999 0 744 809 1519 0 1138 866 140 1425
EUC_2D NODE_COORD_SECTION
NODE_COORD_SECTION
1 4.35841e+02 5.87522e+02
2 6.02539e+02 8.01704e+02
有丢失城市的情况,补无穷
return:
EXPLICIT 一长条int的list,空格隔开
else 三列 n行 list(划掉)
else 一长条int的list,空格隔开
update:
数据还有浮点数,得改一下
可能有‘ 699'这样的数据,不能用数字判别,应该用 非字母逻辑
"""
end_line = len(data_all)-2
print(data_all)
if self.EDGE_WEIGHT_TYPE == 'EXPLICIT':
beging_line = 0
for i in range(10):
if 'EDGE_WEIGHT_SECTION' in data_all[0][i]:
beging_line = i+1
break
else:
pass
if self.debug:
print("发现数据开头标志位置",beging_line)
string_data = data_all[0][beging_line]
for h in range(beging_line+1,end_line+1):
if data_all[0][h][0].isalpha():
break
string_data = string_data + " " + data_all[0][h]
string_data_split = string_data.strip().split(' ')
list_data = [float(i) for i in string_data_split if i.isdigit()]
if self.debug:
print(string_data_split)
print(list_data)
else:
beging_line = 0
for i in range(10):
beging_line = beging_line+1
if 'NODE_COORD_SECTION' in data_all[0][i]:
break
string_data = data_all[0][beging_line]
for h in range(beging_line+1,end_line+1):
if data_all[0][h][0].isalpha():
break
string_data = string_data + ' ' + data_all[0][h]
if self.debug:
print("发现数据开头标志位置",beging_line)
print("数据")
print(data_all[0][0])
string_data_split = string_data.strip().split(' ')
list_data = [float(i) for i in string_data_split if i.isdigit()]
if self.debug:
print(string_data_split)
print(list_data)
return list_data
def get_headline(self, raw_data):
head_dict = {}
head_index = 0
for h in range(len(raw_data)):
if not raw_data[0][h][0].isalpha():
break
else:
head_index = head_index + 1
for i in range(head_index):
if ':' not in raw_data[0][i]:
break
head_dict[raw_data[0][i].split(':')[0]] = raw_data[0][i].split(':')[1]
self.NAME = head_dict['NAME'].strip()
self.TYPE = head_dict['TYPE'].strip()
self.DIMENSION = int(head_dict['DIMENSION'].strip())
self.EDGE_WEIGHT_TYPE = head_dict['EDGE_WEIGHT_TYPE'].strip()
if self.TYPE == "CVRP":
self.CAPACITY = head_dict['CAPACITY'].strip()
else:
pass
if self.EDGE_WEIGHT_TYPE == "EXPLICIT":
self.EDGE_WEIGHT_FORMAT = head_dict['EDGE_WEIGHT_FORMAT'].strip()
else:
if 'NODE_COORD_TYPE' in head_dict.keys():
self.NODE_COORD_TYPE = head_dict['NODE_COORD_TYPE'].strip()
pass
def read_any_file(self,thispath):
if not os.path.isfile(thispath):
raise Exception('数据读取报错,地址非文件')
df = pd.read_csv(thispath,header=None)
if check_sys == 'Linux':
name = thispath.split('/')[-1].split('.')[0]
elif check_sys == 'Windows':
name = thispath.split('\\')[-1].split('.')[0]
else:
raise EnvironmentError
return df,name
def cal_a_distance_by_coordinate(self,a,b):
'''
按照 城市编号 a -> b ,给出两点之间的距离
可能的距离定义式:https://docs.rs/tspf/0.3.0/tspf/enum.WeightKind.html
Explicit 权重在数据文件中明确给出。直接读出来就是距离。
Euc2d 二维欧几里得距离。
Euc3d 三维欧几里得距离。
Max2d 二维马氏距离。????这是衡量矩阵的????
Max3d 三维马氏距离。
Man2d 二维曼哈顿距离。
Man3d 三维曼哈顿距离。
Ceil2d 向上取整的二维欧几里得距离。
Geo 地理距离。 既欧氏距离
Att 问题的特殊距离函数att48和att532。
Xray1 版本 1 晶体学问题的特殊距离函数。
Xray2 版本 2 晶体学问题的特殊距离函数。
Custom 用户定义的距离函数。
Undefined 没有给出距离函数。
'''
if self.EDGE_WEIGHT_TYPE == "EUC_2D" or self.EDGE_WEIGHT_TYPE =="GEO":
distance = (self.adjacency_table(a)[0]-self.adjacency_table(b)[0])**2+\
(self.adjacency_table(a)[1]-self.adjacency_table(b)[1])**2
elif self.EDGE_WEIGHT_TYPE == "EUC_3D":
distance = abs((self.adjacency_table(a)[0]-self.adjacency_table(b)[0])**3+\
(self.adjacency_table(a)[1]-self.adjacency_table(b)[1])**3)
elif self.EDGE_WEIGHT_TYPE == "EXPLICIT":
raise Exception("EXPLICIT距离必须由raw data的邻接矩阵给出")
elif self.EDGE_WEIGHT_TYPE == "MAN_2D":
distance = abs((self.adjacency_table(a)[0]-self.adjacency_table(a)[1])**2-\
(self.adjacency_table(b)[0]-self.adjacency_table(b)[1])**2)
elif self.EDGE_WEIGHT_TYPE == "MAN_3D":
distance = abs((self.adjacency_table(a)[0]-self.adjacency_table(a)[1])**3-\
(self.adjacency_table(b)[0]-self.adjacency_table(b)[1])**3)
elif self.EDGE_WEIGHT_TYPE == "CEIL_2D":
distance = int((self.adjacency_table(a)[0]-self.adjacency_table(b)[0])**2+\
(self.adjacency_table(a)[1]-self.adjacency_table(b)[1])**2) + 1
else:
raise Exception("此类型距离未定义")
return distance
def get_adjacency_matrix(self):
'''专用于TSP问题的原始数据转矩阵函数(由于ATSP距离不对称,优化不能用)
当确认矩阵储存方式 EDGE_WEIGHT_TYPE 为 邻接矩阵 EXPLICIT 时
self.EDGE_WEIGHT_FORMAT 保存矩阵储存格式
self.rawnum 保存raw data中的所有数字
矩阵存放形式
Function 权重由WeightKind中所述的函数计算。
FullMatrix 权重以完整矩阵形式给出。对应FULL_MATRIX于 TSPLIB 中的值。
UpperRow 权重在上三角矩阵中按行给出,没有对角线条目。 对应UPPER_ROW于 TSPLIB 中的值。
LowerRow 权重在下三角矩阵中给出,按行排列,没有对角线条目。 对应LOWE_ROW于 TSPLIB 中的值。
UpperDiagRow 权重在上三角矩阵中给出,按行与对角线条目。 对应UPPER_DIAG_ROW于 TSPLIB 中的值。
LowerDiagRow 权重在下三角矩阵中给出,按行与对角线条目。 对应LOWER_DIAG_ROW于 TSPLIB 中的值。
UpperCol 权重在上三角矩阵中给出,没有对角线条目。 对应UPPER_COL于 TSPLIB 中的值。
LowerCol 权重在下三角矩阵中给出,没有对角线条目。 对应LOWER_COL于 TSPLIB 中的值。
UpperDiagCol 权重在上三角矩阵中给出,与对角线条目并列。 对应UPPER_DIAG_COL于 TSPLIB 中的值。
LowerDiagCol 权重在下三角矩阵中给出,与对角线条目并列。 对应LOWER_DIAG_COL于 TSPLIB 中的值。
Undefined 没有说明如何存储权重。
'''
matrix = []
if self.EDGE_WEIGHT_FORMAT == "UPPER_DIAG_ROW":
d = self.DIMENSION
if not len(self.rawnum) == int((1+d)*d/2):
raise Exception("获取的raw num数据量不对")
for i in range(d):
row = [0 for j in range(i)]
left = int( i*d-(0+i-1)*i/2 )
right = int( (i+1)*d-(0+i)*(i+1)/2 )
row = row + self.rawnum[left : right]
matrix.append(row)
m = np.array(matrix)
matrix = (np.triu(m, k=1).T + np.triu(m, k=0)).tolist()
if self.EDGE_WEIGHT_FORMAT == "LOWER_DIAG_ROW":
d = self.DIMENSION
self.rawnum = self.rawnum.reverse()
if not len(self.rawnum) == int((1+d)*d/2):
raise Exception("获取的raw num数据量不对")
for i in range(d):
row = [0 for j in range(i)]
left = int( i*d-(0+i-1)*i/2 )
right = int( (i+1)*d-(0+i)*(i+1)/2 )
row = row + self.rawnum[left : right]
matrix.append(row)
m = np.array(matrix)
matrix = (np.tril(m, k=1).T + np.tril(m, k=0)).tolist()
elif self.EDGE_WEIGHT_FORMAT == "UPPER_ROW":
d = self.DIMENSION
if not len(self.rawnum) == int((1+d)*d/2-d):
raise Exception("获取的raw num数据量不对")
for i in range(d):
row = [0 for j in range(i+1)]
if i == 0:
left = 0
else:
left = int( d*(i-1) -(i-1)*i/2 )
right = int( d*i -(1+i)*i/2 )
row = row + self.rawnum[left : right]
matrix.append(row)
m = np.array(matrix)
matrix = (np.triu(m, k=1).T + np.triu(m, k=0)).tolist()
elif self.EDGE_WEIGHT_FORMAT == "LOWER_ROW":
d = self.DIMENSION
self.rawnum = self.rawnum.reverse()
if not len(self.rawnum) == int((1+d)*d/2-d):
raise Exception("获取的raw num数据量不对")
for i in range(d):
row = [0 for j in range(i+1)]
if i == 0:
left = 0
else:
left = int( d*(i-1) -(i-1)*i/2 )
right = int( d*i -(1+i)*i/2 )
row = row + self.rawnum[left : right]
matrix.append(row)
m = np.array(matrix)
matrix = (np.tril(m, k=1).T + np.tril(m, k=0)).tolist()
elif self.EDGE_WEIGHT_FORMAT == "FULL_MATRIX":
d = self.DIMENSION
if not len(self.rawnum) == int(d**2):
raise Exception("获取的raw num数据量不对")
for i in range(d):
row = self.rawnum[i:i+d]
matrix.append(row)
elif self.EDGE_WEIGHT_FORMAT == "UNDIFINED":
d = self.DIMENSION
if len(self.rawnum) == int(d**2):
for i in range(d):
row = self.rawnum[i:i+d]
matrix.append(row)
elif len(self.rawnum) == int((1+d)*d/2-d):
for i in range(d):
row = [0 for j in range(i+1)]
if i == 0:
left = 0
else:
left = int( d*(i-1) -(i-1)*i/2 )
right = int( d*i -(1+i)*i/2 )
row = row + self.rawnum[left : right]
matrix.append(row)
m = np.array(matrix)
matrix = (np.triu(m, k=1).T + np.triu(m, k=0)).tolist()
elif len(self.rawnum) == int((1+d)*d/2-d):
if self.rawnum[2] == 0:
for i in range(d):
row = [0 for j in range(i+1)]
if i == 0:
left = 0
else:
left = int( d*(i-1) -(i-1)*i/2 )
right = int( d*i -(1+i)*i/2 )
row = row + self.rawnum[left : right]
matrix.append(row)
m = np.array(matrix)
matrix = (np.tril(m, k=1).T + np.tril(m, k=0)).tolist()
else:
for i in range(d):
row = [0 for j in range(i)]
left = int( i*d-(0+i-1)*i/2 )
right = int( (i+1)*d-(0+i)*(i+1)/2 )
row = row + self.rawnum[left : right]
matrix.append(row)
m = np.array(matrix)
matrix = (np.triu(m, k=1).T + np.triu(m, k=0)).tolist()
else:
raise Exception("储存矩阵形式为定义,且未辨识成功,长度不符合已有类型")
return matrix
def coordinate_2_table(self, optimize=True):
"""
当数据为坐标地图:
坐标表方式储存,每个x->y都需要计算。
规定城市编号从一开始
进一步:
#todo
优化计算,只用算一半
retrun:
字典好查询
或者是表
optimize:
是否使用优化计算方法获取矩阵
"""
whole_table = {}
if optimize and self.TYPE != 'ATSP':
for i in range(1,1+self.DIMENSION):
for j in range(1,1+self.DIMENSION):
if j >= i :
whole_table[(i,j)] = self.cal_a_distance_by_coordinate(i,j)
for i in range(1,1+self.DIMENSION):
for j in range(1,1+self.DIMENSION):
if j < i :
whole_table[(i,j)] = whole_table[(j,i)]
else:
for i in range(1,1+self.DIMENSION):
for j in range(1,1+self.DIMENSION):
whole_table[(i,j)] = self.cal_a_distance_by_coordinate(i,j)
return whole_table
def coordinate_2_matrix(self, optimize=True):
"""
当数据为坐标地图:
坐标表方式储存,每个x->y都需要计算。
规定城市编号从一开始
第一行意为:从城市1到。。。
注意索引是0开始
进一步:
#todo
优化计算,只用算一半
使用numpy,对角矩阵获取,转置,相加,即可
"""
whole_matrix = []
if optimize and self.TYPE != 'ATSP':
for i in range(1,1+self.DIMENSION):
thisRow = []
for j in range(1,1+self.DIMENSION):
if i<j:
thisRow.appned(self.cal_a_distance_by_coordinate(i,j))
else:
thisRow.appned(0)
whole_matrix.append(thisRow)
m = np.array(whole_matrix)
whole_matrix = (np.triu(m, k=1).T + np.triu(m, k=0)).tolist()
else:
for i in range(1,1+self.DIMENSION):
thisRow = []
for j in range(1,1+self.DIMENSION):
thisRow.appned(self.cal_a_distance_by_coordinate(i,j))
whole_matrix.append(thisRow)
return whole_matrix
def table_2_matrix(self,table):
"""
table:
字典类型,x-》y索引距离
"""
whole_matrix = []
for i in range(1,1+self.DIMENSION):
thisRow = []
for j in range(1,1+self.DIMENSION):
thisRow.appned(table[(i,j)])
whole_matrix.append(thisRow)
return whole_matrix
def matex_2_table(self,matrix):
"""
矩阵储存, 需要提取表
区分情况,是否对称等
"""
whole_table = {}
for i in range(1,1+self.DIMENSION):
for j in range(1,1+self.DIMENSION):
whole_table[(i,j)] = matrix[i-1][j-1]
return whole_table