diff --git a/Bin/Config/Lang/cn/nmNum_cn.qm b/Bin/Config/Lang/cn/nmNum_cn.qm
index 5fba4952..776d7652 100644
Binary files a/Bin/Config/Lang/cn/nmNum_cn.qm and b/Bin/Config/Lang/cn/nmNum_cn.qm differ
diff --git a/Bin/Config/Lang/cn/nmNum_cn.ts b/Bin/Config/Lang/cn/nmNum_cn.ts
index 104dcbea..6515933d 100644
--- a/Bin/Config/Lang/cn/nmNum_cn.ts
+++ b/Bin/Config/Lang/cn/nmNum_cn.ts
@@ -1281,20 +1281,20 @@ Reason: %1
进入联合形状调整时重建灵敏度
- Adaptive fitting counts: %1 completed shape rounds, %2 total-stage iterations, %3 total evaluations.
- 自适应拟合统计:已完成 %1 轮形状搜索,整体阶段迭代 %2 次,累计评估 %3 次。
+ Adaptive fitting counts: %1 shape attempts, %2 total-stage iterations, %3 total evaluations.
+ 自适应拟合统计:形状尝试 %1 次,整体阶段迭代 %2 次,累计评估 %3 次。
- LM stage 2: adaptive shape search; confirm stagnation after 2 complete rounds without significant improvement.
- LM 阶段2:自适应形状搜索;连续两轮完整搜索无显著改善后确认停滞。
+ LM stage 2: joint shape search; after 2 ineffective steps, refresh sensitivity and confirm with one global step.
+ LM 第二阶段:联合调整全部可调形状参数;连续两次改善不足后,刷新灵敏度并用一次全局联合调整确认。
LM starting point error: %1; independent total-stage evaluation budget: %2
LM 起点误差:%1;整体阶段独立评估预算:%2
- Shape search round %1: shape error=%2, improvement=%3, required=%4.
- 形状搜索第 %1 轮:形状误差=%2,改善量=%3,所需改善量=%4。
+ Shape search step %1: shape error=%2, accumulated improvement=%3, required=%4.
+ 形状尝试 %1:形状误差=%2,累计改善=%3,有效改善门槛=%4。
Total-stage budget starts now: %1 iterations, %2 evaluations; pre-adjustment is counted separately.
@@ -1305,16 +1305,16 @@ Reason: %1
无法建立有效的形状灵敏度模型。
- confirm stagnation after 2 complete shape rounds
- 完成两轮形状搜索后确认停滞
+ confirm shape stagnation after 2 ineffective steps
+ 连续两次形状改善不足,刷新灵敏度确认停滞
full sensitivity at total-stage entry
进入整体阶段时建立完整灵敏度
- no significant improvement in a complete round after fresh sensitivity confirmation
- 重建灵敏度确认后,完整一轮搜索仍无显著改善
+ no significant shape improvement after fresh sensitivity and one global step
+ 刷新灵敏度并进行一次全局联合调整后,形状仍无显著改善
no valid early sensitivity model
diff --git a/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp b/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp
index 402e5b38..78ab27e9 100644
--- a/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp
+++ b/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp
@@ -594,95 +594,6 @@ static QVector buildTrustRegionFisher(
return information;
}
-static int nextTrustRegionWindow(
- const QVector& windows,
- const QVector& 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 selectTrustRegionFisherColumns(
- const TrustRegionFisher& local,
- const TrustRegionFisher& global,
- const QVector& columnValid,
- const QVector& 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 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 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& 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 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", ¤t.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), ¤t.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), ¤t.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 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 objectiveWindows = shapeStage
- ? calculateAutoFitTimeWindows(objectiveResidual, m_comparisonTimeMin, m_comparisonTimeMax,
- objectiveCoordinates, autoFitLogTimeWeights(objectiveCoordinates))
- : current.breakdown.timeWindows;
const QVector information = buildTrustRegionFisher(
objectiveJacobian, objectiveResidual, jacobianColumnValid, objectiveCoordinates);
const TrustRegionFisher& global = information[kAutoFitTimeWindowCount];
@@ -2870,18 +2773,35 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
QVector selectedColumns;
QVector 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 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 columns;
- if(fullJointStep) columns = proposed;
- else {
- for(int i = 0; i < proposed.size(); ++i) {
- if(combination & (1 << i)) columns.append(proposed[i]);
- }
- }
- QVector 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 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;