We want to do :
c = ModuloCircuit()
a = c.write_element(0)
b = c.write_element(1)
d = a + b # Instead of d = circuit.add(a, b)
circuit.compile_circuit()
We can achieve it by adding the magic methods to the ModuloCircuitElement class and by adding the circuit they are tied to at initialization:
@dataclass(slots=True)
class ModuloCircuitElement:
"""
Represents an element within a modulo circuit with its associated offset.
Attributes:
emulated_felt (PyFelt): The emulated field element in the modulo circuit
offset (int): The offset in the values segment within the modulo circuit where the element is stored.
"""
emulated_felt: PyFelt
offset: int
circuit: ModuloCircuit
__repr__ = lambda self: f"ModuloCircuitElement({hex(self.value)}, {self.offset})"
@property
def value(self) -> int:
return self.emulated_felt.value
@property
def p(self) -> int:
return self.emulated_felt.p
@property
def felt(self) -> PyFelt:
return self.emulated_felt
def __add__(self, other: ModuloCircuitElement) -> ModuloCircuitElement:
return self.circuit.add(self, other)
def __neg__(self) -> ModuloCircuitElement:
return self.circuit.neg(self)
def __sub__(self, other: ModuloCircuitElement) -> ModuloCircuitElement:
return self.circuit.sub(self, other)
def __mul__(self, other: ModuloCircuitElement) -> ModuloCircuitElement:
return self.circuit.mul(self, other)
def __truediv__(self, other: ModuloCircuitElement) -> ModuloCircuitElement:
return self.circuit.div(self, other)
And then changing associated methods in ModuloCircuit :
def write_element(
self,
elmt: PyFelt | int,
write_source: WriteOps = WriteOps.INPUT,
instruction: ModuloCircuitInstruction | None = None,
) -> ModuloCircuitElement:
"""
Register an emulated field element to the circuit given its value and the write source.
Returns a ModuloCircuitElement representing the written element with its offset as identifier.
"""
assert isinstance(elmt, PyFelt) or isinstance(
elmt, int
), f"Expected PyFelt or int, got {type(elmt)}"
if isinstance(elmt, int):
elmt = self.field(elmt)
value_offset = self.values_segment.write_to_segment(
ValueSegmentItem(
elmt,
write_source,
instruction,
)
)
res = ModuloCircuitElement(elmt, value_offset, circuit=self)
return res
We add self.uuid = uuid.uuid4() on the init method the ModuloCircuit, and then on the basic add sub mul div methods of ModuloCircuit, we add the check
assert a.circuit.uuid == b.circuit.uuid, "Cannot multiply elements from different circuits"
However this leads to python cyclic imports and requires bigger refactor of the python package.
We want to do :
We can achieve it by adding the magic methods to the ModuloCircuitElement class and by adding the circuit they are tied to at initialization:
And then changing associated methods in ModuloCircuit :
We add
self.uuid = uuid.uuid4()on the init method the ModuloCircuit, and then on the basic add sub mul div methods of ModuloCircuit, we add the checkHowever this leads to python cyclic imports and requires bigger refactor of the python package.