| 67 | } |
| 68 | |
| 69 | auto py_value_and_grad( |
| 70 | const nb::callable& fun, |
| 71 | std::vector<int> argnums, |
| 72 | std::unordered_set<std::string> argnames, |
| 73 | const std::string& error_msg_tag, |
| 74 | bool scalar_func_only) { |
| 75 | // Sanitize argnums |
| 76 | if (argnums.size() == 0 && argnames.size() == 0) { |
| 77 | throw std::invalid_argument( |
| 78 | error_msg_tag + " Gradient wrt no argument requested"); |
| 79 | } |
| 80 | for (auto arg : argnums) { |
| 81 | std::sort(argnums.begin(), argnums.end()); |
| 82 | if (argnums[0] < 0) { |
| 83 | std::ostringstream msg; |
| 84 | msg << error_msg_tag |
| 85 | << " Can't compute the gradient of negative argument index " |
| 86 | << argnums[0]; |
| 87 | throw std::invalid_argument(msg.str()); |
| 88 | } |
| 89 | for (int i = 1; i < argnums.size(); ++i) { |
| 90 | if (argnums[i] == argnums[i - 1]) { |
| 91 | std::ostringstream msg; |
| 92 | msg << error_msg_tag << " Duplicate argument index " << argnums[0] |
| 93 | << " is not allowed."; |
| 94 | throw std::invalid_argument(msg.str()); |
| 95 | } |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | return [fun, argnums, argnames, error_msg_tag, scalar_func_only]( |
| 100 | nb::args& args, nb::kwargs& kwargs) { |
| 101 | // Sanitize the input |
| 102 | if (argnums.size() > 0 && argnums.back() >= args.size()) { |
| 103 | std::ostringstream msg; |
| 104 | msg << error_msg_tag << " Can't compute the gradient of argument index " |
| 105 | << argnums.back() << " because the function is called with only " |
| 106 | << args.size() << " positional arguments."; |
| 107 | throw std::invalid_argument(msg.str()); |
| 108 | } |
| 109 | |
| 110 | for (auto& key : argnames) { |
| 111 | if (!kwargs.contains(key)) { |
| 112 | std::ostringstream msg; |
| 113 | msg << error_msg_tag |
| 114 | << " Can't compute the gradient of keyword argument '" << key |
| 115 | << "' because the function is called with the " |
| 116 | << "following keyword arguments {"; |
| 117 | for (auto item : kwargs) { |
| 118 | msg << nb::cast<std::string>(item.first) << ","; |
| 119 | } |
| 120 | msg << "}"; |
| 121 | throw std::invalid_argument(msg.str()); |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | // Collect the arrays |
| 126 | std::vector<mx::array> arrays; |
no test coverage detected