# TensorFlow GNN GraphObject incompatible with graph specification

I’m attempting to solve the Time Difference of Arrival (TDoA) multilateration problem using a Graph Neural Network, implemented in `TensorFlow`. The problem statement is as follows: given the known coordinates of `4` “receivers” and the difference in arrival times of some signal between any two such receivers, I wish to determine the entirely unknown coordinates of the signal source. There are many existing ways to solve this problem. I’m pursuing this particular direction out of pure curiosity.

I’ve decided to describe the problem as a fully-connected homogenous graph with `5` nodes, where the “feature” associated with each node is its 3-dimensional coordinates, and the feature associated with each edge is the associated pairwise arrival time difference (e.g. the feature associated with the edge between nodes `1` and `2` is the signal arrival time difference between transmitters `1` and `2`). The 5th node is the signal source, and in practice we know neither its coordinates nor the feature associated with any of the edges connecting it to the remaining nodes (i.e. the distance between the source and any given transmitter).

While I’ve had graph theory, I’m entirely new to the theory of GNN’s, and I’m finding the TensorFlow GNN documentation to be a bit obtuse. I’ve begun working out a rough sketch of the code in Python, starting by defining the graph schema in a file `graph_schema.pbtxt` as follows:

``````node_sets {
key: "node"
value {
description: "The nodes comprising the network (4 receivers + 1 signal source)."
features {
key: "coordinates"
value: {
dtype: DT_FLOAT
shape: { dim: { size: 3 } }
}
}
}
}

edge_sets {
key: "pseudorange"
value {
description: "The arrival time differences."
source: "node"
target: "node"

features {
key: "differences"
value: {
dtype: DT_FLOAT
}
}
}
}
``````

Again, each node is associated with a set of three dimensional coordinates, and each edge with a pairwise arrival time difference. I then attempt to create a graph specification from this schema, and begin producing some training data:

``````import tensorflow as tf
import tensorflow_gnn as tfgnn

import numpy as np

graph_spec = tfgnn.create_graph_spec_from_schema_pb(graph_schema)

def make_graph_tensor():

# Generate random coordinates for 5 nodes, where the 5th node is the "transmitter"
node_coordinates = np.random.random(size=(5,3))

# Compute the arrival times, pairwise arrival time differences
c = 299792

arrival_times = np.sum(np.sqrt((node_coordinates - node_coordinates[4])**2), axis=1) / c
arrival_times = arrival_times[:, np.newaxis]

time_differences = arrival_times - arrival_times.T
time_differences = time_differences[np.triu_indices(len(time_differences), k=1)]

# Define the node adjacency (fully connected graph)
sources = [0,0,0,1,1,2,0,1,2,3]
targets = [1,2,3,2,3,3,4,4,4,4]

target=('node', tf.cast(targets, dtype=tf.int32)))

# Create GraphTensor object
network = tfgnn.NodeSet.from_fields(features={'coordinates': node_coordinates}, sizes=tf.shape(node_coordinates))
pseudoranges = tfgnn.EdgeSet.from_fields(features={'differences': time_differences},
sizes=tf.shape(time_differences))

return tfgnn.GraphTensor.from_pieces(node_sets={'node': network}, edge_sets={'pseudorange': pseudoranges})

print(graph_spec.is_compatible_with(make_graph_tensor()))
``````

In `make_graph_tensor()`, I attempt to create a `GraphTensor` object for one instance of randomly generated training data. One instance consists of some randomly-generated coordinates of 4 nodes + 1 signal source (held in `node_coordinates`), and `10` pairwise arrival time differences (held in `time_differences`). I then define the node adjacency such that the graph is fully connected, and attempt to create a `GraphTensor` object from the node coordinates, adjacency, and pairwise arrival time differences.

When I check that the resulting `GraphTensor` object is compatible with the graph specification using `print(graph_spec.is_compatible_with(make_graph_tensor()))`, however, I get `False`. Unfortunately, it isn’t clear to me why this is. I initially expected it might have something to do with dimensions, so I tried changing `shape: { dim: { size: 3 } }` so that the feature shape would be inferred, but this did not help.

Why is the GraphObject incompatible with the graph specification resulting from the above schema?

Hey,
Even if probably at this point you have already solved the problem,

The features that you represent with dtype: DT_FLOAT in the schema cannot match the features you generate in `make_graph_tensor()` if these are not generated as tf.float32.

I had the same problem and I solved it casting my features from tf.float64 to tf.float32.