Skip to content

BioCompiler API

pykoppu.biocompiler.compiler.BioCompiler

Compiler for translating problems into BioASM instructions.

Source code in pykoppu/biocompiler/compiler.py
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
class BioCompiler:
    """
    Compiler for translating problems into BioASM instructions.
    """

    def __init__(self):
        pass

    def compile(self, problem: Any, strategy: str = "annealing", duration: float = 1000.0) -> List[Instruction]:
        """
        Compile a problem into a sequence of instructions.

        Args:
            problem: The problem instance (must have J and h attributes).
            strategy (str): The compilation strategy. Defaults to "annealing".
            duration (float): Total simulation duration in milliseconds. Defaults to 1000.0.

        Returns:
            List[Instruction]: The sequence of BioASM instructions.
        """
        instructions = []

        # 1. Allocate resources
        # Assuming problem has 'num_variables' or we infer from J
        num_vars = problem.J.shape[0]
        instructions.append(Instruction(OpCode.ALC, [num_vars]))

        # 2. Load Hamiltonian (J and h)
        # We pass the raw data as operands (simplified for this implementation)
        instructions.append(Instruction(OpCode.LDJ, [problem.J.tolist()]))
        instructions.append(Instruction(OpCode.LDH, [problem.h.tolist()]))

        # 3. Apply Strategy
        # Convert duration from ms to seconds
        total_duration_sec = duration / 1000.0

        if strategy == "annealing":
            # Generate SIG instructions: High -> Medium -> Low
            # Increased noise levels to promote activity and break symmetry
            noise_schedule = [10.0e-3, 5.0e-3, 2.0e-3] # 10mV, 5mV, 2mV

            # Divide total duration equally among steps
            step_duration = total_duration_sec / len(noise_schedule)

            for sigma in noise_schedule:
                instructions.append(Instruction(OpCode.SIG, [sigma]))
                instructions.append(Instruction(OpCode.RUN, [step_duration]))

        else:
            # Default single run
            instructions.append(Instruction(OpCode.SIG, [2.0e-3]))
            instructions.append(Instruction(OpCode.RUN, [total_duration_sec]))

        # 4. Read Result
        instructions.append(Instruction(OpCode.RD, []))

        return instructions

compile(problem, strategy='annealing', duration=1000.0)

Compile a problem into a sequence of instructions.

Parameters:

Name Type Description Default
problem Any

The problem instance (must have J and h attributes).

required
strategy str

The compilation strategy. Defaults to "annealing".

'annealing'
duration float

Total simulation duration in milliseconds. Defaults to 1000.0.

1000.0

Returns:

Type Description
List[Instruction]

List[Instruction]: The sequence of BioASM instructions.

Source code in pykoppu/biocompiler/compiler.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
def compile(self, problem: Any, strategy: str = "annealing", duration: float = 1000.0) -> List[Instruction]:
    """
    Compile a problem into a sequence of instructions.

    Args:
        problem: The problem instance (must have J and h attributes).
        strategy (str): The compilation strategy. Defaults to "annealing".
        duration (float): Total simulation duration in milliseconds. Defaults to 1000.0.

    Returns:
        List[Instruction]: The sequence of BioASM instructions.
    """
    instructions = []

    # 1. Allocate resources
    # Assuming problem has 'num_variables' or we infer from J
    num_vars = problem.J.shape[0]
    instructions.append(Instruction(OpCode.ALC, [num_vars]))

    # 2. Load Hamiltonian (J and h)
    # We pass the raw data as operands (simplified for this implementation)
    instructions.append(Instruction(OpCode.LDJ, [problem.J.tolist()]))
    instructions.append(Instruction(OpCode.LDH, [problem.h.tolist()]))

    # 3. Apply Strategy
    # Convert duration from ms to seconds
    total_duration_sec = duration / 1000.0

    if strategy == "annealing":
        # Generate SIG instructions: High -> Medium -> Low
        # Increased noise levels to promote activity and break symmetry
        noise_schedule = [10.0e-3, 5.0e-3, 2.0e-3] # 10mV, 5mV, 2mV

        # Divide total duration equally among steps
        step_duration = total_duration_sec / len(noise_schedule)

        for sigma in noise_schedule:
            instructions.append(Instruction(OpCode.SIG, [sigma]))
            instructions.append(Instruction(OpCode.RUN, [step_duration]))

    else:
        # Default single run
        instructions.append(Instruction(OpCode.SIG, [2.0e-3]))
        instructions.append(Instruction(OpCode.RUN, [total_duration_sec]))

    # 4. Read Result
    instructions.append(Instruction(OpCode.RD, []))

    return instructions

pykoppu.biocompiler.isa.OpCode

Bases: Enum

BioASM Operation Codes.

Source code in pykoppu/biocompiler/isa.py
11
12
13
14
15
16
17
18
19
20
21
class OpCode(Enum):
    """
    BioASM Operation Codes.
    """
    ALC = auto()  # Allocate resources
    LDJ = auto()  # Load Coupling Matrix (J)
    LDH = auto()  # Load Bias Vector (h)
    SIG = auto()  # Set Noise Level (Sigma)
    RUN = auto()  # Run Simulation
    RST = auto()  # Reset State
    RD  = auto()  # Read State

pykoppu.biocompiler.isa.Instruction dataclass

A single BioASM instruction.

Source code in pykoppu/biocompiler/isa.py
23
24
25
26
27
28
29
30
31
32
33
@dataclass
class Instruction:
    """
    A single BioASM instruction.
    """
    opcode: OpCode
    operands: List[Union[int, float, str, list]]

    def __repr__(self) -> str:
        ops = ", ".join(map(str, self.operands))
        return f"{self.opcode.name} {ops}"