class_docstr: Class for representing Structural Equation Models. This class is a wrapper over
  `SEMGraph` and `SEMAlg` to provide a consistent API over the different representations.
  
  Attributes
  ----------
  model: SEMGraph instance
      A graphical representation of the model.
class_docstr_tok: ["Class","for","representing","Structural","Equation","Models",".","This","class","is","a","wrapper","over","`","SEMGraph","`","and","`","SEMAlg","`","to","provide","a","consistent","API","over","the","different","representations",".","Attributes","--","--","--","--","--","model",":","SEMGraph","instance","A","graphical","representation","of","the","model","."]
docstr: Initialize a `SEM` object. Preferred way to initialize the object is to use one of
  the `from_lavaan`, `from_graph`, `from_lisrel`, or `from_RAM` methods.
  
  There are three possible ways to initialize the model:
      1. Lavaan syntax: `lavaan_str` needs to be specified.
      2. Graph structure: `ebunch`, `latents`, `err_corr`, and `err_var` need to be specified.
      3. LISREL syntax: `var_names`, `params`, and `fixed_masks` need to be specified.
      4. Reticular Action Model (RAM/all-y) syntax: `var_names`, `B`, `zeta`, and `wedge_y`
                                                      need to be specified.
  
  Parameters
  ----------
  syntax: str (lavaan|graph|lisrel|ram)
      The syntax used to initialize the model.
  
  kwargs:
      For parameter details, check docstrings for `from_lavaan`, `from_graph`, `from_lisrel`,
      and `from_RAM` methods.
  
  See Also
  --------
  from_lavaan: Initialize a model using lavaan syntax.
  from_graph: Initialize a model using graph structure.
  from_lisrel: Initialize a model using LISREL syntax.
  from_RAM: Initialize a model using Reticular Action Model(RAM/all-y) syntax.
