<技巧探究> 脚本实现数值试验自动进行

2022-11-28

在运筹学算法研究中,每种算法的设计完成后都需要大量的数值试验来验证该算法的效果,并与benchmark/baseline相比较。其中,每组数值试验中需要在算法中修改一定的参数,然后在算法完成后输出算法效果。在以往时刻,由于个人能力的欠缺,我往往是采用手动输入和输出的方式,即每次手动修改算法中的参数,点击运行,利用excel表格等工具记录输出结果,每个实例都需要重复一次。毫无疑问,这种方法是极其傻瓜的,因此打算此后都通过python脚本来自动化运行数值试验,通过csv文件将参数传入程序,然后将输出结果写入”.txt”文件中,每次执行多组数值试验,实现真正意义上的一劳永逸。


Python 系统调用——运行其他程序

脚本自动化的基础是python的特性。在python中,可以方便地调用os模块运行其他的脚本或程序,这给了我们在在脚本中直接使用其他脚本的可能。而这种调用方式往往分为以下几种:

1. os.system()

os模块中的system()函数可以方便地运行其他程序或者脚本。其函数原型如下:

os.system(command)

command是要执行地命令,相当于在cmd窗口中输入的命令。如果要向程序或脚本传递参数,可以使用空格分隔程序及多个参数。

import os
os.system('notepad')	# 打开记事本程序
os.system('notepad 1.txt')	# 打开1.txt文件,若不存在则创建

2. ShellExecute

win32api模块中的ShellExecute函数同样可以实现该功能。其函数原型如下:

ShellExecute(hwnd, op, file, params, dir, bShow)

其函数含义如下所示:

  • hwnd:父窗口的句柄,如果没有父窗口,则为0
  • op:要进行的操作,为”open“、”print“或者为空
  • file:要运行的程序,或者打开的脚本
  • params:要向程序传递的参数,如果打开的为文件,则为空
  • dir:程序初始化的目录
  • bShow:是否显示窗口
import win32api

#在后台运行记事本程序
win32api.ShellExecute(0, 'open', 'notepad.exe', '', '', 0) 

#向记事本传递参数,打开python.txt
win32api.ShellExecute(0, 'open', 'notepad.exe', 'python.txt','',1)

3. CreateProcess

4. ctypes


python脚本实例

import pandas as pd
import os
import win32api

# 打开需要执行的算法程序.exe文件所在目录
os.chdir(r'D:\zhangyue\Algorithm\2022-11-01 CSSLSP_ADP\Debug')

# 后台执行程序
for i in range(1, 10):
    win32api.ShellExecute(0, 'open', '2022-11-01 CSSLSP_ADP.exe',
                         f'input_params.csv 
                         C:\\zhangyue\\log_{i}.txt
                         {7}
                         {0.1} 
                     	 C:\\zhangyue\\train_{i}.csv 
                         C:\\zhangyue\\train_lam{i}.csv', 
                         '', 
                         0
                         )          

cpp程序

#include "Tabu_search.h"
#include <iostream>
using namespace std;

int main(int argc, char* argv[]){
    file_in_path = argv[1];	 	//文件读取路径:input_params.csv
	file_out_path = argv[2];	//文件输出路径:C:\\zhangyue\\log_{i}.txt
	fole_train_save = argv[5];	//文件训练路径:C:\\zhangyue\\train_{i}.csv
	fole_train_lam= argv[6];	//文件训练路径:C:\\zhangyue\\train_lam{i}.csv
    
	LENGTH_TABU = atof(argv[3]);	//禁忌表长度参数读取
	PENALTY_COEF = atof(argv[4]);	//惩罚系数参数读取
    
    //将原本输出在控制台的字符重定向,输出到指定的路径文件中
    freopen(file_out_path.c_str(), "w", stdout);
	for (int i = 0; i < argc; i++) 
        cout << argv[i] << "\t"; 
    cout << endl;
    
    
    ifstream ifile(fole_train_lam, ios::in);
	string line;
	getline(ifile, line); 		//在ifile中接收line的值
	istringstream sin(line);	//定义一个字符串输入流对象sin,将line中所包含的字符串									 放入其中
	
    string tmp;
	for (int t = 0; t < T; ++t) //获取一个数据
	{
		getline(sin, tmp, ',');
		lambda[t]=(stod(tmp)); //存到temp中
	}


	TabuSearch alg(file_in_path);

	//alg.read_init_sol();
	alg.run();

	return 0;
}