/** * @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; }
/** * Sets the coefficient for the a->b edge to the given coefficient, if within range. Otherwise * does nothing. * * @param a a -> b * @param b a -> b * @param coef The coefficient of a -> b. * @return true if the coefficent was set (i.e. was within range), false if not. */ public boolean setEdgeCoefficient(Node a, Node b, final double coef) { Edge edge = Edges.directedEdge(a, b); if (edgeParameters.get(edge) == null) { throw new NullPointerException("Not a coefficient parameter in this model: " + edge); } if (editingEdge == null || !edge.equals(editingEdge)) { range = getParameterRange(edge); editingEdge = edge; } if (coef > range.getLow() && coef < range.getHigh()) { edgeParameters.put(edge, coef); return true; } return false; // if (!paramInBounds(edge, coef)) { // edgeParameters.put(edge, d); // return false; // } // // edgeParameters.put(edge, coef); // return true; }
/** * Sets the covariance for the a<->b edge to the given covariance, if within range. Otherwise does * nothing. * * @param a a <-> b * @param b a <-> b * @param covar The covariance of a <-> b. * @return true if the coefficent was set (i.e. was within range), false if not. */ public boolean setErrorCovariance(Node a, Node b, final double covar) { Edge edge = Edges.bidirectedEdge(semGraph.getExogenous(a), semGraph.getExogenous(b)); if (edgeParameters.get(edge) == null) { throw new IllegalArgumentException("Not a covariance parameter in this model: " + edge); } if (editingEdge == null || !edge.equals(editingEdge)) { range = getParameterRange(edge); editingEdge = edge; } if (covar > range.getLow() && covar < range.getHigh()) { edgeParameters.put(edge, covar); return true; } else { return false; } // if (!paramInBounds(edge, coef)) { // edgeParameters.put(edge, d); // return false; // } // // edgeParameters.put(edge, coef); // return true; // if (!paramInBounds(edge, covar)) { // edgeParameters.put(edge, d); // return false; // } // // edgeParameters.put(edge, covar); // return true; }
/** * @return a map from error to error variances, or to Double.NaN where these cannot be computed. */ public Map<Node, Double> errorVariances() { Map<Node, Double> errorVarances = new HashMap<Node, Double>(); for (Node error : getErrorNodes()) { errorVarances.put(error, getErrorVariance(error)); } return errorVarances; }
/** Returns the next available session name in the series untitled1.tet, untitled2.tet, etc. */ private String getNewSessionName() { String base = "untitled"; String suffix = ".tet"; int i = 0; // Sequence 1, 2, 3, ... loop: while (true) { i++; String name = base + i + suffix; for (Object _o : framesMap.keySet()) { if (_o instanceof SessionEditor) { SessionEditor sessionEditor = (SessionEditor) _o; SessionEditorWorkbench workbench = sessionEditor.getSessionWorkbench(); SessionWrapper sessionWrapper = workbench.getSessionWrapper(); if (sessionWrapper.getName().equals(name)) { continue loop; } } } return name; } }
public void closeFrontmostSession() { JInternalFrame[] frames = desktopPane.getAllFramesInLayer(0); if (frames.length > 0) { frames[0].dispose(); Map<SessionEditor, JInternalFrame> framesMap = this.framesMap; for (Iterator<SessionEditor> i = framesMap.keySet().iterator(); i.hasNext(); ) { SessionEditor key = i.next(); JInternalFrame value = framesMap.get(key); if (value == frames[0]) { i.remove(); break; } } } }
/** * Adds a component to the middle layer of the desktop--that is, the layer for session node * editors. Note: The comp is a SessionEditor */ public void addSessionEditor(SessionEditorIndirectRef editorRef) { SessionEditor editor = (SessionEditor) editorRef; JInternalFrame frame = new TetradInternalFrame(null); frame.getContentPane().add(editor); framesMap.put(editor, frame); editor.addPropertyChangeListener(this); // Set the "small" size of the frame so that it has sensible // bounds when the users unmazimizes it. Dimension fullSize = desktopPane.getSize(); int smallSize = Math.min(fullSize.width - MARGIN, fullSize.height - MARGIN); Dimension size = new Dimension(smallSize, smallSize); setGoodBounds(frame, desktopPane, size); desktopPane.add(frame); // Set the frame to be maximized. This step must come after the frame // is added to the desktop. -Raul. 6/21/01 try { frame.setMaximum(true); } catch (Exception e) { throw new RuntimeException("Problem setting frame to max: " + frame); } desktopPane.setLayer(frame, 0); frame.moveToFront(); frame.setTitle(editor.getName()); frame.setVisible(true); setMainTitle(editor.getName()); }
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); }
private boolean paramInBounds(Edge edge, double newValue) { edgeParameters.put(edge, newValue); Map<Node, Double> errorVariances = new HashMap<Node, Double>(); for (Node node : semPm.getVariableNodes()) { Node error = semGraph.getExogenous(node); double d2 = calculateErrorVarianceFromParams(error); if (Double.isNaN(d2)) { return false; } errorVariances.put(error, d2); } if (!MatrixUtils.isPositiveDefinite(errCovar(errorVariances))) { return false; } return true; }
/** * @param a a->b * @param b a->b * @return The coefficient for a->b. */ public double getErrorCovariance(Node a, Node b) { Edge edge = Edges.bidirectedEdge(semGraph.getExogenous(a), semGraph.getExogenous(b)); Double d = edgeParameters.get(edge); if (d == null) { throw new IllegalArgumentException("Not a covariance parameter in this model: " + edge); } return d; }
/** * @param a a->b * @param b a->b * @return The coefficient for a->b. */ public double getEdgeCoefficient(Node a, Node b) { Edge edge = Edges.directedEdge(a, b); Double d = edgeParameters.get(edge); if (d == null) { return Double.NaN; // throw new IllegalArgumentException("Not a directed edge in this model: " + // edge); } return d; }
/** * @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; }
/** @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(); }
/** * 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; }
/** * @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); }
/** * Constructs a new standardized SEM IM from the freeParameters in the given SEM IM. * * @param im Stop asking me for these things! The given SEM IM!!! * @param initialization CALCULATE_FROM_SEM if the initial values will be calculated from the * given SEM IM; INITIALIZE_FROM_DATA if data will be simulated from the given SEM, * standardized, and estimated. */ public StandardizedSemIm(SemIm im, Initialization initialization) { this.semPm = new SemPm(im.getSemPm()); this.semGraph = new SemGraph(semPm.getGraph()); semGraph.setShowErrorTerms(true); if (semGraph.existsDirectedCycle()) { throw new IllegalArgumentException("The cyclic case is not handled."); } if (initialization == Initialization.CALCULATE_FROM_SEM) { // This code calculates the new coefficients directly from the old ones. edgeParameters = new HashMap<Edge, Double>(); List<Node> nodes = im.getVariableNodes(); TetradMatrix impliedCovar = im.getImplCovar(true); for (Parameter parameter : im.getSemPm().getParameters()) { if (parameter.getType() == ParamType.COEF) { Node a = parameter.getNodeA(); Node b = parameter.getNodeB(); int aindex = nodes.indexOf(a); int bindex = nodes.indexOf(b); double vara = impliedCovar.get(aindex, aindex); double stda = Math.sqrt(vara); double varb = impliedCovar.get(bindex, bindex); double stdb = Math.sqrt(varb); double oldCoef = im.getEdgeCoef(a, b); double newCoef = (stda / stdb) * oldCoef; edgeParameters.put(Edges.directedEdge(a, b), newCoef); } else if (parameter.getType() == ParamType.COVAR) { Node a = parameter.getNodeA(); Node b = parameter.getNodeB(); Node exoa = semGraph.getExogenous(a); Node exob = semGraph.getExogenous(b); double covar = im.getErrCovar(a, b) / Math.sqrt(im.getErrVar(a) * im.getErrVar(b)); edgeParameters.put(Edges.bidirectedEdge(exoa, exob), covar); } } } else { // This code estimates the new coefficients from simulated data from the old model. DataSet dataSet = im.simulateData(1000, false); TetradMatrix _dataSet = dataSet.getDoubleData(); _dataSet = DataUtils.standardizeData(_dataSet); DataSet dataSetStandardized = ColtDataSet.makeData(dataSet.getVariables(), _dataSet); SemEstimator estimator = new SemEstimator(dataSetStandardized, im.getSemPm()); SemIm imStandardized = estimator.estimate(); edgeParameters = new HashMap<Edge, Double>(); for (Parameter parameter : imStandardized.getSemPm().getParameters()) { if (parameter.getType() == ParamType.COEF) { Node a = parameter.getNodeA(); Node b = parameter.getNodeB(); double coef = imStandardized.getEdgeCoef(a, b); edgeParameters.put(Edges.directedEdge(a, b), coef); } else if (parameter.getType() == ParamType.COVAR) { Node a = parameter.getNodeA(); Node b = parameter.getNodeB(); Node exoa = semGraph.getExogenous(a); Node exob = semGraph.getExogenous(b); double covar = -im.getErrCovar(a, b) / Math.sqrt(im.getErrVar(a) * im.getErrVar(b)); edgeParameters.put(Edges.bidirectedEdge(exoa, exob), covar); } } } this.measuredNodes = Collections.unmodifiableList(semPm.getMeasuredNodes()); }