| 894 | }; |
| 895 | |
| 896 | nb::object call_impl(const nb::args& args, const nb::kwargs& kwargs) { |
| 897 | if (!vjp_fun_.has_value() && !jvp_fun_.has_value() && |
| 898 | !vmap_fun_.has_value()) { |
| 899 | return fun_(*args, **kwargs); |
| 900 | } |
| 901 | |
| 902 | // Extract the inputs and their structure in capturable vars |
| 903 | std::vector<mx::array> input_arrays; |
| 904 | nb::object input_structure; |
| 905 | auto full_args = nb::make_tuple(args, kwargs); |
| 906 | std::tie(input_arrays, input_structure) = |
| 907 | tree_flatten_with_structure(full_args, false); |
| 908 | |
| 909 | // The output structure will be stored here to be used in the custom vjp |
| 910 | // function |
| 911 | auto output_structure = std::make_shared<nb::object>(); |
| 912 | |
| 913 | // Make a function that calls fun_ in the forward pass and vjp_ in the |
| 914 | // backward pass. Then call it immediately and return the results. |
| 915 | auto f = mx::custom_function( |
| 916 | InnerFunction(fun_, input_structure, output_structure), |
| 917 | make_vjp_function(input_structure, output_structure), |
| 918 | make_jvp_function(input_structure), |
| 919 | make_vmap_function(input_structure)); |
| 920 | |
| 921 | auto outputs = f(input_arrays); |
| 922 | return tree_unflatten_from_structure(*output_structure, outputs); |
| 923 | } |
| 924 | |
| 925 | PyCustomFunction& set_vjp(nb::callable vjp_fun) { |
| 926 | vjp_fun_ = vjp_fun; |
nothing calls this directly
no test coverage detected