refactor(nmNum): 将 LM 形状阶段改为逐参数单轮调整

feature/AutoFit-Optimize-20260914
lvjunjie 2 weeks ago
parent 50f149970c
commit 452123b06a

Binary file not shown.

@ -1277,16 +1277,16 @@ Reason: %1</source>
<translation>接受灵敏度探针:形状误差=%1</translation>
</message>
<message>
<source>fresh sensitivity at joint shape entry</source>
<translation>进入联合形状调整时重建灵敏度</translation>
<source>fresh sensitivity at single-parameter shape entry</source>
<translation>进入单参数形状调整时重建灵敏度</translation>
</message>
<message>
<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: joint shape search; after 2 ineffective steps, refresh sensitivity and confirm with one global step.</source>
<translation>LM 第二阶段:联合调整全部可调形状参数;连续两次改善不足后,刷新灵敏度并用一次全局联合调整确认。</translation>
<source>LM stage 2: adjust each shape parameter once; double the step after improvement, halve it after rejection, and switch after 3 consecutive rejections.</source>
<translation>LM 第二阶段:逐个调整形状参数,每个参数只调一轮;改善后步长翻倍,拒绝后减半,连续拒绝三次后换下一个参数。</translation>
</message>
<message>
<source>LM starting point error: %1; independent total-stage evaluation budget: %2</source>
@ -1313,8 +1313,8 @@ Reason: %1</source>
<translation>进入整体阶段时建立完整灵敏度</translation>
</message>
<message>
<source>no significant shape improvement after fresh sensitivity and one global step</source>
<translation>刷新灵敏度并进行一次全局联合调整后,形状仍无显著改善</translation>
<source>all shape parameters visited once</source>
<translation>所有形状参数均已完成一轮调整</translation>
</message>
<message>
<source>no valid early sensitivity model</source>

