求解器学习笔记

跟随老师学习线性规划求解,老师推荐了cplex,简单了解了一下,顺便也使用了一下国产copt求解器。

cplex是ibm的,win linux mac平台都有,我以linux平台使用了一下

下载到手解压缩解压缩 ~/program/cplex/opl/oplide/oplide 这是它的图形界面

命令行交互终端是 ~/program/cplex/cplex/bin/x86-64_linux/cplex

ide里新建空opl项目后,可以再新建mod模型文件,数据可以另外存在dat文件里

使用著名diet模型数据跑了一下,初步理解,就是发现输出结果小数位数很多,想格式化输出没找到办法,网上建议也是其他语言调用时用另外语言功能自定义输出

现在做科研,技术选型必不可少的就是要考察一下国产替代。在这方面国产也有好几家,我就选了一家初步看了一下:https://guide.coap.online/copt/zh-doc/intro.html

也支持win linux mac平台,提供c语言java python等各语言接口调用,不知道是不是因为我linux平台缘故,只看到命令copt_cmd,没看到图形界面

与cplex这样成熟平台随意下载免费试用相比,copt需要填写申请(电脑用户名),然后通过邮件发回一个下载地址和授权license文件,将license文件放入适当文件夹,设置好环境变量,就可以试用了。教育邮箱可以1年,普通个人半年。到期可以重新申请。这些措施可能就阻挡了一部分热情不高的用户来了解copt.

看了解压缩后自带官方文档copt/copt80/docs/copt-userguide_cn.pdf ,初步试了几个小实例,用法容易学会,copt默认读业界常用mps模型文件,能够输出求解结果。和cplex里mod文件相比,mps文件理解起来难度稍大 https://developer.aliyun.com/article/785499

cplex也支持进入cplex终端后直接读mps文件求解,常用命令和copt一致,复杂高深功能2者肯定有细节区别,不过作为非专业用户,只是读个文件求个解,这2者软件都能完成,所以在写论文做一般学术研究方面都可以用

mps文件和mod文件的转化,ai了一个python代码,不能完美转化,但是也能加深对这2类文件的理解

复制代码
import re
from collections import defaultdict

def parse_mps(mps_file):
    """解析MPS文件,提取核心信息"""
    model_data = {
        "name": "",
        "rows": defaultdict(dict),  # {行名: {type: 'E/L/G', rhs: 值}}
        "columns": defaultdict(dict),  # {变量名: {行名: 系数}}
        "bounds": defaultdict(dict),  # {变量名: {lb: 值, ub: 值}}
        "rhs": defaultdict(float)  # {行名: 右端值}
    }

    with open(mps_file, 'r') as f:
        lines = [line.strip() for line in f if line.strip()]

    # 解析状态机
    state = None
    rhs_label = ""
    for line in lines:
        # 1. 解析模型名
        if line.startswith('NAME'):
            model_data["name"] = line.split()[1]
            continue
        # 2. 解析行(约束)
        elif line.startswith('ROWS'):
            state = "ROWS"
            continue
        # 3. 解析列(变量+系数)
        elif line.startswith('COLUMNS'):
            state = "COLUMNS"
            continue
        # 4. 解析右端项
        elif line.startswith('RHS'):
            state = "RHS"
            rhs_label = line.split()[1] if len(line.split())>1 else ""
            continue
        # 5. 解析边界
        elif line.startswith('BOUNDS'):
            state = "BOUNDS"
            continue
        # 6. 结束
        elif line.startswith('ENDATA'):
            break

        # 按状态解析行内容
        parts = re.split(r'\s+', line)
        if state == "ROWS":
            # ROWS行格式:[类型(E=等式/L=<=/G=>=)] [行名]
            row_type, row_name = parts[0], parts[1]
            model_data["rows"][row_name]["type"] = row_type
            model_data["rows"][row_name]["rhs"] = 0.0  # 先初始化,后续RHS填充
        elif state == "COLUMNS":
            # COLUMNS行格式:[变量名] [行名1] [系数1] [行名2] [系数2]
            var_name = parts[0]
            for i in range(1, len(parts), 2):
                if i+1 >= len(parts):
                    break
                row_name = parts[i]
                if "'INTORG'"!=parts[i+1] and "'INTEND'"!=parts[i+1] :
                    coeff = float(parts[i+1])
                    model_data["columns"][var_name][row_name] = coeff

        elif state == "RHS":
            # RHS行格式:[RHS标签] [行名1] [值1] [行名2] [值2]
            for i in range(1, len(parts), 2):
                if i+1 >= len(parts):
                    break
                row_name = parts[i]
                rhs_val = float(parts[i+1])
                if row_name in model_data["rows"]:
                    model_data["rows"][row_name]["rhs"] = rhs_val
        elif state == "BOUNDS":
            # BOUNDS行格式:[边界类型] [空/标签] [变量名] [值]
            # 边界类型:LO=下界, UP=上界, FX=固定值, FR=无界, MI=负无穷, PL=正无穷
            bound_type = parts[0]
            var_name = parts[2] if len(parts)>=3 else ""
            bound_val = float(parts[3]) if len(parts)>=4 else 0.0
            
            if bound_type == "LO":  # 下界
                model_data["bounds"][var_name]["lb"] = bound_val
            elif bound_type == "UP":  # 上界
                model_data["bounds"][var_name]["ub"] = bound_val
            elif bound_type == "FX":  # 固定值(上下界相同)
                model_data["bounds"][var_name]["lb"] = bound_val
                model_data["bounds"][var_name]["ub"] = bound_val
            elif bound_type == "FR":  # 无界(默认)
                model_data["bounds"][var_name]["lb"] = -float('inf')
                model_data["bounds"][var_name]["ub"] = float('inf')

    # 补全未定义边界的变量(默认下界0,上界无穷)
    for var in model_data["columns"]:
        if var not in model_data["bounds"]:
            model_data["bounds"][var]["lb"] = 0.0
            model_data["bounds"][var]["ub"] = float('inf')

    return model_data

