docs: public TF_Tensor tensorFromNDArray(INDArray ndArray) {
         if(ndArray == null) {
             throw new IllegalArgumentException("NDArray must not be null!");
         }
          //we infer data type from the ndarray.databuffer()
          //for now we throw an exception
          if(ndArray.data() == null) {
             throw new IllegalArgumentException("Unable to infer data type from null databuffer");
         }
  
          if(ndArray.isView() || ndArray.ordering() != 'c') {
              ndArray = ndArray.dup('c');
          }
  
  
          long[] ndShape = ndArray.shape();
          long[] tfShape = new long[ndShape.length];
          System.arraycopy(ndShape, 0, tfShape, 0, ndShape.length);
  
          int type;
          DataBuffer data = ndArray.data();
          DataType dataType = data.dataType();
          switch (dataType) {
              case DOUBLE: type = DT_DOUBLE; break;
              case FLOAT:  type = DT_FLOAT;  break;
              case INT:    type = DT_INT32;  break;
              case HALF:   type = DT_HALF;   break;
              case COMPRESSED:
                  CompressedDataBuffer compressedData = (CompressedDataBuffer)data;
                  CompressionDescriptor desc = compressedData.getCompressionDescriptor();
                  String algo = desc.getCompressionAlgorithm();
                  switch (algo) {
                      case "FLOAT16": type = DT_HALF;   break;
                      case "INT8":    type = DT_INT8;   break;
                      case "UINT8":   type = DT_UINT8;  break;
                      case "INT16":   type = DT_INT16;  break;
                      case "UINT16":  type = DT_UINT16; break;
                      default: throw new IllegalArgumentException("Unsupported compression algorithm: " + algo);
                  }
                  break;
              case LONG: type = DT_INT64; break;
              case UTF8: type = DT_STRING; break;
              default: throw new IllegalArgumentException("Unsupported data type: " + dataType);
          }
  
          try {
              Nd4j.getAffinityManager().ensureLocation(ndArray, AffinityManager.Location.HOST);
          } catch (Exception e) {
              // ND4J won't let us access compressed data in GPU memory, so we'll leave TensorFlow do the conversion instead
              ndArray.getDouble(0); // forces decompression and data copy to host
              data = ndArray.data();
              dataType = data.dataType();
              switch (dataType) {
                  case DOUBLE: type = DT_DOUBLE; break;
                  case FLOAT:  type = DT_FLOAT;  break;
                  case INT:    type = DT_INT32;  break;
                  case LONG:   type = DT_INT64;  break;
                  case UTF8: type = DT_STRING; break;
                  default: throw new IllegalArgumentException("Unsupported data type: " + dataType);
              }
          }
  
  
          LongPointer longPointer = new LongPointer(tfShape);
          TF_Tensor tf_tensor = null;
  
          if (type == DT_STRING) {
              long size = 0;
              long length = ndArray.length();
              BytePointer[] strings = new BytePointer[(int)length];
              for (int i = 0; i < length; i++) {
                  strings[i] = new BytePointer(ndArray.getString(i));
                  size += TF_StringEncodedSize(strings[i].capacity());
              }
              tf_tensor = TF_AllocateTensor(
                      type,
                      longPointer,
                      tfShape.length,
                      8 * length + size);
  
              long offset = 0;
              BytePointer tf_data = new BytePointer(TF_TensorData(tf_tensor)).capacity(TF_TensorByteSize(tf_tensor));
              TF_Status status = TF_NewStatus();
              for (int i = 0; i < length; i++) {
                  tf_data.position(8 * i).putLong(offset);
                  offset += TF_StringEncode(strings[i], strings[i].capacity() - 1, tf_data.position(8 * length + offset), tf_data.capacity() - tf_data.position(), status);
                  if (TF_GetCode(status) != TF_OK) {
                      throw new IllegalStateException("ERROR: Unable to convert tensor " + TF_Message(status).getString());
                  }
              }
              TF_DeleteStatus(status);
          } else {
              tf_tensor = TF_NewTensor(
                      type,
                      longPointer,
                      tfShape.length,
                      data.pointer(),
                      data.length() * data.getElementSize(),
                      calling,null);
          }
  
          return tf_tensor;
  
      }