diff --git a/osiris/cairo/data_converter/data_statement_generator.py b/osiris/cairo/data_converter/data_statement_generator.py index 3b67e51..4a975bc 100644 --- a/osiris/cairo/data_converter/data_statement_generator.py +++ b/osiris/cairo/data_converter/data_statement_generator.py @@ -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: @@ -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}", ], diff --git a/osiris/cairo/serde/data_structures.py b/osiris/cairo/serde/data_structures.py index fcedf63..4111f9a 100644 --- a/osiris/cairo/serde/data_structures.py +++ b/osiris/cairo/serde/data_structures.py @@ -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): @@ -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)) diff --git a/osiris/cairo/serde/deserialize.py b/osiris/cairo/serde/deserialize.py index 4872fb2..f54c21b 100644 --- a/osiris/cairo/serde/deserialize.py +++ b/osiris/cairo/serde/deserialize.py @@ -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'): @@ -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 @@ -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 ================= @@ -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) @@ -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) diff --git a/osiris/cairo/serde/serialize.py b/osiris/cairo/serde/serialize.py index c49276c..41ca970 100644 --- a/osiris/cairo/serde/serialize.py +++ b/osiris/cairo/serde/serialize.py @@ -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") diff --git a/osiris/cairo/serde/utils.py b/osiris/cairo/serde/utils.py index b2e5f81..6f0e255 100644 --- a/osiris/cairo/serde/utils.py +++ b/osiris/cairo/serde/utils.py @@ -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 diff --git a/pyproject.toml b/pyproject.toml index 4a9d58c..a13879d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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 "] readme = "README.md" diff --git a/tests/test_deserialize.py b/tests/test_deserialize.py index 858e780..a867ef9 100644 --- a/tests/test_deserialize.py +++ b/tests/test_deserialize.py @@ -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 @@ -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)) @@ -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]])) diff --git a/tests/test_serialize.py b/tests/test_serialize.py index cf4750d..b3c3b92 100644 --- a/tests/test_serialize.py +++ b/tests/test_serialize.py @@ -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 @@ -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(): @@ -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]" \ No newline at end of file + assert serialized_data == "[2 2] [65536 0 131072 0 196608 0 262144 0]"