| 709 | } |
| 710 | |
| 711 | std::optional<ValueRefList> where_grad_rule( |
| 712 | const OpDef& op, Span<ValueRef> inputs, Span<bool> inputs_require_grad, |
| 713 | CustomBackward& backward) { |
| 714 | auto&& where = op.cast_final_safe<Where>(); |
| 715 | auto&& param = where.param(); |
| 716 | mgb_assert(inputs.size() == 3); |
| 717 | SmallVector<ValueRef> inps; |
| 718 | if (inputs_require_grad[1] || inputs_require_grad[2]) { |
| 719 | inps.push_back(inputs[0]); |
| 720 | } |
| 721 | bool data1_requires_grad = inputs_require_grad[1], |
| 722 | data2_requires_grad = inputs_require_grad[2]; |
| 723 | auto maker = CustomGradMaker(backward, inputs.size()); |
| 724 | maker.output_size(1).output_captured(0, false); |
| 725 | maker.backward([inputs = std::move(inps), data1_requires_grad, data2_requires_grad, |
| 726 | param](Span<ValueRef> grads) { |
| 727 | mgb_assert(grads.size() == 1); |
| 728 | ValueRef grad = grads[0]; |
| 729 | SmallVector<ValueRef> ret(3); |
| 730 | if (!grad) { |
| 731 | return ret; |
| 732 | } |
| 733 | if (data1_requires_grad == false && data2_requires_grad == false) { |
| 734 | return ret; |
| 735 | } |
| 736 | |
| 737 | auto&& grad_op = WhereBackward::make(); |
| 738 | ValueRefList args_(2); |
| 739 | args_[0] = grads[0]; |
| 740 | args_[1] = inputs[0]; |
| 741 | auto back_grad = imperative::apply(*grad_op, args_); |
| 742 | if (data1_requires_grad) |
| 743 | ret[1] = back_grad[0]; |
| 744 | if (data2_requires_grad) |
| 745 | ret[2] = back_grad[1]; |
| 746 | return ret; |
| 747 | }); |
| 748 | maker.finalize(); |
| 749 | return imperative::apply(op, inputs); |
| 750 | } |
| 751 | |
| 752 | struct Init { |
| 753 | Init() { |
nothing calls this directly
no test coverage detected