| 73 | }); |
| 74 | |
| 75 | Status RFFTShape(InferenceContext* c, const bool forward, const int rank) { |
| 76 | ShapeHandle out; |
| 77 | TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), rank, &out)); |
| 78 | |
| 79 | // Check that fft_length has shape [rank]. |
| 80 | ShapeHandle unused_shape; |
| 81 | DimensionHandle unused_dim; |
| 82 | ShapeHandle fft_length_input = c->input(1); |
| 83 | TF_RETURN_IF_ERROR(c->WithRank(fft_length_input, 1, &unused_shape)); |
| 84 | TF_RETURN_IF_ERROR( |
| 85 | c->WithValue(c->Dim(fft_length_input, 0), rank, &unused_dim)); |
| 86 | const Tensor* fft_length_tensor = c->input_tensor(1); |
| 87 | |
| 88 | // If fft_length is unknown at graph creation time, we can't predict the |
| 89 | // output size. |
| 90 | if (fft_length_tensor == nullptr) { |
| 91 | // We can't know the dimension of any of the rank inner dimensions of the |
| 92 | // output without knowing fft_length. |
| 93 | for (int i = 0; i < rank; ++i) { |
| 94 | TF_RETURN_IF_ERROR(c->ReplaceDim(out, -rank + i, c->UnknownDim(), &out)); |
| 95 | } |
| 96 | } else { |
| 97 | auto fft_length_as_vec = fft_length_tensor->vec<int32>(); |
| 98 | for (int i = 0; i < rank; ++i) { |
| 99 | // For RFFT, replace the last dimension with fft_length/2 + 1. |
| 100 | auto dim = forward && i == rank - 1 && fft_length_as_vec(i) != 0 |
| 101 | ? fft_length_as_vec(i) / 2 + 1 |
| 102 | : fft_length_as_vec(i); |
| 103 | TF_RETURN_IF_ERROR(c->ReplaceDim(out, -rank + i, c->MakeDim(dim), &out)); |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | c->set_output(0, out); |
| 108 | return Status::OK(); |
| 109 | } |
| 110 | |
| 111 | REGISTER_OP("RFFT") |
| 112 | .Input("input: float") |
no test coverage detected