Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(optimizer): add support for weak function composition #629

Merged
merged 4 commits into from
Jan 4, 2024

Conversation

aPere3
Copy link
Contributor

@aPere3 aPere3 commented Dec 8, 2023

This PR adds support for weak composition of functions to the optimizer>compiler>frontend.

@aPere3
Copy link
Contributor Author

aPere3 commented Dec 11, 2023

@slab-ci compiler-cpu-build

@aPere3
Copy link
Contributor Author

aPere3 commented Dec 11, 2023

@slab-ci concrete-python-tests-linux

@aPere3
Copy link
Contributor Author

aPere3 commented Dec 13, 2023

@slab-ci compiler-cpu-build

@aPere3
Copy link
Contributor Author

aPere3 commented Dec 13, 2023

@slab-ci concrete-python-tests-linux

@@ -109,6 +109,10 @@ void mlir::concretelang::python::populateCompilerAPISubmodule(
[](CompilationOptions &options, double global_p_error) {
options.optimizerConfig.global_p_error = global_p_error;
})
.def("set_allow_composition",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe auto_composition instead of composition. How will it be called for composition of a set of function ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should it be a different option for a set of function ? If you prefer the auto_composition label I can change it yes. Do you want me to change it in the whole PR not just the python api ?

// Verify that there is no input symbol in the symbolic variances of the outputs.
assert_no_input_var_in_out_var(&dag, &out_variances, nb_partitions);
// Get the largest output out_variance
let largest_output_variances = dag
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To put in a function (def conservative_final_variance),
And a for loop here would be a lot better. The max-like operation could be in symbolic_variance.

let mut conservative_final_variance = SymbolicVaraince::ZERO;
for (_, _, final_variance)  in extra_final_variances(...) {
    conservative_final_variance = conservative_final_variance.component_wise_max(final_variance);
} 

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it is the max used line 80 below. It is true that here the combinator expression is a bit complex, but this is probably due to the nestedness of out_variances that is a Vec<Vec<SymbolicVariance>>. I'll try to come with something leaner, but in any case we will still have the nestedness somewhere. I am not sure it is gonna be a lot better to have indirection in the middle of it, but I can change it if you are more comfortable with it.

Also, could you elaborate on what extra and conservative stand for here ? I am also not sure about what the word final stands for. It seems to be used to mean output but is there some more meaning to it in the codebase ?

symbolic_variances: &[Vec<SymbolicVariance>],
nb_partitions: usize,
) {
dag.get_output_index()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use the extracted variances that are to be re-injected. here conservative_final_variance. so you don't need to redo everything and duplicate code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see what duplication you refer to, but indeed, doing the assertion after computing the largest output variances for each partitions will save some ops.

nb_partitions: usize,
instr_partition: &InstructionPartition,
input_override: Option<Vec<SymbolicVariance>>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why copying the Option (and Vec) here ? can't you use a ref and only clone the symbolic variance if needed ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What copy do you refer to ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vec is a copy, Option is a copy

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, in rust sense, there is no copy here, it is a move of an existing value. In the calling code, the input_override is just created for this function to call and not used after, so no copy occurs. I mean, in non-optimized code, maybe you have an on-stack copy of a pointer (which the Vec is) but nothing like allocating a new heap storage and copying the elements.

@@ -51,6 +51,7 @@ pub fn analyze(
noise_config: &NoiseBoundConfig,
p_cut: &Option<PrecisionCut>,
default_partition: PartitionIndex,
allow_composition: bool,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be in noise_config, it could be added later to the other solvers, and when more complex composition will be added it will not change the function signature.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm ok, I will do it if you want, but I don't get how this is related to noise bounds and how as an argument it is so different from the p_cut and default_partition parameters.

@aPere3 aPere3 force-pushed the feat/function_composition branch 2 times, most recently from 16431af to 47271cf Compare January 2, 2024 17:03
let mut out_variances = self::out_variances(&dag, nb_partitions, &instrs_partition, &None);
if allow_composition {
// Verify that there is no input symbol in the symbolic variances of the outputs.
assert_no_input_var_in_out_var(&dag, &out_variances, nb_partitions);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be an error here instead of an assert

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe a field could be added,
like support_composition=true/false so the error is not part of the analysis

@BourgerieQuentin BourgerieQuentin force-pushed the feat/function_composition branch 6 times, most recently from 91a7026 to 905f646 Compare January 4, 2024 12:34
@BourgerieQuentin BourgerieQuentin merged commit 1583571 into main Jan 4, 2024
28 of 31 checks passed
@BourgerieQuentin BourgerieQuentin deleted the feat/function_composition branch January 4, 2024 14:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants