refactor(nmNum): 简化 LM 形状阶段联合调整与停滞确认

- 移除时间窗口选参、三参数上限及子集枚举,每步联合调整全部有效非井储表皮参数
- 连续两次改善不足后刷新灵敏度,仅做一次全局联合确认,累计有效改善门槛设为 10%
- 放宽形状扩步条件,取消实际与预测改善比值限制,保留预测下降、步长和边界约束
- 确认步求解失败时有限重试,避免将失败误判为收敛
- 同步拟合轨迹元数据、尝试次数日志及中文翻译
feature/AutoFit-Optimize-20260914
lvjunjie 1 month ago
parent 43b7c770ed
commit 50f149970c

Binary file not shown.

@ -1281,20 +1281,20 @@ Reason: %1</source>
<translation>进入联合形状调整时重建灵敏度</translation>
</message>
<message>
<source>Adaptive fitting counts: %1 completed shape rounds, %2 total-stage iterations, %3 total evaluations.</source>
<translation>自适应拟合统计:已完成 %1 轮形状搜索,整体阶段迭代 %2 次,累计评估 %3 次。</translation>
<source>Adaptive fitting counts: %1 shape attempts, %2 total-stage iterations, %3 total evaluations.</source>
<translation>自适应拟合统计:形状尝试 %1 次,整体阶段迭代 %2 次,累计评估 %3 次。</translation>
</message>
<message>
<source>LM stage 2: adaptive shape search; confirm stagnation after 2 complete rounds without significant improvement.</source>
<translation>LM 阶段2:自适应形状搜索;连续两轮完整搜索无显著改善后确认停滞。</translation>
<source>LM stage 2: joint shape search; after 2 ineffective steps, refresh sensitivity and confirm with one global step.</source>
<translation>LM 第二阶段:联合调整全部可调形状参数;连续两次改善不足后,刷新灵敏度并用一次全局联合调整确认。</translation>
</message>
<message>
<source>LM starting point error: %1; independent total-stage evaluation budget: %2</source>
<translation>LM 起点误差:%1;整体阶段独立评估预算:%2</translation>
</message>
<message>
<source>Shape search round %1: shape error=%2, improvement=%3, required=%4.</source>
<translation>形状搜索第 %1 轮:形状误差=%2,改善量=%3,所需改善量=%4。</translation>
<source>Shape search step %1: shape error=%2, accumulated improvement=%3, required=%4.</source>
<translation>形状尝试 %1:形状误差=%2,累计改善=%3,有效改善门槛=%4。</translation>
</message>
<message>
<source>Total-stage budget starts now: %1 iterations, %2 evaluations; pre-adjustment is counted separately.</source>
@ -1305,16 +1305,16 @@ Reason: %1</source>
<translation>无法建立有效的形状灵敏度模型。</translation>
</message>
<message>
<source>confirm stagnation after 2 complete shape rounds</source>
<translation>完成两轮形状搜索后确认停滞</translation>
<source>confirm shape stagnation after 2 ineffective steps</source>
<translation>连续两次形状改善不足,刷新灵敏度确认停滞</translation>
</message>
<message>
<source>full sensitivity at total-stage entry</source>
<translation>进入整体阶段时建立完整灵敏度</translation>
</message>
<message>
<source>no significant improvement in a complete round after fresh sensitivity confirmation</source>
<translation>重建灵敏度确认后,完整一轮搜索仍无显著改善</translation>
<source>no significant shape improvement after fresh sensitivity and one global step</source>
<translation>刷新灵敏度并进行一次全局联合调整后,形状仍无显著改善</translation>
</message>
<message>
<source>no valid early sensitivity model</source>

