docs: def hhl_circuit(A, C, t, register_size, *input_prep_gates):
      """
      Constructs the HHL circuit.
  
      A is the input Hermitian matrix.
      C and t are tunable parameters for the algorithm.
      register_size is the size of the eigenvalue register.
      input_prep_gates is a list of gates to be applied to |0> to generate the
        desired input state |b>.
      """
  
      ancilla = cirq.GridQubit(0, 0)
      # to store eigenvalues of the matrix
      register = [cirq.GridQubit(i+1, 0) for i in range(register_size)]
      # to store input and output vectors
      memory = cirq.GridQubit(register_size+1, 0)
  
      c = cirq.Circuit()
      hs = HamiltonianSimulation(A, t)
      pe = PhaseEstimation(register_size+1, hs)
      c.append([gate(memory) for gate in input_prep_gates])
      c.append([
          pe(*(register + [memory])),
          EigenRotation(register_size+1, C, t)(*(register+[ancilla])),
          pe(*(register + [memory]))**-1,
          cirq.measure(ancilla)
      ])
  
      # Pauli observable display
      c.append([
          cirq.pauli_string_expectation(
              cirq.PauliString({ancilla: cirq.Z}),
              key='a'
          ),
          cirq.pauli_string_expectation(
              cirq.PauliString({memory: cirq.X}),
              key='x'
          ),
          cirq.pauli_string_expectation(
              cirq.PauliString({memory: cirq.Y}),
              key='y'
          ),
          cirq.pauli_string_expectation(
              cirq.PauliString({memory: cirq.Z}),
              key='z'
          ),
      ])
  
      return c