예제 #1
0
  /**
   * @return Returns the error covariance matrix of the model. i.e. [a][b] is the covariance of E_a
   *     and E_b, with [a][a] of course being the variance of E_a. THESE ARE NOT PARAMETERS OF THE
   *     MODEL; THEY ARE CALCULATED. Note that elements of this matrix may be Double.NaN; this
   *     indicates that these elements cannot be calculated.
   */
  private TetradMatrix errCovar(Map<Node, Double> errorVariances) {
    List<Node> variableNodes = getVariableNodes();
    List<Node> errorNodes = new ArrayList<Node>();

    for (Node node : variableNodes) {
      errorNodes.add(semGraph.getExogenous(node));
    }

    TetradMatrix errorCovar = new TetradMatrix(errorVariances.size(), errorVariances.size());

    for (int index = 0; index < errorNodes.size(); index++) {
      Node error = errorNodes.get(index);
      double variance = getErrorVariance(error);
      errorCovar.set(index, index, variance);
    }

    for (int index1 = 0; index1 < errorNodes.size(); index1++) {
      for (int index2 = 0; index2 < errorNodes.size(); index2++) {
        Node error1 = errorNodes.get(index1);
        Node error2 = errorNodes.get(index2);
        Edge edge = semGraph.getEdge(error1, error2);

        if (edge != null && Edges.isBidirectedEdge(edge)) {
          double covariance = getErrorCovariance(error1, error2);
          errorCovar.set(index1, index2, covariance);
        }
      }
    }

    return errorCovar;
  }
예제 #2
0
  public boolean containsParameter(Edge edge) {
    if (Edges.isBidirectedEdge(edge)) {
      edge =
          Edges.bidirectedEdge(
              semGraph.getExogenous(edge.getNode1()), semGraph.getExogenous(edge.getNode2()));
    }

    return edgeParameters.keySet().contains(edge);
  }
예제 #3
0
 public void setParameterValue(Edge edge, double value) {
   if (Edges.isDirectedEdge(edge)) {
     setEdgeCoefficient(edge.getNode1(), edge.getNode2(), value);
   } else if (Edges.isBidirectedEdge(edge)) {
     setErrorCovariance(edge.getNode1(), edge.getNode2(), value);
   } else {
     throw new IllegalArgumentException(
         "Only directed and bidirected edges are supported: " + edge);
   }
 }
예제 #4
0
  private void uncorrelationExogenousVariables() {
    Graph graph = getWorkbench().getGraph();

    Set<Edge> edges = graph.getEdges();

    for (Edge edge : edges) {
      if (Edges.isBidirectedEdge(edge)) {
        try {
          graph.removeEdge(edge);
        } catch (Exception e) {
          // Ignore.
        }
      }
    }
  }
예제 #5
0
  private void correlateExogenousVariables() {
    Graph graph = getWorkbench().getGraph();

    if (graph instanceof Dag) {
      JOptionPane.showMessageDialog(
          JOptionUtils.centeringComp(), "Cannot add bidirected edges to DAG's.");
      return;
    }

    List<Node> nodes = graph.getNodes();

    List<Node> exoNodes = new LinkedList<Node>();

    for (int i = 0; i < nodes.size(); i++) {
      Node node = nodes.get(i);
      if (graph.isExogenous(node)) {
        exoNodes.add(node);
      }
    }

    for (int i = 0; i < exoNodes.size(); i++) {

      loop:
      for (int j = i + 1; j < exoNodes.size(); j++) {
        Node node1 = exoNodes.get(i);
        Node node2 = exoNodes.get(j);
        List<Edge> edges = graph.getEdges(node1, node2);

        for (int k = 0; k < edges.size(); k++) {
          Edge edge = edges.get(k);
          if (Edges.isBidirectedEdge(edge)) {
            continue loop;
          }
        }

        graph.addBidirectedEdge(node1, node2);
      }
    }
  }