def generate_opl(model_data, mod_file):
    """生成CPLEX OPL的.mod文件"""
    with open(mod_file, 'w') as f:
        # 1. 模型头
        f.write(f"// Auto-generated from {model_data['name']}.mps\n")
        f.write("using CPLEX;\n\n")
        f.write(f"model {model_data['name']} {{\n\n")

        # 2. 定义变量
        f.write("    // Variables\n")
        for var_name, bounds in model_data["bounds"].items():
            lb = bounds.get("lb", 0.0)
            ub = bounds.get("ub", float('inf'))
            
            # 处理无穷值
            lb_str = "-inf" if lb == -float('inf') else str(lb)
            ub_str = "inf" if ub == float('inf') else str(ub)
            
            # 连续变量(如需整数/二进制,需手动调整或扩展脚本)
            f.write(f"    dvar float {var_name} in {lb_str}..{ub_str};\n")
        f.write("\n")

        # 3. 定义约束
        f.write("    // Constraints\n")
        for row_name, row_data in model_data["rows"].items():
            row_type = row_data["type"]
            rhs_val = row_data["rhs"]
            
            # 构建约束左侧表达式
            lhs_parts = []
            for var_name, coeffs in model_data["columns"].items():
                if row_name in coeffs:
                    coeff = coeffs[row_name]
                    if coeff == 1.0:
                        lhs_parts.append(f"+ {var_name}")
                    elif coeff == -1.0:
                        lhs_parts.append(f"- {var_name}")
                    elif coeff > 0:
                        lhs_parts.append(f"+ {coeff}*{var_name}")
                    else:
                        lhs_parts.append(f"- {abs(coeff)}*{var_name}")
            
            # 拼接左侧表达式(去掉第一个+/-)
            if lhs_parts:
                lhs = " ".join(lhs_parts).lstrip("+ ")
            else:
                lhs = "0"
            
            # 约束类型映射
            if row_type == "E":
                constraint = f"    subject to {row_name}: {lhs} == {rhs_val};\n"
            elif row_type == "L":
                constraint = f"    subject to {row_name}: {lhs} <= {rhs_val};\n"
            elif row_type == "G":
                constraint = f"    subject to {row_name}: {lhs} >= {rhs_val};\n"
            else:
                constraint = f"    // Unknown row type {row_type}: {row_name}\n"
            
            f.write(constraint)
        f.write("\n")

        # 4. 目标函数(MPS默认第一个行是目标函数,类型为N)
        f.write("    // Objective (default first row as objective)\n")
        objective_row = next(iter(model_data["rows"].keys())) if model_data["rows"] else ""
        if objective_row and model_data["rows"][objective_row].get("type") == "N":
            # 构建目标函数表达式
            obj_parts = []
            for var_name, coeffs in model_data["columns"].items():
                if objective_row in coeffs:
                    coeff = coeffs[objective_row]
                    if coeff == 1.0:
                        obj_parts.append(f"+ {var_name}")
                    elif coeff == -1.0:
                        obj_parts.append(f"- {var_name}")
                    elif coeff > 0:
                        obj_parts.append(f"+ {coeff}*{var_name}")
                    else:
                        obj_parts.append(f"- {abs(coeff)}*{var_name}")
            obj_expr = " ".join(obj_parts).lstrip("+ ") if obj_parts else "0"
            f.write(f"    minimize obj: {obj_expr};\n")  # 默认最小化,如需最大化改maximize
        else:
            f.write("    // No objective function defined\n")

        # 5. 模型尾
        f.write("\n}")

# 执行转换
if __name__ == "__main__":
    mps_path = "x3.mps"  # 输入MPS文件路径
    mod_path = "x3.mod"  # 输出MOD文件路径
    
    # 解析MPS
    model_data = parse_mps(mps_path)
    # 生成OPL
    generate_opl(model_data, mod_path)
    
    print(f"转换完成!MOD文件已保存至: {mod_path}")

不同格式文件转化ai并不能完美达成,还是需要学会真正规则才能方便实际中纠正ai的失误。

相关推荐
不会编程的懒洋洋2 小时前
C# P/Invoke 基础
开发语言·c++·笔记·安全·机器学习·c#·p/invoke
kexnjdcncnxjs2 小时前
Redis如何记录每一次写操作_开启AOF持久化机制实现命令级追加记录
jvm·数据库·python
程序媛徐师姐2 小时前
Python基于Django的小区果蔬预定系统【附源码、文档说明】
python·django·小区果蔬预定系统·果蔬预定·python小区果蔬预定系统·小区果蔬预定·python果蔬预定系统
bendandawugui2 小时前
PCIe协议学习-PCIe的No Snoop Attr使用
学习
xian_wwq2 小时前
【学习笔记】网络与数据安全领域强制性标准
笔记·学习
24白菜头2 小时前
【无标题】
c++·笔记·学习·harmonyos
qq_589568102 小时前
java基础学习,案例练习,即时通讯
java·开发语言·学习
吟安安安安2 小时前
适合短期冲刺的学习工作流(针对算法)
学习·算法