Overview¶
| Class | Description |
|---|---|
BinaryExpr | |
BinaryModel | |
BinarySampleSet | |
VarType |
Functions¶
binary [source]¶
def binary(index: int) -> BinaryExpr[VarType]Create a binary variable expression.
Parameters:
| Name | Type | Description |
|---|---|---|
index | int | The index of the binary variable. |
Returns:
BinaryExpr[VarType] — BinaryExpr[VarType.BINARY]: The binary variable expression.
spin [source]¶
def spin(index: int) -> BinaryExpr[VarType]Create a spin variable expression.
Parameters:
| Name | Type | Description |
|---|---|---|
index | int | The index of the spin variable. |
Returns:
BinaryExpr[VarType] — BinaryExpr[VarType.SPIN]: The spin variable expression.
Classes¶
BinaryExpr [source]¶
class BinaryExpr(Generic[VT])Constructor¶
def __init__(
self,
vartype: VT = VarType.BINARY,
constant: float = 0.0,
coefficients: dict[tuple[int, ...], float] = dict(),
) -> NoneAttributes¶
coefficients: dict[tuple[int, ...], float]constant: floatvartype: VT
Methods¶
copy¶
def copy(self) -> BinaryExpr[VT]reduce_indices¶
@staticmethod
def reduce_indices(vartype: VarType, inds: tuple[int, ...]) -> tuple[int, ...]Apply vartype-specific idempotency rules to a term’s index tuple.
Encodes the algebraic identity for each variable type so that
repeated indices within a single product collapse to a canonical
sorted tuple. Shared between in-place multiplication of
:class:BinaryExpr and the higher-order factory constructors on
:class:BinaryModel so the reduction semantics stay consistent.
Parameters:
| Name | Type | Description |
|---|---|---|
vartype | VarType | The variable type whose idempotency rule applies. SPIN uses s_i**2 = 1 (pairs of identical indices cancel); BINARY uses x_i**2 = x_i (duplicates collapse to a single occurrence). |
inds | tuple[int, ...] | Index tuple to reduce. Order is irrelevant — the returned tuple is always sorted ascending. |
Returns:
int — tuple[int, ...]: The reduced, sorted index tuple. Can be
... — empty if every index in inds cancels (SPIN, even counts
tuple[int, ...] — for all indices).
Raises:
ValueError— Ifvartypeis not a recognized :class:VarTypemember.
BinaryModel [source]¶
class BinaryModel(Generic[VT])Constructor¶
def __init__(self, expr: BinaryExpr[VT]) -> NoneAttributes¶
coefficients: dict[tuple[int, ...], float] All coefficients as a single flat dictionary using sequential indices.constant: floathigher: dict[tuple[int, ...], float]index_new_to_originindex_origin_to_newlinear: dict[int, float]num_bits: intorderquad: dict[tuple[int, int], float]vartype: VT
Methods¶
calc_energy¶
def calc_energy(self, state: list[int]) -> floatCalculate the energy for a given variable assignment.
Parameters:
| Name | Type | Description |
|---|---|---|
state | list[int] | Variable values indexed by sequential (zero-origin) indices. For SPIN: values must be +1 or -1. For BINARY: values must be 0 or 1. |
Returns:
float — The energy value.
Raises:
ValueError— If state values are invalid for the vartype.
change_vartype¶
def change_vartype(self, vartype: VarType) -> 'BinaryModel'decode_from_sampleresult¶
def decode_from_sampleresult(self, result: SampleResult[list[int]]) -> BinarySampleSet[VT]Decode quantum measurement results into samples with energies.
Converts raw measurement bitstrings (0/1 from quantum hardware) into the model’s variable domain and calculates energies.
Parameters:
| Name | Type | Description |
|---|---|---|
result | SampleResult[list[int]] | Measurement results with sequential bit indices |
Returns:
BinarySampleSet[VT] — BinarySampleSet with samples in expression domain, using original indices
from_higher_ising¶
@classmethod
def from_higher_ising(
cls,
higher_ising: dict[tuple[int, ...], float],
constant: float = 0.0,
simplify: bool = False,
) -> 'BinaryModel'Create a SPIN BinaryModel from higher-order Ising coefficients.
Accepts Ising-style terms of arbitrary order (linear, quadratic, cubic,
quartic, and beyond) in a single coefficient dictionary. Duplicate
indices within a term are reduced using the identity s_i**2 = 1
for SPIN variables: each pair of repeated indices cancels to a
constant factor, so e.g. (0, 0, 2) becomes (2,) and
(0, 0, 1, 1, 2) becomes (2,). A warning is emitted whenever
such reduction occurs.
Parameters:
| Name | Type | Description |
|---|---|---|
higher_ising | dict[tuple[int, ...], float] | Higher-order Ising coefficients mapping index tuples to SPIN interaction strengths. Index tuples are sorted; repeated indices are reduced via s_i**2 = 1. Empty tuples (()) are accumulated into the constant term. |
constant | float | Constant offset term. Defaults to 0.0. |
simplify | bool | If True, remove near-zero coefficients after accumulation. Defaults to False. |
Returns:
'BinaryModel' — BinaryModel with SPIN vartype whose coefficients encode the
'BinaryModel' — supplied higher-order Ising terms.
Example:
>>> model = BinaryModel.from_higher_ising(
... {(0,): 1.0, (0, 1): -2.0, (0, 1, 2): 0.5},
... constant=0.25,
... )
>>> model.vartype
<VarType.SPIN: 'SPIN'>from_hubo¶
@classmethod
def from_hubo(
cls,
hubo: dict[tuple[int, ...], float],
constant: float = 0.0,
simplify: bool = False,
) -> 'BinaryModel'Create a BINARY BinaryModel from HUBO coefficients.
Parameters:
| Name | Type | Description |
|---|---|---|
hubo | dict[tuple[int, ...], float] | HUBO coefficients mapping index tuples to values. Index tuples are sorted and deduplicated. Duplicate indices in a single term (e.g., (0, 0, 2)) emit a warning and are normalized to unique indices ((0, 2)). Empty tuples (()) are accumulated into the constant term. |
constant | float | Constant offset term. |
simplify | bool | If True, remove near-zero coefficients. |
Returns:
'BinaryModel' — BinaryModel with BINARY vartype.
from_ising¶
@classmethod
def from_ising(
cls,
linear: dict[int, float],
quad: dict[tuple[int, int], float],
constant: float = 0.0,
simplify: bool = False,
) -> 'BinaryModel'from_qubo¶
@classmethod
def from_qubo(
cls,
qubo: dict[tuple[int, int], float],
constant: float = 0.0,
simplify: bool = False,
) -> 'BinaryModel'normalize_by_abs_max¶
def normalize_by_abs_max(self, replace: bool = False) -> BinaryModel[VT]Normalize the BinaryModel by its absolute maximum coefficient.
Returns:
BinaryModel[VT] — BinaryModel[VT]: The normalized binary model.
normalize_by_factor¶
def normalize_by_factor(self, factor: float, replace: bool = False) -> BinaryModel[VT]Normalize the BinaryModel by a given factor.
Parameters:
| Name | Type | Description |
|---|---|---|
factor | float | The normalization factor. |
Returns:
BinaryModel[VT] — BinaryModel[VT]: The normalized binary model.
normalize_by_rms¶
def normalize_by_rms(self, replace: bool = False) -> BinaryModel[VT]Normalize the BinaryModel by its root mean square.
Returns:
BinaryModel[VT] — BinaryModel[VT]: The normalized binary model.
BinarySampleSet [source]¶
class BinarySampleSet(Generic[VT])Constructor¶
def __init__(
self,
samples: list[dict[int, int]],
num_occurrences: list[int],
energy: list[float],
vartype: VT = VarType.BINARY,
) -> NoneAttributes¶
energy: list[float]num_occurrences: list[int]samples: list[dict[int, int]]vartype: VT
Methods¶
energy_mean¶
def energy_mean(self) -> floatlowest¶
def lowest(self) -> tuple[dict[int, int], float, int]VarType [source]¶
class VarType(enum.StrEnum)Attributes¶
BINARYSPIN
qamomile.optimization.binary_model.expr¶
Overview¶
| Function | Description |
|---|---|
binary | Create a binary variable expression. |
is_close_zero | Check if a given floating-point value is close to zero within a small tolerance. |
spin | Create a spin variable expression. |
| Class | Description |
|---|---|
BinaryExpr | |
VarType |
Functions¶
binary [source]¶
def binary(index: int) -> BinaryExpr[VarType]Create a binary variable expression.
Parameters:
| Name | Type | Description |
|---|---|---|
index | int | The index of the binary variable. |
Returns:
BinaryExpr[VarType] — BinaryExpr[VarType.BINARY]: The binary variable expression.
is_close_zero [source]¶
def is_close_zero(value: float, abs_tol: float = 1e-15) -> boolCheck if a given floating-point value is close to zero within a small tolerance.
Parameters:
| Name | Type | Description |
|---|---|---|
value | float | The floating-point value to check. |
abs_tol | float | Absolute tolerance passed to :func:math.isclose. Defaults to 1e-15. |
Returns:
bool — True if the value is close to zero, False otherwise.
spin [source]¶
def spin(index: int) -> BinaryExpr[VarType]Create a spin variable expression.
Parameters:
| Name | Type | Description |
|---|---|---|
index | int | The index of the spin variable. |
Returns:
BinaryExpr[VarType] — BinaryExpr[VarType.SPIN]: The spin variable expression.
Classes¶
BinaryExpr [source]¶
class BinaryExpr(Generic[VT])Constructor¶
def __init__(
self,
vartype: VT = VarType.BINARY,
constant: float = 0.0,
coefficients: dict[tuple[int, ...], float] = dict(),
) -> NoneAttributes¶
coefficients: dict[tuple[int, ...], float]constant: floatvartype: VT
Methods¶
copy¶
def copy(self) -> BinaryExpr[VT]reduce_indices¶
@staticmethod
def reduce_indices(vartype: VarType, inds: tuple[int, ...]) -> tuple[int, ...]Apply vartype-specific idempotency rules to a term’s index tuple.
Encodes the algebraic identity for each variable type so that
repeated indices within a single product collapse to a canonical
sorted tuple. Shared between in-place multiplication of
:class:BinaryExpr and the higher-order factory constructors on
:class:BinaryModel so the reduction semantics stay consistent.
Parameters:
| Name | Type | Description |
|---|---|---|
vartype | VarType | The variable type whose idempotency rule applies. SPIN uses s_i**2 = 1 (pairs of identical indices cancel); BINARY uses x_i**2 = x_i (duplicates collapse to a single occurrence). |
inds | tuple[int, ...] | Index tuple to reduce. Order is irrelevant — the returned tuple is always sorted ascending. |
Returns:
int — tuple[int, ...]: The reduced, sorted index tuple. Can be
... — empty if every index in inds cancels (SPIN, even counts
tuple[int, ...] — for all indices).
Raises:
ValueError— Ifvartypeis not a recognized :class:VarTypemember.
VarType [source]¶
class VarType(enum.StrEnum)Attributes¶
BINARYSPIN
qamomile.optimization.binary_model.model¶
Overview¶
| Function | Description |
|---|---|
is_close_zero | Check if a given floating-point value is close to zero within a small tolerance. |
normalize_by_abs_max | Normalize the BinaryExpr by its absolute maximum coefficient. |
normalize_by_factor | Normalize the BinaryExpr by a given factor. |
normalize_by_rms | Normalize coefficients by the root mean square. |
| Class | Description |
|---|---|
BinaryExpr | |
BinaryModel | |
BinarySampleSet | |
SampleResult | Result of a sample() execution. |
VarType |
Functions¶
is_close_zero [source]¶
def is_close_zero(value: float, abs_tol: float = 1e-15) -> boolCheck if a given floating-point value is close to zero within a small tolerance.
Parameters:
| Name | Type | Description |
|---|---|---|
value | float | The floating-point value to check. |
abs_tol | float | Absolute tolerance passed to :func:math.isclose. Defaults to 1e-15. |
Returns:
bool — True if the value is close to zero, False otherwise.
normalize_by_abs_max [source]¶
def normalize_by_abs_max(model: BinaryExpr, replace: bool = False) -> BinaryExprNormalize the BinaryExpr by its absolute maximum coefficient.
Parameters:
| Name | Type | Description |
|---|---|---|
model | BinaryExpr | The binary expression to be normalized. |
Returns:
BinaryExpr — The normalized binary expression.
normalize_by_factor [source]¶
def normalize_by_factor(model: BinaryExpr, factor: float, replace: bool = False) -> BinaryExprNormalize the BinaryExpr by a given factor.
Parameters:
| Name | Type | Description |
|---|---|---|
model | BinaryExpr | The binary expression to be normalized. |
factor | float | The normalization factor. |
Returns:
BinaryExpr — The normalized binary expression.
normalize_by_rms [source]¶
def normalize_by_rms(expr: BinaryExpr, replace: bool = False) -> BinaryExprNormalize coefficients by the root mean square.
The coefficients for normalized is defined as:
where w are coefficients and their subscriptions imply a term to be applied. E_i are the number of i-th order terms. We normalize the Ising Hamiltonian as
This method is proposed in [Sureshbabu2024parametersettingin]
Classes¶
BinaryExpr [source]¶
class BinaryExpr(Generic[VT])Constructor¶
def __init__(
self,
vartype: VT = VarType.BINARY,
constant: float = 0.0,
coefficients: dict[tuple[int, ...], float] = dict(),
) -> NoneAttributes¶
coefficients: dict[tuple[int, ...], float]constant: floatvartype: VT
Methods¶
copy¶
def copy(self) -> BinaryExpr[VT]reduce_indices¶
@staticmethod
def reduce_indices(vartype: VarType, inds: tuple[int, ...]) -> tuple[int, ...]Apply vartype-specific idempotency rules to a term’s index tuple.
Encodes the algebraic identity for each variable type so that
repeated indices within a single product collapse to a canonical
sorted tuple. Shared between in-place multiplication of
:class:BinaryExpr and the higher-order factory constructors on
:class:BinaryModel so the reduction semantics stay consistent.
Parameters:
| Name | Type | Description |
|---|---|---|
vartype | VarType | The variable type whose idempotency rule applies. SPIN uses s_i**2 = 1 (pairs of identical indices cancel); BINARY uses x_i**2 = x_i (duplicates collapse to a single occurrence). |
inds | tuple[int, ...] | Index tuple to reduce. Order is irrelevant — the returned tuple is always sorted ascending. |
Returns:
int — tuple[int, ...]: The reduced, sorted index tuple. Can be
... — empty if every index in inds cancels (SPIN, even counts
tuple[int, ...] — for all indices).
Raises:
ValueError— Ifvartypeis not a recognized :class:VarTypemember.
BinaryModel [source]¶
class BinaryModel(Generic[VT])Constructor¶
def __init__(self, expr: BinaryExpr[VT]) -> NoneAttributes¶
coefficients: dict[tuple[int, ...], float] All coefficients as a single flat dictionary using sequential indices.constant: floathigher: dict[tuple[int, ...], float]index_new_to_originindex_origin_to_newlinear: dict[int, float]num_bits: intorderquad: dict[tuple[int, int], float]vartype: VT
Methods¶
calc_energy¶
def calc_energy(self, state: list[int]) -> floatCalculate the energy for a given variable assignment.
Parameters:
| Name | Type | Description |
|---|---|---|
state | list[int] | Variable values indexed by sequential (zero-origin) indices. For SPIN: values must be +1 or -1. For BINARY: values must be 0 or 1. |
Returns:
float — The energy value.
Raises:
ValueError— If state values are invalid for the vartype.
change_vartype¶
def change_vartype(self, vartype: VarType) -> 'BinaryModel'decode_from_sampleresult¶
def decode_from_sampleresult(self, result: SampleResult[list[int]]) -> BinarySampleSet[VT]Decode quantum measurement results into samples with energies.
Converts raw measurement bitstrings (0/1 from quantum hardware) into the model’s variable domain and calculates energies.
Parameters:
| Name | Type | Description |
|---|---|---|
result | SampleResult[list[int]] | Measurement results with sequential bit indices |
Returns:
BinarySampleSet[VT] — BinarySampleSet with samples in expression domain, using original indices
from_higher_ising¶
@classmethod
def from_higher_ising(
cls,
higher_ising: dict[tuple[int, ...], float],
constant: float = 0.0,
simplify: bool = False,
) -> 'BinaryModel'Create a SPIN BinaryModel from higher-order Ising coefficients.
Accepts Ising-style terms of arbitrary order (linear, quadratic, cubic,
quartic, and beyond) in a single coefficient dictionary. Duplicate
indices within a term are reduced using the identity s_i**2 = 1
for SPIN variables: each pair of repeated indices cancels to a
constant factor, so e.g. (0, 0, 2) becomes (2,) and
(0, 0, 1, 1, 2) becomes (2,). A warning is emitted whenever
such reduction occurs.
Parameters:
| Name | Type | Description |
|---|---|---|
higher_ising | dict[tuple[int, ...], float] | Higher-order Ising coefficients mapping index tuples to SPIN interaction strengths. Index tuples are sorted; repeated indices are reduced via s_i**2 = 1. Empty tuples (()) are accumulated into the constant term. |
constant | float | Constant offset term. Defaults to 0.0. |
simplify | bool | If True, remove near-zero coefficients after accumulation. Defaults to False. |
Returns:
'BinaryModel' — BinaryModel with SPIN vartype whose coefficients encode the
'BinaryModel' — supplied higher-order Ising terms.
Example:
>>> model = BinaryModel.from_higher_ising(
... {(0,): 1.0, (0, 1): -2.0, (0, 1, 2): 0.5},
... constant=0.25,
... )
>>> model.vartype
<VarType.SPIN: 'SPIN'>from_hubo¶
@classmethod
def from_hubo(
cls,
hubo: dict[tuple[int, ...], float],
constant: float = 0.0,
simplify: bool = False,
) -> 'BinaryModel'Create a BINARY BinaryModel from HUBO coefficients.
Parameters:
| Name | Type | Description |
|---|---|---|
hubo | dict[tuple[int, ...], float] | HUBO coefficients mapping index tuples to values. Index tuples are sorted and deduplicated. Duplicate indices in a single term (e.g., (0, 0, 2)) emit a warning and are normalized to unique indices ((0, 2)). Empty tuples (()) are accumulated into the constant term. |
constant | float | Constant offset term. |
simplify | bool | If True, remove near-zero coefficients. |
Returns:
'BinaryModel' — BinaryModel with BINARY vartype.
from_ising¶
@classmethod
def from_ising(
cls,
linear: dict[int, float],
quad: dict[tuple[int, int], float],
constant: float = 0.0,
simplify: bool = False,
) -> 'BinaryModel'from_qubo¶
@classmethod
def from_qubo(
cls,
qubo: dict[tuple[int, int], float],
constant: float = 0.0,
simplify: bool = False,
) -> 'BinaryModel'normalize_by_abs_max¶
def normalize_by_abs_max(self, replace: bool = False) -> BinaryModel[VT]Normalize the BinaryModel by its absolute maximum coefficient.
Returns:
BinaryModel[VT] — BinaryModel[VT]: The normalized binary model.
normalize_by_factor¶
def normalize_by_factor(self, factor: float, replace: bool = False) -> BinaryModel[VT]Normalize the BinaryModel by a given factor.
Parameters:
| Name | Type | Description |
|---|---|---|
factor | float | The normalization factor. |
Returns:
BinaryModel[VT] — BinaryModel[VT]: The normalized binary model.
normalize_by_rms¶
def normalize_by_rms(self, replace: bool = False) -> BinaryModel[VT]Normalize the BinaryModel by its root mean square.
Returns:
BinaryModel[VT] — BinaryModel[VT]: The normalized binary model.
BinarySampleSet [source]¶
class BinarySampleSet(Generic[VT])Constructor¶
def __init__(
self,
samples: list[dict[int, int]],
num_occurrences: list[int],
energy: list[float],
vartype: VT = VarType.BINARY,
) -> NoneAttributes¶
energy: list[float]num_occurrences: list[int]samples: list[dict[int, int]]vartype: VT
Methods¶
energy_mean¶
def energy_mean(self) -> floatlowest¶
def lowest(self) -> tuple[dict[int, int], float, int]SampleResult [source]¶
class SampleResult(Generic[T])Result of a sample() execution.
Contains results as a list of (value, count) tuples.
Example:
result.results # [(0.25, 500), (0.75, 500)]Constructor¶
def __init__(self, results: list[tuple[T, int]], shots: int) -> NoneAttributes¶
results: list[tuple[T, int]] List of (value, count) tuples.shots: int Total number of shots executed.
Methods¶
most_common¶
def most_common(self, n: int = 1) -> list[tuple[T, int]]Return the n most common results.
Parameters:
| Name | Type | Description |
|---|---|---|
n | int | Number of results to return. |
Returns:
list[tuple[T, int]] — List of (result, count) tuples sorted by count descending.
probabilities¶
def probabilities(self) -> list[tuple[T, float]]Return probability distribution over results.
Returns:
list[tuple[T, float]] — List of (value, probability) tuples.
VarType [source]¶
class VarType(enum.StrEnum)Attributes¶
BINARYSPIN
qamomile.optimization.binary_model.normalize¶
Overview¶
| Function | Description |
|---|---|
normalize_by_abs_max | Normalize the BinaryExpr by its absolute maximum coefficient. |
normalize_by_factor | Normalize the BinaryExpr by a given factor. |
normalize_by_rms | Normalize coefficients by the root mean square. |
| Class | Description |
|---|---|
BinaryExpr |
Functions¶
normalize_by_abs_max [source]¶
def normalize_by_abs_max(model: BinaryExpr, replace: bool = False) -> BinaryExprNormalize the BinaryExpr by its absolute maximum coefficient.
Parameters:
| Name | Type | Description |
|---|---|---|
model | BinaryExpr | The binary expression to be normalized. |
Returns:
BinaryExpr — The normalized binary expression.
normalize_by_factor [source]¶
def normalize_by_factor(model: BinaryExpr, factor: float, replace: bool = False) -> BinaryExprNormalize the BinaryExpr by a given factor.
Parameters:
| Name | Type | Description |
|---|---|---|
model | BinaryExpr | The binary expression to be normalized. |
factor | float | The normalization factor. |
Returns:
BinaryExpr — The normalized binary expression.
normalize_by_rms [source]¶
def normalize_by_rms(expr: BinaryExpr, replace: bool = False) -> BinaryExprNormalize coefficients by the root mean square.
The coefficients for normalized is defined as:
where w are coefficients and their subscriptions imply a term to be applied. E_i are the number of i-th order terms. We normalize the Ising Hamiltonian as
This method is proposed in [Sureshbabu2024parametersettingin]
Classes¶
BinaryExpr [source]¶
class BinaryExpr(Generic[VT])Constructor¶
def __init__(
self,
vartype: VT = VarType.BINARY,
constant: float = 0.0,
coefficients: dict[tuple[int, ...], float] = dict(),
) -> NoneAttributes¶
coefficients: dict[tuple[int, ...], float]constant: floatvartype: VT
Methods¶
copy¶
def copy(self) -> BinaryExpr[VT]reduce_indices¶
@staticmethod
def reduce_indices(vartype: VarType, inds: tuple[int, ...]) -> tuple[int, ...]Apply vartype-specific idempotency rules to a term’s index tuple.
Encodes the algebraic identity for each variable type so that
repeated indices within a single product collapse to a canonical
sorted tuple. Shared between in-place multiplication of
:class:BinaryExpr and the higher-order factory constructors on
:class:BinaryModel so the reduction semantics stay consistent.
Parameters:
| Name | Type | Description |
|---|---|---|
vartype | VarType | The variable type whose idempotency rule applies. SPIN uses s_i**2 = 1 (pairs of identical indices cancel); BINARY uses x_i**2 = x_i (duplicates collapse to a single occurrence). |
inds | tuple[int, ...] | Index tuple to reduce. Order is irrelevant — the returned tuple is always sorted ascending. |
Returns:
int — tuple[int, ...]: The reduced, sorted index tuple. Can be
... — empty if every index in inds cancels (SPIN, even counts
tuple[int, ...] — for all indices).
Raises:
ValueError— Ifvartypeis not a recognized :class:VarTypemember.
qamomile.optimization.binary_model.sampleset¶
Overview¶
| Class | Description |
|---|---|
BinarySampleSet | |
VarType |
Classes¶
BinarySampleSet [source]¶
class BinarySampleSet(Generic[VT])Constructor¶
def __init__(
self,
samples: list[dict[int, int]],
num_occurrences: list[int],
energy: list[float],
vartype: VT = VarType.BINARY,
) -> NoneAttributes¶
energy: list[float]num_occurrences: list[int]samples: list[dict[int, int]]vartype: VT
Methods¶
energy_mean¶
def energy_mean(self) -> floatlowest¶
def lowest(self) -> tuple[dict[int, int], float, int]VarType [source]¶
class VarType(enum.StrEnum)Attributes¶
BINARYSPIN