예제 #6
0
  /**
   * @return The edge coefficient matrix of the model, a la SemIm. Note that this will normally need
   *     to be transposed, since [a][b] is the edge coefficient for a-->b, not b-->a. Sorry.
   *     History. THESE ARE PARAMETERS OF THE MODEL--THE ONLY PARAMETERS.
   */
  public TetradMatrix edgeCoef() {
    List<Node> variableNodes = getVariableNodes();

    TetradMatrix edgeCoef = new TetradMatrix(variableNodes.size(), variableNodes.size());

    for (Edge edge : edgeParameters.keySet()) {
      if (Edges.isBidirectedEdge(edge)) {
        continue;
      }

      Node a = edge.getNode1();
      Node b = edge.getNode2();

      int aindex = variableNodes.indexOf(a);
      int bindex = variableNodes.indexOf(b);

      double coef = edgeParameters.get(edge);

      edgeCoef.set(aindex, bindex, coef);
    }

    return edgeCoef;
  }
예제 #7
0
  /** @return a string representation of the coefficients and variances of the model. */
  public String toString() {
    StringBuilder buf = new StringBuilder();
    NumberFormat nf = NumberFormatUtil.getInstance().getNumberFormat();

    buf.append("\nStandardized SEM:");
    buf.append("\n\nEdge coefficients (parameters):\n");

    for (Edge edge : edgeParameters.keySet()) {
      if (!Edges.isDirectedEdge(edge)) {
        continue;
      }

      buf.append("\n" + edge + " " + nf.format(edgeParameters.get(edge)));
    }

    buf.append("\n\nError covariances (parameters):\n");

    for (Edge edge : edgeParameters.keySet()) {
      if (!Edges.isBidirectedEdge(edge)) {
        continue;
      }

      buf.append("\n" + edge + " " + nf.format(edgeParameters.get(edge)));
    }

    buf.append("\n\nError variances (calculated):\n");

    for (Node error : getErrorNodes()) {
      double variance = getErrorVariance(error);
      buf.append("\n" + error + " " + (Double.isNaN(variance) ? "Undefined" : nf.format(variance)));
    }

    buf.append("\n");

    return buf.toString();
  }
