def _compute_multi_group_ds_store(
        self,
        # In the future we may want to pass in a single list of compound types instead of three parallel lists.
        batched_inference_request_spec: list[InferenceRequestSpec],
        # Sometimes T will be GroupId; sometimes it will be tuple[str, GroupId].
        batched_dst_and_configs_by_processing_step: list[DstAndConfigsByProcessingStep],
        # Return three parallel lists:
        #   1) a batched list of input token ints
        #   2) a batched list of derived scalar stores
        #   3) a batched list of inference data objects
        # Each list should be the same length.
    ) -> tuple[
        list[list[int]],
        list[dict[str, MultiGroupDerivedScalarStore]],
        list[InferenceData],
    ]:
        """
        Helper method (first step) that computes a DerivedScalarStore for each group ID. The
        quantities within each group ID are intended to be comparable (e.g. the write vector norms
        of attention heads, and the write vector norms of MLP neurons).
        """
        assert len(batched_inference_request_spec) == len(
            batched_dst_and_configs_by_processing_step
        )
        batched_ds_computation_params = []
        for inference_request_spec, dst_and_configs_by_processing_step in zip(
            batched_inference_request_spec,
            batched_dst_and_configs_by_processing_step,
        ):
            prompt = inference_request_spec.prompt
            unpadded_tokens_as_ints = self.encode(prompt)
            tokens_as_ints = unpadded_tokens_as_ints

            multi_group_scalar_derivers_by_processing_step = {
                spec_name: (
                    MultiGroupScalarDerivers.from_dst_and_config_list_by_group_id(
                        dst_and_config_list_by_group_id=dst_and_configs_by_processing_step[
                            spec_name
                        ],
                    )
                )
                for spec_name in dst_and_configs_by_processing_step.keys()
            }

            # if at least one of the scalar derivers is intended to operate on GPU,
            # then we'll use GPU for the raw activations. Otherwise the CPU.
            devices_for_raw_activations = []
            for (
                multi_group_scalar_derivers
            ) in multi_group_scalar_derivers_by_processing_step.values():
                devices_for_raw_activations += (
                    multi_group_scalar_derivers.devices_for_raw_activations
                )
            if any(device.type == "cuda" for device in devices_for_raw_activations):
                device_for_raw_activations = torch.device("cuda", 0)
            elif any(device.type == "mps" for device in devices_for_raw_activations):
                device_for_raw_activations = torch.device("mps")
            else:
                device_for_raw_activations = torch.device("cpu")
            trace_config = (  # mirrored -> non-mirrored TraceConfig
                inference_request_spec.trace_config.to_trace_config()
                if inference_request_spec.trace_config is not None
                else None
            )
            ds_computation_params = DerivedScalarComputationParams(
                input_token_ints=tokens_as_ints,
                multi_group_scalar_derivers_by_processing_step=multi_group_scalar_derivers_by_processing_step,
                loss_fn_for_backward_pass=maybe_construct_loss_fn_for_backward_pass(
                    model_context=self._standard_model_context,
                    config=inference_request_spec.loss_fn_config,
                ),
                trace_config=trace_config,
                ablation_specs=inference_request_spec.ablation_specs,
                device_for_raw_activations=device_for_raw_activations,
            )
            batched_ds_computation_params.append(ds_computation_params)

        batched_multi_group_ds_store_by_processing_step: list[
            dict[str, MultiGroupDerivedScalarStore]
        ]
        (
            batched_multi_group_ds_store_by_processing_step,
            batched_inference_data,
            _,
        ) = compute_derived_scalar_groups_for_input_token_ints(
            model_context=self._standard_model_context,
            batched_ds_computation_params=batched_ds_computation_params,
            multi_autoencoder_context=self._multi_autoencoder_context,
        )

        return (
            [params.input_token_ints for params in batched_ds_computation_params],
            batched_multi_group_ds_store_by_processing_step,
            batched_inference_data,
        )

        Helper method (first step) that computes a DerivedScalarStore for each group ID. The
        quantities within each group ID are intended to be comparable (e.g. the write vector norms
        of attention heads, and the write vector norms of MLP neurons).
        
neuron_explainer/activation_server/interactive_model.py