lihuayuli 2025-05-06 22:46 采纳率: 100%
浏览 29
已结题

C语言,GLPK库求解线性规划模型,一直报相同的错,怎么解决呀?

问题遇到的现象和发生背景

reproduce一篇DEA模型的论文(线性规划),之前代码用Python写好了,但导师让用C再重新写一遍,用的GLPK库。因为这个库我之前没用过,很多操作都是借助AI完成。数据文件重新另存成csv格式,跑不通后,又拿前两行数据重新存了个csv文件调试,还是相同的报错。debug了两天,没找着问题在哪,不知道是库配置或者环境的问题还是环境或者代码的问题。

遇到的现象和发生背景,请写出第一个错误信息
用代码块功能插入代码,请勿粘贴截图。 不用代码块回答率下降 50%

根据回答修改了数组传递和索引,还是报错

修改后的完整代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glpk.h>

#define MAX_LINE_LEN 1024

typedef struct
{
    int year;
    char securities_code[20];
    double financial_expense;
    double dividend;
    double operating_cost;
    double total_asset;
    double employee;
    double total_profit;
    double operating_income;
    double non_current_liabilities;
    double paid_in_capital;
} DMU;

DMU *read_csv(const char *filename, int *count)
{
    FILE *fp = fopen(filename, "r");
    if (!fp)
    {
        perror("Error opening file");
        return NULL;
    }

    DMU *data = NULL;
    char line[MAX_LINE_LEN];
    *count = 0;

    // 跳过 UTF-8 BOM
    if (fgetc(fp) == 0xEF && fgetc(fp) == 0xBB && fgetc(fp) == 0xBF)
    {
        // BOM 已检测
    }
    else
    {
        rewind(fp);
    }

    // 跳过标题行
    fgets(line, sizeof(line), fp);

    while (fgets(line, sizeof(line), fp))
    {
        DMU *temp = realloc(data, (*count + 1) * sizeof(DMU));
        if (!temp)
        {
            free(data);
            fclose(fp);
            return NULL;
        }
        data = temp;

        DMU *d = &data[*count];
        memset(d, 0, sizeof(DMU));

        char *token;
        int field = 0;       // 定义一次
        int max_fields = 11; // 总字段数

        token = strtok(line, ",");
        while (token != NULL && field < max_fields)
        {
            switch (field)
            {
            case 0:
                d->year = atoi(token);
                printf("Parsing field %d: year = %d\n", field, d->year);
                break;
            case 1:
                strncpy(d->securities_code, token, sizeof(d->securities_code) - 1);
                d->securities_code[sizeof(d->securities_code) - 1] = '\0'; // 确保终止
                break;
            case 2:
                d->financial_expense = atof(token);
                printf("Parsing field %d: financial_expense = %f\n", field, d->financial_expense);
                break;
            case 3:
                d->dividend = atof(token);
                break;
            case 4:
                d->operating_cost = atof(token);
                break;
            case 5:
                d->total_asset = atof(token);
                break;
            case 6:
                d->employee = atof(token);
                break;
            case 7:
                d->total_profit = atof(token);
                if (d->total_profit <= 0)
                {
                    fprintf(stderr, "Error: Line %d has invalid total_profit.\n", *count + 1);
                    free(data);
                    fclose(fp);
                    return NULL;
                }
                break;
            case 8:
                d->operating_income = atof(token);
                if (d->operating_income <= 0)
                {
                    fprintf(stderr, "Error: Line %d has invalid operating_income.\n", *count + 1);
                    free(data);
                    fclose(fp);
                    return NULL;
                }
                break;
            case 9:
                d->non_current_liabilities = atof(token);
                break;
            case 10:
                d->paid_in_capital = atof(token);
                if (d->paid_in_capital < 0)
                {
                    fprintf(stderr, "Error: Line %d has invalid paid_in_capital.\n", *count + 1);
                    free(data);
                    fclose(fp);
                    return NULL;
                }
                break;
            default:
                break;
            }
            token = strtok(NULL, ",");
            field++;
        }

        // 检查字段数量
        if (field != max_fields)
        {
            fprintf(stderr, "Error: Line %d has %d fields (expected 11).\n", *count + 1, field);
            free(data);
            fclose(fp);
            return NULL;
        }

        (*count)++;
    }

    fclose(fp);
    return data;
}

