def ising_energy(sample, h, J, offset=0.0):
    """Calculate the energy for the specified sample of an Ising model.

    Energy of a sample for a binary quadratic model is defined as a sum, offset
    by the constant energy offset associated with the model, of
    the sample multipled by the linear bias of the variable and
    all its interactions. For an Ising model,

    .. math::

        E(\\mathbf{s}) = \\sum_v h_v s_v + \\sum_{u,v} J_{u,v} s_u s_v + c

    where :math:`s_v` is the sample, :math:`h_v` is the linear bias, :math:`J_{u,v}`
    the quadratic bias (interactions), and :math:`c` the energy offset.

    Args:
        sample (dict[variable, spin]):
            Sample for a binary quadratic model as a dict of form {v: spin, ...},
            where keys are variables of the model and values are spins (either -1 or 1).
        h (dict[variable, bias]):
            Linear biases as a dict of the form {v: bias, ...}, where keys are variables of
            the model and values are biases.
        J (dict[(variable, variable), bias]):
           Quadratic biases as a dict of the form {(u, v): bias, ...}, where keys
           are 2-tuples of variables of the model and values are quadratic biases
           associated with the pair of variables (the interaction).
        offset (numeric, optional, default=0):
            Constant offset to be applied to the energy. Default 0.

    Returns:
        float: The induced energy.

    Notes:
        No input checking is performed.

    Examples:
        This example calculates the energy of a sample representing two down spins for
        an Ising model of two variables that have positive biases of value 1 and
        are positively coupled with an interaction of value 1.

        >>> import dimod
        >>> sample = {1: -1, 2: -1}
        >>> h = {1: 1, 2: 1}
        >>> J = {(1, 2): 1}
        >>> dimod.ising_energy(sample, h, J, 0.5)
        -0.5

    References
    ----------

    `Ising model on Wikipedia <https://en.wikipedia.org/wiki/Ising_model>`_

    """
    for v in h:
        offset += h[v] * sample[v]
    for v0, v1 in J:
        offset += J[v0, v1] * sample[v0] * sample[v1]
    return offset
