Implementing alignment based optimization for single-cell data - #72
Implementing alignment based optimization for single-cell data#72scjlee wants to merge 46 commits into
Conversation
| #' @export | ||
| optim_config <- function( | ||
| method = "positivity", # positivity/coordinate_descent/theta | ||
| method = c("positivity", "coordinate_descent", "theta", "alignment"), # let R handel selection and checking |
| @@ -1,2 +1,3 @@ | |||
| PKG_LIBS = $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) | |||
| PKG_CPPFLAGS = -DARMA_64BIT_WORD=1 | |||
| CXX_STD = CXX17 No newline at end of file | |||
There was a problem hiding this comment.
GitHub action use C++20 but the current R which failed in CMD INSTALL step. Is most like to due to issue with RcppSpdlog.
Currently (2026/08/10) R use C++17 as the default compiler since version 4.4, and C++20 become default after 4.6 ‘where available’. I think it is save to use C++17 as our compiler because its is available (but not necessarily installed) on all known R platforms. according to CRAN.
There was a problem hiding this comment.
ok, let's keep it but can you please create an issue to support other versions. I think once we change logging as we discussed it should work
|
|
||
|
|
||
|
|
||
| //' Main training loop with all gradient steps. This is the main algorithm for now. |
There was a problem hiding this comment.
add documentation please. looks like this one copied
| #include <map> | ||
| #include <fstream> | ||
|
|
||
| class ILogger { |
There was a problem hiding this comment.
shouldn't we have something like errortracker
There was a problem hiding this comment.
Popular framework like pytorch and tensorflow use logger for error tracking. I would like to keep this convention and don't see too much issue still. But I defiantly open to discuss alternative naming.
And I don't see it will be confused with spdlog which is usually called as spdl or spdlog.
There was a problem hiding this comment.
I understand this but if a new guy will debug error he met. He will try to search "logger" first and will be transferred to the class which is not related to logger
There was a problem hiding this comment.
Sorry, I don't understand why logger is closely related to debugging Could you provide some examples?
There was a problem hiding this comment.
I meet error in DEBUG or ERROR log. I open vscode and search "log" or "logger" to find the places where error logging happened, to investigate the error. But will find this class, which does not do this logging. So I will spend some time trying to figure it out.
| } | ||
| }; | ||
|
|
||
| class CsvLogger : public ILogger { |
7ab323c to
21639e3
Compare
…provide freedom of tuning
…add legacy matrix conversion support
…ted header and source files
… iteration loop to start from 1
…lper functions in the optimization loop
…kward compatibility
…gradient descent (PGD)
8589001 to
1b1028f
Compare
| D_h = Dh | ||
| )) | ||
| }, | ||
| legacy_random_invertible = function(proj, kwargs = NULL) { |
There was a problem hiding this comment.
This is the "quasi-old" method I used to test the original alignment optimization which failing with the newest initialization. Since the new PGD-based optimization works with new initialization so far. I can remove it if you like.
e2a10e9 to
1fa16e4
Compare
scjlee
left a comment
There was a problem hiding this comment.
- Implement new alignment optimization algorithm using projected gradient descent. It should fix the convergence problem encountered for the previous inverse-based optimization
- Implement
get_historyandget_history_longfunction for accessing the optimization history. They only work with histories created by the new logger. - Explaining implementation choice to most of the previous comments.
a996fca to
1f55d05
Compare
|
|
||
| #' @description | ||
| #' Get history of optimization. | ||
| get_history = function() { |
There was a problem hiding this comment.
history$history sounds ambiguous. It can be confused with points history.
I think it should be error_log or metrics_log if you like, since it is what it is.
Also I think method should be called differently
| virtual void log_metadata(const std::map<std::string, std::string>& metadata) = 0; | ||
| }; | ||
|
|
||
| class RcppLogger : public ILogger { |
There was a problem hiding this comment.
RcppLogger still looks like you are logging some Rcpp events, since this is only error tracking, I guess name should be transparent. Also I think the name should be directly related to the R naming, to improve code understanding (I mean we should avoid transforming entity RcppLogger into history$history
There was a problem hiding this comment.
I agree. Rename it to ErrorLogger or others will be better.
Meanwhile, I don't understand what do you mean "we should avoid transforming entity RcppLogger into history$history". Are you against to use logger system?
There was a problem hiding this comment.
No, I just mean that it should be transparent everywhere. both RcppLogger and history$history are to vague.
So I vote just for very similar names both in R and C++ for easy navigation.
| #include <map> | ||
| #include <fstream> | ||
|
|
||
| class ILogger { |
There was a problem hiding this comment.
I understand this but if a new guy will debug error he met. He will try to search "logger" first and will be transferred to the class which is not related to logger
| } | ||
|
|
||
| std::vector<Metric> HingeProportionsErrorCalculator::calculate(const OptimizationState& state) const { | ||
| arma::mat H = state.X * state.R; |
There was a problem hiding this comment.
shouldn't we make it H_inf just in case?
| class ILogger { | ||
| public: | ||
| virtual ~ILogger() = default; | ||
| virtual void log_metrics(int iteration, const std::vector<Metric>& metrics) = 0; |
There was a problem hiding this comment.
The name Ilogger does not give us clue of what this interface doing. Because if this is logger then it is expected that you will implement "log" method
There was a problem hiding this comment.
I don't understand. Doesn't this interface require its child classes have both log_metrics and log_metadata implementations?
There was a problem hiding this comment.
This is just naming issue for me. (As most of my comments, sorry!)
ILogger --> assumes we want log() method to be implemented.
for example IMetricsLogger -> means we want log_metrics() to be implemented.
Imagine you will have 10 implemented interfaces. It will be good if the name will be very transparent
scjlee
left a comment
There was a problem hiding this comment.
Can you resolve comments which you think is done? It is hard to track now.
| D_h = Dh | ||
| )) | ||
| }, | ||
| legacy_random_invertible = function(proj, kwargs = NULL) { |
| @@ -1,2 +1,3 @@ | |||
| PKG_LIBS = $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) | |||
| PKG_CPPFLAGS = -DARMA_64BIT_WORD=1 | |||
| CXX_STD = CXX17 No newline at end of file | |||
There was a problem hiding this comment.
ok, let's keep it but can you please create an issue to support other versions. I think once we change logging as we discussed it should work
| virtual void log_metadata(const std::map<std::string, std::string>& metadata) = 0; | ||
| }; | ||
|
|
||
| class RcppLogger : public ILogger { |
There was a problem hiding this comment.
No, I just mean that it should be transparent everywhere. both RcppLogger and history$history are to vague.
So I vote just for very similar names both in R and C++ for easy navigation.
| class ILogger { | ||
| public: | ||
| virtual ~ILogger() = default; | ||
| virtual void log_metrics(int iteration, const std::vector<Metric>& metrics) = 0; |
There was a problem hiding this comment.
This is just naming issue for me. (As most of my comments, sorry!)
ILogger --> assumes we want log() method to be implemented.
for example IMetricsLogger -> means we want log_metrics() to be implemented.
Imagine you will have 10 implemented interfaces. It will be good if the name will be very transparent
| #include <map> | ||
| #include <fstream> | ||
|
|
||
| class ILogger { |
There was a problem hiding this comment.
I meet error in DEBUG or ERROR log. I open vscode and search "log" or "logger" to find the places where error logging happened, to investigate the error. But will find this class, which does not do this logging. So I will spend some time trying to figure it out.
| // Optimization Control Flow & Learning Rate Scheduling | ||
| // ------------------------------------------------------------- | ||
| // TODO(cjlee): maybe we should compare to best_error_value instead? | ||
| double relative_change = (prev_error_value - current_error_value) / (std::abs(prev_error_value) + epsilon); |
There was a problem hiding this comment.
don't we have this implemented in other optimizations using these ?
stop_criteria_window = 800,
convergence_tol = 1e-9,
Implement new optimization algorithm for single-cell data.
src/optimization_dsaUse
match.argfunction check if user input method is valid inoptim_config.R/opimizationImplement new logger system.
src/optimization_loggerThe new error logger records errors as a long format data.frame. This data.frame contains 3 columns: {iteration, metric_name, value}. This design increase the freedom to add/remove tracked values
For backward compatibility, the logger class contains a
to_legacy_matrixmethod for converting data.frame to the old 21 column matrix .Modify
optimize_solutionto support output of the history data.frame.The long format could make plotting interface cleaner:

Currently, only
optimize_alignmentuse this new logger. All other algorithms are kept the same.Implement new error calculator.
src/optimization_error_metrics.IErrorCalculatorclass.CompositeErrorCalculatorobject which providecalculatemethod to compute all the registered error. This design is aim to reduce boilerplate code.DeconvErrorCalculator,HingeProportionsErrorCalculator,HingeBasisErrorCalculator,ScaleNormErrorCalculator.optimize_alignmentuse this new error calculator.. All other algorithms are kept the same.Implement GitHub action for automatic RcppExports and documents generation.
.github/workflowsRcpp::compileAttributesandroxygen2::roxygeniseto make sure all the R-Cpp bindings and documentations are uptodate. If there is any change, GitHub action will automatically create a new commit with modified files.devtools::document. Once syncing is passed, package should be ready to install viaremotes::install_github.