double calculate_efficiency(DMU *dmus, int num_dmus, int target_idx)
{
    DMU *target = &dmus[target_idx];
    glp_prob *lp = glp_create_prob();
    glp_set_obj_dir(lp, GLP_MAX);

    // ================== Add Variables ==================
    glp_add_cols(lp, 7); // 列索引1-7

    for (int i = 1; i <= 7; i++)
    {
        glp_set_col_bnds(lp, i, GLP_LO, 0.0, 0.0);
    }

    // ================== Objective Function ==================
    glp_set_obj_coef(lp, 6, target->operating_income); // u0 (第6列)
    glp_set_obj_coef(lp, 7, target->total_profit);     // u1 (第7列)

    // ================== Constraints ==================
    int row_count = 0;

    // 约束1: 标准化输入
    row_count++;
    glp_add_rows(lp, 1);
    glp_set_row_bnds(lp, row_count, GLP_FX, 1.0, 1.0);
    {
        int ind[] = {1, 2, 3, 4, 5}; // 前5列变量
        double val[] = {target->financial_expense,
                        target->operating_cost,
                        target->total_asset,
                        target->employee,
                        target->non_current_liabilities};
        printf("Setting row %d, ind[] = ", row_count);
        for (int k = 0; k < 5; k++)
        { // 正确循环次数
            printf("%d ", ind[k]);
        }
        printf("\n");
        glp_set_mat_row(lp, row_count, 5, ind, val);
    }

    // 约束2: 所有DMU的约束
    for (int j = 0; j < num_dmus; j++)
    {
        printf("Setting DMU %d constraint (row %d):\n", j, row_count);
        DMU *dmu = &dmus[j];
        printf("  financial_expense = %f\n", dmu->financial_expense);
        printf("  operating_cost = %f\n", dmu->operating_cost);
        printf("  total_asset = %f\n", dmu->total_asset);
        printf("  employee = %f\n", dmu->employee);
        printf("  non_current_liabilities = %f\n", dmu->non_current_liabilities);
        printf("  operating_income = %f\n", dmu->operating_income);
        printf("  total_profit = %f\n", dmu->total_profit);
        row_count++;
        glp_add_rows(lp, 1);
        glp_set_row_bnds(lp, row_count, GLP_LO, 0.0, 0.0);

        int ind[] = {1, 2, 3, 4, 5, 6, 7}; // 必须包含7个合法索引
        double val[] = {dmu->financial_expense,

                        dmu->financial_expense,
                        dmu->operating_cost,
                        dmu->total_asset,
                        dmu->employee,
                        dmu->non_current_liabilities,
                        -dmu->operating_income,
                        -dmu->total_profit};
        // 打印调试信息
        printf("Setting DMU %d constraint (row %d): ind[] = ", j, row_count);
        // 检查索引合法性
        for (int k = 0; k < 7; k++)
        {
            if (ind[k] < 1 || ind[k] > 7)
            {
                fprintf(stderr, "Invalid column index %d at row %d\n", ind[k], row_count);
                printf("  ind[%d] = %d, val[%d] = %f\n", k, ind[k], k, val[k]);
                exit(1);
            }
        }

        glp_set_mat_row(lp, row_count, 7, ind, val);
    }

    // ================== 求解 ==================
    glp_simplex(lp, NULL);
    double eff = glp_get_obj_val(lp);
    glp_delete_prob(lp);
    return eff;
}
int main()
{
    int num_dmus;
    DMU *dmus = read_csv("./test.csv", &num_dmus);
    if (!dmus)
        return 1;

    for (int i = 0; i < num_dmus; i++)
    {
        double eff = calculate_efficiency(dmus, num_dmus, i);
        printf("DMU %s (%d): Efficiency = %.4f\n",
               dmus[i].securities_code, dmus[i].year, eff);
    }

    free(dmus);
    return 0;
}

VScode终端运行结果及详细报错内容
PS D:\DEA_code> .\model2   
Parsing field 0: year = 2023
Parsing field 2: financial_expense = 1000.000000
Parsing field 0: year = 2023
Parsing field 2: financial_expense = 2000.000000
Setting row 1, ind[] = 1 2 3 4 5 
glp_set_mat_row: i = 1; ind[5] = -804953840; column index out of range
Error detected in file ../../glpk-5.0/src/api/prob1.c at line 771
PS D:\DEA_code> 

目录结构如图

img

我的解答思路和尝试过的方法,不写自己思路的,回答率下降 60%

尝试过添加各种调试信息,并截取前两行数据单独放csv测试,以及重新安装GLPK库,都没有解决
根据回答修改了数组传递和索引,还是报错
新的报错信息和运行结果:

