You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用LAPACK复现Schur分解结果与MATLAB不匹配的技术求助

Troubleshooting LAPACK Schur Decomposition Mismatches with MATLAB

I've gone through your problem and code, and let's break down the issues you're facing with both the dgehrd/dhseqr pipeline and the dgees sorting option.


1. Why dgehrd + dhseqr Isn't Matching MATLAB

Your pipeline has a few critical mistakes that are throwing off the results:

a. Incorrect ilo/ihi Values

LAPACK uses 1-based indexing, so for an n×n matrix, you need to set ilo=1 and ihi=nrows (not nrows-1) to process the entire matrix. Your original setting skipped the last row/column, which broke the decomposition.

b. Missing Proper Orthogonal Transformation Accumulation

You mentioned calling dorghr but seeing no effect—this is likely because you didn't initialize the Z matrix to the identity before calling dorghr. The dorghr function applies the Householder transformations from dgehrd to an existing matrix; starting with identity ensures you build the full orthogonal matrix U.

c. Potential Storage Order Confusion

LAPACK uses column-major (Fortran-style) storage, while your C code uses row-major. When copying results from Z (U) and val (T) to your output arrays, you have the transpose right, but make sure your input matrix val is passed in column-major order. If your input A is row-major, you need to transpose it first before feeding it to LAPACK.

Fixed dgehrd + dhseqr Code Snippet

Here's the corrected pipeline:

int ilo = 1, ihi = nrows; // Correct 1-based bounds for full matrix
double *tau = (double*)calloc(nrows-1, sizeof(double));
double wkopt;
int lwork = -1;
int info;

// Step 1: Generate Householder reductions
LAPACK_dgehrd(&nrows, &ilo, &ihi, val, &nrows, tau, &wkopt, &lwork, &info);
if (info != 0) {
    fprintf(stderr, "dgehrd failed with info=%d\n", info);
    exit(1);
}
lwork = (int)wkopt;
double *work = (double*)malloc(lwork * sizeof(double));
LAPACK_dgehrd(&nrows, &ilo, &ihi, val, &nrows, tau, work, &lwork, &info);

// Step 2: Initialize Z to identity, then accumulate orthogonal transforms
for (int i=0; i<nrows*nrows; i++) Z[i] = 0.0;
for (int i=0; i<nrows; i++) Z[i*nrows + i] = 1.0;
LAPACK_dorghr(&nrows, &ilo, &ihi, Z, &nrows, tau, work, &lwork, &info);
if (info != 0) {
    fprintf(stderr, "dorghr failed with info=%d\n", info);
    exit(1);
}

// Step 3: Compute Schur form T
LAPACK_dhseqr("S", "V", &nrows, &ilo, &ihi, val, &nrows, wr, wi, Z, &nrows, work, &lwork, &info);
if (info > 0) {
    fprintf(stderr, "dhseqr failed to converge at eigenvalue %d\n", info);
    exit(1);
}

// Copy column-major results to row-major U/T (your existing code here is correct)
for (int i=0; i<nrows; i++) {
    for (int j=0; j<nrows; j++) {
        U[i*nrows+j] = Z[j*nrows+i];
        T[i*nrows+j] = val[j*nrows+i];
    }
}

2. Fixing dgees Sorting & Crash Issues

Your dgees setup has two main problems:

a. Misconfigured sdim Parameter

The sdim variable is an output parameter—it tells you how many eigenvalues matched your SELECT criteria. You shouldn't set it to nrows-1 upfront; initialize it to 0 instead. Setting it to a non-zero value as input can cause memory corruption and crashes.

b. Incorrect SELECT Function Logic

MATLAB's default schur(A) sorts Schur blocks by descending real part of eigenvalues (with complex conjugate blocks grouped together). Your current SELECT function only checks if an eigenvalue is exactly (1,0), which doesn't match MATLAB's behavior.

If you want to replicate MATLAB's default order, you need a SELECT function that prioritizes eigenvalues with larger real parts. For example, here's a version that selects eigenvalues with real parts greater than the average real part (adjust based on your specific matrix):

// Global variable to store real parts of all eigenvalues (compute before calling dgees)
double *all_wr;
int nrows_global; // Pass nrows via global to avoid function parameter issues

lapack_logical SELECT(double er, double ei) {
    // Select eigenvalues with real part >= average real part (matches MATLAB's descending order intent)
    double avg = 0.0;
    for (int i=0; i<nrows_global; i++) avg += all_wr[i];
    avg /= nrows_global;
    return (er >= avg) ? 1 : 0;
}

Note: Before calling dgees, compute all eigenvalues with dgeev to populate all_wr, and set nrows_global to your matrix size.

Fixed dgees Call

Here's the corrected dgees setup:

int sdim = 0; // Initialize to 0 (output parameter)
lapack_logical *bwork = (lapack_logical*)calloc(nrows, sizeof(lapack_logical));
double wkopt;
int lwork = -1;
int info;

// First query optimal workspace size
LAPACK_dgees("V", "S", SELECT, &nrows, val, &nrows, &sdim, wr, wi, Z, &nrows, &wkopt, &lwork, bwork, &info);
lwork = (int)wkopt;
double *work = (double*)malloc(lwork * sizeof(double));

// Actual decomposition with sorting
LAPACK_dgees("V", "S", SELECT, &nrows, val, &nrows, &sdim, wr, wi, Z, &nrows, work, &lwork, bwork, &info);

General Critical Notes

  • Column-Major vs Row-Major: Always ensure your input matrix is in column-major order when passing to LAPACK. If your input is row-major (C-style), transpose it first.
  • Workspace Allocation: Never skip the workspace query step (lwork=-1). Using insufficient workspace can lead to crashes or incorrect results.
  • Indexing: LAPACK uses 1-based integers for parameters like ilo, ihi, and matrix dimensions—don't mix with C's 0-based indexing.

内容的提问来源于stack exchange,提问作者user2971034

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:14:13