예제 #8
0
  /** Constructs a new SemPm from the given SemGraph. */
  public GeneralizedSemPm(SemGraph graph) {
    if (graph == null) {
      throw new NullPointerException("Graph must not be null.");
    }

    //        if (graph.existsDirectedCycle()) {
    //            throw new IllegalArgumentExcneption("Cycles are not supported.");
    //        }

    // Cannot afford to allow error terms on this graph to be shown or hidden from the outside; must
    // make a
    // hidden copy of it and make sure error terms are shown.
    this.graph = new SemGraph(graph);
    this.graph.setShowErrorTerms(true);

    for (Edge edge : this.graph.getEdges()) {
      if (Edges.isBidirectedEdge(edge)) {
        throw new IllegalArgumentException(
            "The generalized SEM PM cannot currently deal with bidirected " + "edges. Sorry.");
      }
    }

    this.nodes = Collections.unmodifiableList(this.graph.getNodes());

    for (Node node : nodes) {
      namesToNodes.put(node.getName(), node);
    }

    this.variableNodes = new ArrayList<>();
    this.measuredNodes = new ArrayList<>();

    for (Node variable : this.nodes) {
      if (variable.getNodeType() == NodeType.MEASURED
          || variable.getNodeType() == NodeType.LATENT) {
        variableNodes.add(variable);
      }

      if (variable.getNodeType() == NodeType.MEASURED) {
        measuredNodes.add(variable);
      }
    }

    this.errorNodes = new ArrayList<>();

    for (Node variable : this.variableNodes) {
      List<Node> parents = this.graph.getParents(variable);
      boolean added = false;

      for (Node _node : parents) {
        if (_node.getNodeType() == NodeType.ERROR) {
          errorNodes.add(_node);
          added = true;
          break;
        }
      }

      if (!added) {
        errorNodes.add(null);
      }
    }

    this.referencedParameters = new HashMap<>();
    this.referencedNodes = new HashMap<>();
    this.nodeExpressions = new HashMap<>();
    this.nodeExpressionStrings = new HashMap<>();
    this.parameterExpressions = new HashMap<>();
    this.parameterExpressionStrings = new HashMap<>();
    this.parameterEstimationInitializationExpressions = new HashMap<>();
    this.parameterEstimationInitializationExpressionStrings = new HashMap<>();
    this.startsWithParametersTemplates = new HashMap<>();
    this.startsWithParametersEstimationInitializationTemplates = new HashMap<>();

    this.variableNames = new ArrayList<>();
    for (Node _node : variableNodes) variableNames.add(_node.getName());
    for (Node _node : errorNodes) variableNames.add(_node.getName());

    try {
      List<Node> variableNodes = getVariableNodes();

      for (Node node : variableNodes) {
        if (!this.graph.isParameterizable(node)) continue;

        if (nodeExpressions.get(node) != null) {
          continue;
        }

        String variablestemplate = getVariablesTemplate();
        String formula =
            TemplateExpander.getInstance().expandTemplate(variablestemplate, this, node);
        setNodeExpression(node, formula);
        Set<String> parameters = getReferencedParameters(node);

        String parametersTemplate = getParametersTemplate();

        for (String parameter : parameters) {
          if (parameterExpressions.get(parameter) == null) {
            if (parametersTemplate != null) {
              setParameterExpression(parameter, parametersTemplate);
            } else if (this.graph.isTimeLagModel()) {
              String expressionString = "Split(-0.9, -.1, .1, 0.9)";
              setParameterExpression(parameter, expressionString);
              setParametersTemplate(expressionString);
            } else {
              String expressionString = "Split(-1.5, -.5, .5, 1.5)";
              setParameterExpression(parameter, expressionString);
              setParametersTemplate(expressionString);
            }
          }
        }

        for (String parameter : parameters) {
          if (parameterEstimationInitializationExpressions.get(parameter) == null) {
            if (parametersTemplate != null) {
              setParameterEstimationInitializationExpression(parameter, parametersTemplate);
            } else if (this.graph.isTimeLagModel()) {
              String expressionString = "Split(-0.9, -.1, .1, 0.9)";
              setParameterEstimationInitializationExpression(parameter, expressionString);
            } else {
              String expressionString = "Split(-1.5, -.5, .5, 1.5)";
              setParameterEstimationInitializationExpression(parameter, expressionString);
            }
          }

          setStartsWithParametersTemplate("s", "Split(-1.5, -.5, .5, 1.5)");
          setStartsWithParametersEstimationInitializaationTemplate(
              "s", "Split(-1.5, -.5, .5, 1.5)");
        }
      }

      for (Node node : errorNodes) {
        if (node == null) continue;

        String template = getErrorsTemplate();
        String formula = TemplateExpander.getInstance().expandTemplate(template, this, node);
        setNodeExpression(node, formula);
        Set<String> parameters = getReferencedParameters(node);

        setStartsWithParametersTemplate("s", "U(1, 3)");
        setStartsWithParametersEstimationInitializaationTemplate("s", "U(1, 3)");

        for (String parameter : parameters) {
          setParameterExpression(parameter, "U(1, 3)");
        }
      }
    } catch (ParseException e) {
      throw new IllegalStateException("Parse error in constructing initial model.", e);
    }
  }
