mirror of
https://github.com/zama-ai/concrete.git
synced 2026-02-09 12:15:09 -05:00
dev(dtypes): add a function to make Integers able to hold a set of values
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
"""This file holds the definitions for integer types"""
|
||||
|
||||
import math
|
||||
from typing import Iterable
|
||||
|
||||
from . import base
|
||||
|
||||
|
||||
@@ -79,3 +82,60 @@ def create_unsigned_integer(bit_width: int) -> Integer:
|
||||
|
||||
|
||||
UnsignedInteger = create_unsigned_integer
|
||||
|
||||
|
||||
def make_integer_to_hold_ints(values: Iterable[int], force_signed: bool) -> Integer:
|
||||
"""Returns an Integer able to hold all values, it is possible to force the Integer to be signed
|
||||
|
||||
Args:
|
||||
values (Iterable[int]): The values to hold
|
||||
force_signed (bool): Set to True to force the result to be a signed Integer
|
||||
|
||||
Returns:
|
||||
Integer: The Integer able to hold values
|
||||
"""
|
||||
assert all(map(lambda x: isinstance(x, int), values))
|
||||
min_value = min(values)
|
||||
max_value = max(values)
|
||||
|
||||
make_signed_integer = force_signed or min_value < 0
|
||||
|
||||
num_bits = max(
|
||||
get_bits_to_represent_int(min_value, make_signed_integer),
|
||||
get_bits_to_represent_int(max_value, make_signed_integer),
|
||||
)
|
||||
|
||||
return Integer(num_bits, is_signed=make_signed_integer)
|
||||
|
||||
|
||||
def get_bits_to_represent_int(value: int, force_signed: bool) -> int:
|
||||
"""Returns how many bits are required to represent a single int
|
||||
|
||||
Args:
|
||||
value (int): The int for which we want to know how many bits are required
|
||||
force_signed (bool): Set to True to force the result to be a signed Integer
|
||||
|
||||
Returns:
|
||||
int: required amount of bits
|
||||
"""
|
||||
|
||||
# Writing this in a very dumb way
|
||||
num_bits: int
|
||||
if value < 0:
|
||||
abs_value = abs(value)
|
||||
if abs_value > 1:
|
||||
num_bits = math.ceil(math.log2(abs_value)) + 1
|
||||
else:
|
||||
# -1 case
|
||||
num_bits = 2
|
||||
else:
|
||||
if value > 1:
|
||||
num_bits = math.ceil(math.log2(value + 1))
|
||||
else:
|
||||
# 0 and 1 case
|
||||
num_bits = 1
|
||||
|
||||
if force_signed:
|
||||
num_bits += 1
|
||||
|
||||
return num_bits
|
||||
|
||||
@@ -4,7 +4,12 @@ import random
|
||||
|
||||
import pytest
|
||||
|
||||
from hdk.common.data_types.integers import Integer, SignedInteger, UnsignedInteger
|
||||
from hdk.common.data_types.integers import (
|
||||
Integer,
|
||||
SignedInteger,
|
||||
UnsignedInteger,
|
||||
make_integer_to_hold_ints,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -68,3 +73,40 @@ def test_basic_integers(integer: Integer, expected_min: int, expected_max: int):
|
||||
def test_integers_repr(integer: Integer, expected_repr_str: str):
|
||||
"""Test integer repr"""
|
||||
assert integer.__repr__() == expected_repr_str
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"values,force_signed,expected_result",
|
||||
[
|
||||
([0], False, Integer(1, is_signed=False)),
|
||||
([0], True, Integer(2, is_signed=True)),
|
||||
([1], False, Integer(1, is_signed=False)),
|
||||
([1], True, Integer(2, is_signed=True)),
|
||||
([-1], False, Integer(2, is_signed=True)),
|
||||
([-2], False, Integer(2, is_signed=True)),
|
||||
([0, 1], False, Integer(1, is_signed=False)),
|
||||
([0, 1], True, Integer(2, is_signed=True)),
|
||||
([7], False, Integer(3, is_signed=False)),
|
||||
([7], True, Integer(4, is_signed=True)),
|
||||
([8], False, Integer(4, is_signed=False)),
|
||||
([8], True, Integer(5, is_signed=True)),
|
||||
([-7], False, Integer(4, is_signed=True)),
|
||||
([-8], False, Integer(4, is_signed=True)),
|
||||
([-7, -8], False, Integer(4, is_signed=True)),
|
||||
([-9], False, Integer(5, is_signed=True)),
|
||||
([-9], True, Integer(5, is_signed=True)),
|
||||
([0, 127], False, Integer(7, is_signed=False)),
|
||||
([0, 127], True, Integer(8, is_signed=True)),
|
||||
([0, 128], False, Integer(8, is_signed=False)),
|
||||
([0, 128], True, Integer(9, is_signed=True)),
|
||||
([-1, 127], False, Integer(8, is_signed=True)),
|
||||
([-256, 127], False, Integer(9, is_signed=True)),
|
||||
([-128, 127], False, Integer(8, is_signed=True)),
|
||||
([-128, 128], False, Integer(9, is_signed=True)),
|
||||
([-13, 4], False, Integer(5, is_signed=True)),
|
||||
([42, 1019], False, Integer(10, is_signed=False)),
|
||||
],
|
||||
)
|
||||
def test_make_integer_to_hold(values, force_signed, expected_result):
|
||||
"""Test make_integer_to_hold"""
|
||||
assert expected_result == make_integer_to_hold_ints(values, force_signed)
|
||||
|
||||
Reference in New Issue
Block a user