From afa32b950b812bd0a40c3f8b14a848e80c18f881 Mon Sep 17 00:00:00 2001
From: Yaman Umuroglu <yamanu@xilinx.com>
Date: Wed, 21 Aug 2019 13:39:03 +0000
Subject: [PATCH] sketch some basics for datatypes and the Tensor type

---
 src/finn/core/tensor.py | 121 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 121 insertions(+)
 create mode 100644 src/finn/core/tensor.py

diff --git a/src/finn/core/tensor.py b/src/finn/core/tensor.py
new file mode 100644
index 000000000..274f66d7f
--- /dev/null
+++ b/src/finn/core/tensor.py
@@ -0,0 +1,121 @@
+# Copyright (c) 2018, Xilinx
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#    3. Neither the name of the <organization> nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import numpy as np
+from enum import Enum
+
+class DataType(Enum):
+  FLOAT32 = 0
+  BINARY = 1
+  BIPOLAR = 2
+  UINT2 = 3
+  UINT3 = 4
+  UINT4 = 5
+  UINT8 = 6
+  UINT16 = 7
+  UINT32 = 8
+  INT2 = 9
+  INT3 = 10
+  INT4 = 11
+  INT8 = 12
+  INT16 = 13
+  INT32 = 14
+
+  def bitwidth(self):
+    """Returns the number of bits required for this DataType."""
+
+    if self.name.startswith("UINT"):
+      return int(self.name.strip("UINT"))
+    elif self.name.startswith("INT"):
+      return int(self.name.strip("INT"))
+    elif "FLOAT" in self.name:
+      return int(self.name.strip("FLOAT"))
+    elif self.name in ["BINARY", "BIPOLAR"]:
+      return 1
+    else:
+      raise Exception("Unrecognized data type: %s" % self.name)
+
+  def min(self):
+    """Returns the smallest possible value allowed by this DataType."""
+
+    if self.name.startswith("UINT") or self.name == "BINARY":
+      return 0
+    elif self.name.startswith("INT"):
+      return -(2 ** (self.bitwidth() - 1))
+    elif self.name == "FLOAT32":
+      return np.finfo(np.float32).min
+    elif self.name == "BIPOLAR":
+      return -1
+    else:
+      raise Exception("Unrecognized data type: %s" % self.name)
+
+  def max(self):
+    """Returns the largest possible value allowed by this DataType."""
+
+    if self.name.startswith("UINT"):
+      return (2 ** (self.bitwidth())) - 1
+    elif self.name == "BINARY":
+      return +1
+    elif self.name.startswith("INT"):
+      return (2 ** (self.bitwidth() - 1)) - 1
+    elif self.name == "FLOAT32":
+      return np.finfo(np.float32).max
+    elif self.name == "BIPOLAR":
+      return +1
+    else:
+      raise Exception("Unrecognized data type: %s" % self.name)
+
+  def allowed(self, value):
+    """Check whether given value is allowed for this DataType.
+
+    value (float32): value to be checked"""
+
+    if "FLOAT" in self.name:
+      return True
+    elif "INT" in self.name:
+      return (self.min() <= value) and (value <= self.max())
+    elif self.name == "BINARY":
+      return value in [0, 1]
+    elif self.name == "BIPOLAR":
+      return value in [-1, +1]
+    else:
+      raise Exception("Unrecognized data type: %s" % self.name)
+
+class Tensor(object):
+  """A multidimensional array of numbers of given datatype.
+
+  Attributes:
+    dtype (DataType): Element data type for this Tensor
+    data (numpy ndarray of float32): Numpy container for data
+    ndims (int): Number of dimensions in array, 0 indicates scalar
+    dim_names (list of str): names associated with each dimension, e.g.
+      ["N", "C", "H", "W"]
+  """
+
+  def __init__(self, dtype, data, dim_names = []):
+    self.dtype = dtype
+    self.data = data
+    self.dim_names = dim_names
-- 
GitLab