예제 #9
0
  /**
   * Calculates the error variance for the given error node, given all of the coefficient values in
   * the model.
   *
   * @param error An error term in the model--i.e. a variable with NodeType.ERROR.
   * @return The value of the error variance, or Double.NaN is the value is undefined.
   */
  private double calculateErrorVarianceFromParams(Node error) {
    error = semGraph.getNode(error.getName());

    Node child = semGraph.getChildren(error).get(0);
    List<Node> parents = semGraph.getParents(child);

    double otherVariance = 0;

    for (Node parent : parents) {
      if (parent == error) continue;
      double coef = getEdgeCoefficient(parent, child);
      otherVariance += coef * coef;
    }

    if (parents.size() >= 2) {
      ChoiceGenerator gen = new ChoiceGenerator(parents.size(), 2);
      int[] indices;

      while ((indices = gen.next()) != null) {
        Node node1 = parents.get(indices[0]);
        Node node2 = parents.get(indices[1]);

        double coef1, coef2;

        if (node1.getNodeType() != NodeType.ERROR) {
          coef1 = getEdgeCoefficient(node1, child);
        } else {
          coef1 = 1;
        }

        if (node2.getNodeType() != NodeType.ERROR) {
          coef2 = getEdgeCoefficient(node2, child);
        } else {
          coef2 = 1;
        }

        List<List<Node>> treks = GraphUtils.treksIncludingBidirected(semGraph, node1, node2);

        double cov = 0.0;

        for (List<Node> trek : treks) {
          double product = 1.0;

          for (int i = 1; i < trek.size(); i++) {
            Node _node1 = trek.get(i - 1);
            Node _node2 = trek.get(i);

            Edge edge = semGraph.getEdge(_node1, _node2);
            double factor;

            if (Edges.isBidirectedEdge(edge)) {
              factor = edgeParameters.get(edge);
            } else if (!edgeParameters.containsKey(edge)) {
              factor = 1;
            } else if (semGraph.isParentOf(_node1, _node2)) {
              factor = getEdgeCoefficient(_node1, _node2);
            } else {
              factor = getEdgeCoefficient(_node2, _node1);
            }

            product *= factor;
          }

          cov += product;
        }

        otherVariance += 2 * coef1 * coef2 * cov;
      }
    }

    return 1.0 - otherVariance <= 0 ? Double.NaN : 1.0 - otherVariance;
  }
예제 #10
0
  /**
   * @param edge a->b or a<->b.
   * @return the range of the covariance parameter for a->b or a<->b.
   */
  public ParameterRange getParameterRange(Edge edge) {
    if (Edges.isBidirectedEdge(edge)) {
      edge =
          Edges.bidirectedEdge(
              semGraph.getExogenous(edge.getNode1()), semGraph.getExogenous(edge.getNode2()));
    }

    if (!(edgeParameters.keySet().contains(edge))) {
      throw new IllegalArgumentException("Not an edge in this model: " + edge);
    }

    double initial = edgeParameters.get(edge);

    if (initial == Double.NEGATIVE_INFINITY) {
      initial = Double.MIN_VALUE;
    } else if (initial == Double.POSITIVE_INFINITY) {
      initial = Double.MAX_VALUE;
    }

    double value = initial;

    // look upward for a point that fails.
    double high = value + 1;

    while (paramInBounds(edge, high)) {
      high = value + 2 * (high - value);

      if (high == Double.POSITIVE_INFINITY) {
        break;
      }
    }

    // find the boundary using binary search.
    double rangeHigh;

    if (high == Double.POSITIVE_INFINITY) {
      rangeHigh = high;
    } else {
      double low = value;

      while (high - low > 1e-10) {
        double midpoint = (high + low) / 2.0;

        if (paramInBounds(edge, midpoint)) {
          low = midpoint;
        } else {
          high = midpoint;
        }
      }

      rangeHigh = (high + low) / 2.0;
    }

    // look downard for a point that fails.
    double low = value - 1;

    while (paramInBounds(edge, low)) {
      low = value - 2 * (value - low);

      if (low == Double.NEGATIVE_INFINITY) {
        break;
      }
    }

    double rangeLow;

    if (low == Double.NEGATIVE_INFINITY) {
      rangeLow = low;
    } else {

      // find the boundary using binary search.
      high = value;

      while (high - low > 1e-10) {
        double midpoint = (high + low) / 2.0;

        if (paramInBounds(edge, midpoint)) {
          high = midpoint;
        } else {
          low = midpoint;
        }
      }

      rangeLow = (high + low) / 2.0;
    }

    if (Edges.isDirectedEdge(edge)) {
      edgeParameters.put(edge, initial);
    } else if (Edges.isBidirectedEdge(edge)) {
      edgeParameters.put(edge, initial);
    }

    return new ParameterRange(edge, value, rangeLow, rangeHigh);
  }