docstr_tok: ["Initialize","a","`","SEM","`","object",".","Preferred","way","to","initialize","the","object","is","to","use","one","of","the","`","from_lavaan","`",",","`","from_graph","`",",","`","from_lisrel","`",",","or","`","from_RAM","`","methods",".","There","are","three","possible","ways","to","initialize","the","model",":","1",".","Lavaan","syntax",":","`","lavaan_str","`","needs","to","be","specified",".","2",".","Graph","structure",":","`","ebunch","`",",","`","latents","`",",","`","err_corr","`",",","and","`","err_var","`","need","to","be","specified",".","3",".","LISREL","syntax",":","`","var_names","`",",","`","params","`",",","and","`","fixed_masks","`","need","to","be","specified",".","4",".","Reticular","Action","Model","(","RAM\/all-y",")","syntax",":","`","var_names","`",",","`","B","`",",","`","zeta","`",",","and","`","wedge_y","`","need","to","be","specified",".","Parameters","--","--","--","--","--","syntax",":","str","(","lavaan|graph|lisrel|ram",")","The","syntax","used","to","initialize","the","model",".","kwargs",":","For","parameter","details",",","check","docstrings","for","`","from_lavaan","`",",","`","from_graph","`",",","`","from_lisrel","`",",","and","`","from_RAM","`","methods",".","See","Also","--","--","--","--","from_lavaan",":","Initialize","a","model","using","lavaan","syntax",".","from_graph",":","Initialize","a","model","using","graph","structure",".","from_lisrel",":","Initialize","a","model","using","LISREL","syntax",".","from_RAM",":","Initialize","a","model","using","Reticular","Action","Model","(","RAM\/all-y",")","syntax","."]
code: def __init__(self, syntax, **kwargs):
      """
      Initialize a `SEM` object. Preferred way to initialize the object is to use one of
      the `from_lavaan`, `from_graph`, `from_lisrel`, or `from_RAM` methods.
  
      There are three possible ways to initialize the model:
          1. Lavaan syntax: `lavaan_str` needs to be specified.
          2. Graph structure: `ebunch`, `latents`, `err_corr`, and `err_var` need to be specified.
          3. LISREL syntax: `var_names`, `params`, and `fixed_masks` need to be specified.
          4. Reticular Action Model (RAM/all-y) syntax: `var_names`, `B`, `zeta`, and `wedge_y`
                                                          need to be specified.
  
      Parameters
      ----------
      syntax: str (lavaan|graph|lisrel|ram)
          The syntax used to initialize the model.
  
      kwargs:
          For parameter details, check docstrings for `from_lavaan`, `from_graph`, `from_lisrel`,
          and `from_RAM` methods.
  
      See Also
      --------
      from_lavaan: Initialize a model using lavaan syntax.
      from_graph: Initialize a model using graph structure.
      from_lisrel: Initialize a model using LISREL syntax.
      from_RAM: Initialize a model using Reticular Action Model(RAM/all-y) syntax.
      """
      if syntax.lower() == "lavaan":
          # Create a SEMGraph model using the lavaan str.
  
          # Step 1: Define the grammar for each type of string.
          var = Word(alphanums)
          reg_gram = (
              OneOrMore(
                  var.setResultsName("predictors", listAllMatches=True)
                  + Optional(Suppress("+"))
              )
              + "~"
              + OneOrMore(
                  var.setResultsName("covariates", listAllMatches=True)
                  + Optional(Suppress("+"))
              )
          )
          intercept_gram = var("inter_var") + "~" + Word("1")
          covar_gram = (
              var("covar_var1")
              + "~~"
              + OneOrMore(
                  var.setResultsName("covar_var2", listAllMatches=True)
                  + Optional(Suppress("+"))
              )
          )
          latent_gram = (
              var("latent")
              + "=~"
              + OneOrMore(
                  var.setResultsName("obs", listAllMatches=True)
                  + Optional(Suppress("+"))
              )
          )
  
          # Step 2: Preprocess string to lines
          lines = kwargs["lavaan_str"]
  
          # Step 3: Initialize arguments and fill them by parsing each line.
          ebunch = []
          latents = []
          err_corr = []
          err_var = []
          for line in lines:
              line = line.strip()
              if (line != "") and (not line.startswith("#")):
                  if intercept_gram.matches(line):
                      continue
                  elif reg_gram.matches(line):
                      results = reg_gram.parseString(
                          line, parseAll=True
                      )
                      for pred in results["predictors"]:
                          ebunch.extend(
                              [
                                  (covariate, pred)
                                  for covariate in results["covariates"]
                              ]
                          )
                  elif covar_gram.matches(line):
                      results = covar_gram.parseString(
                          line, parseAll=True
                      )
                      for var in results["covar_var2"]:
                          err_corr.append((results["covar_var1"], var))
  
                  elif latent_gram.matches(line):
                      results = latent_gram.parseString(
                          line, parseAll=True
                      )
                      latents.append(results["latent"])
                      ebunch.extend(
                          [
                              (results["latent"], obs)
                              for obs in results["obs"]
                          ]
                      )
  
          # Step 4: Call the parent __init__ with the arguments
          super(SEM, self).__init__(
              ebunch=ebunch, latents=latents, err_corr=err_corr
          )
  
      elif syntax.lower() == "graph":
          super(SEM, self).__init__(
              ebunch=kwargs["ebunch"],
              latents=kwargs["latents"],
              err_corr=kwargs["err_corr"],
              err_var=kwargs["err_var"],
          )
  
      elif syntax.lower() == "lisrel":
          model = SEMAlg(
              var_names=var_names,
              params=params,
              fixed_masks=fixed_masks,
          ).to_SEMGraph()
          # Initialize an empty SEMGraph instance and set the properties.
          # TODO: Boilerplate code, find a better way to do this.
          super(SEM, self).__init__(
              ebunch=[], latents=[], err_corr=[], err_var={}
          )
          self.graph = model.graph
          self.latents = model.latents
          self.obseved = model.observed
          self.err_graph = model.err_graph
          self.full_graph_struct = model.full_graph_struct
  
      elif syntax.lower() == "ram":
          model = SEMAlg(
              eta=kwargs["var_names"],
              B=kwargs["B"],
              zeta=kwargs["zeta"],
              wedge_y=kwargs["wedge_y"],
              fixed_values=fixed_masks,
          )
  
imports: import itertools
  import networkx
  import numpy
  import pandas
  from networkx.algorithms.dag import descendants
  from pyparsing import OneOrMore, Optional, Suppress, Word, alphanums, nums
  from pgmpy.base import DAG
  from pgmpy.global_vars import logger
label_desc: Use image node_id 1 to create a new SEM object from inherited base classes: SEMGraph with example: obj = SEM(syntax)