\documentclass{article}
\newcommand{\titel}{\pkg{lavaan}: internals}
%\usepackage{Sweave}
\usepackage{fancyvrb}
\usepackage{graphicx}
\usepackage{color}


\usepackage{times}
\usepackage{sectsty}
\usepackage{tikz}
\tikzstyle{ov}=[shape=rectangle,
                draw=black!80,
                minimum height=0.6cm,
                minimum width=0.6cm,
                thick]

\tikzstyle{av}=[shape=rectangle,
                draw=black!80,
                fill=black!10,
                minimum height=0.6cm,
                minimum width=0.6cm,
                thick]

\tikzstyle{lv}=[shape=circle,draw=black!80,thick,minimum width=0.7cm]


\fvset{fontfamily=courier}
\DefineVerbatimEnvironment{Sinput}{Verbatim}
{fontseries=b, fontsize=\footnotesize, xleftmargin=0.2cm}
\DefineVerbatimEnvironment{Routput}{Verbatim}
{fontsize=\footnotesize, xleftmargin=1cm}
\DefineVerbatimEnvironment{Routput}{Verbatim}
{fontseries=b,fontsize=\scriptsize, xleftmargin=0.2cm}
\DefineVerbatimEnvironment{Binput}{Verbatim}
{fontseries=b, fontsize=\scriptsize,frame=single, label=\fbox{lavaan model syntax}, framesep=2mm}
%\DefineShortVerb{\!}
\DefineVerbatimEnvironment{Rinput}{Verbatim}
{fontseries=b, fontsize=\scriptsize, frame=single, label=\fbox{R code}, framesep=5mm}


