You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
expose compile-time options to R users (if possible) #41
Ripser includes several compile-time options that ideally would be made available to R users. I can see two naïve ways that this could definitely be done, neither appropriate:
Turn "on" each of the options in the source code, incurring their cumulative additional cost to all R executions.
Duplicate the source code for each desired combination of settings and (internally) export separate functions to be called according to parameters passed to the user-facing R function.
I wonder if either of the following is instead possible:
3. Allow users to control these options at installation or (far preferable) at loading.
4. Iterate compilation of the source code over each desired combination of settings to produce separate compiled functions to serve as in (2).
I searched through much of the {Rcpp} documentation and SO exchanges and found no insight into this issue.
Faced the same issue, but I skipped the functionality I couldn't implement and found a workaround for the remaining, as follows:
USE_COEFFICIENTS: subjectively assumed this was an optimization (i.e., could speed up processing without affecting outputs); did not prioritize including functionality for this
INDICATE_PROGRESS: useful but did not prioritize including functionality for this; potential workaround is adding a boolean parameter in the C++ code (i.e., in the function that Rcpp calls) and, if true, could add an update output message in one of the for or while loops in the calculation (e.g., one output per dimension)
PRINT_PERSISTENCE_PAIRS: intentionally did not implement this; the persistence pairs were returned to R through Rcpp; if output was desired, could implement this in the R function
USE_ROBINHOOD_HASHMAP: I don't recall this being available, but it has been a few years (i.e., potentially a more recent addition to Ripser)
--format: worked around this; what Ripser in C++ does is take all the formats and converts to a single one (I believe lower triangular distance matrix) before actually processing; what I did was remove the C++ code for these formatting conversions from Ripser, implement them in R (e.g., using the dist function), and then only have the lower triangular distance matrix ever passed from R to C++; it all looked the same to the user but the formatting conversion was happening in R instead of C++, so the --format's functionality was still preserved (i.e., in R), but I did not need to do anything with the C++ compile-time option. In theory, you could switch it to a parameter in the C++ function that Rcpp calls and preserve all the formatting conversion code in C++.
--dim: believe I moved this to be a parameter of the function Rcpp called and changed the appropriate references in the C++ code from the compile-time option to the parameter
--threshold: same as --dim
--modulus: unsure if I did anything for this, but it should work the same as --dim as well
--ratio: I do not recall this being available, but it should work the same as --dim as well
Please pardon any memory lapses on my part, hope above helps!
@rrrlw thank you! Though i should have better articulated my interests—i'm on the train with spotty wifi.
The execution-time options (--* ... at least this is my understanding) i think the students and i figured out how to handle properly—they're not all done yet but we think we know how to proceed.
Of the compile time options listed on the current README, which i struggle to imagine how to make available to the R user, i'm only concerned and hopeful that we can enable arbitrary finite field coefficients. Though i wonder if the form that takes will inform an eventual solution to inserting code to collect cycle and cocycle representatives. I think these three features are essential in the medium term.
By the way, we also plan to convert the value type for persistent pairs from floats to doubles (without an option), partly in the interest of an ongoing project that requires such precision but also because R users are accustomed to it. Do you foresee any problems doing this?
A few approaches came up while thinking about how to handle the compile-time options:
Option A: Separate helper functions for the key compile-time flags (e.g. one for binary coefficients, one for arbitrary), which lines up with Cory’s suggestion.
Option B: Build each desired variant at compile time and call the appropriate compiled function.
Option C: Add runtime toggles, which would give the most flexibility but would require more invasive refactoring.
From the discussion so far, Option A looks like the most practical first step, since it would expose important settings (like the coefficient field) without forcing everything on or duplicating the codebase.
Meanwhile, benchmarking is still ongoing to get a clearer picture of which flags have the biggest effect on performance. Those results should help decide which options are worth prioritizing when moving toward a more flexible interface.
@SeanHersh thank you! Though could you distinguish between Options A and B? (We had an email exchange and i'm not sure whether the options here are the same as there.)
Here's what i imagine making the most sense, based on what we've discussed—the "flag" might be USE_COEFFICIENTS or USE_ROBINHOOD_HASHMAP:
Set up the source code and/or {Rcpp} to build multiple binaries using different flag settings. CRAN provides binaries but users can also install packages from source code, so this might be done at distribution or at installation.
Ensure that this results in multiple compiled functions that can both be accessed through {Rcpp}. Expose these to R, but don't export them to the user.
Add an argument to vietoris_rips() for each flag. Internally, but still on the R side, the value of that argument would determine which compiled function is called, using the same values of the remaining arguments.
Does that sound right? I'm not sure how (1) and (2) would be done, but we can create a branch to experiment.
Activity
corybrunson commentedon Jul 5, 2025
@astamm, do you have any ideas?
corybrunson commentedon Jul 5, 2025
@rrrlw i don't believe you faced this issue originally, but you might well have insights i don't.
rrrlw commentedon Jul 5, 2025
Faced the same issue, but I skipped the functionality I couldn't implement and found a workaround for the remaining, as follows:
USE_COEFFICIENTS: subjectively assumed this was an optimization (i.e., could speed up processing without affecting outputs); did not prioritize including functionality for thisINDICATE_PROGRESS: useful but did not prioritize including functionality for this; potential workaround is adding a boolean parameter in the C++ code (i.e., in the function that Rcpp calls) and, iftrue, could add an update output message in one of thefororwhileloops in the calculation (e.g., one output per dimension)PRINT_PERSISTENCE_PAIRS: intentionally did not implement this; the persistence pairs were returned to R through Rcpp; if output was desired, could implement this in the R functionUSE_ROBINHOOD_HASHMAP: I don't recall this being available, but it has been a few years (i.e., potentially a more recent addition to Ripser)--format: worked around this; what Ripser in C++ does is take all the formats and converts to a single one (I believe lower triangular distance matrix) before actually processing; what I did was remove the C++ code for these formatting conversions from Ripser, implement them in R (e.g., using thedistfunction), and then only have the lower triangular distance matrix ever passed from R to C++; it all looked the same to the user but the formatting conversion was happening in R instead of C++, so the--format's functionality was still preserved (i.e., in R), but I did not need to do anything with the C++ compile-time option. In theory, you could switch it to a parameter in the C++ function that Rcpp calls and preserve all the formatting conversion code in C++.--dim: believe I moved this to be a parameter of the function Rcpp called and changed the appropriate references in the C++ code from the compile-time option to the parameter--threshold: same as--dim--modulus: unsure if I did anything for this, but it should work the same as--dimas well--ratio: I do not recall this being available, but it should work the same as--dimas wellPlease pardon any memory lapses on my part, hope above helps!
corybrunson commentedon Jul 5, 2025
@rrrlw thank you! Though i should have better articulated my interests—i'm on the train with spotty wifi.
The execution-time options (
--*... at least this is my understanding) i think the students and i figured out how to handle properly—they're not all done yet but we think we know how to proceed.Of the compile time options listed on the current README, which i struggle to imagine how to make available to the R user, i'm only concerned and hopeful that we can enable arbitrary finite field coefficients. Though i wonder if the form that takes will inform an eventual solution to inserting code to collect cycle and cocycle representatives. I think these three features are essential in the medium term.
By the way, we also plan to convert the value type for persistent pairs from floats to doubles (without an option), partly in the interest of an ongoing project that requires such precision but also because R users are accustomed to it. Do you foresee any problems doing this?
SeanHersh commentedon Oct 7, 2025
Hello!
This is a really helpful discussion to follow.
A few approaches came up while thinking about how to handle the compile-time options:
Option A: Separate helper functions for the key compile-time flags (e.g. one for binary coefficients, one for arbitrary), which lines up with Cory’s suggestion.
Option B: Build each desired variant at compile time and call the appropriate compiled function.
Option C: Add runtime toggles, which would give the most flexibility but would require more invasive refactoring.
From the discussion so far, Option A looks like the most practical first step, since it would expose important settings (like the coefficient field) without forcing everything on or duplicating the codebase.
Meanwhile, benchmarking is still ongoing to get a clearer picture of which flags have the biggest effect on performance. Those results should help decide which options are worth prioritizing when moving toward a more flexible interface.
corybrunson commentedon Oct 7, 2025
@SeanHersh thank you! Though could you distinguish between Options A and B? (We had an email exchange and i'm not sure whether the options here are the same as there.)
Here's what i imagine making the most sense, based on what we've discussed—the "flag" might be
USE_COEFFICIENTSorUSE_ROBINHOOD_HASHMAP:vietoris_rips()for each flag. Internally, but still on the R side, the value of that argument would determine which compiled function is called, using the same values of the remaining arguments.Does that sound right? I'm not sure how (1) and (2) would be done, but we can create a branch to experiment.
corybrunson commentedon Oct 8, 2025
@astamm might have missed the first ping—not sure you're getting notifications from this thread but would be grateful for your thoughts.