@ -594,95 +594,6 @@ static QVector<TrustRegionFisher> buildTrustRegionFisher(
return information;
}
static int nextTrustRegionWindow(
const QVector<AutoFitTimeWindowLM>& windows,
const QVector<bool>& attempted)
{
// 每次都按当前误差能量重新排序;本轮无效的窗口暂时跳过,-1 表示全局回退。
int selected = -1;
double largestEnergy = 0.0;
for(int k = 0; k < windows.size(); ++k) {
if(!attempted[k] && isFiniteNumber(windows[k].energy) &&
windows[k].energy > largestEnergy) {
largestEnergy = windows[k].energy;
selected = k;
}
}
return selected;
}
static QVector<int> selectTrustRegionFisherColumns(
const TrustRegionFisher& local,
const TrustRegionFisher& global,
const QVector<bool>& columnValid,
const QVector<double>& coordinates,
double minimumStep)
{
// g^2/F 衡量修正当前残差的潜力,避免仅按影响强度选中无助于降误差的参数。
const int dimensions = columnValid.size();
double maximumDiagonal = 0.0;
for(int p = 0; p < dimensions; ++p) {
if(columnValid[p] && isFiniteNumber(local.matrix[p][p])) {
maximumDiagonal = qMax(maximumDiagonal, local.matrix[p][p]);
}
}
const double diagonalFloor = qMax(1.0e-30, maximumDiagonal * 1.0e-12);
QVector<double> scores(dimensions, 0.0);
double maximumScore = 0.0;
for(int p = 0; p < dimensions; ++p) {
if(!columnValid[p] || local.matrix[p][p] <= diagonalFloor ||
!isFiniteNumber(local.matrix[p][p]) ||
!isFiniteNumber(local.gradient[p]) ||
!isFiniteNumber(global.gradient[p])) {
continue;
}
// 全局下降方向指向边界外时暂不选该参数,避免它挤占可移动参数的位置。
if((coordinates[p] <= minimumStep && global.gradient[p] > 0.0) ||
(coordinates[p] >= 1.0 - minimumStep && global.gradient[p] < 0.0)) {
continue;
}
double scaledGradient = local.gradient[p] /
qSqrt(local.matrix[p][p] + diagonalFloor);
double score = scaledGradient * scaledGradient;
if(isFiniteNumber(score)) {
scores[p] = score;
maximumScore = qMax(maximumScore, score);
}
}
QVector<int> selected;
for(int selection = 0; selection < qMin(3, dimensions); ++selection) {
int best = -1;
double bestScore = maximumScore * 1.0e-12;
for(int p = 0; p < dimensions; ++p) {
if(selected.contains(p) || scores[p] <= bestScore) {
continue;
}
// 沿用现有全局 0.995 共线限制,不因单个窗口内响应相似而冻结参数。
bool correlated = false;
for(int i = 0; i < selected.size(); ++i) {
int q = selected[i];
double denominator = qSqrt(global.matrix[p][p]) *
qSqrt(global.matrix[q][q]);
if(denominator > 0.0 &&
qAbs(global.matrix[p][q]) / denominator > 0.995) {
correlated = true;
break;
}
}
if(!correlated) {
best = p;
bestScore = scores[p];
}
}
if(best < 0) {
break;
}
selected.append(best);
}
return selected;
}
static bool buildTrustRegionFisherStep(
const TrustRegionFisher& global,
const QVector<int>& selected,
@ -1212,7 +1123,7 @@ void nmCalculationAutoFitLM::writeTraceMetaFile()
QTextStream out(&metaFile);
out << "{\n";
out << " \"schema_version\": 31,\n";
out << " \"schema_version\": 36,\n";
out << " \"strategy\": \"permeability_height_then_shape_then_joint_lm\",\n";
out << " \"height_acceptance\": \"reliable_vertical_loss_decrease; no_shape_or_total_loss_constraint\",\n";
out << " \"shape_priority\": \"storage_then_skin_then_shape_without_wellbore_then_optional_wellbore_recheck\",\n";
@ -1228,10 +1139,10 @@ void nmCalculationAutoFitLM::writeTraceMetaFile()
out << " \"shape_stage_total_constraint\": false,\n";
out << " \"shape_wellbore_parameters_frozen\": true,\n";
out << " \"shape_sensitivity_refresh\": \"non_wellbore_columns_only at joint shape entry and stagnation confirmation; full Jacobian rebuilt at total-stage entry\",\n";
out << " \"shape_expansion_policy\": \"one expansion per reliable shape direction, up to 2x when actual rho exceeds 0.75; retain ordinary step on failure\",\n";
out << " \"shape_global_parameter_selection\": \"all_valid_non_wellbore_columns_with_positive_response\",\n";
out << " \"stage2_budget\": \"adaptive, no fixed iteration or evaluation quota; full window/global rounds, 2 ineffective rounds then fresh-J confirmation\",\n";
out << " \"shape_round_improvement_threshold\": \"max(0.0001, 1% of round entry shape loss)\",\n";
out << " \"shape_expansion_policy\": \"one expansion per accepted shape direction, up to 2x with predicted descent and parameter bounds; no_rho_gate; retain ordinary step on failure\",\n";
out << " \"shape_global_parameter_selection\": \"all_valid_non_wellbore_columns_with_positive_response_at_every_shape_step; no_window_selection\",\n";
out << " \"stage2_budget\": \"adaptive, no fixed iteration or evaluation quota; 2 ineffective shape attempts then one fresh-J global confirmation\",\n";
out << " \"shape_step_improvement_threshold\": \"max(0.0001, 10% of last effective shape loss); accumulate small improvements\",\n";
out << " \"iteration_count_scope\": \"max_iterations applies to total-stage LM; trace iteration remains cumulative\",\n";
out << " \"wellbore_recheck_trigger\": \"early loss exceeds initial early-stage exit by max(0.0001, 10%)\",\n";
out << " \"wellbore_recheck_acceptance\": \"early decrease with fixed entry shape limit max(0.0001, 5%); no_total_loss_constraint\",\n";
@ -2033,7 +1944,6 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
const char* rebuildReason = QT_TR_NOOP("initial sensitivity model");
bool modelRebuiltAtMinimumRadius = false;
bool stagnationConfirmationRequested = false;
QVector<bool> attemptedWindows(kAutoFitTimeWindowCount, false);
bool globalFallbackAttempted = false;
StopReasonLM stopReason = LM_MAX_ITERATIONS;
@ -2210,13 +2120,13 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
if(m_shouldStop) return LM_USER_STOPPED;
// 第二阶段不按迭代比例截断;普通形状按完整搜索轮次判断是否仍有显著改善。
// 第二阶段不按迭代比例截断;连续两次改善不足后,刷新灵敏度并仅做一次全局联合确认。
// 普通形状调整冻结井储、表皮,只按形状验收;总误差达标只在第三阶段判断。
bool shapeStage = true;
bool jointShapeStarted = false;
double shapeRoundBaseline = current.breakdown.shapeLoss;
int shapeRoundNumber = 0;
int ineffectiveShapeRounds = 0;
double shapeImprovementBaseline = current.breakdown.shapeLoss;
int shapeStepCount = 0;
int ineffectiveShapeSteps = 0;
bool shapeConfirmationRequested = false;
const int storageColumn = m_enabledParamIndices.indexOf(2);
const int skinColumn = m_enabledParamIndices.indexOf(1);
@ -2283,7 +2193,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
restoreEvaluationState(current);
};
emit logMessageGenerated(shapeStage
? tr("LM stage 2: adaptive shape search; confirm stagnation after 2 complete rounds without significant improvement.")
? tr("LM stage 2: joint shape search; after 2 ineffective steps, refresh sensitivity and confirm with one global step.")
: tr("LM stage 3: original LM fitting; accept by total error only."));
if(earlyShapeStage) {
emit logMessageGenerated(earlyShapeParameter == 2
@ -2328,7 +2238,6 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
consecutivePoorPredictions = 0;
modelRebuiltAtMinimumRadius = false;
stagnationConfirmationRequested = false;
attemptedWindows.fill(false);
globalFallbackAttempted = false;
fullDataRejections = 0;
effectiveImprovementBaseline = stageError(current);
@ -2357,7 +2266,6 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
consecutiveRejectedSteps = 0;
consecutiveSolverFailures = 0;
stagnationConfirmationRequested = false;
attemptedWindows.fill(false);
globalFallbackAttempted = false;
trustRadius = 0.12;
damping = 0.01;
@ -2454,35 +2362,36 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
true, 0, "early_wellbore_to_shape", &current.breakdown);
};
auto completeShapeSearchRound = [&]() {
if(!shapeStage || earlyShapeStage || !globalFallbackAttempted) return;
if(m_shouldStop) return;
const double required = qMax(1.0e-4, 0.01 * shapeRoundBaseline);
const double improvement = shapeRoundBaseline - current.breakdown.shapeLoss;
auto completeShapeSearchStep = [&]() {
if(!shapeStage || earlyShapeStage || m_shouldStop) return;
// 改善相对上一次有效改善累计,避免单次小步被立即否定;不再等待完整窗口轮次。
const double required = qMax(1.0e-4, 0.10 * shapeImprovementBaseline);
const double improvement = shapeImprovementBaseline - current.breakdown.shapeLoss;
const bool improved = improvement >= required;
++shapeRoundNumber;
++shapeStepCount;
writeTraceRow(m_currentIteration, -1, "shape_step_end", current.parameters, current.fitness,
true, 0, QString(improved ? "improved_step_%1" : "ineffective_step_%1").arg(shapeStepCount), &current.breakdown);
emit logMessageGenerated(tr("Shape search step %1: shape error=%2, accumulated improvement=%3, required=%4.")
.arg(shapeStepCount).arg(current.breakdown.shapeLoss, 0, 'g', 6)
.arg(improvement, 0, 'g', 6).arg(required, 0, 'g', 6));
// 每次形状调整都是全局联合步,结束后清除本次尝试标记。
globalFallbackAttempted = false;
if(improved) {
ineffectiveShapeRounds = 0;
shapeImprovementBaseline = current.breakdown.shapeLoss;
ineffectiveShapeSteps = 0;
shapeConfirmationRequested = false;
} else ++ineffectiveShapeRounds;
writeTraceRow(m_currentIteration, -1, "shape_round_end", current.parameters, current.fitness,
true, 0, QString(improved ? "improved_round_%1" : "ineffective_round_%1").arg(shapeRoundNumber), &current.breakdown);
emit logMessageGenerated(tr("Shape search round %1: shape error=%2, improvement=%3, required=%4.")
.arg(shapeRoundNumber).arg(current.breakdown.shapeLoss, 0, 'g', 6)
.arg(improvement, 0, 'g', 6).arg(required, 0, 'g', 6));
if(!improved && shapeConfirmationRequested) {
finishShapeStage(tr("no significant improvement in a complete round after fresh sensitivity confirmation"));
return;
}
// 下一轮重新覆盖窗口和全部有效参数的全局步;单步小改善不重置本轮进度。
shapeRoundBaseline = current.breakdown.shapeLoss;
attemptedWindows.fill(false);
globalFallbackAttempted = false;
if(!improved && ineffectiveShapeRounds >= 2) {
++ineffectiveShapeSteps;
if(shapeConfirmationRequested) {
finishShapeStage(tr("no significant shape improvement after fresh sensitivity and one global step"));
return;
}
if(ineffectiveShapeSteps >= 2) {
jacobian.clear();
reuseSensitivityForNextStage();
rebuildRequested = true;
rebuildReason = QT_TR_NOOP("confirm stagnation after 2 complete shape rounds");
rebuildReason = QT_TR_NOOP("confirm shape stagnation after 2 ineffective steps");
shapeConfirmationRequested = true;
}
};
@ -2498,8 +2407,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
return false;
}
// 有效改善后重新开放全部窗口,并按新工作点的能量排序。
attemptedWindows.fill(false);
// 有效改善后更新累计基准,并清除停滞计数。
globalFallbackAttempted = false;
effectiveImprovementBaseline = fitness;
consecutiveIneffectiveSteps = 0;
@ -2507,11 +2415,11 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
return true;
};
// 无效尝试仍累计,但所有窗口及一次全局回退尝试完毕前,不触发停滞收敛。
// 完整一轮仍无改善时沿用原有重建确认,避免某个难处理窗口提前终止拟合。
// 普通形状按连续尝试判断停滞,并用新灵敏度下的全局联合步确认;
// 前期井储、表皮与整体 LM 沿用各自的无效次数处理。
auto recordIneffectiveStep = [&]() -> bool {
if(shapeStage && !earlyShapeStage) {
completeShapeSearchRound();
completeShapeSearchStep();
return false;
}
++consecutiveIneffectiveSteps;
@ -2524,7 +2432,6 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
if(!globalFallbackAttempted) {
return false;
}
attemptedWindows.fill(false);
globalFallbackAttempted = false;
if(consecutiveIneffectiveSteps < maximumIneffectiveSteps) {
return false;
@ -2771,7 +2678,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
enterTotalStage(tr("early shape error restored within tolerance"));
if(shapeStage && !earlyShapeStage && !jointShapeStarted) {
jointShapeStarted = true;
shapeRoundBaseline = current.breakdown.shapeLoss;
shapeImprovementBaseline = current.breakdown.shapeLoss;
// 初调已改变井储/表皮,普通形状必须在新的工作点重测其余可调参数的响应。
jacobian.clear();
reuseSensitivityForNextStage();
@ -2840,7 +2747,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
// 第三阶段独立计数;方向不可行也消耗一次局部尝试,不能无限缩步循环。
if(!shapeStage) ++totalIterations;
// 每轮从最新 J 和当前残差重算窗口 Fisher,包含有限差分与割线更新的变化。
// 每次从最新 J 和当前阶段残差重算 Fisher,联合步使用全局信息。
const QVector<double> objectiveResidual = earlyShapeStage
? current.breakdown.earlyParallelResiduals
: (shapeStage ? current.breakdown.shapeResiduals : current.breakdown.residualVector);
@ -2854,10 +2761,6 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
objectiveCoordinates.clear();
for(int i = 0; i < 73; ++i) objectiveCoordinates.append((i + 4.0) / 80.0);
}
const QVector<AutoFitTimeWindowLM> objectiveWindows = shapeStage
? calculateAutoFitTimeWindows(objectiveResidual, m_comparisonTimeMin, m_comparisonTimeMax,
objectiveCoordinates, autoFitLogTimeWeights(objectiveCoordinates))
: current.breakdown.timeWindows;
const QVector<TrustRegionFisher> information = buildTrustRegionFisher(
objectiveJacobian, objectiveResidual, jacobianColumnValid, objectiveCoordinates);
const TrustRegionFisher& global = information[kAutoFitTimeWindowCount];
@ -2870,18 +2773,35 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
QVector<int> selectedColumns;
QVector<double> coordinateStep;
double predictedReduction = 0.0;
int selectedWindow = -1;
if(!shapeStage) {
// 整体阶段联合求解全部有效自由列,不按窗口得分、三参数上限或共线阈值删列。
// 边界列也参与耦合求解,是否向内移动由联合解及其边界投影决定。
for(int column = 0; column < dimensions; ++column) {
// 仅跳过完全没有总残差响应的列,保留弱敏感列及相互相关的列。
if(stageColumnValid[column] && global.matrix[column][column] > 0.0)
selectedColumns.append(column);
const int selectedWindow = earlyShapeStage ? 0 : -1;
// 前期只开放当前井储或表皮;普通形状和整体 LM 都联合求解全部有效自由列。
// 保留弱敏感、相关及边界列,让参数相互配合;窗口只保留作误差诊断。
for(int column = 0; column < dimensions; ++column) {
if(stageColumnValid[column] && (earlyShapeStage || global.matrix[column][column] > 0.0))
selectedColumns.append(column);
}
if(earlyShapeStage) {
double earlyStepRadius = trustRadius;
if(!earlyShapeHasImproved && selectedColumns.size() == 1) {
// 首次调整沿用小步起调,形状变差时由后面的同向扩步循环处理。
const int column = selectedColumns[0];
const int parameterIndex = m_enabledParamIndices[column];
const double lower = m_parameterLower[parameterIndex];
const double upper = m_parameterUpper[parameterIndex];
const double smallStep = useTrustRegionLogScale(parameterIndex, lower, upper)
? qLn(1.05) / (qLn(upper) - qLn(lower))
: (parameterIndex == 1 ? 0.02 * qMax(0.1, qAbs(current.parameters[column]))
: 0.05 * qMax(1.0e-8, qAbs(current.parameters[column]))) / (upper - lower);
earlyStepRadius = qMin(trustRadius, smallStep);
}
if(selectedColumns.isEmpty() || !buildEarlyGapGuidedStep(
stepInformation, selectedColumns, current.coordinates, earlyGapDirection,
damping, earlyStepRadius, minimumCoordinateStep, &coordinateStep, &predictedReduction)) {
selectedColumns.clear();
}
// 当前候选已使用全局信息,停滞判断无需再逐一尝试窗口子集。
attemptedWindows.fill(true);
} else {
// 普通调整和停滞确认共用全局联合方向,不再遍历窗口或枚举三参数子集。
globalFallbackAttempted = true;
if(selectedColumns.isEmpty() || !buildTrustRegionFisherStep(
global, selectedColumns, current.coordinates, damping,
@ -2889,81 +2809,6 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
selectedColumns.clear();
}
}
// 形状阶段先覆盖局部窗口,再用全部有效自由列求一次全局联合步。
while(shapeStage && selectedColumns.isEmpty()) {
selectedWindow = earlyShapeStage ? 0 : nextTrustRegionWindow(
objectiveWindows, attemptedWindows);
if(selectedWindow >= 0) {
attemptedWindows[selectedWindow] = true;
} else {
globalFallbackAttempted = true;
}
const TrustRegionFisher& local = selectedWindow >= 0
? information[selectedWindow] : global;
QVector<int> proposed;
if(earlyShapeStage) {
// 前期只开放当前的井储或表皮参数。
for(int column = 0; column < dimensions; ++column) {
if(stageColumnValid[column]) proposed.append(column);
}
} else if(selectedWindow < 0) {
// 全局步保留弱敏感及相关列,避免参数长期被窗口前三名或共线筛选排除。
for(int column = 0; column < dimensions; ++column) {
if(stageColumnValid[column] && global.matrix[column][column] > 0.0)
proposed.append(column);
}
} else {
proposed = selectTrustRegionFisherColumns(
local, global, stageColumnValid,
current.coordinates, minimumCoordinateStep);
}
// 局部窗口至多三列,比较非空子集;全局只求完整组合,不枚举全部参数子集。
const bool fullJointStep = !earlyShapeStage && selectedWindow < 0;
const int combinationCount = proposed.isEmpty() ? 0 : (fullJointStep ? 1 : (1 << proposed.size()) - 1);
for(int combination = 1; combination <= combinationCount; ++combination) {
QVector<int> columns;
if(fullJointStep) columns = proposed;
else {
for(int i = 0; i < proposed.size(); ++i) {
if(combination & (1 << i)) columns.append(proposed[i]);
}
}
QVector<double> step;
double reduction = 0.0;
double earlyStepRadius = trustRadius;
if(earlyShapeStage && !earlyShapeHasImproved && columns.size() == 1) {
// 确定方向后先小步:井储最多 1.05 倍,表皮为局部尺度的 2%。
// 首次形状变差由后面的扩步循环处理,首次接受后恢复正常 LM 幅度。
const int column = columns[0];
const int parameterIndex = m_enabledParamIndices[column];
const double lower = m_parameterLower[parameterIndex];
const double upper = m_parameterUpper[parameterIndex];
const double smallStep = useTrustRegionLogScale(parameterIndex, lower, upper)
? qLn(1.05) / (qLn(upper) - qLn(lower))
: (parameterIndex == 1 ? 0.02 * qMax(0.1, qAbs(current.parameters[column]))
: 0.05 * qMax(1.0e-8, qAbs(current.parameters[column]))) / (upper - lower);
earlyStepRadius = qMin(trustRadius, smallStep);
}
// 井储、表皮沿间距确定的方向调整;其他阶段保持原来的 LM 求步。
const bool stepBuilt = earlyShapeStage
? buildEarlyGapGuidedStep(stepInformation, columns, current.coordinates, earlyGapDirection,
damping, earlyStepRadius, minimumCoordinateStep, &step, &reduction)
: buildTrustRegionFisherStep(stepInformation, columns, current.coordinates,
damping, trustRadius, minimumCoordinateStep, &step, &reduction);
if(!stepBuilt) continue;
const double tolerance = 1.0e-12 * qMax(predictedReduction, reduction);
if(selectedColumns.isEmpty() || reduction > predictedReduction + tolerance ||
(qAbs(reduction - predictedReduction) <= tolerance &&
columns.size() < selectedColumns.size())) {
selectedColumns = columns;
coordinateStep = step;
predictedReduction = reduction;
}
}
if(earlyShapeStage || selectedWindow < 0) {
break;
}
}
// 当前阶段没有可行下降步时,收缩半径并进入原有重建/收敛处理。
if(selectedColumns.isEmpty()) {
@ -2974,7 +2819,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
continue;
}
if(shapeStage) {
completeShapeSearchRound();
completeShapeSearchStep();
--iteration;
continue;
}
@ -3096,6 +2941,8 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
stopReason = LM_CONSECUTIVE_FAILURES;
break;
}
// 确认步求解失败不代表形状已收敛,沿用有限重试后按求解失败退出。
if(shapeStage && !earlyShapeStage && shapeConfirmationRequested) continue;
if(recordIneffectiveStep()) {
if(promoteSampling(false)) continue;
stopReason = LM_LOCAL_OPTIMUM;
@ -3104,16 +2951,12 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
continue;
}
// 普通形状步真实表现可靠时,沿同一联合方向最多扩步试算一次,不区分参数类型。
// 普通形状步真实改善后,沿同一联合方向最多扩步一次,不再用预测兑现比例拦截。
// 扩步只按整体形状验收,优于原步才替换,否则保留原候选。
if(shapeStage && !earlyShapeStage && acceptable(candidate, current) && processPauseAndStop()) {
const double ordinaryEnergy = 0.5 * trustRegionSquaredNorm(objectiveResidual);
const double ordinaryReduction = ordinaryEnergy - 0.5 * trustRegionSquaredNorm(candidate.breakdown.shapeResiduals);
const double predictionFloor = qMax(1.0e-14, ordinaryEnergy * 1.0e-8);
QVector<double> expandedStep;
double expandedPrediction = 0.0;
if(predictedReduction > predictionFloor && ordinaryReduction / predictedReduction > 0.75 &&
buildExpandedTrustRegionStep(stepInformation, current.coordinates, coordinateStep,
if(buildExpandedTrustRegionStep(stepInformation, current.coordinates, coordinateStep,
maximumTrustRadius, &expandedStep, &expandedPrediction)) {
writeTraceRow(m_currentIteration, -1, "shape_step_base", candidate.parameters,
candidate.fitness, true, candidate.elapsedMs, "eligible_for_expansion", &candidate.breakdown);
@ -3291,8 +3134,8 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
m_currentIteration = completedIterations - 1;
}
restoreEvaluationState(current);
emit logMessageGenerated(tr("Adaptive fitting counts: %1 completed shape rounds, %2 total-stage iterations, %3 total evaluations.")
.arg(shapeRoundNumber).arg(totalIterations).arg(m_totalEvaluations));
emit logMessageGenerated(tr("Adaptive fitting counts: %1 shape attempts, %2 total-stage iterations, %3 total evaluations.")
.arg(shapeStepCount).arg(totalIterations).arg(m_totalEvaluations));
if(m_shouldStop) {
return LM_USER_STOPPED;

Loading…
Cancel
Save