Skip to content

LinearExpression

Bases: QuadraticProgramElement

Representation of a linear expression by its coefficients.

Source code in q3as/quadratic/problems/linear_expression.py
class LinearExpression(QuadraticProgramElement):
    """Representation of a linear expression by its coefficients."""

    def __init__(
        self,
        quadratic_program: Any,
        coefficients: Union[
            ndarray, spmatrix, List[float], Dict[Union[int, str], float]
        ],
    ) -> None:
        """Creates a new linear expression.

        The linear expression can be defined via an array, a list, a sparse matrix, or a dictionary
        that uses variable names or indices as keys and stores the values internally as a
        dok_matrix.

        Args:
            quadratic_program: The parent QuadraticProgram.
            coefficients: The (sparse) representation of the coefficients.

        """
        super().__init__(quadratic_program)
        self.coefficients = coefficients

    def __getitem__(self, i: Union[int, str]) -> float:
        """Returns the i-th coefficient where i can be a variable name or index.

        Args:
            i: the index or name of the variable corresponding to the coefficient.

        Returns:
            The coefficient corresponding to the addressed variable.
        """
        if isinstance(i, str):
            i = self.quadratic_program.variables_index[i]
        return self.coefficients[0, i]

    def __setitem__(self, i: Union[int, str], value: float) -> None:
        if isinstance(i, str):
            i = self.quadratic_program.variables_index[i]
        self._coefficients[0, i] = value

    def _coeffs_to_dok_matrix(
        self, coefficients: Union[ndarray, spmatrix, List, Dict[Union[int, str], float]]
    ) -> dok_matrix:
        """Maps given 1d-coefficients to a dok_matrix.

        Args:
            coefficients: The 1d-coefficients to be mapped.

        Returns:
            The given 1d-coefficients as a dok_matrix

        Raises:
            QiskitOptimizationError: if coefficients are given in unsupported format.
        """
        if (
            isinstance(coefficients, list)
            or isinstance(coefficients, ndarray)
            and len(coefficients.shape) == 1
        ):
            coefficients = dok_matrix([coefficients])
        elif isinstance(coefficients, spmatrix):
            coefficients = dok_matrix(coefficients)
        elif isinstance(coefficients, dict):
            coeffs = dok_matrix((1, self.quadratic_program.get_num_vars()))
            for index, value in coefficients.items():
                if isinstance(index, str):
                    index = self.quadratic_program.variables_index[index]
                coeffs[0, index] = value
            coefficients = coeffs
        else:
            raise QiskitOptimizationError("Unsupported format for coefficients.")
        return coefficients

    @property
    def coefficients(self) -> dok_matrix:
        """Returns the coefficients of the linear expression.

        Returns:
            The coefficients of the linear expression.
        """
        return self._coefficients

    @coefficients.setter
    def coefficients(
        self,
        coefficients: Union[
            ndarray, spmatrix, List[float], Dict[Union[str, int], float]
        ],
    ) -> None:
        """Sets the coefficients of the linear expression.

        Args:
            coefficients: The coefficients of the linear expression.
        """
        self._coefficients = self._coeffs_to_dok_matrix(coefficients)

    def to_array(self) -> ndarray:
        """Returns the coefficients of the linear expression as array.

        Returns:
            An array with the coefficients corresponding to the linear expression.
        """
        return self._coefficients.toarray()[0]

    def to_dict(self, use_name: bool = False) -> Dict[Union[int, str], float]:
        """Returns the coefficients of the linear expression as dictionary, either using variable
        names or indices as keys.

        Args:
            use_name: Determines whether to use index or names to refer to variables.

        Returns:
            An dictionary with the coefficients corresponding to the linear expression.
        """
        if use_name:
            return {
                self.quadratic_program.variables[k].name: v
                for (_, k), v in self._coefficients.items()
            }
        else:
            return {k: v for (_, k), v in self._coefficients.items()}

    def evaluate(self, x: Union[ndarray, List, Dict[Union[int, str], float]]) -> float:
        """Evaluate the linear expression for given variables.

        Args:
            x: The values of the variables to be evaluated.

        Returns:
            The value of the linear expression given the variable values.
        """
        # cast input to dok_matrix if it is a dictionary
        x = self._coeffs_to_dok_matrix(x)

        # compute the dot-product of the input and the linear coefficients
        val = (x @ self.coefficients.transpose())[0, 0]

        # return the result
        return val

    # pylint: disable=unused-argument
    def evaluate_gradient(
        self, x: Union[ndarray, List, Dict[Union[int, str], float]]
    ) -> ndarray:
        """Evaluate the gradient of the linear expression for given variables.

        Args:
            x: The values of the variables to be evaluated.

        Returns:
            The value of the gradient of the linear expression given the variable values.
        """

        # extract the coefficients as array and return it
        return self.to_array()

    @property
    def bounds(self) -> ExpressionBounds:
        """Returns the lower bound and the upper bound of the linear expression

        Returns:
            The lower bound and the upper bound of the linear expression

        Raises:
            QiskitOptimizationError: if the linear expression contains any unbounded variable

        """
        l_b = u_b = 0.0
        for ind, coeff in self.to_dict().items():
            x = self.quadratic_program.get_variable(ind)
            if x.lowerbound == -INFINITY or x.upperbound == INFINITY:
                raise QiskitOptimizationError(
                    f"Linear expression contains an unbounded variable: {x.name}"
                )
            lst = [coeff * x.lowerbound, coeff * x.upperbound]
            l_b += min(lst)
            u_b += max(lst)
        return ExpressionBounds(lowerbound=l_b, upperbound=u_b)

    def __repr__(self):
        # pylint: disable=cyclic-import
        from ..translators.prettyprint import expr2str, DEFAULT_TRUNCATE

        return f"<{self.__class__.__name__}: {expr2str(linear=self, truncate=DEFAULT_TRUNCATE)}>"

    def __str__(self):
        # pylint: disable=cyclic-import
        from ..translators.prettyprint import expr2str

        return f"{expr2str(linear=self)}"

