def get_energy_estimate(stats, hw):
    """
    Estimate the energy consumption in picojoules of a given computation on
    given hardware.

    ASSUMPTIONS:
    * Weights are read from DRAM exactly once.
    * Input activations are read from DRAM exactly once.
    * Output activations are written to DRAM exactly once.

    :param stats: a StatsRecorder containing details of the computation.
    :param hw: a HardwareModel containing details of the processor.
    """
    total = 0.0

    if hw.compress_sparse_weights:
        total += hw.memory_cost * stats.non_zero_parameters
    else:
        total += hw.memory_cost * stats.total_parameters

    if hw.compress_sparse_activations:
        total += hw.memory_cost * (stats.non_zero_input_activations +
                                   stats.non_zero_output_activations)
    else:
        total += hw.memory_cost * (stats.total_input_activations +
                                   stats.total_output_activations)

    compute_fraction = 1.0

    if hw.compute_skip_zero_weights:
        compute_fraction *= (stats.non_zero_parameters / stats.total_parameters)

    if hw.compute_skip_zero_activations:
        compute_fraction *= (stats.non_zero_input_activations /
                             stats.total_input_activations)

    total += compute_fraction * stats.computations * hw.compute_cost

    return total