| 2531 | } |
| 2532 | |
| 2533 | Status BatchToSpaceShapeHelper(InferenceContext* c, ShapeHandle input_shape, |
| 2534 | ShapeHandle block_shape_shape, |
| 2535 | const Tensor* block_shape_t, |
| 2536 | ShapeHandle crops_shape, const Tensor* crops_t) { |
| 2537 | if (c->Rank(block_shape_shape) != 1) { |
| 2538 | return errors::InvalidArgument("block_shape must have rank 1."); |
| 2539 | } |
| 2540 | |
| 2541 | const DimensionHandle num_block_dims_handle = c->Dim(block_shape_shape, 0); |
| 2542 | if (!c->ValueKnown(num_block_dims_handle)) { |
| 2543 | return errors::InvalidArgument("block_shape must have known size."); |
| 2544 | } |
| 2545 | |
| 2546 | const int64 num_block_dims = c->Value(num_block_dims_handle); |
| 2547 | |
| 2548 | TF_RETURN_IF_ERROR( |
| 2549 | c->WithRankAtLeast(input_shape, num_block_dims + 1, &input_shape)); |
| 2550 | |
| 2551 | TF_RETURN_IF_ERROR( |
| 2552 | c->Merge(crops_shape, c->Matrix(num_block_dims, 2), &crops_shape)); |
| 2553 | |
| 2554 | DimensionHandle batch_size = c->Dim(input_shape, 0); |
| 2555 | std::vector<int64> block_shape_vec; |
| 2556 | if (block_shape_t) { |
| 2557 | block_shape_vec = GetFlatInt64(*block_shape_t); |
| 2558 | for (int64 dim = 0; dim < num_block_dims; ++dim) { |
| 2559 | const int64 block_shape_value = block_shape_vec[dim]; |
| 2560 | if (block_shape_value < 1) { |
| 2561 | return errors::InvalidArgument("block_shape must be positive"); |
| 2562 | } |
| 2563 | if (c->ValueKnown(batch_size)) { |
| 2564 | TF_RETURN_IF_ERROR(c->Divide(batch_size, block_shape_value, |
| 2565 | /*evenly_divisible=*/true, &batch_size)); |
| 2566 | } else { |
| 2567 | batch_size = c->UnknownDim(); |
| 2568 | } |
| 2569 | } |
| 2570 | } else if (num_block_dims > 0) { |
| 2571 | batch_size = c->UnknownDim(); |
| 2572 | } |
| 2573 | |
| 2574 | std::vector<DimensionHandle> output_dims{batch_size}; |
| 2575 | output_dims.resize(num_block_dims + 1, c->UnknownDim()); |
| 2576 | |
| 2577 | if (crops_t) { |
| 2578 | const std::vector<int64> crops_vec = GetFlatInt64(*crops_t); |
| 2579 | for (int64 dim = 0; dim < num_block_dims; ++dim) { |
| 2580 | const int64 crop_start = crops_vec[dim * 2], |
| 2581 | crop_end = crops_vec[dim * 2 + 1]; |
| 2582 | if (crop_start < 0 || crop_end < 0) { |
| 2583 | return errors::InvalidArgument("crops cannot be negative"); |
| 2584 | } |
| 2585 | if (block_shape_t) { |
| 2586 | DimensionHandle cropped_size; |
| 2587 | TF_RETURN_IF_ERROR(c->Multiply(c->Dim(input_shape, dim + 1), |
| 2588 | block_shape_vec[dim], &cropped_size)); |
| 2589 | TF_RETURN_IF_ERROR( |
| 2590 | c->Subtract(cropped_size, crop_start, &cropped_size)); |
no test coverage detected