bounds: ExpressionBounds property

Returns the lower bound and the upper bound of the linear expression

Returns:

Type Description
ExpressionBounds

The lower bound and the upper bound of the linear expression

Raises:

Type Description
QiskitOptimizationError

if the linear expression contains any unbounded variable

coefficients: dok_matrix property writable

Returns the coefficients of the linear expression.

Returns:

Type Description
dok_matrix

The coefficients of the linear expression.

__getitem__(i)

Returns the i-th coefficient where i can be a variable name or index.

Parameters:

Name Type Description Default
i Union[int, str]

the index or name of the variable corresponding to the coefficient.

required

Returns:

Type Description
float

The coefficient corresponding to the addressed variable.

Source code in q3as/quadratic/problems/linear_expression.py
def __getitem__(self, i: Union[int, str]) -> float:
    """Returns the i-th coefficient where i can be a variable name or index.

    Args:
        i: the index or name of the variable corresponding to the coefficient.

    Returns:
        The coefficient corresponding to the addressed variable.
    """
    if isinstance(i, str):
        i = self.quadratic_program.variables_index[i]
    return self.coefficients[0, i]

__init__(quadratic_program, coefficients)

Creates a new linear expression.

The linear expression can be defined via an array, a list, a sparse matrix, or a dictionary that uses variable names or indices as keys and stores the values internally as a dok_matrix.

Parameters:

Name Type Description Default
quadratic_program Any

The parent QuadraticProgram.

required
coefficients Union[ndarray, spmatrix, List[float], Dict[Union[int, str], float]]

The (sparse) representation of the coefficients.

required
Source code in q3as/quadratic/problems/linear_expression.py
def __init__(
    self,
    quadratic_program: Any,
    coefficients: Union[
        ndarray, spmatrix, List[float], Dict[Union[int, str], float]
    ],
) -> None:
    """Creates a new linear expression.

    The linear expression can be defined via an array, a list, a sparse matrix, or a dictionary
    that uses variable names or indices as keys and stores the values internally as a
    dok_matrix.

    Args:
        quadratic_program: The parent QuadraticProgram.
        coefficients: The (sparse) representation of the coefficients.

    """
    super().__init__(quadratic_program)
    self.coefficients = coefficients

evaluate(x)

Evaluate the linear expression for given variables.

Parameters:

Name Type Description Default
x Union[ndarray, List, Dict[Union[int, str], float]]

The values of the variables to be evaluated.

required

Returns:

Type Description
float

The value of the linear expression given the variable values.

Source code in q3as/quadratic/problems/linear_expression.py
def evaluate(self, x: Union[ndarray, List, Dict[Union[int, str], float]]) -> float:
    """Evaluate the linear expression for given variables.

    Args:
        x: The values of the variables to be evaluated.

    Returns:
        The value of the linear expression given the variable values.
    """
    # cast input to dok_matrix if it is a dictionary
    x = self._coeffs_to_dok_matrix(x)

    # compute the dot-product of the input and the linear coefficients
    val = (x @ self.coefficients.transpose())[0, 0]

    # return the result
    return val

evaluate_gradient(x)

Evaluate the gradient of the linear expression for given variables.

Parameters:

Name Type Description Default
x Union[ndarray, List, Dict[Union[int, str], float]]

The values of the variables to be evaluated.

required

Returns:

Type Description
ndarray

The value of the gradient of the linear expression given the variable values.

Source code in q3as/quadratic/problems/linear_expression.py
def evaluate_gradient(
    self, x: Union[ndarray, List, Dict[Union[int, str], float]]
) -> ndarray:
    """Evaluate the gradient of the linear expression for given variables.

    Args:
        x: The values of the variables to be evaluated.

    Returns:
        The value of the gradient of the linear expression given the variable values.
    """

    # extract the coefficients as array and return it
    return self.to_array()

to_array()

Returns the coefficients of the linear expression as array.

Returns:

Type Description
ndarray

An array with the coefficients corresponding to the linear expression.

Source code in q3as/quadratic/problems/linear_expression.py
def to_array(self) -> ndarray:
    """Returns the coefficients of the linear expression as array.

    Returns:
        An array with the coefficients corresponding to the linear expression.
    """
    return self._coefficients.toarray()[0]

to_dict(use_name=False)

Returns the coefficients of the linear expression as dictionary, either using variable names or indices as keys.

Parameters:

Name Type Description Default
use_name bool

Determines whether to use index or names to refer to variables.

False

Returns:

Type Description
Dict[Union[int, str], float]

An dictionary with the coefficients corresponding to the linear expression.

Source code in q3as/quadratic/problems/linear_expression.py
def to_dict(self, use_name: bool = False) -> Dict[Union[int, str], float]:
    """Returns the coefficients of the linear expression as dictionary, either using variable
    names or indices as keys.

    Args:
        use_name: Determines whether to use index or names to refer to variables.

    Returns:
        An dictionary with the coefficients corresponding to the linear expression.
    """
    if use_name:
        return {
            self.quadratic_program.variables[k].name: v
            for (_, k), v in self._coefficients.items()
        }
    else:
        return {k: v for (_, k), v in self._coefficients.items()}