Skip to content

Commit 7ff1434

Browse files
committed
feat: Improve numerical stability and performance
This commit introduces several improvements to the codebase: - **Numerical Stability:** - Adds a mechanism to enforce constraint violations during likelihood function computations, controlled by the `ENFORCE_CONSTRAINT_VIOLATIONS` environment variable. - Improves warnings for numerical issues in `GradientLocateTheBump`. - **Performance:** - Optimizes matrix multiplication functions using SIMD instructions for better performance. - **Build:** - Adds the `-Wno-maybe-uninitialized` compiler flag for GNU compilers. - Ensures `HYPHYMPI` is always built and installed if MPI is found. - **Version:** - Bumps the version to 2.5.82.
1 parent 7cc0408 commit 7ff1434

File tree

11 files changed

+1373
-355
lines changed

11 files changed

+1373
-355
lines changed

CMakeLists.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ endif()
113113

114114
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
115115
list(APPEND COMMON_COMPILE_FLAGS "-Wno-overloaded-virtual")
116+
list(APPEND COMMON_COMPILE_FLAGS "-Wno-maybe-uninitialized")
116117
endif()
117118

118119
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
@@ -255,7 +256,7 @@ install(TARGETS hyphy RUNTIME DESTINATION bin)
255256
# Other Executables
256257
#------------------------------------------------------------------------------
257258
if(MPI_FOUND)
258-
add_executable(HYPHYMPI EXCLUDE_FROM_ALL ${SRC_COMMON} ${SRC_UNIXMAIN})
259+
add_executable(HYPHYMPI ${SRC_COMMON} ${SRC_UNIXMAIN})
259260
target_compile_options(HYPHYMPI PRIVATE ${COMMON_COMPILE_FLAGS} ${HYPHY_SIMD_FLAGS})
260261
target_compile_definitions(HYPHYMPI PRIVATE
261262
__AFYP_REWRITE_BGM__
@@ -285,7 +286,7 @@ if(MPI_FOUND)
285286
target_include_directories(HYPHYMPI PRIVATE ${ZLIB_INCLUDE_DIRS})
286287
target_compile_definitions(HYPHYMPI PRIVATE __ZLIB__)
287288
endif()
288-
install(TARGETS HYPHYMPI RUNTIME DESTINATION bin OPTIONAL)
289+
install(TARGETS HYPHYMPI RUNTIME DESTINATION bin)
289290
endif()
290291

291292
add_executable(HYPHYDEBUG EXCLUDE_FROM_ALL ${SRC_COMMON} ${SRC_UNIXMAIN})

compile_commands.json

Lines changed: 1172 additions & 0 deletions
Large diffs are not rendered by default.

res/TemplateBatchFiles/SelectionAnalyses/RELAX.bf

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
RequireVersion ("2.5.21");
1+
RequireVersion ("2.5.82");
22

33
LoadFunctionLibrary("libv3/all-terms.bf"); // must be loaded before CF3x4
44

@@ -31,6 +31,7 @@ LoadFunctionLibrary("libv3/models/rate_variation.bf");
3131
utility.SetEnvVariable ("NORMALIZE_SEQUENCE_NAMES", TRUE);
3232
utility.SetEnvVariable ("ASSUME_REVERSIBLE_MODELS", TRUE);
3333
utility.SetEnvVariable ("USE_MEMORY_SAVING_DATA_STRUCTURES", 1e8);
34+
utility.SetEnvVariable ("ENFORCE_CONSTRAINT_VIOLATIONS", TRUE);
3435

3536
//relax.OPTIMIZATION_LOGS = 1;
3637

@@ -482,7 +483,6 @@ if (relax.model_set == "All") { // run all the models
482483
relax.distribution = models.codon.BS_REL.ExtractMixtureDistribution(relax.ge.bsrel_model);
483484
relax.weight_multipliers = parameters.helper.stick_breaking (utility.SwapKeysAndValues(utility.MatrixToDict(relax.distribution["weights"])),None);
484485
relax.constrain_parameters = parameters.ConstrainMeanOfSet(relax.distribution["rates"],relax.weight_multipliers,1,"relax");
485-
486486

487487

488488
relax.i = 0;
@@ -1071,6 +1071,9 @@ function relax.FitMainTestPair (prompt) {
10711071
relax.save_fit_path = io.PromptUserForFilePath ("Save RELAX model fit to this file ['/dev/null' to skip]");
10721072
}
10731073

1074+
1075+
relax.stashLF = estimators.TakeLFStateSnapshot (relax.alternative_model.fit[terms.likelihood_function]);
1076+
10741077
io.SpoolLFToPath(relax.alternative_model.fit[terms.likelihood_function], relax.save_fit_path);
10751078

10761079
if (relax.numbers_of_tested_groups == 2 && relax.analysis_run_mode != relax.kGroupMode) {
@@ -1148,7 +1151,7 @@ function relax.FitMainTestPair (prompt) {
11481151
{estimators.GetGlobalMLE (relax.alternative_model.fit.take2,terms.relax.k), relax.alternative_model.fit.take2 [terms.fit.log_likelihood]}
11491152
});
11501153

1151-
if (relax.alternative_model.fit.take2 [terms.fit.log_likelihood] > relax.alternative_model.fit.take2[terms.fit.log_likelihood]) {
1154+
if (relax.alternative_model.fit.take2 [terms.fit.log_likelihood] > relax.alternative_model.fit [terms.fit.log_likelihood]) {
11521155
relax.stash_fitted_K = relax.fitted.K;
11531156

11541157
io.ReportProgressMessageMD("RELAX", "alt-2", "\n### Potential for highly unreliable K inference due to multiple local maxima in the likelihood function, treat results with caution ");
@@ -1171,6 +1174,8 @@ function relax.FitMainTestPair (prompt) {
11711174

11721175
relax.alternative_model.fit = relax.alternative_model.fit.take2;
11731176
io.SpoolLFToPath(relax.alternative_model.fit.take2[terms.likelihood_function], relax.save_fit_path);
1177+
relax.stashLF = estimators.TakeLFStateSnapshot (relax.alternative_model.fit[terms.likelihood_function]);
1178+
11741179
} else {
11751180
estimators.RestoreLFStateFromSnapshot(relax.alternative_model.fit[terms.likelihood_function], relax.take1_snapshot);
11761181
}

src/core/batchlanruntime.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3120,7 +3120,7 @@ bool _ElementaryCommand::HandleSetParameter(_ExecutionList &current_program) {
31203120
_SimpleList _modelCache;
31213121
_AVLListXL modelCache(&_modelCache);
31223122

3123-
for (long i = 0; i < node_names.countitems(); i++) {
3123+
for (unsigned long i = 0; i < node_names.countitems(); i++) {
31243124
const _String object_name = *(_String *)node_names.GetItem(i);
31253125
_CalcNode *tree_node = nil;
31263126

src/core/global_things.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ _String const kEmptyString, kPromptForFilePlaceholder("PROMPT_FOR_FILE"),
115115
"\"ENV=TOLERATE_NUMERICAL_ERRORS=1;\" as the command line "
116116
"argument. This often resolves the issue, which is "
117117
"indicative of numerical instability."),
118-
kHyPhyVersion = _String("2.5.81"),
118+
kHyPhyVersion = _String("2.5.82"),
119119

120120
kNoneToken = "None", kNullToken = "null",
121121
kNoKWMatch = "__input_value_not_given__",

src/core/hbl_env.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,9 +351,11 @@ _String const accept_branch_lengths("ACCEPT_BRANCH_LENGTHS"),
351351
use_traversal_heuristic("USE_TRAVERSAL_HEURISTIC"),
352352
// TODO (20170413): don't remember what this does; , see @
353353
// _DataSetFilter::MatchStartNEnd #DEPRECATE
354-
verbosity_level_string("VERBOSITY_LEVEL")
354+
verbosity_level_string("VERBOSITY_LEVEL"),
355355
// controls verbosity level during optimization and other long-running
356-
// operations
356+
// operations,
357+
enforce_constraint_violations("ENFORCE_CONSTRAINT_VIOLATIONS")
358+
357359
;
358360

359361
/** default values get set up in hy_global:: */

src/core/include/hbl_env.h

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,43 +49,53 @@ namespace hy_env {
4949
* @brief Check if the value of the environment variable is "true".
5050
*
5151
* @param name The name of the environment variable (in HBL).
52-
* @param default_true The default value to return if the variable is not defined.
53-
* @return true if the variable is defined and true-like (not zero), false otherwise.
52+
* @param default_true The default value to return if the variable is not
53+
* defined.
54+
* @return true if the variable is defined and true-like (not zero), false
55+
* otherwise.
5456
*/
5557
bool EnvVariableTrue(_String const &name, bool default_true = false);
5658

5759
/**
5860
* @brief Look up the default numeric value for a given environment variable.
5961
*
6062
* @param name The name of the environment variable (in HBL).
61-
* @return The default value if available and of the correct type, otherwise HY_INVALID_RETURN_VALUE.
63+
* @return The default value if available and of the correct type, otherwise
64+
* HY_INVALID_RETURN_VALUE.
6265
*/
6366
hyFloat EnvVariableGetDefaultNumber(_String const &name);
6467

6568
/**
66-
* @brief Look up the default value for a given environment variable, checking that it is of a particular type.
69+
* @brief Look up the default value for a given environment variable, checking
70+
* that it is of a particular type.
6771
*
6872
* @param name The name of the environment variable (in HBL).
6973
* @param type The expected type of the variable.
70-
* @return The default value if available and of the correct type, otherwise nil.
74+
* @return The default value if available and of the correct type, otherwise
75+
* nil.
7176
*/
7277
HBLObjectRef EnvVariableGetDefault(_String const &name, unsigned long type);
7378

7479
/**
75-
* @brief Look up the value for a given environment variable, checking that it is of a particular type.
80+
* @brief Look up the value for a given environment variable, checking that it
81+
* is of a particular type.
7682
*
7783
* @param name The name of the environment variable (in HBL).
7884
* @param type The expected type of the variable.
79-
* @return The current value if set and of the correct type, otherwise the default value if available and of the correct type, otherwise nil.
85+
* @return The current value if set and of the correct type, otherwise the
86+
* default value if available and of the correct type, otherwise nil.
8087
*/
8188
HBLObjectRef EnvVariableGet(_String const &name, unsigned long type);
8289

8390
/**
8491
* @brief Look up the numeric value for a given environment variable.
8592
*
8693
* @param name The name of the environment variable (in HBL).
87-
* @param default_value The default value to return if the variable is not defined.
88-
* @return The current value if set and of the correct type, otherwise the default value if available and of the correct type, otherwise HY_INVALID_RETURN_VALUE.
94+
* @param default_value The default value to return if the variable is not
95+
* defined.
96+
* @return The current value if set and of the correct type, otherwise the
97+
* default value if available and of the correct type, otherwise
98+
* HY_INVALID_RETURN_VALUE.
8999
*/
90100
hyFloat EnvVariableGetNumber(_String const &name,
91101
hyFloat default_value = HY_INVALID_RETURN_VALUE);
@@ -100,7 +110,8 @@ hyFloat EnvVariableGetNumber(_String const &name,
100110
void EnvVariableSet(_String const &name, HBLObjectRef value, bool copy);
101111

102112
/**
103-
* @brief Set the value for an environment variable (in a given namespace if provided).
113+
* @brief Set the value for an environment variable (in a given namespace if
114+
* provided).
104115
*
105116
* @param name The name of the environment variable (in HBL).
106117
* @param value The value to set the variable to.
@@ -139,8 +150,9 @@ extern const _String accept_rooted_trees, accept_branch_lengths,
139150
soft_fileio_exceptions, last_fileio_exception, last_raw_file_prompt,
140151
include_model_spec, lf_convergence_criterion, try_numeric_sequence_match,
141152
short_mpi_return, kSCFGCorpus, verbosity_level_string,
142-
tolerate_numerical_errors, tolerate_constraint_violation, number_threads,
143-
gzip_compression_level, tree_parser_namespace, global_kwargs;
153+
enforce_constraint_violations, tolerate_numerical_errors,
154+
tolerate_constraint_violation, number_threads, gzip_compression_level,
155+
tree_parser_namespace, global_kwargs;
144156

145157
;
146158

src/core/likefunc.cpp

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,6 +2030,9 @@ bool _LikelihoodFunction::SendOffToMPI(long index, void *request) {
20302030
//_______________________________________________________________________________________
20312031

20322032
bool _LikelihoodFunction::PreCompute(void) {
2033+
2034+
bool validated_contstraints = true;
2035+
20332036
if (compiled_constraints) {
20342037
// populate all the independent variables
20352038
for (unsigned long i = 0; i < compiled_constraints->varIndex.lLength; i++) {
@@ -2082,6 +2085,9 @@ bool _LikelihoodFunction::PreCompute(void) {
20822085
if (!cornholio->IsValueInBounds(tp)) {
20832086
ReportWarning(_String("Failing bound checks on ") &
20842087
*cornholio->GetName() & " = " & _String(tp, "%25.16g"));
2088+
ReportWarning(_String(
2089+
cornholio->GetFormulaString(kFormulaStringConversionReportRanges)));
2090+
validated_contstraints = false;
20852091
// break;
20862092
}
20872093
}
@@ -2099,6 +2105,12 @@ bool _LikelihoodFunction::PreCompute(void) {
20992105
}
21002106
*/
21012107

2108+
if (!CheckEqual(hy_env::EnvVariableGetNumber(
2109+
hy_env::enforce_constraint_violations, 0.),
2110+
0.0)) {
2111+
return validated_contstraints;
2112+
}
2113+
21022114
return (i == arrayToCheck->lLength);
21032115
}
21042116
}
@@ -7903,14 +7915,20 @@ hyFloat _LikelihoodFunction::GradientLocateTheBump(hyFloat gPrecision,
79037915
if (maxSoFar < initialValue &&
79047916
!CheckEqual(maxSoFar, initialValue,
79057917
kMachineEpsilon * errorTolerance)) {
7906-
_TerminateAndDump(_String(" _LikelihoodFunction::GradientLocateTheBump:"
7907-
" in the Brent loop iteration ") &
7908-
long(outcome) & ". " & _String(maxSoFar, "%18.16g") &
7909-
" / " & _String(initialValue, "%18.16g") &
7910-
".\n Optimization direction: \n" &
7911-
_String((_String *)gradient.toStr()));
7912-
7913-
return 0.;
7918+
_String errorStr =
7919+
_String(" _LikelihoodFunction::GradientLocateTheBump:"
7920+
" in the Brent loop iteration ") &
7921+
long(outcome) & ". " & _String(maxSoFar, "%18.16g") & " / " &
7922+
_String(initialValue, "%18.16g") &
7923+
".\n Optimization direction: \n" &
7924+
_String((_String *)gradient.toStr());
7925+
7926+
if (hy_env::EnvVariableTrue(hy_env::tolerate_numerical_errors)) {
7927+
ReportWarningConsole(errorStr);
7928+
} else {
7929+
_TerminateAndDump(errorStr);
7930+
return 0.;
7931+
}
79147932
}
79157933
}
79167934
}

src/core/mathobj.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ HBLObjectRef _MathObject::ExecuteSingleOp(long opCode, _List *arguments,
396396
default:
397397
WarnNotDefined(this, opCode, context);
398398
}
399-
} catch (const _String err) {
399+
} catch (const _String &err) {
400400
if (context) {
401401
context->ReportError(err);
402402
} else {

src/core/matrix.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5670,7 +5670,7 @@ void _Matrix::CopyMatrixToDenseAndMultiply(_Matrix const &source, hyFloat C,
56705670
} else {
56715671
throw(_String("The target argument must be a dense numeric matrix"));
56725672
}
5673-
} catch (_String const err) {
5673+
} catch (_String const &err) {
56745674
HandleApplicationError(_String("Internal error in ") &
56755675
_String(__PRETTY_FUNCTION__).Enquote() & ": " & err);
56765676
}

0 commit comments

Comments
 (0)