Simulate a set of phase gates on the xmon architecture.

        Args:
            phase_map: A map from a tuple of indices to a value, one for each
                phase gate being simulated. If the tuple key has one index, then
                this is a Z phase gate on the index-th qubit with a rotation
                angle of pi times the value of the map. If the tuple key has two
                indices, then this is a |11> phasing gate, acting on the qubits
                at the two indices, and a rotation angle of pi times the value
                of the map.

def simulate_phases(self, phase_map: Dict[Tuple[int, ...], float]):
        """Simulate a set of phase gates on the xmon architecture.

        Args:
            phase_map: A map from a tuple of indices to a value, one for each
                phase gate being simulated. If the tuple key has one index, then
                this is a Z phase gate on the index-th qubit with a rotation
                angle of pi times the value of the map. If the tuple key has two
                indices, then this is a |11> phasing gate, acting on the qubits
                at the two indices, and a rotation angle of pi times the value
                of the map.
        """
        self._pool.map(_clear_scratch, self._shard_num_args())
        # Iterate over the map of phase data.
        for indices, half_turns in phase_map.items():
            args = self._shard_num_args(
                {'indices': indices, 'half_turns': half_turns})
            if len(indices) == 1:
                self._pool.map(_single_qubit_accumulate_into_scratch, args)
            elif len(indices) == 2:
                self._pool.map(_two_qubit_accumulate_into_scratch, args)
        # Exponentiate the phases and add them into the state.
        self._pool.map(_apply_scratch_as_phase, self._shard_num_args())