@ -671,6 +671,30 @@ static bool buildTrustRegionFisherStep(
return projectAndPredict();
}
// 为每个可调参数独立求解 LM 步,按边界投影后的预测下降量选择一个参数。
static bool buildBestSingleParameterStep(const TrustRegionFisher& information,
const QVector<int>& available, const QVector<double>& coordinates,
double damping, double trustRadius, double minimumStep,
QVector<int>* selected, QVector<double>* step, double* predictedReduction)
{
selected->clear();
step->fill(0.0, coordinates.size());
*predictedReduction = 0.0;
for(int i = 0; i < available.size(); ++i) {
QVector<int> singleColumn(1, available[i]);
QVector<double> trialStep;
double trialPrediction = 0.0;
if(buildTrustRegionFisherStep(information, singleColumn, coordinates,
damping, trustRadius, minimumStep, &trialStep, &trialPrediction) &&
trialPrediction > *predictedReduction) {
*selected = singleColumn;
*step = trialStep;
*predictedReduction = trialPrediction;
}
}
return !selected->isEmpty();
}
// 前期每次只调一个参数:间距锁定符号,形状 LM 提供幅度和后续验收依据。
static bool buildEarlyGapGuidedStep(const TrustRegionFisher& shapeInformation,
const QVector<int>& selected, const QVector<double>& coordinates, double direction,
@ -691,7 +715,7 @@ static bool buildEarlyGapGuidedStep(const TrustRegionFisher& shapeInformation,
}
// 放大当前方向,仍受传入的最大半径和参数边界限制。
// 普通形状步要求预测下降;前期初始探路可跨过预测上坡区,最终仍按真实形状验收。
// 前期初始探路可跨过预测上坡区,最终仍按真实形状验收。
static bool buildExpandedTrustRegionStep(const TrustRegionFisher& information,
const QVector<double>& coordinates, const QVector<double>& originalStep,
double maximumRadius, QVector<double>* expandedStep, double* prediction,
@ -1123,7 +1147,7 @@ void nmCalculationAutoFitLM::writeTraceMetaFile()
QTextStream out(&metaFile);
out << "{\n";
out << " \"schema_version\": 36,\n";
out << " \"schema_version\": 39,\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";
@ -1138,11 +1162,12 @@ void nmCalculationAutoFitLM::writeTraceMetaFile()
out << " \"early_wellbore_total_constraint\": false,\n";
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 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 << " \"shape_sensitivity_refresh\": \"non_wellbore_columns_once_at_sweep_entry; secant updates during sweep; full Jacobian rebuilt at total-stage entry\",\n";
out << " \"shape_expansion_policy\": \"lock parameter and direction; after each strict shape decrease double next coordinate step from accepted point; otherwise retain point and halve step\",\n";
out << " \"shape_radius_policy\": \"initial LM step capped at 0.24; subsequent coordinate steps capped at 0.60; no prediction-ratio gate\",\n";
out << " \"shape_global_parameter_selection\": \"largest predicted reduction among unvisited non-wellbore parameters; finish current parameter before selecting next; each parameter visited once\",\n";
out << " \"stage2_budget\": \"one parameter sweep; each parameter stops after 3 consecutive non-improving trials, a bound, or minimum step; existing solver failure limit retained\",\n";
out << " \"shape_step_improvement_threshold\": \"any strict shape loss decrease; no cumulative improvement threshold\",\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";
@ -1924,6 +1949,9 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
const double minimumCoordinateStep = 1.0e-5;
const double minimumTrustRadius = 2.0e-3;
const double maximumTrustRadius = 0.30;
// 第二阶段整体形状允许更大步幅;第三阶段继续使用原来的半径和预测验收规则。
const double initialShapeTrustRadius = 0.24;
const double maximumShapeTrustRadius = 0.60;
// 误差下降至少达到绝对 1e-5 且相对当前有效基准 0.2% 才算有效改善。
// 更小的下降仍保留为最佳解,但不能反复清除停滞状态、延长拟合时间。
const double effectiveRelativeImprovement = 2.0e-3;
@ -2120,14 +2148,16 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
if(m_shouldStop) return LM_USER_STOPPED;
// 第二阶段不按迭代比例截断;连续两次改善不足后,刷新灵敏度并仅做一次全局联合确认。
// 第二阶段先测灵敏度,再逐个调完非井筒参数;每个参数只访问一次。
// 普通形状调整冻结井储、表皮,只按形状验收;总误差达标只在第三阶段判断。
bool shapeStage = true;
bool jointShapeStarted = false;
double shapeImprovementBaseline = current.breakdown.shapeLoss;
bool singleShapeStarted = false;
int shapeStepCount = 0;
int ineffectiveShapeSteps = 0;
bool shapeConfirmationRequested = false;
QVector<bool> shapeParameterFinished(dimensions, false);
int activeShapeColumn = -1;
double shapeCoordinateStep = 0.0;
int consecutiveShapeRejections = 0;
const int maximumShapeRejections = 3;
const int storageColumn = m_enabledParamIndices.indexOf(2);
const int skinColumn = m_enabledParamIndices.indexOf(1);
bool hasRemainingShapeParameters = false;
@ -2193,7 +2223,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
restoreEvaluationState(current);
};
emit logMessageGenerated(shapeStage
? tr("LM stage 2: joint shape search; after 2 ineffective steps, refresh sensitivity and confirm with one global step.")
? tr("LM stage 2: adjust each shape parameter once; double the step after improvement, halve it after rejection, and switch after 3 consecutive rejections.")
: tr("LM stage 3: original LM fitting; accept by total error only."));
if(earlyShapeStage) {
emit logMessageGenerated(earlyShapeParameter == 2
@ -2267,7 +2297,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
consecutiveSolverFailures = 0;
stagnationConfirmationRequested = false;
globalFallbackAttempted = false;
trustRadius = 0.12;
trustRadius = shapeStage && !earlyShapeStage ? initialShapeTrustRadius : 0.12;
damping = 0.01;
};
auto enterTotalStage = [&](const QString& reason) {
@ -2362,38 +2392,37 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
true, 0, "early_wellbore_to_shape", &current.breakdown);
};
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;
++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) {
shapeImprovementBaseline = current.breakdown.shapeLoss;
ineffectiveShapeSteps = 0;
shapeConfirmationRequested = false;
return;
}
++ineffectiveShapeSteps;
if(shapeConfirmationRequested) {
finishShapeStage(tr("no significant shape improvement after fresh sensitivity and one global step"));
return;
auto finishShapeParameter = [&](const QString& reason) {
// 已完成的参数不再参与后续选优,保证所有可调参数只扫一遍。
if(activeShapeColumn >= 0) {
shapeParameterFinished[activeShapeColumn] = true;
writeTraceRow(m_currentIteration, activeShapeColumn, "shape_parameter_end",
current.parameters, current.fitness, true, 0, reason, &current.breakdown);
}
if(ineffectiveShapeSteps >= 2) {
jacobian.clear();
reuseSensitivityForNextStage();
rebuildRequested = true;
rebuildReason = QT_TR_NOOP("confirm shape stagnation after 2 ineffective steps");
shapeConfirmationRequested = true;
activeShapeColumn = -1;
shapeCoordinateStep = 0.0;
consecutiveShapeRejections = 0;
for(int column = 0; column < dimensions; ++column) {
if(parameterAllowedInStage(column) && !shapeParameterFinished[column]) return;
}
finishShapeStage(tr("all shape parameters visited once"));
};
auto completeShapeSearchStep = [&](bool accepted) {
if(!shapeStage || earlyShapeStage || m_shouldStop) return;
// 只按本次真实下降控制实际步长;不再使用累计 10% 门槛提前结束整轮。
++shapeStepCount;
consecutiveShapeRejections = accepted ? 0 : consecutiveShapeRejections + 1;
shapeCoordinateStep = qBound(-maximumShapeTrustRadius,
shapeCoordinateStep * (accepted ? 2.0 : 0.5), maximumShapeTrustRadius);
writeTraceRow(m_currentIteration, activeShapeColumn, "shape_step_end", current.parameters,
current.fitness, true, 0,
QString("%1_step_%2_rejections_%3_next_delta_%4")
.arg(accepted ? "improved" : "rejected").arg(shapeStepCount)
.arg(consecutiveShapeRejections).arg(shapeCoordinateStep, 0, 'g', 12), &current.breakdown);
if(consecutiveShapeRejections >= maximumShapeRejections)
finishShapeParameter("3_consecutive_non_improving_trials");
else if(qAbs(shapeCoordinateStep) < minimumCoordinateStep)
finishShapeParameter("minimum_coordinate_step");
};
auto registerEffectiveImprovement = [&](double fitness) -> bool {
@ -2415,11 +2444,11 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
return true;
};
// 普通形状按连续尝试判断停滞,并用新灵敏度下的全局联合步确认;
// 普通形状的失败试算缩步并累计当前参数的拒绝次数;
// 前期井储、表皮与整体 LM 沿用各自的无效次数处理。
auto recordIneffectiveStep = [&]() -> bool {
if(shapeStage && !earlyShapeStage) {
completeShapeSearchStep();
completeShapeSearchStep(false);
return false;
}
++consecutiveIneffectiveSteps;
@ -2587,9 +2616,11 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
jacobianColumnValid[column] = true;
columnBuilt = true;
// 后半段形状探针仅用于灵敏度,正式调整必须经过单参数 LM 预测选优。
// 前期同时测井储和表皮,但缓存探针不能绕过当前子阶段的选参限制。
// 前期首次正式调整必须从小步开始,测形状灵敏度的大探针不能提前成为工作点。
if((!earlyShapeStage || earlyShapeHasImproved) &&
if((!shapeStage || earlyShapeStage) &&
(!earlyShapeStage || earlyShapeHasImproved) &&
parameterAllowedInStage(column) && acceptable(probe, base) &&
(!bestProbe.valid || stageError(probe) < stageError(bestProbe))) {
bestProbe = probe;
@ -2609,14 +2640,14 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
if(parameterAllowedInStage(i)) hasActiveSensitivity = true;
}
}
// 冻结列成功不能掩盖所有可调形状列的求解失败;有效零梯度仍由停滞逻辑处理。
// 冻结列成功不能掩盖所有可调形状列的求解失败;有效零梯度交给逐参数选步处理。
if(validColumnCount == 0 || (shapeStage && !earlyShapeStage && !hasActiveSensitivity) || m_shouldStop) {
restoreEvaluationState(base);
return false;
}
// 灵敏度试算本身若找到更优真实解也应保留。所有列先基于同一个 base
// 建完,再用该已知割线把 Jacobian 平移到新工作点,避免边算边移动基点。
// 前期井储/表皮和整体阶段仍可接受更优缓存探针;后半段形状只由 LM 选步。
// 所有列先基于同一个 base 建完,再用已知割线平移 Jacobian,避免边算边移动基点。
if(bestProbe.valid && bestProbeColumn >= 0) {
QVector<double> acceptedStep(dimensions, 0.0);
acceptedStep[bestProbeColumn] = bestProbeDelta;
@ -2676,14 +2707,13 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
if(wellboreRecheck && current.breakdown.earlyParallelLoss <=
earlyWellboreBaseline + qMax(1.0e-4, 0.10 * earlyWellboreBaseline))
enterTotalStage(tr("early shape error restored within tolerance"));
if(shapeStage && !earlyShapeStage && !jointShapeStarted) {
jointShapeStarted = true;
shapeImprovementBaseline = current.breakdown.shapeLoss;
if(shapeStage && !earlyShapeStage && !singleShapeStarted) {
singleShapeStarted = true;
// 初调已改变井储/表皮,普通形状必须在新的工作点重测其余可调参数的响应。
jacobian.clear();
reuseSensitivityForNextStage();
rebuildRequested = true;
rebuildReason = QT_TR_NOOP("fresh sensitivity at joint shape entry");
rebuildReason = QT_TR_NOOP("fresh sensitivity at single-parameter shape entry");
}
if(m_shouldStop) break;
if(!shapeStage && (totalIterations >= m_maxIterations || m_totalEvaluations >= maximumEvaluations)) break;
@ -2741,13 +2771,13 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
--iteration;
continue;
}
// 单列探针没有改善不代表联合步无效;重建后继续真实候选评价,再确认停滞。
// 差分探针不等于 LM 候选;重建后继续按当前阶段求步并真实评价,再确认停滞。
registerEffectiveImprovement(stageError(current));
}
// 第三阶段独立计数;方向不可行也消耗一次局部尝试,不能无限缩步循环。
if(!shapeStage) ++totalIterations;
// 每次从最新 J 和当前阶段残差重算 Fisher,联合步使用全局信息。
// 每次从最新 J 和当前阶段残差重算全局信息,供单参数或联合 LM 求步。
const QVector<double> objectiveResidual = earlyShapeStage
? current.breakdown.earlyParallelResiduals
: (shapeStage ? current.breakdown.shapeResiduals : current.breakdown.residualVector);
@ -2775,8 +2805,8 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
double predictedReduction = 0.0;
const int selectedWindow = earlyShapeStage ? 0 : -1;
// 前期只开放当前井储或表皮;普通形状和整体 LM 都联合求解全部有效自由列。
// 保留弱敏感、相关及边界列,让参数相互配合;窗口只保留作误差诊断。
// 前期只开放当前井储或表皮;后半段形状从有效自由列中选一个,整体 LM 仍联合求解。
// 保留弱敏感、相关及边界列供预测比较;窗口只保留作误差诊断。
for(int column = 0; column < dimensions; ++column) {
if(stageColumnValid[column] && (earlyShapeStage || global.matrix[column][column] > 0.0))
selectedColumns.append(column);
@ -2800,8 +2830,54 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
damping, earlyStepRadius, minimumCoordinateStep, &coordinateStep, &predictedReduction)) {
selectedColumns.clear();
}
} else if(shapeStage) {
// 首步由灵敏度选出尚未调过的参数;后续锁定方向,直接使用扩缩后的步长。
if(activeShapeColumn < 0) {
QVector<int> availableColumns;
for(int i = 0; i < selectedColumns.size(); ++i) {
if(!shapeParameterFinished[selectedColumns[i]]) availableColumns.append(selectedColumns[i]);
}
buildBestSingleParameterStep(global, availableColumns, current.coordinates,
0.01, initialShapeTrustRadius, minimumCoordinateStep,
&selectedColumns, &coordinateStep, &predictedReduction);
if(!selectedColumns.isEmpty()) {
activeShapeColumn = selectedColumns[0];
shapeCoordinateStep = coordinateStep[activeShapeColumn];
consecutiveShapeRejections = 0;
writeTraceRow(m_currentIteration, activeShapeColumn, "shape_parameter_start",
current.parameters, current.fitness, true, 0,
"largest_predicted_reduction_unvisited", &current.breakdown);
} else {
// 剩余参数均无可行预测下降步时逐项记录,不能重复选择已完成参数。
for(int column = 0; column < dimensions; ++column) {
if(!parameterAllowedInStage(column) || shapeParameterFinished[column]) continue;
activeShapeColumn = column;
finishShapeParameter(jacobianColumnValid[column]
? "no_feasible_descent_step" : "invalid_sensitivity");
if(!shapeStage || earlyShapeStage) break;
}
--iteration;
continue;
}
} else {
selectedColumns.clear();
selectedColumns.append(activeShapeColumn);
coordinateStep.fill(0.0, dimensions);
shapeCoordinateStep = qBound(0.0,
current.coordinates[activeShapeColumn] + shapeCoordinateStep, 1.0)
- current.coordinates[activeShapeColumn];
if(qAbs(shapeCoordinateStep) < minimumCoordinateStep) {
finishShapeParameter("parameter_bound_or_minimum_step");
--iteration;
continue;
}
coordinateStep[activeShapeColumn] = shapeCoordinateStep;
predictedReduction = -global.gradient[activeShapeColumn] * shapeCoordinateStep
- 0.5 * global.matrix[activeShapeColumn][activeShapeColumn]
* shapeCoordinateStep * shapeCoordinateStep;
}
} else {
// 普通调整和停滞确认共用全局联合方向,不再遍历窗口或枚举三参数子集。
// 第三阶段保持全部有效自由参数的联合 LM 调整。
globalFallbackAttempted = true;
if(selectedColumns.isEmpty() || !buildTrustRegionFisherStep(
global, selectedColumns, current.coordinates, damping,
@ -2818,11 +2894,6 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
--iteration;
continue;
}
if(shapeStage) {
completeShapeSearchStep();
--iteration;
continue;
}
if(trustRadius <= minimumTrustRadius * 1.01 &&
modelRebuiltAtMinimumRadius) {
if(promoteSampling(false)) continue;
@ -2933,7 +3004,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
"solver_invalid_" + selectionName,
nullptr);
restoreEvaluationState(current);
if(consecutiveSolverFailures >= 2) {
if(consecutiveSolverFailures >= 2 && (!shapeStage || earlyShapeStage)) {
rebuildRequested = true;
rebuildReason = QT_TR_NOOP("2 consecutive solver failures");
}
@ -2941,8 +3012,6 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
stopReason = LM_CONSECUTIVE_FAILURES;
break;
}
// 确认步求解失败不代表形状已收敛,沿用有限重试后按求解失败退出。
if(shapeStage && !earlyShapeStage && shapeConfirmationRequested) continue;
if(recordIneffectiveStep()) {
if(promoteSampling(false)) continue;
stopReason = LM_LOCAL_OPTIMUM;
@ -2951,37 +3020,6 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
continue;
}
// 普通形状步真实改善后,沿同一联合方向最多扩步一次,不再用预测兑现比例拦截。
// 扩步只按整体形状验收,优于原步才替换,否则保留原候选。
if(shapeStage && !earlyShapeStage && acceptable(candidate, current) && processPauseAndStop()) {
QVector<double> expandedStep;
double expandedPrediction = 0.0;
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);
TrustRegionEvaluation expanded;
expanded.coordinates = current.coordinates;
for(int i = 0; i < dimensions; ++i) expanded.coordinates[i] += expandedStep[i];
expanded.parameters = parametersFromCoordinates(expanded.coordinates);
expanded.valid = evaluateTrustRegionPoint(expanded.parameters, &expanded.fitness,
&expanded.breakdown, &expanded.curve, &expanded.elapsedMs);
const bool useExpanded = acceptable(expanded, current) && expanded.breakdown.shapeLoss < candidate.breakdown.shapeLoss;
writeTraceRow(m_currentIteration, -1, "shape_step_expanded", expanded.parameters,
expanded.fitness, expanded.valid, expanded.elapsedMs, useExpanded ? "selected_expanded" : "retain_ordinary",
expanded.valid ? &expanded.breakdown : nullptr);
if(useExpanded) {
candidate = expanded;
coordinateStep = expandedStep;
predictedReduction = expandedPrediction;
stepNorm = qSqrt(trustRegionSquaredNorm(coordinateStep));
selectionName += "_expanded";
}
// 两次真实调用已分别记录,下方候选行只记录最终决策,避免重复统计耗时。
candidate.elapsedMs = -1;
restoreEvaluationState(current);
}
}
if(m_shouldStop) {
restoreEvaluationState(current);
stopReason = LM_USER_STOPPED;
@ -3011,7 +3049,7 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
const bool poorPrediction = predictedReduction > predictionFloor &&
(!isFiniteNumber(reductionRatio) || reductionRatio < 0.25);
consecutivePoorPredictions = poorPrediction ? consecutivePoorPredictions + 1 : 0;
if(consecutivePoorPredictions >= 2) {
if(consecutivePoorPredictions >= 2 && (!shapeStage || earlyShapeStage)) {
rebuildRequested = true;
rebuildReason = QT_TR_NOOP("2 consecutive steps with actual improvement below 25% of prediction");
}
@ -3032,21 +3070,24 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
++acceptedSinceRebuild;
consecutiveRejectedSteps = 0;
if(reductionRatio > 0.75) {
damping = qMax(1.0e-8, damping * 0.5);
if(stepNorm >= trustRadius * 0.8) {
trustRadius = qMin(
maximumTrustRadius, trustRadius * 1.6);
// 井筒调整及第三阶段保留原 LM 控制;逐参数粗调在步末直接扩缩实际步长。
if(!shapeStage || earlyShapeStage) {
if(reductionRatio > 0.75) {
damping = qMax(1.0e-8, damping * 0.5);
if(stepNorm >= trustRadius * 0.8) {
trustRadius = qMin(
maximumTrustRadius, trustRadius * 1.6);
}
} else if(reductionRatio > 0.25) {
damping = qMax(1.0e-8, damping * 0.8);
} else {
damping = qMin(1.0e8, damping * 2.0);
trustRadius = qMax(
minimumTrustRadius, trustRadius * 0.75);
}
} else if(reductionRatio > 0.25) {
damping = qMax(1.0e-8, damping * 0.8);
} else {
damping = qMin(1.0e8, damping * 2.0);
trustRadius = qMax(
minimumTrustRadius, trustRadius * 0.75);
}
if(acceptedSinceRebuild >= 10 && !rebuildRequested) {
if(acceptedSinceRebuild >= 10 && !rebuildRequested && (!shapeStage || earlyShapeStage)) {
rebuildRequested = true;
rebuildReason = QT_TR_NOOP("10 accepted steps since last rebuild");
}
@ -3102,6 +3143,10 @@ StopReasonLM nmCalculationAutoFitLM::runTrustRegionFitting()
finishEarlyShapeStage(tr("initial same-direction expansion reached the parameter bound without early shape improvement"));
continue;
}
if(shapeStage && !earlyShapeStage) {
completeShapeSearchStep(accepted);
continue;
}
const bool effectiveImprovement = registerEffectiveImprovement(stageError(current));
if(!effectiveImprovement && recordIneffectiveStep()) stopReason = LM_LOCAL_OPTIMUM;

Loading…
Cancel
Save