code: def _noise_model_program_header(noise_model):
      
      from pyquil.quil import Program
      p = Program()
      defgates = set()
      for k in noise_model.gates:
  
          # obtain ideal gate matrix and new, noisy name by looking it up in the NOISY_GATES dict
          try:
              ideal_gate, new_name = get_noisy_gate(k.gate, tuple(k.params))
  
              # if ideal version of gate has not yet been DEFGATE'd, do this
              if new_name not in defgates:
                  p.defgate(new_name, ideal_gate)
                  defgates.add(new_name)
          except NoisyGateUndefined:
              print("WARNING: Could not find ideal gate definition for gate {}".format(k.gate),
                    file=sys.stderr)
              new_name = k.gate
  
          # define noisy version of gate on specific targets
          p.define_noisy_gate(new_name, k.targets, k.kraus_ops)
  
      # define noisy readouts
      for q, ap in noise_model.assignment_probs.items():
          p.define_noisy_readout(q, p00=ap[0, 0], p11=ap[1, 1])
      return p
docs: Generate the header for a pyquil Program that uses ``noise_model`` to overload noisy gates.
      The program header consists of 3 sections:
  
          - The ``DEFGATE`` statements that define the meaning of the newly introduced "noisy" gate
            names.
          - The ``PRAGMA ADD-KRAUS`` statements to overload these noisy gates on specific qubit
            targets with their noisy implementation.
          - THe ``PRAGMA READOUT-POVM`` statements that define the noisy readout per qubit.
  
      :param NoiseModel noise_model: The assumed noise model.
      :return: A quil Program with the noise pragmas.
      :rtype: pyquil.quil.Program