Skip to content

Commit

Permalink
Merge pull request #4 from gizatechxyz/refactor-signed-int
Browse files Browse the repository at this point in the history
Refactor signed int
  • Loading branch information
raphaelDkhn authored Jan 22, 2024
2 parents 93dab50 + 203e582 commit 4fbcafe
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 115 deletions.
14 changes: 3 additions & 11 deletions osiris/cairo/data_converter/data_statement_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,8 @@ def get_data_statement(data: np.ndarray, dtype: Dtype) -> list[str]:
list[str]: The generated data statements.
"""
match dtype:
case Dtype.U32:
case Dtype.U32 | Dtype.I32 | Dtype.I8:
return [f"{int(x)}" for x in data.flatten()]
case Dtype.I32:
return ["i32 { "+f"mag: {abs(int(x))}, sign: {str(x < 0).lower()} "+"}" for x in data.flatten()]
case Dtype.I8:
return ["i8 { "+f"mag: {abs(int(x))}, sign: {str(x < 0).lower()} "+"}" for x in data.flatten()]
case Dtype.FP8x23:
return ["FP8x23 { "+f"mag: {abs(int(x))}, sign: {str(x < 0).lower()} "+"}" for x in data.flatten()]
case Dtype.FP16x16:
Expand Down Expand Up @@ -99,12 +95,8 @@ def get_data_statement_for_sequences(data: Sequence, dtype: Dtype) -> list[list[

dtype_to_numbers = {
Dtype.U32: [],
Dtype.I32: [
"orion::numbers::{IntegerTrait, i32}",
],
Dtype.I8: [
"orion::numbers::{IntegerTrait, i8}",
],
Dtype.I32: [],
Dtype.I8: [],
Dtype.FP8x23: [
"orion::numbers::{FixedTrait, FP8x23}",
],
Expand Down
19 changes: 5 additions & 14 deletions osiris/cairo/serde/data_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,9 @@ def __init__(self, shape: tuple, data):
self.shape = shape
self.data = data

class UnsignedInt:
def __init__(self, mag):
self.mag = mag

class SignedInt:
def __init__(self, mag, sign):
self.mag = mag
self.sign = sign

class Int:
def __init__(self, val):
self.val = val

class FixedPoint:
def __init__(self, mag, sign):
Expand All @@ -32,11 +26,8 @@ def create_tensor_from_array(arr: np.ndarray, fp_impl='FP16x16'):
tensor_data = []

for value in flat_array:
if isinstance(value, (np.unsignedinteger)):
tensor_data.append(UnsignedInt(value))
elif isinstance(value, (int, np.integer, np.signedinteger)):
sign = 0 if value >= 0 else 1
tensor_data.append(SignedInt(abs(value), sign))
if isinstance(value, (np.integer)):
tensor_data.append(Int(value))
elif isinstance(value, (float, np.floating)):
(mag, sign) = to_fp(value, fp_impl)
tensor_data.append(FixedPoint(mag, sign))
Expand Down
73 changes: 17 additions & 56 deletions osiris/cairo/serde/deserialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import numpy as np

from .utils import from_fp
from .utils import felt_to_int, from_fp


def deserializer(serialized: str, data_type: str, fp_impl='FP16x16'):
Expand All @@ -17,22 +17,16 @@ def deserializer(serialized: str, data_type: str, fp_impl='FP16x16'):

serialized = convert_data(serialized)

if data_type == 'unsigned_int':
return deserialize_unsigned_int(serialized)
elif data_type == 'signed_int':
return deserialize_signed_int(serialized)
if data_type == 'int':
return deserialize_int(serialized)
elif data_type == 'fixed_point':
return deserialize_fixed_point(serialized, fp_impl)
elif data_type == 'arr_uint':
return deserialize_arr_uint(serialized)
elif data_type == 'arr_signed_int':
return deserialize_arr_signed_int(serialized)
elif data_type == 'arr_int':
return deserialize_arr_int(serialized)
elif data_type == 'arr_fixed_point':
return deserialize_arr_fixed_point(serialized, fp_impl)
elif data_type == 'tensor_uint':
return deserialize_tensor_uint(serialized)
elif data_type == 'tensor_signed_int':
return deserialize_tensor_signed_int(serialized)
elif data_type == 'tensor_int':
return deserialize_tensor_int(serialized)
elif data_type == 'tensor_fixed_point':
return deserialize_tensor_fixed_point(serialized)
# TODO: Support Tuples
Expand Down Expand Up @@ -87,23 +81,13 @@ def convert_data(data):
return result


# ================= UNSIGNED INT =================
# ================= INT =================


def deserialize_unsigned_int(serialized: list) -> np.int64:
return np.int64(serialized[0])
def deserialize_int(serialized: list) -> np.int64:
return np.int64(felt_to_int(serialized[0]))


# ================= SIGNED INT =================


def deserialize_signed_int(serialized: list) -> np.int64:
serialized_mag = serialized[0]
serialized_sign = serialized[1]

deserialized = serialized_mag if serialized_sign == 0 else -serialized_mag
return np.int64(deserialized)

# ================= FIXED POINT =================


Expand All @@ -114,31 +98,17 @@ def deserialize_fixed_point(serialized: list, impl='FP16x16') -> np.float64:
deserialized = serialized_mag if serialized_sign == 0 else -serialized_mag
return np.float64(deserialized)

# ================= ARRAY UINT =================

# ================= ARRAY INT =================

def deserialize_arr_uint(serialized: list) -> np.array:
return np.array(serialized[0], dtype=np.int64)

# ================= ARRAY SIGNED INT =================


def deserialize_arr_signed_int(serialized):
def deserialize_arr_int(serialized):

serialized = serialized[0]

if len(serialized) % 2 != 0:
raise ValueError("Array length must be even")

deserialized = []
for i in range(0, len(serialized), 2):
mag = serialized[i]
sign = serialized[i + 1]

if sign == 1:
mag = -mag

deserialized.append(mag)
for ele in serialized:
deserialized.append(felt_to_int(ele))

return np.array(deserialized)

Expand All @@ -162,21 +132,12 @@ def deserialize_arr_fixed_point(serialized: list, impl='FP16x16'):
return np.array(deserialized)


# ================= TENSOR UINT =================


def deserialize_tensor_uint(serialized: list) -> np.array:
shape = serialized[0]
data = serialized[1]

return np.array(data, dtype=np.int64).reshape(shape)

# ================= TENSOR SIGNED INT =================
# ================= TENSOR INT =================


def deserialize_tensor_signed_int(serialized: list) -> np.array:
def deserialize_tensor_int(serialized: list) -> np.array:
shape = serialized[0]
data = deserialize_arr_signed_int([serialized[1]])
data = deserialize_arr_int([serialized[1]])

return np.array(data, dtype=np.int64).reshape(shape)

Expand Down
16 changes: 6 additions & 10 deletions osiris/cairo/serde/serialize.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
from osiris.cairo.serde.data_structures import (
FixedPoint,
SignedInt,
Int,
Tensor,
UnsignedInt,
)
from osiris.cairo.serde.utils import int_to_felt


def serializer(data):
if isinstance(data, bool):
return "1" if data else "0"
elif isinstance(data, int):
if data >= 0:
return f"{data}"
else:
raise ValueError("Native signed integers are not supported yet")
# TODO: Support native singned-int
return f"{int_to_felt(data)}"
elif isinstance(data, Int):
return f"{int_to_felt(data.val)}"
elif isinstance(data, (list, tuple)):
joined_elements = ' '.join(serializer(e) for e in data)
return f"[{joined_elements}]"
elif isinstance(data, Tensor):
return f"{serializer(data.shape)} {serializer(data.data)}"
elif isinstance(data, (SignedInt, FixedPoint)):
elif isinstance(data, FixedPoint):
return f"{serializer(data.mag)} {serializer(data.sign)}"
elif isinstance(data, UnsignedInt):
return f"{data.mag}"

else:
raise ValueError("Unsupported data type for serialization")
16 changes: 16 additions & 0 deletions osiris/cairo/serde/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,19 @@ def from_fp(value, fp_impl='FP16x16'):
return value / 2**32
case 'FP64x64':
return value / 2**64

def int_to_felt(n):
PRIME_FIELD = 2**251 + 17 * 2**192 + 1
if n < 0:
return (PRIME_FIELD + n) % PRIME_FIELD
else:
return n % PRIME_FIELD

def felt_to_int(felt):
PRIME_FIELD = 2**251 + 17 * 2**192 + 1
HALF_FIELD = PRIME_FIELD // 2

if felt > HALF_FIELD:
return felt - PRIME_FIELD
else:
return felt
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "giza-osiris"
version = "0.1.8"
version = "0.1.9"
description = "Osiris is a Python library designed for efficient data conversion and management, primarily transforming data into Cairo programs"
authors = ["Fran Algaba <[email protected]>"]
readme = "README.md"
Expand Down
30 changes: 13 additions & 17 deletions tests/test_deserialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
from osiris.cairo.serde.deserialize import *


def test_deserialize_signed_int():
serialized = '[{"Int":"2A"}, {"Int":"0"}]'
deserialized = deserializer(serialized, 'signed_int')
def test_deserialize_int():
serialized = '[{"Int":"2A"}]'
deserialized = deserializer(serialized, 'int')
assert deserialized == 42

serialized = '[{"Int":"2A"}, {"Int":"0x1"}]'
deserialized = deserializer(serialized, 'signed_int')
serialized = '[{"Int":"800000000000010FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7"}]'
deserialized = deserializer(serialized, 'int')
assert deserialized == -42


Expand All @@ -25,15 +25,13 @@ def test_deserialize_fp():
assert isclose(deserialized, -42.42, rel_tol=1e-7)


def test_deserialize_array_uint():
def test_deserialize_array_int():
serialized = '[{"Array": [{"Int": "0x1"}, {"Int": "0x2"}]}]'
deserialized = deserializer(serialized, 'arr_uint')
deserialized = deserializer(serialized, 'arr_int')
assert np.array_equal(deserialized, np.array([1, 2], dtype=np.int64))


def test_deserialize_array_signed_int():
serialized = '[{"Array": [{"Int": "2A"}, {"Int": "0"}, {"Int": "2A"}, {"Int": "0x1"}]}]'
deserialized = deserializer(serialized, 'arr_signed_int')
serialized = '[{"Array": [{"Int": "2A"}, {"Int": "800000000000010FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7"}]}]'
deserialized = deserializer(serialized, 'arr_int')
assert np.array_equal(deserialized, np.array([42, -42], dtype=np.int64))


Expand All @@ -44,16 +42,14 @@ def test_deserialize_arr_fixed_point():
assert np.all(np.isclose(deserialized, expected, atol=1e-7))


def test_deserialize_tensor_uint():
def test_deserialize_tensor_int():
serialized = '[{"Array": [{"Int": "0x2"}, {"Int": "0x2"}]}, {"Array": [{"Int": "0x1"}, {"Int": "0x2"}, {"Int": "0x3"}, {"Int": "0x4"}]}]'
deserialized = deserializer(serialized, 'tensor_uint')
deserialized = deserializer(serialized, 'tensor_int')
assert np.array_equal(deserialized, np.array(
([1, 2], [3, 4]), dtype=np.int64))


def test_deserialize_tensor_signed_int():
serialized = '[{"Array": [{"Int": "0x2"}, {"Int": "0x2"}]}, {"Array": [{"Int": "2A"}, {"Int": "0x0"}, {"Int": "2A"}, {"Int": "0x0"}, {"Int": "2A"}, {"Int": "0x1"}, {"Int": "2A"}, {"Int": "0x1"}]}]'
deserialized = deserializer(serialized, 'tensor_signed_int')
serialized = '[{"Array": [{"Int": "0x2"}, {"Int": "0x2"}]}, {"Array": [{"Int": "2A"}, {"Int": "2A"},{"Int": "800000000000010FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7"}, {"Int": "800000000000010FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7"}]}]'
deserialized = deserializer(serialized, 'tensor_int')
assert np.array_equal(deserialized, np.array([[42, 42], [-42, -42]]))


Expand Down
15 changes: 9 additions & 6 deletions tests/test_serialize.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import numpy as np
import pytest
from osiris.cairo.serde.data_structures import create_tensor_from_array, Tensor, SignedInt, FixedPoint
from osiris.cairo.serde.data_structures import create_tensor_from_array, Tensor, FixedPoint, Int
from osiris.cairo.serde.serialize import serializer


Expand All @@ -9,7 +9,7 @@ def test_create_tensor_from_array_with_integers():
tensor = create_tensor_from_array(arr)
assert isinstance(tensor, Tensor)
assert tensor.shape == arr.shape
assert all(isinstance(x, SignedInt) for x in tensor.data)
assert all(isinstance(x, Int) for x in tensor.data)


def test_create_tensor_from_array_with_floats():
Expand Down Expand Up @@ -48,19 +48,22 @@ def test_serializer_for_tuple():
serialized_data = serializer(data)
assert serialized_data == "[1 2 3]"


def test_serializer_for_fixedpoint():
data = FixedPoint(42, True)
serialized_data = serializer(data)
assert serialized_data == "42 1"
assert serialized_data == "42 1"


def test_serializer_for_tensor_uint():
def test_serializer_for_tensor_int():
arr = np.array([[1, 2], [3, 4]], dtype=np.uint64)
tensor = create_tensor_from_array(arr)
serialized_data = serializer(tensor)
assert serialized_data == "[2 2] [1 2 3 4]"
assert serialized_data == "[2 2] [1 2 3 4]"


def test_serializer_for_tensor_fixedpoint():
arr = np.array([[1, 2], [3, 4]], dtype=np.float32)
tensor = create_tensor_from_array(arr)
serialized_data = serializer(tensor)
assert serialized_data == "[2 2] [65536 0 131072 0 196608 0 262144 0]"
assert serialized_data == "[2 2] [65536 0 131072 0 196608 0 262144 0]"

0 comments on commit 4fbcafe

Please sign in to comment.