docs: def forward_inference(self, variables, evidence=None, args=None):
          """
          Forward inference method using belief propagation.
  
          Parameters:
          ----------
          variables: list
              list of variables for which you want to compute the probability
  
          evidence: dict
              a dict key, value pair as {var: state_of_var_observed}
              None if no evidence
  
          Examples:
          --------
          >>> from pgmpy.factors.discrete import TabularCPD
          >>> from pgmpy.models import DynamicBayesianNetwork as DBN
          >>> from pgmpy.inference import DBNInference
          >>> dbnet = DBN()
          >>> dbnet.add_edges_from([(('Z', 0), ('X', 0)), (('X', 0), ('Y', 0)),
          ...                       (('Z', 0), ('Z', 1))])
          >>> z_start_cpd = TabularCPD(('Z', 0), 2, [[0.5, 0.5]])
          >>> x_i_cpd = TabularCPD(('X', 0), 2, [[0.6, 0.9],
          ...                                    [0.4, 0.1]],
          ...                      evidence=[('Z', 0)],
          ...                      evidence_card=[2])
          >>> y_i_cpd = TabularCPD(('Y', 0), 2, [[0.2, 0.3],
          ...                                    [0.8, 0.7]],
          ...                      evidence=[('X', 0)],
          ...                      evidence_card=[2])
          >>> z_trans_cpd = TabularCPD(('Z', 1), 2, [[0.4, 0.7],
          ...                                        [0.6, 0.3]],
          ...                      evidence=[('Z', 0)],
          ...                      evidence_card=[2])
          >>> dbnet.add_cpds(z_start_cpd, z_trans_cpd, x_i_cpd, y_i_cpd)
          >>> dbnet.initialize_initial_state()
          >>> dbn_inf = DBNInference(dbnet)
          >>> dbn_inf.forward_inference([('X', 2)], {('Y', 0):1, ('Y', 1):0, ('Y', 2):1})[('X', 2)].values
          array([ 0.76738736,  0.23261264])
          """
          variable_dict = defaultdict(list)
          for var in variables:
              variable_dict[var[1]].append(var)
  
          time_range = max(variable_dict)
          if evidence:
              evid_time_range = max([time_slice for var, time_slice in evidence.keys()])
              time_range = max(time_range, evid_time_range)
  
          start_bp = BeliefPropagation(self.start_junction_tree)
          mid_bp = BeliefPropagation(self.one_and_half_junction_tree)
          evidence_0 = self._get_evidence(evidence, 0, 0)
          interface_nodes_dict = {}
          potential_dict = {}
  
          if evidence:
              interface_nodes_dict = {k: v for k, v in evidence_0.items() if k in self.interface_nodes_0}
          initial_factor = self._get_factor(start_bp, evidence_0)
          marginalized_factor = self._marginalize_factor(self.interface_nodes_0, initial_factor)
          potential_dict[0] = marginalized_factor
          self._update_belief(mid_bp, self.in_clique, marginalized_factor)
  
          if variable_dict[0]:
              factor_values = start_bp.query(variable_dict[0], evidence=evidence_0, joint=False)
          else:
              factor_values = {}
  
          for time_slice in range(1, time_range + 1):
              evidence_time = self._get_evidence(evidence, time_slice, 1)
              if interface_nodes_dict:
                  evidence_time.update(interface_nodes_dict)
  
              if variable_dict[time_slice]:
                  variable_time = self._shift_nodes(variable_dict[time_slice], 1)
                  new_values = mid_bp.query(variable_time, evidence=evidence_time, joint=False)
                  changed_values = {}
                  for key in new_values.keys():
                      new_key = (key[0], time_slice)
                      new_factor = DiscreteFactor([new_key], new_values[key].cardinality, new_values[key].values)
                      changed_values[new_key] = new_factor
                  factor_values.update(changed_values)
  
              clique_phi = self._get_factor(mid_bp, evidence_time)
              out_clique_phi = self._marginalize_factor(self.interface_nodes_1, clique_phi)
              new_factor = self._shift_factor(out_clique_phi, 0)
              potential_dict[time_slice] = new_factor
              mid_bp = BeliefPropagation(self.one_and_half_junction_tree)
              self._update_belief(mid_bp, self.in_clique, new_factor)
  
              if evidence_time:
                  interface_nodes_dict = {(k[0], 0): v for k, v in evidence_time.items() if k in self.interface_nodes_1}
              else:
                  interface_nodes_dict = {}
  
          if args == 'potential':
              return potential_dict
  
          return factor_values