Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor signed int #4

Merged
merged 5 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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]"