Repository: tensorflow
Issue: The dim size of inferred shape in GraphProperties is less than -1, which is inconsistent with TensorShapeProto
Labels: stat:awaiting tensorflower,type:bug,type:build/install,subtype: ubuntu/linux,TF 2.12

<details><summary>Click to expand!</summary> 
 
 ### Issue Type

Bug

### Have you reproduced the bug with TF nightly?

No

### Source

source

### Tensorflow Version

2.12.0

### Custom Code

No

### OS Platform and Distribution

Ubuntu 22.04

### Mobile device

_No response_

### Python version

3.9

### Bazel version

5.3.0

### GCC/Compiler version

11.3.0

### CUDA/cuDNN version

_No response_

### GPU model and memory

_No response_

### Current Behaviour?

### Behavior
Viewed dim size less than -1 after called `GraphProperties::InferStatically`, while in [TensorShapeProto](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/framework/tensor_shape.proto#L17) the comment says either the dim size is greater than 0 or -1 (meaning unknown). 
```
message Dim {
    // Size of the tensor in that dimension.
    // This value must be >= -1, but values of -1 are reserved for "unknown"
    // shapes (values of -1 mean "unknown" dimension). 
    int64 size = 1;
};
```
The two are inconsistent.
### The Cause
In [this code](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/grappler/costs/graph_properties.cc#L118) which constructs the inferred dims, it assigns a negative id to unknown dimensions, starting at -2. 
```c++
// Assign a negative id to unknown dimensions, starting at -2 (the -1 id
// reserved by TensorFlow).
void ExtractValue(DimensionHandle d, int64_t* result) {
  if (!InferenceContext::ValueKnown(d)) {
    *result = -counter;
    counter++;
  } else {
    ...
  }
}
```
It can be seen from the code that size<=-1 means unknown, but the unknown size in [this code](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/grappler/utils/symbolic_shapes.cc#L42) is identified with `==-1`.
`bool IsUnknown(const TensorShapeProto::Dim& dim) { return dim.size() == -1; }`
And the [`ShapeIsSymbolicallyDefined`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/grappler/utils/symbolic_shapes.cc#L44), which calls `IsUnknown `may cause bugs.
```c++
bool ShapeIsSymbolicallyDefined(const TensorShapeProto& shape) {
  return !shape.unknown_rank() &&
         std::all_of(
             shape.dim().begin(), shape.dim().end(),
             [](const TensorShapeProto::Dim& dim) { return !IsUnknown(dim); });
}
```
[`ShapesSymbolicallyEqual`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/grappler/utils/symbolic_shapes.cc#L76) function is the same problem. 
### Questions:
1. The inferred dim size is less than -1, inconsistent with TensorShapeProto, is this expected?
2. Is the `IsUnknown` function reasonable?
3. Do the `ShapeIsSymbolicallyDefined` and `ShapesSymbolicallyEqual` cause undefined behavior? I see some graph optimization path will call this function after shape inference.

### Standalone code to reproduce the issue
I manually print the shape inference log in the Tensorflow source code. First, patch my log into the Tensorflow source code, then compile the source code, and finally run the python script I gave. It can be seen from the log that the result of shape inference has dimensions less than -1.
```shell
git checkout v2.12.0

# apply patch
echo 'diff --git a/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc b/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc
index 40c27828d26..899a9d059cb 100644
--- a/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc
+++ b/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc
@@ -4452,6 +4452,26 @@ Status ArithmeticOptimizer::Optimize(Cluster* /*cluster*/,
     VLOG(1) << "Shape inference failed." << status.error_message();
   }

+  for (auto& node : optimized_graph_->node()) {
+    VLOG(0) << "node_name: " << node.name();
+    const auto& input_properties =
+        graph_properties_->GetInputProperties(node.name());
+    for (int i = 0; i < input_properties.size(); i++) {
+      auto& property = input_properties[i];
+      VLOG(0) << "input" << i << ": ";
+      const TensorShapeProto& tsp = property.shape();
+      if (tsp.unknown_rank()) {
+        VLOG(0) << "unknown shape";
+        continue;
+      }
+      VLOG(0) << "input_rank: " << tsp.dim_size();
+      for (int j = 0; j < tsp.dim_size(); j++) {
+        VLOG(0) << "dim" << j << " size: " << tsp.dim(j).size();
+      }
+    }
+    VLOG(0);
+  }
+
   // Perform the optimizations.
   TF_RETURN_IF_ERROR(SimplifyArithmeticOps(can_use_shapes));
   *optimized_graph = std::move(*optimized_graph_);
' | git apply

# build
bazel build //tensorflow/tools/pip_package:build_pip_package
...(continue to build)
```

```python
import numpy as np
import tensorflow as tf

@tf.function(input_signature=[tf.TensorSpec(shape=(None, None), dtype=tf.float32)])
def fun(x):
    y = tf.constant(np.ones((2, 4)), dtype=tf.float32)
    return tf.add(x, y)

output = fun(np.ones((2, 4), dtype=np.float32))
print("output: ", output)
```


### Relevant log output

```shell
node_name: Add
input0:
input_rank: 2
dim0 size: 2
dim1 size: 4
input1:
input_rank: 2
dim0 size: -2
dim1 size: -3
```
</details>