\newcommand{\pkg}[1]{{\normalfont\fontseries{b}\selectfont #1}}
\let\proglang=\textsf
\let\code=\texttt

\usepackage{amsmath}
\newcommand{\tr}{\textsf{tr}}
\usepackage{bm}
\newcommand{\vet}[1]{\ensuremath{\bm{\mathrm{#1}}}}

% colors
\definecolor{darkred}{rgb}{.4, .0, .0}
\definecolor{darkblue}{rgb}{.0, .0, .4}
\definecolor{darkgreen}{rgb}{.0, .3, .0}
\definecolor{darkgray}{rgb}{.6, .6, .6}
\definecolor{brown}{rgb}{.3, .3, .0}
\subsectionfont{\color{darkgreen}}
\sectionfont{\color{darkblue}}
\subsubsectionfont{\sffamily\color{brown}}

\usepackage{geometry}
\geometry{paperwidth=12.8cm, paperheight=9.6cm,
          includeheadfoot,
          scale={0.90,0.95},
          headsep=0.3cm,footskip=0.4cm
         }

\usepackage{fancyhdr}
\usepackage{lastpage}
\pagestyle{fancy}
\renewcommand{\headrulewidth}{0.1mm}
\renewcommand{\footrulewidth}{0.1mm}
\lhead{\tiny \sffamily Department of Data Analysis}
\chead{}
\rhead{\tiny \sffamily Ghent University}
\lfoot{\tiny \sffamily Yves Rosseel}
\cfoot{\tiny \sffamily \textcolor{darkred}{\titel}}
\rfoot{\tiny \sffamily \thepage\ / {\normalcolor \pageref{LastPage}}}

\usepackage{booktabs}
\renewcommand{\arraystretch}{1.2}



\author{Yves Rosseel\\
Department of Data Analysis\\
Ghent University -- Belgium}
\date{\vspace*{1cm}Utrecht -- April 24, 2012}
\title{\textcolor{darkred}{\titel}}

\newcommand{\sss}[1]{\subsubsection*{#1}}
\newcommand{\lijn}{\mbox{}\\*[0.04\textheight]}


\begin{document}
\maketitle\thispagestyle{fancy}\newpage
%\tableofcontents\newpage

\subsection*{Overview}
\begin{enumerate}
\item model, data, and discrepancy functions
\item from model syntax to model matrices
\item the lavaan class for representing a fitted model
\item how to extend lavaan
\end{enumerate}

\newpage
\subsection*{Model fitting: model + data + discrepancy function}
\sss{The model}
\begin{itemize}
\item the user needs to be able to specify/describe his/her model
\item the default approach: lavaan model syntax
\item internal representation: the {\bfseries parameter table}
\begin{itemize}
\item complete description of the model 
\item does not depend on the traditional `matrix' representation\\
    (LISREL, Bentler-Weeks, RAM, \ldots)
\item computing on the model
\end{itemize}
\item future plans:
\begin{itemize}
\item specify model matrices directly
\item read/parse/write LISREL/EQS/Mplus syntax
\item graphical/GUI interface
\end{itemize}
\end{itemize}

\newpage
\sss{The data}
\begin{itemize}
\item default input: a regular R data.frame
\begin{itemize}
\item @Data slot describes the data: which observed variables are used,
number of groups, missing data, \ldots
\item @Data@X contains a copy of the raw data (a list of matrices; one per group)
\end{itemize}
\item alternative input: sample statistics (covariance matrix, mean vector)
\begin{itemize}
\item no robust standard errors, no scaled test statistics
\item no missing data
\end{itemize}
\item partially implemented: simulated data
\begin{itemize}
\item \code{simulateData()}
\item \code{bootstrapLavaan()}
\end{itemize}
\end{itemize}

\newpage
\sss{The discrepancy function}
\begin{itemize}
\item currently all discrepancy function are hard-wired in the code
\item focus on covariance structure and mean structure analysis
\begin{itemize}
\item traditional ML
\[ F_{ML}(\vet{\theta}) = \log |\vet{\Sigma}| + 
  \tr(\vet{S} \vet{\Sigma}^{-1}) - \log |\vet{S}| - p
\]
\item FIML (direct ML, missing data, pattern-based)
\item least-squares: GLS, WLS
\end{itemize}
\item future plans:
\begin{itemize}
\item user-specified discrepancy functions
\item not only covariance/mean structure analysis, but any arbitrary model
    fitting function
\end{itemize}
\end{itemize}

\newpage
\sss{The optimizer}
\begin{itemize}
\item default without constraints:
\begin{itemize}
    \item \code{nlminb} (builtin R optimizer)
    \item quasi-newton with analytical gradients
    \item manual parameter scaling
\end{itemize}        
\item with constraints: 
\begin{itemize}
\item \code{nlminb.constr} (lavaan specific)
\item augmented Lagrangian multiplier method
\item slow for simple problems
\item we need better strategies for specific cases
\end{itemize}
\item we need better optimizers (in R)!
\end{itemize}

\newpage
\subsection*{From model syntax to model matrices}
\sss{The model syntax}
\begin{Sinput}
HS.model <- ' 
    # some random comment
    visual  =~ x1 + a*x2 + a*x3
    textual =~ x4 + 0.8*x5 + 1.2*x6

    # some blank lines
    speed   =~ x7 + start(0.5)*x8 + x9
'    
\end{Sinput}
\sss{The lavaanify() function}
\begin{enumerate}
    \item phase I:  parses the model syntax and `flattens' the model equations
    \item phase II: creates a complete parameter table, representing the model
          as specified by the user
\end{enumerate}

\newpage
\sss{phase I: parseModelString()}
\begin{Sinput}
FLAT <- parseModelString(HS.model)
as.data.frame(FLAT)
\end{Sinput}
\begin{Routput}
      lhs op rhs mod.idx group fixed start label
1  visual =~  x1       0     0                  
2  visual =~  x2       1     0                 a
3  visual =~  x3       2     0                 a
4 textual =~  x4       0     0                  
5 textual =~  x5       3     0   0.8            
6 textual =~  x6       4     0   1.2            
7   speed =~  x7       0     0                  
8   speed =~  x8       5     0         0.5      
9   speed =~  x9       0     0    
\end{Routput}

\sss{phase II: lavaanify()}
\begin{Sinput}
ParTable <- lavaanify(FLAT, auto.var=TRUE, auto.cov.lv.x=TRUE)
ParTable
\end{Sinput}

\newpage
\sss{The parameter table}
\begin{Routput}
   id     lhs op     rhs user group free ustart exo label eq.id unco
1   1  visual =~      x1    1     1    1     NA   0           0    1
2   2  visual =~      x2    1     1    2     NA   0     a     2    2
3   3  visual =~      x3    1     1    2     NA   0     a     2    3
4   4 textual =~      x4    1     1    3     NA   0           0    4
5   5 textual =~      x5    1     1    0    0.8   0           0    0
6   6 textual =~      x6    1     1    0    1.2   0           0    0
7   7   speed =~      x7    1     1    4     NA   0           0    5
8   8   speed =~      x8    1     1    5    0.5   0           0    6
9   9   speed =~      x9    1     1    6     NA   0           0    7
10 10      x1 ~~      x1    0     1    7     NA   0           0    8
11 11      x2 ~~      x2    0     1    8     NA   0           0    9
12 12      x3 ~~      x3    0     1    9     NA   0           0   10
13 13      x4 ~~      x4    0     1   10     NA   0           0   11
14 14      x5 ~~      x5    0     1   11     NA   0           0   12
15 15      x6 ~~      x6    0     1   12     NA   0           0   13
16 16      x7 ~~      x7    0     1   13     NA   0           0   14
17 17      x8 ~~      x8    0     1   14     NA   0           0   15
18 18      x9 ~~      x9    0     1   15     NA   0           0   16
19 19  visual ~~  visual    0     1   16     NA   0           0   17
20 20 textual ~~ textual    0     1   17     NA   0           0   18
21 21   speed ~~   speed    0     1   18     NA   0           0   19
22 22  visual ~~ textual    0     1   19     NA   0           0   20
23 23  visual ~~   speed    0     1   20     NA   0           0   21
24 24 textual ~~   speed    0     1   21     NA   0           0   22
\end{Routput}

\sss{lavaanify() arguments}
\begin{Sinput}
lavaanify(model = NULL, meanstructure = FALSE, int.ov.free = FALSE, 
    int.lv.free = FALSE, orthogonal = FALSE, std.lv = FALSE, 
    fixed.x = TRUE, constraints = NULL, auto = FALSE, model.type = "sem", 
    auto.fix.first = FALSE, auto.fix.single = FALSE, auto.var = FALSE, 
    auto.cov.lv.x = FALSE, auto.cov.y = FALSE, ngroups = 1L, 
    group.equal = NULL, group.partial = NULL, debug = FALSE, 
    warn = TRUE, as.data.frame. = TRUE)
\end{Sinput}

\sss{extracting variable names from a parameter table}
\begin{Sinput}
# observed variables
lavaanNames(ParTable, type="ov")
\end{Sinput}
\begin{Routput}
[1] "x1" "x2" "x3" "x4" "x5" "x6" "x7" "x8" "x9"    
\end{Routput}

\begin{Sinput}
# latent variables
lavaanNames(ParTable, type="lv")
\end{Sinput}
\begin{Routput}
[1] "visual"  "textual" "speed"
\end{Routput}

\newpage
\sss{Computing on the parameter table}
\begin{itemize}
\item get number of free parameters 
\begin{Sinput}
> lavaan:::getNPAR(ParTable)
[1] 21
\end{Sinput}
\item get number of datapoints
\begin{Sinput}
> lavaan:::getNDAT(ParTable)
[1] 45
\end{Sinput}
\item get degrees of freedom
\begin{Sinput}
> lavaan:::getDF(ParTable)
[1] 24
\end{Sinput}
\item check if the model is identified
\item plot the model
\item export the model to LISREL/EQS/Mplus/... syntax
\item \ldots
\end{itemize}

\newpage
\sss{From parameter table to model matrices}
\begin{Sinput}
LisrelMM <- as.data.frame(lavaan:::representation.LISREL(ParTable))
cbind(ParTable[,1:7], LisrelMM)
\end{Sinput}
\begin{Routput}
   id     lhs op     rhs user group free    mat row col
1   1  visual =~      x1    1     1    1 lambda   1   1
2   2  visual =~      x2    1     1    2 lambda   2   1
3   3  visual =~      x3    1     1    2 lambda   3   1
4   4 textual =~      x4    1     1    3 lambda   4   2
5   5 textual =~      x5    1     1    0 lambda   5   2
6   6 textual =~      x6    1     1    0 lambda   6   2
7   7   speed =~      x7    1     1    4 lambda   7   3
8   8   speed =~      x8    1     1    5 lambda   8   3
9   9   speed =~      x9    1     1    6 lambda   9   3
10 10      x1 ~~      x1    0     1    7  theta   1   1
11 11      x2 ~~      x2    0     1    8  theta   2   2
12 12      x3 ~~      x3    0     1    9  theta   3   3
13 13      x4 ~~      x4    0     1   10  theta   4   4
14 14      x5 ~~      x5    0     1   11  theta   5   5
15 15      x6 ~~      x6    0     1   12  theta   6   6
16 16      x7 ~~      x7    0     1   13  theta   7   7
17 17      x8 ~~      x8    0     1   14  theta   8   8
18 18      x9 ~~      x9    0     1   15  theta   9   9
19 19  visual ~~  visual    0     1   16    psi   1   1
20 20 textual ~~ textual    0     1   17    psi   2   2
21 21   speed ~~   speed    0     1   18    psi   3   3
...
\end{Routput}

\sss{Model matrices: free parameters}
\begin{Routput}
$lambda                                $psi
   visual textul speed                         visual textul speed
x1      0      0     0                 visual  13
x2      1      0     0                 textual 16     14
x3      1      0     0                 speed   17     18     15
x4      0      0     0
x5      0      0     0
x6      0      0     0
x7      0      0     0
x8      0      0     2
x9      0      0     3

$theta
   x1 x2 x3 x4 x5 x6 x7 x8 x9
x1  4                        
x2  0  5                     
x3  0  0  6                  
x4  0  0  0  7               
x5  0  0  0  0  8
x6  0  0  0  0  0  9
x7  0  0  0  0  0  0 10
x8  0  0  0  0  0  0  0 11
x9  0  0  0  0  0  0  0  0 12
\end{Routput}
\begin{itemize}
    \item version 0.4-13: no self-contained function (yet!)
\end{itemize}

\newpage
\sss{Model matrices: starting values}
\begin{Routput}
$lambda                                $psi
   visual textul speed                         visual textul speed
x1      1    0.0   0.0                 visual  0.05
x2      1    0.0   0.0                 textual 0.00   0.05
x3      1    0.0   0.0                 speed   0.00   0.00   0.05
x4      0    1.0   0.0
x5      0    0.8   0.0
x6      0    1.2   0.0
x7      0    0.0   1.0
x8      0    0.0   0.5
x9      0    0.0   1.0

$theta
   x1    x2    x3    x4    x5    x6    x7    x8    x9   
x1 0.679                                                
x2 0.000 0.691                                          
x3 0.000 0.000 0.637                                    
x4 0.000 0.000 0.000 0.675                              
x5 0.000 0.000 0.000 0.000 0.830                        
x6 0.000 0.000 0.000 0.000 0.000 0.598                  
x7 0.000 0.000 0.000 0.000 0.000 0.000 0.592            
x8 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.511      
x9 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.508
\end{Routput}

\newpage
\sss{From model matrices to a parameter vector \ldots}
\begin{itemize}
\item the optimizer needs a parameter vector (not a matrix list)
\item we extract the `free' parameters from each matrix and place
the unduplicated ones in a vector
\begin{Routput}
> fit@Model@x.free.idx
[[1]]
[1] 1 1 2 3

[[2]]
[1]  4  5  6  7  8  9 10 11 12

[[3]]
[1] 13 16 17 16 14 18 17 18 15
\end{Routput}
\item internal function:
\begin{Sinput}
> x <- lavaan:::getModelParameters(Model)
> x
 [1] 1.0000000 0.5000000 1.0000000 0.6791849 0.6908919 0.6374324
 [7] 0.6753323 0.8298929 0.5981792 0.5915697 0.5109914 0.5075019
[13] 0.0500000 0.0500000 0.0500000 0.0000000 0.0000000 0.0000000
\end{Sinput}
\end{itemize}

\newpage
\sss{\ldots and back}
\begin{itemize}
\item each iteration, we need to (re)compute the model-implied
covariance matrix
\begin{Routput}
> fit@Model@m.free.idx
[[1]]
[1]  2  3 26 27

[[2]]
[1]  1 11 21 31 41 51 61 71 81

[[3]]
[1] 1 2 3 4 5 6 7 8 9
\end{Routput}
\item objective function (simplified):
\begin{Sinput}
minimize.this.function <- function(x) {

    # update model matrices
    GLIST <- x2GLIST(object, x=x)

    # compute function value
    fx <- computeObjective(object, GLIST=GLIST, sample, ...)

    fx
}                           
\end{Sinput}
\end{itemize}

\newpage
\subsection*{The `lavaan' class}
\begin{itemize}
\item all fitting functions (\code{sem}, \code{cfa}, \code{growth}, \code{lavaan}) create an object of class `lavaan'
\item lavaan 0.4-13 currently uses S4 classes
\item future releases may replace this partially/entirely with reference
    classes
\item many methods for this `lavaan' class exist; see \code{class?lavaan}
for an overview
\item a `lavaan' object contains the following slots:
\begin{Sinput}
> example(cfa)
> slotNames(fit)
[1] "call"    "timing"  "Options" "User"    "Data"    "Sample" 
[7] "Model"   "Fit"
\end{Sinput}
\item warning: the names are likely to change in the (near) future
\end{itemize}

\newpage
\sss{slots \code{@call} and \code{@timing}}
\begin{itemize}
\item \code{@call} contains the function call as returned by \code{match.called()}
\begin{Sinput}
lavaan(model = HS.model, model.type = "cfa", int.ov.free = TRUE, 
    int.lv.free = FALSE, auto.fix.first = TRUE, auto.fix.single = TRUE, 
    auto.var = TRUE, auto.cov.lv.x = TRUE, auto.cov.y = TRUE, 
    data = HolzingerSwineford1939)
\end{Sinput}
\item \code{@timing} contains the elapsed time (user+system) for various 
parts of the program as a list, including the total time
\begin{Sinput}
> unlist(fit@timing)
InitOptions.elapsed    InitData.elapsed        User.elapsed 
              0.002               0.002               0.003 
     Sample.elapsed       Start.elapsed       Model.elapsed 
              0.002               0.001               0.003 
   Estimate.elapsed        VCOV.elapsed        TEST.elapsed 
              0.036               0.002               0.000 
      total.elapsed 
              0.054
\end{Sinput}
\end{itemize}

\newpage
\sss{slot \code{@Options}}
\begin{itemize}
\item program-wide options
\item in future releases, we may remove this slot
\item example:
\begin{Sinput}
          model      model.type   meanstructure     int.ov.free 
    "   ...   "           "cfa"         "FALSE"          "TRUE" 
    int.lv.free         fixed.x      orthogonal          std.lv 
        "FALSE"          "TRUE"         "FALSE"         "FALSE" 
 auto.fix.first auto.fix.single        auto.var   auto.cov.lv.x 
         "TRUE"          "TRUE"          "TRUE"          "TRUE" 
     auto.cov.y          std.ov         missing     constraints 
         "TRUE"         "FALSE"      "listwise"              "" 
      estimator      likelihood     information              se 
           "ML"        "normal"      "expected"      "standard" 
           test       bootstrap           mimic  representation 
     "standard"          "1000"        "lavaan"        "LISREL" 
         do.fit         verbose            warn           debug 
         "TRUE"         "FALSE"          "TRUE"         "FALSE" 
      data.type 
         "full"
\end{Sinput}
\end{itemize}

\newpage
\sss{slot \code{@User}}
\begin{itemize}
\item the parameter table
\item the name refers to the 'user'-specified model
\item is a list, but can be coerced to a data.frame
\end{itemize}
\begin{Sinput}
$id
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22
[23] 23 24

$lhs
 [1] "visual"  "visual"  "visual"  "textual" "textual" "textual"
 [7] "speed"   "speed"   "speed"   "x1"      "x2"      "x3"     
[13] "x4"      "x5"      "x6"      "x7"      "x8"      "x9"     
[19] "visual"  "textual" "speed"   "visual"  "visual"  "textual"

$op
 [1] "=~" "=~" "=~" "=~" "=~" "=~" "=~" "=~" "=~" "~~" "~~" "~~" "~~"
[14] "~~" "~~" "~~" "~~" "~~" "~~" "~~" "~~" "~~" "~~" "~~"
...
\end{Sinput}

\newpage
\sss{slot \code{@Data}}
\begin{itemize}
\item a description of the data
\end{itemize} 
\begin{Sinput}
Formal class 'lavaanData' [package "lavaan"] with 9 slots
  ..@ ngroups    : int 1
  ..@ group.label: chr(0) 
  ..@ nobs       :List of 1
  .. ..$ : int 301
  ..@ norig      :List of 1
  .. ..$ : int 301
  ..@ ov.names   :List of 1
  .. ..$ : chr [1:9] "x1" "x2" "x3" "x4" ...
  ..@ ov.idx     :List of 1
  .. ..$ : int [1:9] 7 8 9 10 11 12 13 14 15
  ..@ case.idx   :List of 1
  .. ..$ : int [1:301] 1 2 3 4 5 6 7 8 9 10 ...
  ..@ Mp         :List of 1
  .. ..$ : NULL
  ..@ X          :List of 1
  .. ..$ : num [1:301, 1:9] 3.33 5.33 4.5 5.33 4.83 ...
\end{Sinput}

\newpage
\sss{slot \code{@Sample}: sample statistics}
\begin{Sinput}
Formal class 'SampleStats' [package "lavaan"] with 12 slots
  ..@ cov         :List of 1
  .. ..$ : num [1:9, 1:9] 1.358 0.407 0.58 0.505 0.441 ...
  ..@ mean        :List of 1
  .. ..$ : num [1:9] 4.94 6.09 2.25 3.06 4.34 ...
  ..@ nobs        :List of 1
  .. ..$ : int 301
  ..@ ntotal      : int 301
  ..@ ngroups     : int 1
  ..@ icov        :List of 1
  .. ..$ : num [1:9, 1:9] 1.1474 -0.1051 -0.3267 -0.2723 0.0344 ...
  ..@ cov.log.det :List of 1
  .. ..$ : num -0.989
  ..@ cov.vecs    :List of 1
  .. ..$ : num [1:45] 1.358 0.407 0.58 0.505 0.441 ...
  ..@ WLS.V       :List of 1
  .. ..$ : NULL
  ..@ missing.flag: logi FALSE
  ..@ missing     :List of 1
  .. ..$ : NULL
  ..@ missing.h1  :List of 1
  .. ..$ : NULL
\end{Sinput}

\newpage
\sss{slot \code{@Model}: model matrices and more}
\begin{Sinput}
Formal class 'Model' [package "lavaan"] with 30 slots
  ..@ GLIST           :List of 3
  .. ..$ lambda: num [1:9, 1:3] 1 0.553 0.729 0 0 ...
  .. ..$ theta : num [1:9, 1:9] 0.549 0 0 0 0 ...
  .. ..$ psi   : num [1:3, 1:3] 0.809 0.408 0.262 0.408 0.979 ...
  ..@ dimNames        :List of 3
  .. ..$ :List of 2
  .. .. ..$ : chr [1:9] "x1" "x2" "x3" "x4" ...
  .. .. ..$ : chr [1:3] "visual" "textual" "speed"
  .. ..$ :List of 2
  .. .. ..$ : chr [1:9] "x1" "x2" "x3" "x4" ...
  .. .. ..$ : chr [1:9] "x1" "x2" "x3" "x4" ...
  .. ..$ :List of 2
  .. .. ..$ : chr [1:3] "visual" "textual" "speed"
  .. .. ..$ : chr [1:3] "visual" "textual" "speed"
  ..@ isSymmetric     : logi [1:3] FALSE TRUE TRUE
  ..@ mmSize          : int [1:3] 27 45 6
  ..@ representation  : chr "LISREL"
  ..@ meanstructure   : logi FALSE
  ..@ ngroups         : int 1
  ..@ nmat            : int 3
  ..@ nvar            : int 9
  ..@ nx.free         : int 21
  ..@ nx.unco         : int 21
  ..@ nx.user         : int 24
  ..@ m.free.idx      :List of 3
  .. ..$ : int [1:6] 2 3 14 15 26 27
  .. ..$ : int [1:9] 1 11 21 31 41 51 61 71 81
  .. ..$ : int [1:9] 1 2 3 4 5 6 7 8 9
  ..@ x.free.idx      :List of 3
  .. ..$ : int [1:6] 1 2 3 4 5 6
  .. ..$ : int [1:9] 7 8 9 10 11 12 13 14 15
  .. ..$ : int [1:9] 16 19 20 19 17 21 20 21 18
  ..@ m.unco.idx      :List of 3
  .. ..$ : int [1:6] 2 3 14 15 26 27
  .. ..$ : int [1:9] 1 11 21 31 41 51 61 71 81
  .. ..$ : int [1:9] 1 2 3 4 5 6 7 8 9
  ..@ x.unco.idx      :List of 3
  .. ..$ : int [1:6] 1 2 3 4 5 6
  .. ..$ : int [1:9] 7 8 9 10 11 12 13 14 15
  .. ..$ : int [1:9] 16 19 20 19 17 21 20 21 18
  ..@ m.user.idx      :List of 3
  .. ..$ : int [1:9] 1 2 3 13 14 15 25 26 27
  .. ..$ : int [1:9] 1 11 21 31 41 51 61 71 81
  .. ..$ : int [1:9] 1 2 3 4 5 6 7 8 9
  ..@ x.user.idx      :List of 3
  .. ..$ : int [1:9] 1 2 3 4 5 6 7 8 9
  .. ..$ : int [1:9] 10 11 12 13 14 15 16 17 18
  .. ..$ : int [1:9] 19 22 23 22 20 24 23 24 21
  ..@ x.def.idx       : int(0) 
  ..@ x.ceq.idx       : int(0) 
  ..@ x.cin.idx       : int(0) 
  ..@ eq.constraints  : logi FALSE
  ..@ eq.constraints.K: num[0 , 0 ] 
  ..@ def.function    :function ()  
  ..@ ceq.function    :function ()  
  ..@ ceq.jacobian    :function ()  
  ..@ cin.function    :function ()  
  ..@ cin.jacobian    :function ()  
  ..@ con.jac         : num[0 , 0 ] 
  ..@ fixed.x         : logi FALSE
\end{Sinput}

\newpage
\sss{slot \code{@Fit}: model fit results}
\begin{Sinput}
Formal class 'Fit' [package "lavaan"] with 13 slots
  ..@ npar      : int 21
  ..@ x         : num [1:21] 0.553 0.729 1.113 0.926 1.18 ...
  ..@ start     : num [1:24] 1 0.778 1.107 1 1.133 ...
  ..@ est       : num [1:24] 1 0.553 0.729 1 1.113 ...
  ..@ se        : num [1:24] 0 0.0997 0.1091 0 0.0654 ...
  ..@ fx        : num 0.142
  ..@ fx.group  : num 0.142
  ..@ iterations: int 41
  ..@ converged : logi TRUE
  ..@ control   :List of 7
  .. ..$ eval.max: int 20000
  .. ..$ iter.max: int 10000
  .. ..$ trace   : int 0
  .. ..$ abs.tol : num 2.22e-15
  .. ..$ rel.tol : num 1e-10
  .. ..$ x.tol   : num 1.5e-08
  .. ..$ step.min: num 2.2e-14
  ..@ Sigma.hat :List of 1
  .. ..$ : num [1:9, 1:9] 1.358 0.448 0.59 0.408 0.454 ...
  ..@ Mu.hat    :List of 1
  .. ..$ : num [1:9] 0 0 0 0 0 0 0 0 0
  ..@ test      :List of 1
  .. ..$ :List of 5
  .. .. ..$ test      : chr "standard"
  .. .. ..$ stat      : num 85.3
  .. .. ..$ stat.group: num 85.3
  .. .. ..$ df        : int 24
  .. .. ..$ pvalue    : num 8.5e-09
\end{Sinput}

\newpage
\subsection*{How to extend lavaan?}
\sss{Some general guidelines}
\begin{itemize}
\item does your code need to go into lavaan, or in a separate package?
\begin{itemize}
\item soon on CRAN: the \code{semTools} package
\end{itemize}
\item use github!
\begin{itemize}
\item \verb!https://github.com/yrosseel/lavaan/!
\end{itemize}
\item try to use `accessor' functions (e.g.\ \code{coef}, 
    \code{inspect()},\ldots) 
    to `extract' information from a fitted lavaan object
\item try to avoid using internal functions that are not exported 
\item if you must use them, contact me
\item keep your contributed code in a separate file
\item will your code work with multiple groups, missing data, \ldots?
\end{itemize}

\end{document}
