class_docstr: An autoguide helper to match a group of model sites.
  
  :ivar torch.Size event_shape: The total flattened concatenated shape of all
      matching sample sites in the model.
  :ivar list prototype_sites: A list of all matching sample sites in a
      prototype trace of the model.
  :param EasyGuide guide: An easyguide instance.
  :param list sites: A list of model sites.
code: def __init__(self, guide, sites):
      assert isinstance(sites, list)
      assert sites
      self._guide = weakref.ref(guide)
      self.prototype_sites = sites
      self._site_sizes = {}
      self._site_batch_shapes = {}
  
      # A group is in a frame only if all its sample sites are in that frame.
      # Thus a group can be subsampled only if all its sites can be subsampled.
      self.common_frames = frozenset.intersection(
          *(
              frozenset(
                  f for f in site["cond_indep_stack"] if f.vectorized
              )
              for site in sites
          )
      )
      rightmost_common_dim = -float("inf")
      if self.common_frames:
          rightmost_common_dim = max(f.dim for f in self.common_frames)
  
      # Compute flattened concatenated event_shape and split batch_shape into
      # a common batch_shape (which can change each SVI step due to
      # subsampling) and site batch_shapes (which must remain constant size).
      for site in sites:
          site_event_numel = torch.Size(site["fn"].event_shape).numel()
          site_batch_shape = list(site["fn"].batch_shape)
          for f in self.common_frames:
              # Consider this dim part of the common_batch_shape.
              site_batch_shape[f.dim] = 1
          while site_batch_shape and site_batch_shape[0] == 1:
              site_batch_shape = site_batch_shape[1:]
          if len(site_batch_shape) > -rightmost_common_dim:
              raise ValueError(
                  "Group expects all per-site plates to be right of all common plates, "
                  "but found a per-site plate {} on left at site {}".format(
                      -len(site_batch_shape), repr(site["name"])
                  )
              )
          site_batch_shape = torch.Size(site_batch_shape)
          self._site_batch_shapes[site["name"]] = site_batch_shape
          self._site_sizes[site["name"]] = (
              site_batch_shape.numel() * site_event_numel
          )
      self.event_shape = torch.Size([sum(self._site_sizes.values())])
  
imports: import re
  import weakref
  from abc import ABCMeta, abstractmethod
  from contextlib import ExitStack
  import torch
  from torch.distributions import biject_to
  import pyro
  import pyro.distributions
  import pyro.poutine
  import pyro.poutine.runtime
  from pyro.distributions.util import broadcast_shape, sum_rightmost
  from pyro.infer.autoguide.guides import prototype_hide_fn
  from pyro.infer.autoguide.initialization import InitMessenger
  from pyro.nn.module import PyroModule, PyroParam
label_desc: Use image node_id 1 to create a new Group object  with example: obj = Group(guide, sites)