code: def test_sequential_sum_product_multi(
      impl, x_domain, y_domain, batch_inputs, num_steps
  ):
      sum_op = ops.logaddexp
      prod_op = ops.add
      inputs = OrderedDict(batch_inputs)
      inputs.update(
          x_prev=x_domain,
          x_curr=x_domain,
          y_prev=y_domain,
          y_curr=y_domain,
      )
      if num_steps is None:
          num_steps = 1
      else:
          inputs["time"] = Bint[num_steps]
      if any(v.dtype == "real" for v in inputs.values()):
          trans = random_gaussian(inputs)
      else:
          trans = random_tensor(inputs)
      time = Variable("time", Bint[num_steps])
      step = {"x_prev": "x_curr", "y_prev": "y_curr"}
  
      with moment_matching:
          actual = impl(sum_op, prod_op, trans, time, step)
          expected_inputs = batch_inputs.copy()
          expected_inputs.update(
              x_prev=x_domain,
              x_curr=x_domain,
              y_prev=y_domain,
              y_curr=y_domain,
          )
          assert dict(actual.inputs) == expected_inputs
  
          # Check against contract.
          operands = tuple(
              trans(
                  time=t,
                  x_prev="x_{}".format(t),
                  x_curr="x_{}".format(t + 1),
                  y_prev="y_{}".format(t),
                  y_curr="y_{}".format(t + 1),
              )
              for t in range(num_steps)
          )
          reduce_vars = frozenset(
              "x_{}".format(t) for t in range(1, num_steps)
          ).union("y_{}".format(t) for t in range(1, num_steps))
          expected = sum_product(sum_op, prod_op, operands, reduce_vars)
          expected = expected(
              **{
                  "x_0": "x_prev",
                  "x_{}".format(num_steps): "x_curr",
                  "y_0": "y_prev",
                  "y_{}".format(num_steps): "y_curr",
              }
          )
          expected = expected.align(tuple(actual.inputs.keys()))
  
imports: import os
  import re
  from collections import OrderedDict
  from functools import partial, reduce
  import pytest
  import funsor.ops
  from funsor.domains import Bint, Real, Reals
  from funsor.interpretations import compress_gaussians, eager, eager_or_die, lazy, moment_matching, reflect
  from funsor.interpreter import reinterpret
  from funsor.optimizer import apply_optimizer
  from funsor.sum_product import MarkovProduct, _partition, dynamic_partial_sum_product, mixed_sequential_sum_product, modified_partial_sum_product, naive_sarkka_bilmes_product, naive_sequential_sum_product, partial_sum_product, partial_unroll, sarkka_bilmes_product, sequential_sum_product, sum_product
  from funsor.tensor import Tensor, get_default_prototype
  from funsor.terms import Cat, Variable
  from funsor.testing import assert_close, random_gaussian, random_tensor
  from funsor.util import get_backend
label_desc: Use image node_id 30 for calling a global function with example usage: test_sequential_sum_product_multi(impl, x_domain, y_domain, batch_inputs, num_steps) without return types