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;