PS D:\DEA_code> .\model2                                                                         
Parsing field 0: year = 2023
Parsing field 2: financial_expense = 1000.000000
Parsing field 0: year = 2023
Parsing field 2: financial_expense = 2000.000000
Setting row 1, ind[] = 1 2 3 4 5 
glp_set_mat_row: i = 1; ind[5] = 0; column index out of range
Error detected in file ../../glpk-5.0/src/api/prob1.c at line 771
PS D:\DEA_code> 

我想要达到的结果,如果你需要快速回答,请尝试 “付费悬赏”

我想找到什么地方出了问题,怎么解决

  • 写回答

4条回答 默认 最新

  • 宝码香车 优质创作者: JavaScript技术领域 2025-05-06 23:22
    关注

    让【宝码香车】来帮你解答,本回答参考DeepSeek编写,并整理提供。
    如果还有疑问可以点击头像关注私信或评论。如果答案让您满意,请采纳、点赞、关注,非常感谢!

    根据您提供的错误信息和代码,问题出在GLPK库设置矩阵行时的列索引越界。以下是详细分析和解决方案:

    1. 问题分析

    错误信息显示:

    glp_set_mat_row: i = 1; ind[5] = -804953840; column index out of range
    

    这表明在设置矩阵行时,列索引出现了非法值(负数或超出范围)。

    2. 主要问题点

    calculate_efficiency函数中,有两个关键问题:

    问题1:索引数组定义错误

    int ind[] = {0, 1, 2, 3, 4, 5}; // 前5列变量
    

    GLPK的列索引应该从1开始,但您包含了0,这会导致后续索引偏移错误。

    问题2:数组访问越界

    glp_set_mat_row(lp, row_count, 5, &ind[1], &val[1]);
    

    这里传递的是从索引1开始的数组,但indval数组定义时已经考虑了0索引,导致实际访问越界。

    3. 解决方案

    修改calculate_efficiency函数中的相关代码:

    修正后的约束1部分

    // 约束1: 标准化输入
    row_count++;
    glp_add_rows(lp, 1);
    glp_set_row_bnds(lp, row_count, GLP_FX, 1.0, 1.0);
    {
        // 列索引从1开始,对应您添加的7个变量
        int ind[] = {1, 2, 3, 4, 5}; // 只包含实际使用的列索引
        double val[] = {
            target->financial_expense,
            target->operating_cost,
            target->total_asset,
            target->employee,
            target->non_current_liabilities
        };
        printf("Setting row %d, ind[] = ", row_count);
        for (int k = 0; k < 5; k++) {
            printf("%d ", ind[k]);
        }
        printf("\n");
        glp_set_mat_row(lp, row_count, 5, ind, val); // 直接传递数组
    }
    

    修正后的约束2部分

    // 约束2: 所有DMU的约束
    for (int j = 0; j < num_dmus; j++) {
        DMU *dmu = &dmus[j];
        row_count++;
        glp_add_rows(lp, 1);
        glp_set_row_bnds(lp, row_count, GLP_LO, 0.0, 0.0);
        
        int ind[] = {1, 2, 3, 4, 5, 6, 7}; // 列索引1-7
        double val[] = {
            dmu->financial_expense,
            dmu->operating_cost,
            dmu->total_asset,
            dmu->employee,
            dmu->non_current_liabilities,
            -dmu->operating_income,
            -dmu->total_profit
        };
        
        glp_set_mat_row(lp, row_count, 7, ind, val);
    }
    

    4. 关键修改点

    1. 所有列索引从1开始(GLPK要求)
    2. 移除了不必要的0索引
    3. 确保索引数组和值数组大小匹配
    4. 直接传递数组而不是偏移后的指针

    5. 其他建议

    1. 检查GLPK库是否正确安装和链接
    2. 确保编译命令包含正确的GLPK头文件和库路径,例如:
      gcc -o model2 model2.c -lglpk -I/usr/local/include -L/usr/local/lib
      
    3. 对于更复杂的调试,可以使用GLPK的内置调试功能:
      glp_term_out(GLP_ON); // 开启求解器输出
      

    这些修改应该能解决您遇到的列索引越界问题。如果仍有问题,建议检查数据文件内容是否与代码预期一致。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 5月12日
  • 已采纳回答 5月7日
  • 修改了问题 5月7日
  • 创建了问题 5月6日