# Consensus Mechanism
# Paul Sztorc
# Written in R (v 3.1.1) using Rstudio (v 0.98.1028)

# This is the mechanism that, theoretically,
 #   1] allows the software to determine the state of Decisions truthfully, and
 #   2] only allows an efficient number of most-traded-upon-Decisions.

# To my knowledge, R does not feature 'automatic working directories' unless it is being run as a script
# try(setwd("~/GitHub/Truthcoin/lib/consensus"))
source("CustomMath.r")

## Functions:

DemocracyRep <- function(X) {
  # Run this if no Reputations were given...gives everyone an equal share and equal vote.

  Dem_Rep <- ReWeight(rep(1,nrow(X)))
  return( Dem_Rep )
}

BinaryScales <- function(X, IndexOnly=FALSE) {
  # Run this if no Scales were provided..assumes none were Scaled, all are Binary (0 or 1).

  Bin_Scales <- matrix( c( rep(FALSE,ncol(X)),
                       rep(0,ncol(X)),
                       rep(1,ncol(X))), 3, byrow=TRUE, dimnames=list(c("Scaled","Min","Max"),colnames(X)) )

  if(IndexOnly) return( as.logical( Bin_Scales["Scaled",] ) )
  return( Bin_Scales )
}

GetDecisionOutcomes <- function(Mtemp, Rep = DemocracyRep(Mtemp), ScaledIndex = BinaryScales(Mtemp, TRUE), Verbose=FALSE) {
  # Determines the (raw) Outcomes of Decisions based on the provided reputation (weighted vote)

  if(Verbose) { print("****************************************************") ; print("Begin 'GetDecisionOutcomes'")}

  DecisionOutcomes.Raw  <- 1:ncol(Mtemp) # Declare this (filled below)

  for(i in 1:ncol(Mtemp)) {
    #For each column:
    Row <- ReWeight(Rep[!is.na(Mtemp[,i])]) # The Reputation of the row-players who DID provide judgements, rescaled to sum to 1.
    Col <- Mtemp[!is.na(Mtemp[,i]),i]       # The relevant Decision with NAs removed. ("What these row-players had to say about the Decisions they DID judge.")

    #Discriminate Based on Contract Type
    if(!ScaledIndex[i]) DecisionOutcomes.Raw[i] <- Row %*% Col                   # Our Current best-guess for this Binary Decision (weighted average)
    if(ScaledIndex[i]) DecisionOutcomes.Raw[i] <- weighted.median(w=Row, x=Col)  # Our Current best-guess for this Scaled Decision (weighted median)

    if(Verbose) { print("** **"); print("Column:"); print(i); print(AsMatrix(Row)); print(Col); print("Consensus:"); print(DecisionOutcomes.Raw[i]) }
  }

  #Output
  return(DecisionOutcomes.Raw)
}

# M <- matrix( data=c(
#       1,    1,    0,    0,    0.5356322, 6.689658e-01,
#       1,    0,    0,    0,    0.4574713,           NA,
#       1,    1,    0,    0,    0.5356322, 6.689658e-01,
#       1,    1,    1,    0,    0.5747126,           NA,
#       0,    0,    1,    1,    1.0000000, 8.333333e-05,
#       0,    0,    1,    1,    1.0000000, 9.999167e-01),
#   nrow=6,byrow=TRUE)

# > GetDecisionOutcomes(Mtemp=M, ScaledIndex=c(FALSE, FALSE, FALSE, FALSE, TRUE, TRUE))
# [1] 0.6666667 0.5000000 0.5000000 0.3333333 0.5551724 0.6689658
# > GetDecisionOutcomes(Mtemp=M, ScaledIndex=c(FALSE, FALSE, FALSE, FALSE, FALSE, TRUE))
# [1] 0.6666667 0.5000000 0.5000000 0.3333333 0.6839080 0.6689658
# > GetDecisionOutcomes(Mtemp=M, ScaledIndex=c(TRUE, FALSE, FALSE, FALSE, FALSE, FALSE), Rep=c(.2,.2,.1,.4,.04,.06))
# [1] 1.0000000 0.7000000 0.5000000 0.1000000 0.5820690 0.6517202

GetRewardWeights <- function(M, Rep=DemocracyRep(M), ScaledIndex = BinaryScales(M, TRUE), alpha=.1, Tol=.2, Verbose=FALSE, RBCR=6) {
  # Calculates the new reputations using WPCA

  if(Verbose) {
    print("****************************************************")
    print("Begin 'GetRewardWeights'")
    print("Inputs...")
    print("Matrix:")
    print(M)
    print("")
    print("Reputation:")
    print(AsMatrix(Rep))
    print("")
  }

  Results <- WeightedPrinComp(M,Rep)

  FirstLoading <- Results$Loadings #The first loading is designed to indicate which Decisions were more 'agreed-upon' than others.
  FirstScore   <- Results$Scores   #The scores show loadings on consensus (to what extent does this observation represent consensus?)

  if(Verbose) { print("First Loading:"); print(FirstLoading); print("First Score:"); print(AsMatrix(FirstScore)) }

  # Skip all of this if there is pefect consensus (ie, all people agree).

  # Declared here, filled below (unless there was a perfect consensus).
  NewRep <- Rep # By default, reputations don't change if everyone agrees.

  if( ! sum(abs(FirstScore))==0 ) {

    ## Choosing Among Two Score-Persepectives

    # Now we have some work to do on the FirstScore.

    # PCA, being an abstract factorization, is incapable of determining anything absolute.
    # Therefore the results of the entire procedure would theoretically be reversed if the average state of Decisions changed from TRUE to FALSE.
    # Because the average state of Decisions is a function both of randomness and the way the Decisions are worded, I check to see which of the
    # two possible 'new' reputation vectors had more opinion in common with the original 'old' reputation.

    # The two options:
    Option1 <-  FirstScore + abs( min(FirstScore) )
    Option2 <-  abs( FirstScore - max(FirstScore) )

    # For each option:

    Score_Reflect <- function( Component, Previous_Reputation ) {
      # Takes an adjusted score, and breaks it at a median point.

      # Only if there actually is a median point.
      if( length( unique(Component) ) <= 2 ) return(Component)

      # If the Reps are calculated directly, there is an exploit in generating "sacrificial variance" and passing it to a teammate.
      # Although initially the sac-var is zero-sum (pointless), after reweighting it can become helpful to attackers.

      # Instead, a simple adjustment:
      MedianFactor <- weighted.median(Component, w = Previous_Reputation) # Which component is in the center?
      # This central value will be the next maximum, NOT the value opposite the most-deviant.

      # By how much does the component exceed the Median?
      Reflection <- Component - MedianFactor
      # Where does the Component exceed the Median?
      Excessive <- ( Reflection > 0 )

      # Declare and Fill Answer
      AdjPrinComp <- Component
      AdjPrinComp[ Excessive ] <- Component[ Excessive ] - (  Reflection[ Excessive ] * 0.5  ) # Mixes in some of the old method.
      # Check: max(Component) == MedianFactor # TRUE

      return(AdjPrinComp)
    }

    NewScore_1 <- Score_Reflect(Option1, Rep)
    NewScore_2 <- Score_Reflect(Option2, Rep)

    # Now, by what criteria do we compare the options?
    # (This should be easy, because one option will be the opposite of truth, but it deserves some thought nonetheless.)

    Method <- RBCR # All of these work very well, but I'm pretty sure that Method 6 is the best.

    if( Method == 1 ) {
      # Statistics Method
      # "Which set would produce more representative results?"

      New1 <- GetWeight(Set1) %*% M  # reweight to the reputation units first, then calculate what outcomes would resolve to using this Rep
      New2 <- GetWeight(Set2) %*% M

      RefInd <- sum( (New1-Old)^2 ) -  sum( (New2-Old)^2 ) # squared errors

    }

    if( Method == 2 ) {
      # Mathematics Method
      # "Which set moves the results the shortest distance?"

      New1 <- Set1 %*% M # Do not change units at all (only shift one observation to zero, and remove negatives).
      New2 <- Set2 %*% M # Notice that Set1 and Set2 already have the same max and min.

      RefInd <- sum( abs(New1-Old)) -  sum( abs(New2-Old))  # Raw errors, no squaring.

    }

    if( Method == 3 ) {
      # Rank Method
      # "Which set moves the direction the least?"

      rOld <- rank(Old)

      # Same as method 2, but focusing only on rank order. The logic being that we are focusing on the measurement of a single direction here.
      New1 <- rank( (GetWeight(Set1) %*% M) + 0.01*Old ) # I add Old because rank will erase data if final values are non-unique values
      New2 <- rank( (GetWeight(Set2) %*% M) + 0.01*Old )

      RefInd <- sum( abs(New1-rOld) ) - sum( abs(New2-rOld) )  # Raw errors, no squaring.

      if(RefInd==0) { # If the ranks are a tie, go back to Method 1

        New1 <- GetWeight(Set1) %*% M
        New2 <- GetWeight(Set2) %*% M

        RefInd <- sum( (New1-Old)^2 ) -  sum( (New2-Old)^2 ) # squared errors
      }
    }

    if( Method == 4 ) {
      # Norm Method - Operating Logic Unknown

      # Caluclate Potential Outcomes
      New1 <- GetDecisionOutcomes(M, GetWeight(Set1), ScaledIndex)
      New2 <- GetDecisionOutcomes(M, GetWeight(Set2), ScaledIndex)

      # Absolute Differences in Outcome
      Choice1 <- abs( New1 - Old )
      Choice2 <- abs( New2 - Old )

      # Absolute Relevance of Dissagreement
      Dissent <- abs(FirstLoading)

      RefInd <- (Choice1 %*% Dissent) - (Choice2 %*% Dissent)
    }

    if( Method == 5 | Method == 6 ) {
      # Use Old Reputation to calculate outcomes.
      # Examine each voter's agreement with these outcomes.
      # Collapse this agreement using this period's Loading.

      # Old Outcomes
      Old_raw <- GetDecisionOutcomes(M, Rep, ScaledIndex) # Outcomes under the previous period's reputation
      # Bin non-scaled modes into < 0, .5, 1 > using Catch()
      Old_c <- vapply(Old_raw, FUN = Catch, Tolerance = Tol, FUN.VALUE = 1)
      Old_f <- Old_c ;  Old_f[ScaledIndex] <- Old_raw[ScaledIndex]

      # Build distance matrix: absolute value of difference between "Group Outcomes (using Old)" and "Individual Outcomes"
      Distance <- abs(  M - ( array(1, dim(M)) %*% diag(Old_f) )  )

      # Separately, build index of question-cohesion
      Dissent <- abs(FirstLoading) # FirstLoading is higher when people disagree, lower when people agree, zero for perfect agreement.
      Dissent[Dissent==0] <- NA # Remove Zeros (zeros are irrelevant, not infinitely important), avoid division-by-zero problems
      Mainstream <- ReWeight( 1/Dissent )

      # Integrate the Two
      NonCompliance <- Distance %*% t(t(Mainstream))
      Compliance <- ReWeight(  abs( NonCompliance - max(NonCompliance) )  )

      # Compare - Which score has more error when it is matched up against compliance?
      Choice1 <- sum( (GetWeight(NewScore_1) - Compliance)^2 )  # Reweight is absolutely required here, as the components will always sum to different values.
      Choice2 <- sum( (GetWeight(NewScore_2) - Compliance)^2 )

      # When RefInd becomes positive, switch to Set2.
      RefInd <- Choice1 - Choice2  # When Choice1 has greater error, this will be positive.

    }

    # Rep/mean(Rep) is a correction ensuring Reputation is additive. Therefore, nothing can be gained by splitting/combining Reputation into single/multiple accounts.
    Rep1 <- GetWeight( (NewScore_1 * Rep/mean(Rep)) )
    Rep2 <- GetWeight( (NewScore_2 * Rep/mean(Rep)) )

    # The Reference Index is a measurement of error, if >0, then New1 had higher errors (use New2), and conversely if <0 use 1.
    if(RefInd <  0 ) NewRep <- Rep1
    if(RefInd >= 0 ) NewRep <- Rep2

  }

  if(Verbose) {

    print("")
    print(paste(" %% Reference Index %% :",RefInd))
    print("Estimations using: Previous Rep, Option 1, Option 2")
    print(  cbind( AsMatrix(Old_f), AsMatrix( GetDecisionOutcomes(M, Rep1, ScaledIndex) ), AsMatrix( GetDecisionOutcomes(M, Rep2, ScaledIndex) ) )  )
    print("")
    print("Previous period reputations, Option 1, Option 2, Raw1, Raw2, Selection")
    print(  cbind( AsMatrix(Rep), AsMatrix(Rep1), AsMatrix(Rep2), AsMatrix(NewScore_1), AsMatrix(NewScore_2), AsMatrix(NewRep) )  )

  }

  # Freshly-Calculated Reward (Reputation) - Exponential Smoothing
  # New Reward: NewRep
  # Old Reward: Rep
  SmoothedR <- alpha*(NewRep) + (1-alpha)*Rep

  if(Verbose) {
    print("")
    print("Corrected for Additivity , Smoothed _1 period")
    print( cbind( AsMatrix(NewRep), AsMatrix(SmoothedR)) )
  }

  # Return Data
  Out <- list("FirstL"=FirstLoading,"OldRep"=Rep,"ThisRep"=NewRep,"SmoothRep"=SmoothedR)  # Keep the factors and time information along for the ride, they are interesting.
  return(Out)
}

# M <- matrix(nrow=3,byrow=TRUE,data=c(1,0,1,0,
#                                      1,0,1,0,
#                                      1,0,0,1))
#
# M2 <- matrix(nrow=3,byrow=TRUE,data=c(.80, .1, .72, 0,
#                                       .80, .1, .62, 0,
#                                       .43, .1, .00, 1))
#
# > GetRewardWeights(M)
# $FirstL
# [1]  0.0000000  0.0000000 -0.7071068  0.7071068
# $OldRep
# [1] 0.3333333 0.3333333 0.3333333
# $ThisRep
# [1] 0.5 0.5 0.0
# $SmoothRep
# [1] 0.35 0.35 0.30
#
# > GetRewardWeights(M, Rep=c(.2,.2,.6), Tol = .1)
# $FirstL
# [1]  0.0000000  0.0000000 -0.7071068  0.7071068
# $OldRep
# [1] 0.2 0.2 0.6
# $ThisRep
# [1] 0 0 1
# $SmoothRep
# [1] 0.18 0.18 0.64
#
# > GetRewardWeights(M2)
# $FirstL
# [1] -0.2934226  0.0000000 -0.5338542  0.7930340
# $OldRep
# [1] 0.3333333 0.3333333 0.3333333
# $ThisRep
# [1] 0.505356 0.494644 0.000000
# $SmoothRep
# [1] 0.3505356 0.3494644 0.3000000
#
# > GetRewardWeights(M2, Rep=c(.2,.2,.6), alpha=.5, Verbose = TRUE)
# [1] "****************************************************"
# [1] "Begin 'GetRewardWeights'"
# [1] "Inputs..."
# [1] "Matrix:"
# [,1] [,2] [,3] [,4]
# [1,] 0.80  0.1 0.72    0
# [2,] 0.80  0.1 0.62    0
# [3,] 0.43  0.1 0.00    1
# [1] ""
# [1] "Reputation:"
# [,1]
# [1,]  0.2
# [2,]  0.2
# [3,]  0.6
# [1] ""
# [1] "First Loading:"
# [1] -0.2935984  0.0000000 -0.5330507  0.7935092
# [1] "First
# [1] "Previous period reputations, Option 1, Option 2, Raw1, Raw2, Selection"
# [,1]       [,2]      [,3]       [,4]      [,5]       [,6]
# [1,]  0.2 0.00000000 0.5105824 0.00000000 0.6429686 0.00000000
# [2,]  0.2 0.01362912 0.4894176 0.05330507 0.6163160 0.01362912
# [3,]  0.6 0.98637088 0.0000000 1.28593716 0.0000000 0.98637088
# [1] ""
# [1] "Corrected for Additivity , Smoothed _1 period"
# [,1]      [,2]
# [1,] 0.00000000 0.1000000
# [2,] 0.01362912 0.1068146
# [3,] 0.98637088 0.7931854
# $FirstL
# [1] -0.2935984  0.0000000 -0.5330507  0.7935092
#
# $OldRep
# [1] 0.2 0.2 0.6
#
# $ThisRep
# [1] 0.00000000 0.01362912 0.98637088
#
# $SmoothRep
# [1] 0.1000000 0.1068146 0.7931854

# Score:"
# [,1]
# [1,] -0.7822233
# [2,] -0.7289182
# [3,]  0.5037139
# [1] ""
# [1] " %% Reference Index %% : -1.26355970920342"
# [1] "Estimations using: Previous Rep, Option 1, Option 2"
# [,1]        [,2]      [,3]
# [1,]  0.5 0.435042774 0.8000000
# [2,]  0.0 0.100000000 0.1000000
# [3,]  0.0 0.008450054 0.6710582
# [4,]  0.5 0.986370881 0.0000000
# [1] ""

FillNa <- function(Mna, Rep = DemocracyRep(Mna), ScaledIndex = BinaryScales(Mna), CatchP=.1, Verbose=FALSE) {
  # Uses exisiting data and reputations to fill missing observations.
  # Essentially a weighted average using all availiable non-NA data.
  # How much should slackers who arent voting suffer? I decided this would depend on the global percentage of slacking.

  Mnew <- Mna # Declare (in case no Missing values, Mnew, MnewC, and Mna will be the same)
  MnewC <- Mna

  if(sum(is.na(Mna))>0) {
    #Of course, only do this process if there ARE missing values.

    if(Verbose) print("Missing Values Detected. Beginning presolve using availiable values.")

    #Decision Outcome - Our best guess for the Decision state (FALSE=0, Ambiguous=.5, TRUE=1) so far (ie, using the present, non-missing, values).
    DecisionOutcomes.Raw <- GetDecisionOutcomes(Mna,Rep,ScaledIndex,Verbose)

    #Fill in the predictions to the original M
    NAmat <- is.na(Mna)   #Defines the slice of the matrix which needs to be edited.
    Mnew[NAmat] <- 0       #Erase the NA's

    #Slightly complicated:
    NAsToFill <- ( NAmat%*%diag(as.vector(DecisionOutcomes.Raw)) )
    #   This builds a matrix whose columns j:
        #          NAmat was false (the observation wasn't missing)     ...  have a value of Zero
        #          NAmat was true (the observation was missing)         ...  have a value of the jth element of DecisionOutcomes.Raw (the 'current best guess')
    Mnew <- Mnew + NAsToFill
    #This replaces the NAs, which were zeros, with the predicted Decision outcome.

    if(Verbose) { print("Missing Values:"); print(NAmat) ; print("Imputed Values:"); print(NAsToFill)}

    #Declare Output
    MnewC <- Mnew
    ## Discriminate based on contract type
    #Fill ONLY Binary contracts by appropriately forcing predictions into their discrete (0,.5,1) slot. (reveals .5 coordination, continuous variables are more gameable).
    MnewC[,!ScaledIndex] <- apply(Mnew[,!ScaledIndex], c(1,2), function(x) Catch(x,Tolerance = CatchP) )
    #

  }

  if(Verbose) { print("Raw Results:"); print(Mnew) ; print("Binned:"); print(MnewC) ; print("*** ** Missing Values Filled ** ***") }

  return(MnewC)
}

# M <- matrix( data=c(
#       1,    1,     0,     0,    0.5356322, 6.689658e-01,
#       1,    0,    NA,    NA,    0.4574713,           NA,
#       1,    NA,    0,    NA,    0.5356322, 6.689658e-01,
#       1,    1,     1,    NA,    0.5747126,           NA,
#       0,    NA,    1,    NA,    1.0000000, 8.333333e-05,
#       0,    0,     1,     1,    NA,        9.999167e-01),
#   nrow=6,byrow=TRUE)

# > FillNa(M,ScaledIndex=c(FALSE,FALSE,FALSE,FALSE,TRUE,TRUE))
#       [,1] [,2] [,3] [,4]      [,5]         [,6]
# [1,]    1  1.0    0  0.0 0.5356322 6.689658e-01
# [2,]    1  0.0    1  0.5 0.4574713 6.689658e-01
# [3,]    1  0.5    0  0.5 0.5356322 6.689658e-01
# [4,]    1  1.0    1  0.5 0.5747126 6.689658e-01
# [5,]    0  0.5    1  0.5 1.0000000 8.333333e-05
# [6,]    0  0.0    1  1.0 0.5356322 9.999167e-01
# > FillNa(M,ScaledIndex=c(FALSE,FALSE,FALSE,FALSE,FALSE,FALSE))
#       [,1] [,2] [,3] [,4] [,5] [,6]
# [1,]    1  1.0    0  0.0  0.5    1
# [2,]    1  0.0    1  0.5  0.5    1
# [3,]    1  0.5    0  0.5  0.5    1
# [4,]    1  1.0    1  0.5  1.0    1
# [5,]    0  0.5    1  0.5  1.0    0
# [6,]    0  0.0    1  1.0  1.0    1

#Putting it all together:
Factory <- function(M0, Scales = BinaryScales(M0), Rep = DemocracyRep(M0), CatchP=.2, MaxRow=5000, Verbose=FALSE, RBCR = 6) {
  # Main Routine

  ScaledIndex=as.logical( Scales["Scaled",] )
  MScaled <- Rescale(M0, Scales)

  #Handle Missing Values
  Filled <- FillNa(MScaled, Rep, ScaledIndex, CatchP, Verbose)

  ## Consensus - Row Players
  # New Consensus Reward
  PlayerInfo <- GetRewardWeights(M = Filled, Rep, ScaledIndex, alpha = .1, Tol = CatchP, Verbose, RBCR)
  AdjLoadings <- PlayerInfo$FirstL

  ## Column Players (The Decision Creators)
  # Calculation of Reward for Decision Authors
  # Consensus - "Who won?" Decision Outcome
  DecisionOutcomes.Raw <- PlayerInfo$SmoothRep %*% Filled # Declare (all binary), Simple matrix multiplication ... highest information density at RowBonus, but need DecisionOutcomes.Raw to get to that
  for(i in 1:ncol(Filled)) {    # slow implementation.. 'for loop' bad on R, much faster on python
    # Discriminate Based on Contract Type
    if(ScaledIndex[i]) DecisionOutcomes.Raw[i] <- weighted.median(Filled[,i], w=PlayerInfo$SmoothRep)  #Our Current best-guess for this Scaled Decision (weighted median)
  }

  # The Outcome Itself
  # Discriminate Based on Contract Type
  DecisionOutcome.Adj <- mapply(Catch,DecisionOutcomes.Raw,Tolerance=CatchP) # Declare first (assumes all binary)
  DecisionOutcome.Adj[ScaledIndex] <- DecisionOutcomes.Raw[ScaledIndex]      # Replace Scaled with raw (weighted-median)
  DecisionOutcome.Final <- t( Scales["Max",] - Scales["Min",] ) %*% diag( DecisionOutcome.Adj )    # Rescale these back up.
  DecisionOutcome.Final <- DecisionOutcome.Final + Scales["Min",]                                  # Recenter these back up.

  # Quality of Outcomes - is there confusion?

  Certainty <- vector("numeric",ncol(Filled))
  # For each Decision
  for(i in 1:ncol(Filled)) {
    # Sum of, the reputations which, met the condition that they voted for the outcome which was selected for this Decision.
    Certainty[i] <- sum( PlayerInfo$SmoothRep [ DecisionOutcome.Final[i] == Filled[,i] ] )
  }
  Avg.Certainty <- mean(Certainty)    # How well did beliefs converge?

  # Stability of Voter Reports is not the same as "Clear Instructions" (one can be 'certain' that something was 'unclear' if you all agree it was).
  # Want to discourage .5's
  Resolveable <- Filled!=.5
  MaxClairity <- Rep %*% Resolveable # All of the answers for .5 are an instant-veto on Clairity. If 30% said 'unclear' can't do better than 70%.
  Clarity <- MaxClairity * Certainty

  ConReward <- GetWeight(Clarity)   # Grading Authors on a curve. -not necessarily the best idea?

  if(Verbose) {
    print("*Decision Outcomes Sucessfully Calculated*")
    Temp <- rbind(DecisionOutcomes.Raw, Certainty, ConReward)
    row.names(Temp) <- c("Raw Outcomes", "Certainty", "AuthorPayoutFactor")
    print(Temp)
  }

  ## Participation

  #Information about missing values
  NAmat <- M0*0
  NAmat[is.na(NAmat)] <- 1 #indicator matrix for missing

  #Participation Within Decisions (Columns)
  # % of reputation that answered each Decision
  ParticipationC <- 1-(PlayerInfo$SmoothRep%*%NAmat)

  #Participation Within Agents (Rows)
  # Many options

  # 1- Democracy Option - all Decisions treated equally.
  ParticipationR  <- 1-( apply(NAmat,1,sum)/ncol(M0) )

  #General Participation
  PercentNA <- 1-mean(ParticipationC)
  #(Possibly integrate two functions of participation?) Chicken and egg problem...

  if(Verbose) {
    print("*Participation Information*")
    print("Voter Turnout by question"); print( ParticipationC )
    print("Voter Turnout across questions"); print ( ParticipationR )
  }

  ## Combine Information
  # Row
  NAbonusR <- GetWeight(ParticipationR)
  RowBonus <- (NAbonusR*(PercentNA))+(PlayerInfo$SmoothR*(1-PercentNA))

  # Column
  NAbonusC <- GetWeight(ParticipationC)
  ColBonus <- (NAbonusC*(PercentNA))+(ConReward*(1-PercentNA))

  # Present Results
  Output <- vector("list",6) #Declare
  names(Output) <- c("Original","Filled","Agents","Decisions","Participation","Certainty")

  Output[[1]] <- M0
  Output[[2]] <- Filled
  Output[[3]] <- cbind(PlayerInfo$OldRep, PlayerInfo$ThisRep,PlayerInfo$SmoothRep,apply(NAmat,1,sum),ParticipationR,NAbonusR,RowBonus)
  colnames(Output[[3]]) <- c("OldRep", "ThisRep", "SmoothRep", "NArow", "ParticipationR","RelativePart","RowBonus")
  Output[[4]] <- rbind(AdjLoadings,DecisionOutcomes.Raw,ConReward,Certainty,apply(NAmat,2,sum),ParticipationC,ColBonus,DecisionOutcome.Final)
  rownames(Output[[4]]) <- c("First Loading","DecisionOutcomes.Raw","Consensus Reward","Certainty","NAs Filled","ParticipationC","Author Bonus","DecisionOutcome.Final")
  Output[[5]] <- (1-PercentNA) # Using this to set inclusion fees.
  Output[[6]] <- Avg.Certainty # Using this to set Catch Parameter

  return(Output)
}

# M1 <-  rbind(
#   c(1,1,0,0),
#   c(1,0,0,0),
#   c(1,1,0,0),
#   c(1,1,1,0),
#   c(0,0,1,1),
#   c(0,0,1,1))
#
# row.names(M1) <- c("True", "Distort 1", "True", "Distort 2", "Liar", "Liar")
# colnames(M1) <- c("D1.1","D2.1","D3.0","D4.0")
#
# > Factory(M1)
# $Original
# D1.1 D2.1 D3.0 D4.0
# True         1    1    0    0
# Distort 1    1    0    0    0
# True         1    1    0    0
# Distort 2    1    1    1    0
# Liar         0    0    1    1
# Liar         0    0    1    1
#
# $Filled
# D1.1 D2.1 D3.0 D4.0
# True         1    1    0    0
# Distort 1    1    0    0    0
# True         1    1    0    0
# Distort 2    1    1    1    0
# Liar         0    0    1    1
# Liar         0    0    1    1
#
# $Agents
# OldRep   ThisRep SmoothRep NArow ParticipationR RelativePart  RowBonus
# True      0.1666667 0.2823757 0.1782376     0              1    0.1666667 0.1782376
# Distort 1 0.1666667 0.2176243 0.1717624     0              1    0.1666667 0.1717624
# True      0.1666667 0.2823757 0.1782376     0              1    0.1666667 0.1782376
# Distort 2 0.1666667 0.2176243 0.1717624     0              1    0.1666667 0.1717624
# Liar      0.1666667 0.0000000 0.1500000     0              1    0.1666667 0.1500000
# Liar      0.1666667 0.0000000 0.1500000     0              1    0.1666667 0.1500000
#
# $Decisions
# D1.1       D2.1      D3.0      D4.0
# First Loading         -0.5395366 -0.4570561 0.4570561 0.5395366
# DecisionOutcomes.Raw   0.7000000  0.5282376 0.4717624 0.3000000
# Consensus Reward       0.5000000  0.0000000 0.0000000 0.5000000
# Certainty              0.7000000  0.0000000 0.0000000 0.7000000
# NAs Filled             0.0000000  0.0000000 0.0000000 0.0000000
# ParticipationC         1.0000000  1.0000000 1.0000000 1.0000000
# Author Bonus           0.5000000  0.0000000 0.0000000 0.5000000
# DecisionOutcome.Final  1.0000000  0.5000000 0.5000000 0.0000000
#
# $Participation
# [1] 1
#
# $Certainty
# [1] 0.35
#
#
#
# MS <- matrix( data=c(
#       1,    1,    0,    0,    233,   16027.59,
#       1,    0,    0,    0,    199,         NA,
#       1,    1,    0,    0,    233,   16027.59,
#       1,    1,    1,    0,    250,         NA,
#       0,    0,    1,    1,    435,    8001.00,
#       0,    0,    1,    1,    435,   19999.00),
#   nrow=6,byrow=TRUE, dimnames=list( rownames(M1), paste("D",1:6,sep=".")))
#
#
# Scales <- matrix( data=c(
#             0, 0, 0, 0,   1,     1,
#             0, 0, 0, 0,   0,  8000,
#             1, 1, 1, 1, 435, 20000),
#       nrow=3, byrow=TRUE, dimnames=list( c("Scaled","Min","Max"), colnames(MS)) )
#
#
# > Factory(M0=MS,Scales=Scales)
# $Original
# D.1 D.2 D.3 D.4 D.5      D.6
# True        1   1   0   0 233 16027.59
# Distort 1   1   0   0   0 199       NA
# True        1   1   0   0 233 16027.59
# Distort 2   1   1   1   0 250       NA
# Liar        0   0   1   1 435  8001.00
# Liar        0   0   1   1 435 19999.00
#
# $Filled
# D.1 D.2 D.3 D.4       D.5          D.6
# True        1   1   0   0 0.5356322 6.689658e-01
# Distort 1   1   0   0   0 0.4574713 6.689658e-01
# True        1   1   0   0 0.5356322 6.689658e-01
# Distort 2   1   1   1   0 0.5747126 6.689658e-01
# Liar        0   0   1   1 1.0000000 8.333333e-05
# Liar        0   0   1   1 1.0000000 9.999167e-01
#
# $Agents
# OldRep    ThisRep SmoothRep NArow ParticipationR RelativePart  RowBonus
# True      0.1666667 0.27512698 0.1775127     0      1.0000000    0.1764706 0.1774530
# Distort 1 0.1666667 0.22080941 0.1720809     1      0.8333333    0.1470588 0.1706477
# True      0.1666667 0.27512698 0.1775127     0      1.0000000    0.1764706 0.1774530
# Distort 2 0.1666667 0.21600171 0.1716002     1      0.8333333    0.1470588 0.1701944
# Liar      0.1666667 0.00000000 0.1500000     0      1.0000000    0.1764706 0.1515162
# Liar      0.1666667 0.01293492 0.1512935     0      1.0000000    0.1764706 0.1527356
#
# $Decisions
# D.1         D.2        D.3       D.4         D.5           D.6
# First Loading         -0.5223889 -0.43411264 0.44195128 0.5223889   0.2463368 -9.880889e-02
# DecisionOutcomes.Raw   0.6987065  0.52662557 0.47289366 0.3012935   0.5356322  6.689658e-01
# Consensus Reward       0.2850531  0.00000000 0.00000000 0.2850531   0.1448406  2.850531e-01
# Certainty              0.6987065  0.00000000 0.00000000 0.6987065   0.3550254  6.987065e-01
# NAs Filled             0.0000000  0.00000000 0.00000000 0.0000000   0.0000000  2.000000e+00
# ParticipationC         1.0000000  1.00000000 1.00000000 1.0000000   1.0000000  6.563189e-01
# Author Bonus           0.2788520  0.01012676 0.01012676 0.2788520   0.1466709  2.753716e-01
# DecisionOutcome.Final  1.0000000  0.50000000 0.50000000 0.0000000 233.0000000  1.602759e+04
#
# $Participation
# [1] 0.9427198
#
# $Certainty
# [1] 0.4085242
#
# > Factory(M0=MS,Scales=Scales,Rep=c(.05,.05,.05,.05,.10,.70))
# $Original
#           D.1 D.2 D.3 D.4 D.5      D.6
# True        1   1   0   0 233 16027.59
# Distort 1   1   0   0   0 199       NA
# True        1   1   0   0 233 16027.59
# Distort 2   1   1   1   0 250       NA
# Liar        0   0   1   1 435  8001.00
# Liar        0   0   1   1 435 19999.00
#
# $Filled
#           D.1 D.2 D.3 D.4       D.5          D.6
# True        1   1   0   0 0.5356322 6.689658e-01
# Distort 1   1   0   0   0 0.4574713 9.999167e-01
# True        1   1   0   0 0.5356322 6.689658e-01
# Distort 2   1   1   1   0 0.5747126 9.999167e-01
# Liar        0   0   1   1 1.0000000 8.333333e-05
# Liar        0   0   1   1 1.0000000 9.999167e-01
#
# $Agents
#           OldRep    ThisRep  SmoothRep NArow ParticipationR RelativePart   RowBonus
# True        0.05 0.00000000 0.04500000     0      1.0000000    0.1764706 0.04702833
# Distort 1   0.05 0.01235137 0.04623514     1      0.8333333    0.1470588 0.04779064
# True        0.05 0.00000000 0.04500000     0      1.0000000    0.1764706 0.04702833
# Distort 2   0.05 0.01332745 0.04633275     1      0.8333333    0.1470588 0.04788674
# Liar        0.10 0.11962886 0.10196289     0      1.0000000    0.1764706 0.10311239
# Liar        0.70 0.85469232 0.71546923     0      1.0000000    0.1764706 0.70715357
#
# $Decisions
#                              D.1        D.2       D.3       D.4         D.5          D.6
# First Loading         -0.5369880 -0.4210132 0.4240200 0.5369880   0.2540098 4.149213e-02
# DecisionOutcomes.Raw   0.1825679  0.1363327 0.8637649 0.8174321   1.0000000 9.999167e-01
# Consensus Reward       0.1638874  0.1731571 0.1731767 0.1638874   0.1638874 1.620038e-01
# Certainty              0.8174321  0.8636673 0.8637649 0.8174321   0.8174321 8.080371e-01
# NAs Filled             0.0000000  0.0000000 0.0000000 0.0000000   0.0000000 2.000000e+00
# ParticipationC         1.0000000  1.0000000 1.0000000 1.0000000   1.0000000 9.074321e-01
# Author Bonus           0.1639706  0.1730973 0.1731166 0.1639706   0.1639706 1.618743e-01
# DecisionOutcome.Final  0.0000000  0.0000000 1.0000000 1.0000000 435.0000000 1.999900e+04
#
# $Participation
# [1] 0.984572
#
# $Certainty
# [1] 0.8312943

# Double-Factory (more reliable)

DoubleFactory <- function(X, Scales = BinaryScales(X), Rep = DemocracyRep(X), CatchP=.1, MaxRow=5000, Phi=.65, Verbose=FALSE) {
  # see http://forum.truthcoin.info/index.php/topic,102.msg289.html#msg289

  WaveOne <- Factory(X,Scales,Rep,CatchP,MaxRow,Verbose)

  Safe  <- ( WaveOne$Decisions["Certainty",] ) >= Phi # all those contracts which were unanimous for a subset of proportion ("Phi")

  if(Verbose) {
    print(" Wave One Complete.")
    print( sum(Safe)/ncol(X) )
  }

  WaveTwo <- Factory( X[,Safe] ,
                      Scales[,Safe],
                      Rep,CatchP,MaxRow,Verbose)

  return(WaveTwo)
}

# M1 is defined above

# > DoubleFactory(M1)
# $Original
#           D1.1 D4.0
# True         1    0
# Distort 1    1    0
# True         1    0
# Distort 2    1    0
# Liar         0    1
# Liar         0    1
#
# $Filled
#           D1.1 D4.0
# True         1    0
# Distort 1    1    0
# True         1    0
# Distort 2    1    0
# Liar         0    1
# Liar         0    1
#
# $Agents
#              OldRep ThisRep SmoothRep NArow ParticipationR RelativePart RowBonus
# True      0.1666667    0.25     0.175     0              1    0.1666667    0.175
# Distort 1 0.1666667    0.25     0.175     0              1    0.1666667    0.175
# True      0.1666667    0.25     0.175     0              1    0.1666667    0.175
# Distort 2 0.1666667    0.25     0.175     0              1    0.1666667    0.175
# Liar      0.1666667    0.00     0.150     0              1    0.1666667    0.150
# Liar      0.1666667    0.00     0.150     0              1    0.1666667    0.150
#
# $Decisions
#                             D1.1      D4.0
# First Loading         -0.7071068 0.7071068
# DecisionOutcomes.Raw   0.7000000 0.3000000
# Consensus Reward       0.5000000 0.5000000
# Certainty              0.7000000 0.7000000
# NAs Filled             0.0000000 0.0000000
# ParticipationC         1.0000000 1.0000000
# Author Bonus           0.5000000 0.5000000
# DecisionOutcome.Final  1.0000000 0.0000000
#
# $Participation
# [1] 1
#
# $Certainty
# [1] 0.7

# M2 <- matrix( data=c(
#   c(0.5, 0.5, 1,  0),
#   c(0.5, 0.0, 1,  0),
#   c(0.5, 1.0, 1,  0),
#   c(1.0,  NA, 1, NA),
#   c(0.5, 1.0, 1,  1),
#   c(0.0, 0.0, 1,  1)), nrow=6, byrow=TRUE, dimname=list(paste("V",1:6,sep="."), colnames(M1)) )
#
# > DoubleFactory(M2)
# $Original
#     D1.1 D3.0 D4.0
# V.1  0.5    1    0
# V.2  0.5    1    0
# V.3  0.5    1    0
# V.4  1.0    1   NA
# V.5  0.5    1    1
# V.6  0.0    1    1
#
# $Filled
#     D1.1 D3.0 D4.0
# V.1  0.5    1    0
# V.2  0.5    1    0
# V.3  0.5    1    0
# V.4  1.0    1    0
# V.5  0.5    1    1
# V.6  0.0    1    1

# $Agents
#        OldRep    ThisRep SmoothRep NArow ParticipationR RelativePart  RowBonus
# V.1 0.1666667 0.22833653 0.1728337     0      1.0000000    0.1764706 0.1730484
# V.2 0.1666667 0.22833653 0.1728337     0      1.0000000    0.1764706 0.1730484
# V.3 0.1666667 0.22833653 0.1728337     0      1.0000000    0.1764706 0.1730484
# V.4 0.1666667 0.27166347 0.1771663     1      0.6666667    0.1176471 0.1736514
# V.5 0.1666667 0.04332693 0.1543327     0      1.0000000    0.1764706 0.1556401
# V.6 0.1666667 0.00000000 0.1500000     0      1.0000000    0.1764706 0.1515632
#
# $Decisions
#                             D1.1      D3.0      D4.0
# First Loading         -0.4241554 0.0000000 0.9055894
# DecisionOutcomes.Raw   0.5135832 1.0000000 0.3043327
# Consensus Reward       0.1168147 0.5208482 0.3623371
# Certainty              0.6728337 1.0000000 0.6956673
# NAs Filled             0.0000000 0.0000000 1.0000000
# ParticipationC         1.0000000 1.0000000 0.8228337
# Author Bonus           0.1308368 0.5110099 0.3581533
# DecisionOutcome.Final  0.5000000 1.0000000 0.0000000
#
# $Participation
# [1] 0.9409446
#
# $Certainty
# [1] 0.7895003


# Elvis Sun
# 250696535
# Feb 8th

#function params

dcfFunc <- function(
  currentRevenue, currentCapitalSpending, currentDepreciation, taxRateIncome,
  bookValueDebt, bookValueEquity, nolCarriedForward, publiclyTradedFlag,     #8
  lastTradedPrice, numberSharesOutstanding, marketValueDebt, debtCapitalRatio,
  costEquity, betaStock, riskFreeRate, riskPremium,   #16
  costDebt, growthRateStablePeriod, operatingExpenseStablePeriod, workingCapitalStablePeriod,   #20
  betaStablePeriod, debtRatioStablePeriod, costDebtFlag, costDebtStablePeriod,   #24
  capitalExpendituresStablePeriod, growthRateRevenueRng, #26
  operatingExpenseRng, growthRateCapitalSpendingRng,
  growthRateDepreciationRng, workingCapitalRng,  #30
  excessReturnPeriods = 10, capPeriods = 5, output = 1
){

  #transpose if horizontal, and raise an error
  if (nrow(growthRateRevenueRng) == 1){
    growthRateRevenueRng <- t(growthRateRevenueRng)
  }
  if (nrow(growthRateRevenueRng) != excessReturnPeriods){
    stop("Different Dimension Than Excess Return Periods")
  }

  if (nrow(operatingExpenseRng) == 1){
    operatingExpenseRng <- t(operatingExpenseRng)
  }
  if (nrow(operatingExpenseRng) != excessReturnPeriods){
    stop("Different Dimension Than Excess Return Periods")
  }

  if (nrow(growthRateCapitalSpendingRng) == 1){
    growthRateCapitalSpendingRng <- t(growthRateCapitalSpendingRng)
  }
  if (nrow(growthRateCapitalSpendingRng) != excessReturnPeriods){
    stop("Different Dimension Than Excess Return Periods")
  }

  if (nrow(growthRateDepreciationRng) == 1){
    growthRateDepreciationRng <- t(growthRateDepreciationRng)
  }
  if (nrow(growthRateDepreciationRng) != excessReturnPeriods){
    stop("Different Dimension Than Excess Return Periods")
  }

  if (nrow(workingCapitalRng) == 1){
    workingCapitalRng <- t(workingCapitalRng)
  }
  if (nrow(workingCapitalRng) != excessReturnPeriods){
    stop("Different Dimension Than Excess Return Periods")
  }

  #rename variables
  growthRateRevenueVector <- growthRateRevenueRng
  operatingExpenseVector <- operatingExpenseRng
  growthRateCapitalSpendingVector <- growthRateCapitalSpendingRng
  growthRateDepreciationVector <- growthRateDepreciationRng
  workingCapitalVector <- workingCapitalRng

  #if else to calculate some constant
  costEquityVal <- riskFreeRate + betaStock * riskPremium
  if (costEquity != 0 ){
    costEquityVal <- costEquity
  }

  temp <- 1 - debtCapitalRatio
  if (debtCapitalRatio == 0){
    temp <- 1 - bookValueDebt
  }
  equityDebtRatio <- temp
  if (publiclyTradedFlag) {
    equityDebtRatio <- lastTradedPrice * numberSharesOutstanding / (marketValueDebt + lastTradedPrice * numberSharesOutstanding)
  }

  #calculate more constant
  afterTaxCostDebt <- costDebt * (1 - taxRateIncome)
  debtCapitalVal <- 1 - equityDebtRatio
  costCapitalVal <- costEquityVal * equityDebtRatio + afterTaxCostDebt * debtCapitalVal

  #make matrix
  temp <- matrix(, nrow = 33, ncol = excessReturnPeriods + 1)

  for(j in 1:excessReturnPeriods) {
    temp[1,j] <- j

    ifelse(j > 1, temp[2,j] <- temp[2,j-1], temp[2,j] <- currentRevenue * (1 + growthRateRevenueVector[j,1]))
    temp[3,j] <- temp[2,j] * operatingExpenseVector[j,1]
    temp[4,j] <- temp[2,j] - temp[3,j]

    if(j > 1) {
      temp[5,j] <- ifelse(temp[4,j] > 0, ifelse(temp[12,j-1] > temp[4,j], 0, (temp[4,j] - temp[12,j-1])) * taxRateIncome, 0)
      temp[7,j] <- temp[7,j-1] * (1 + growthRateDepreciationVector[j,1])
      temp[8,j] <- temp[8,j-1] * (1 + growthRateCapitalSpendingVector[j,1])
      temp[9,j] <- (temp[2,j] - temp [2,j-1]) * workingCapitalVector[j,1]
      temp[12,j] <- ifelse(temp[12,j-1] > temp[4,j], temp[12,j-1] - temp[4,j], 0)
    }
    else {
      temp[5,j] <- ifelse(temp[4,j] > 0, ifelse(nolCarriedForward > temp[4,j], 0, (temp[4,j] - nolCarriedForward) * taxRateIncome), 0)
      temp[7,j] <- currentDepreciation * (1 + growthRateDepreciationVector[j,1])
      temp[8,j] <- currentCapitalSpending * (1 + growthRateCapitalSpendingVector[j,1])
      temp[9,j] <- (temp[2,j] - currentRevenue) * workingCapitalVector[j,1]
      temp[12,j] <- ifelse(nolCarriedForward > 0, ifelse(nolCarriedForward < temp[2,j], 0, nolCarriedForward - temp[2,j]), 0)
    }

    temp[6,j] <- temp[4,j] - temp[5,j]
    temp[10,j] <- temp[6,j] + temp[7,j] + temp[8,j] - temp[9,j]
    temp[13,j] <- temp[5,j] / temp[4,j]

    if(j <= capPeriods) {
      temp[14,j] <- betaStock
      temp[17,j] <- debtCapitalVal
    }
    else {
      temp[14,j] <- ifelse(betaStablePeriod != 0, temp[14,capPeriods] - ((temp[14,capPeriods] - betaStablePeriod) / capPeriods) * (j - capPeriods), betaStock)
      temp[17,j] <- ifelse(debtRatioStablePeriod != 0, temp[17,capPeriods] - ((temp[17,capPeriods] - debtCapitalVal) / capPeriods) * (j - capPeriods), debtCapitalVal)
    }

    temp[15,j] <- ifelse(costEquity == 0, riskFreeRate + temp[14,j] * riskPremium, costEquity)
    temp[16,j] <- costDebtStablePeriod * (1 - taxRateIncome)
    temp[18,j] <- temp[15,j] * (1 - temp[17,j]) + temp[16,j] * temp[17,j]
    ifelse(j > 1, temp[19,j] <- temp[19,j-1] * (1 + temp[18,j]), temp[19,j] <- 1 + temp[18,j])
    temp[11,j] <- temp[10,j] / temp[19,j]
    ifelse(is.na(temp[28,1]), temp[28,1] <- temp[11,j], temp[28,1] <- temp[28,1] + temp[11,j])
  }

  #temp[1,excessReturnPeriods+1] <- "TN"
  temp[2,excessReturnPeriods+1] <- temp[2,excessReturnPeriods] * (1+ growthRateStablePeriod)
  temp[3,excessReturnPeriods+1] <- temp[2,excessReturnPeriods+1] * operatingExpenseStablePeriod
  temp[4,excessReturnPeriods+1] <- temp[2,excessReturnPeriods+1] - temp[3,excessReturnPeriods+1]
  temp[5,excessReturnPeriods+1] <- ifelse(temp[4,excessReturnPeriods+1] > 0, ifelse(temp[12,excessReturnPeriods] > temp[4,excessReturnPeriods+1], 0, (temp[4,excessReturnPeriods+1] - temp[12,excessReturnPeriods]) * taxRateIncome), 0)
  temp[6,excessReturnPeriods+1] <- temp[4,excessReturnPeriods+1] - temp[5,excessReturnPeriods+1]
  temp[7,excessReturnPeriods+1] <- temp[7,excessReturnPeriods]
  temp[8,excessReturnPeriods+1] <- ifelse(capitalExpendituresStablePeriod == 0, temp[7,excessReturnPeriods+1], temp[7,excessReturnPeriods+1] * capitalExpendituresStablePeriod)
  temp[9,excessReturnPeriods+1] <- (temp[2,excessReturnPeriods+1] - temp[2,excessReturnPeriods]) * workingCapitalStablePeriod
  temp[10,excessReturnPeriods+1] <- temp[6,excessReturnPeriods+1] + temp[7,excessReturnPeriods+1] - temp[8,excessReturnPeriods+1] - temp[9,excessReturnPeriods+1]
  temp[13,excessReturnPeriods+1] <- temp[5,excessReturnPeriods+1] / temp[4,excessReturnPeriods+1]
  temp[14,excessReturnPeriods+1] <- temp[14,excessReturnPeriods]
  temp[15,excessReturnPeriods+1] <- ifelse(costEquity == 0, riskFreeRate + temp[14,excessReturnPeriods+1] * riskPremium, costEquity)
  temp[16,excessReturnPeriods+1] <- temp[16,excessReturnPeriods]
  temp[17,excessReturnPeriods+1] <- temp[17,excessReturnPeriods]
  temp[18,excessReturnPeriods+1] <- temp[15,excessReturnPeriods+1] * (1 - temp[17,excessReturnPeriods+1]) + temp[16,excessReturnPeriods+1] * temp[17,excessReturnPeriods+1]
  temp[20,1] <- growthRateStablePeriod
  temp[21,1] <-temp[10,excessReturnPeriods+1]
  temp[22,1] <- ifelse(betaStablePeriod == 0, riskFreeRate + betaStock * riskPremium, riskFreeRate + betaStablePeriod * riskPremium)
  temp[23,1] <- ifelse(debtRatioStablePeriod != 0, 1 - debtRatioStablePeriod, equityDebtRatio)
  temp[24,1] <- ifelse(costDebtFlag == TRUE, costDebtStablePeriod * (1 - taxRateIncome), afterTaxCostDebt)
  temp[25,1] <- 1 - temp[23,1]
  temp[26,1] <- temp[22,1] * temp[23,1] + temp[24,1] * temp[25,1]
  temp[27,1] <- temp[21,1] / (temp[26,1] - temp[20,1])
  temp[29,1] <- temp[27,1] / temp[19,excessReturnPeriods]
  temp[30,1] <- temp[28,1] + temp[29,1]
  temp[31,1] <- ifelse(publiclyTradedFlag == TRUE, marketValueDebt, bookValueDebt)
  temp[32,1] <- temp[30,1] - temp[31,1]
  temp[33,1] <- temp[32,1] / numberSharesOutstanding

  intrinsicValueShare <- temp[33,1]

  if(output == 0) {
    intrinsicValueShare
  }
  else if(output == 1) {
    temp
  }
}

dcfFunc(108249, 7696, 1814, 0.242157579,
        0.1, 76615, 200000, TRUE, #8
        500, 929.3, 0.1, 0,       #12
        0.07, 1, 0.02, 0.05,      #16
        0.025, 0.03, 0.8165, 0.01,#20
        1, 0.15, TRUE, 0.08,      #24
        1.1,
        matrix(c(rep(0.06,7),rep(0.03,13)),ncol=1),
        matrix(c(rep(0.82,20)),ncol=1),
        matrix(c(0.02,rep(0.06,4),rep(0.03,15)),ncol=1),
        matrix(c(-0.07,rep(0.06,5),rep(0.03,14)),ncol=1),
        matrix(c(rep(0.05,20)),ncol=1),
        20,5,0
)


# Comments start with number symbols.

# You can't make multi-line comments,
# but you can stack multiple comments like so.

# in Windows you can use CTRL-ENTER to execute a line.
# on Mac it is COMMAND-ENTER

#############################################################################
# Stuff you can do without understanding anything about programming
#############################################################################

# In this section, we show off some of the cool stuff you can do in
# R without understanding anything about programming. Do not worry
# about understanding everything the code does. Just enjoy!

data()          # browse pre-loaded data sets
data(rivers)    # get this one: "Lengths of Major North American Rivers"
ls()            # notice that "rivers" now appears in the workspace
head(rivers)    # peek at the data set
# 735 320 325 392 524 450

length(rivers)  # how many rivers were measured?
# 141
summary(rivers) # what are some summary statistics?
#   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.
#  135.0   310.0   425.0   591.2   680.0  3710.0

# make a stem-and-leaf plot (a histogram-like data visualization)
stem(rivers)

#  The decimal point is 2 digit(s) to the right of the |
#
#   0 | 4
#   2 | 011223334555566667778888899900001111223333344455555666688888999
#   4 | 111222333445566779001233344567
#   6 | 000112233578012234468
#   8 | 045790018
#  10 | 04507
#  12 | 1471
#  14 | 56
#  16 | 7
#  18 | 9
#  20 |
#  22 | 25
#  24 | 3
#  26 |
#  28 |
#  30 |
#  32 |
#  34 |
#  36 | 1

stem(log(rivers)) # Notice that the data are neither normal nor log-normal!
# Take that, Bell curve fundamentalists.

#  The decimal point is 1 digit(s) to the left of the |
#
#  48 | 1
#  50 |
#  52 | 15578
#  54 | 44571222466689
#  56 | 023334677000124455789
#  58 | 00122366666999933445777
#  60 | 122445567800133459
#  62 | 112666799035
#  64 | 00011334581257889
#  66 | 003683579
#  68 | 0019156
#  70 | 079357
#  72 | 89
#  74 | 84
#  76 | 56
#  78 | 4
#  80 |
#  82 | 2

# make a histogram:
hist(rivers, col="#333333", border="white", breaks=25) # play around with these parameters
hist(log(rivers), col="#333333", border="white", breaks=25) # you'll do more plotting later

# Here's another neat data set that comes pre-loaded. R has tons of these.
data(discoveries)
plot(discoveries, col="#333333", lwd=3, xlab="Year",
     main="Number of important discoveries per year")
plot(discoveries, col="#333333", lwd=3, type = "h", xlab="Year",
     main="Number of important discoveries per year")

# Rather than leaving the default ordering (by year),
# we could also sort to see what's typical:
sort(discoveries)
#  [1]  0  0  0  0  0  0  0  0  0  1  1  1  1  1  1  1  1  1  1  1  1  2  2  2  2
# [26]  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  3  3  3
# [51]  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  4  4  4  4  4  4  4  4
# [76]  4  4  4  4  5  5  5  5  5  5  5  6  6  6  6  6  6  7  7  7  7  8  9 10 12

stem(discoveries, scale=2)
#
#  The decimal point is at the |
#
#   0 | 000000000
#   1 | 000000000000
#   2 | 00000000000000000000000000
#   3 | 00000000000000000000
#   4 | 000000000000
#   5 | 0000000
#   6 | 000000
#   7 | 0000
#   8 | 0
#   9 | 0
#  10 | 0
#  11 |
#  12 | 0

max(discoveries)
# 12
summary(discoveries)
#   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.
#    0.0     2.0     3.0     3.1     4.0    12.0

# Roll a die a few times
round(runif(7, min=.5, max=6.5))
# 1 4 6 1 4 6 4
# Your numbers will differ from mine unless we set the same random.seed(31337)

# Draw from a standard Gaussian 9 times
rnorm(9)
# [1]  0.07528471  1.03499859  1.34809556 -0.82356087  0.61638975 -1.88757271
# [7] -0.59975593  0.57629164  1.08455362

##################################################
# Data types and basic arithmetic
##################################################

# Now for the programming-oriented part of the tutorial.
# In this section you will meet the important data types of R:
# integers, numerics, characters, logicals, and factors.
# There are others, but these are the bare minimum you need to
# get started.

# INTEGERS
# Long-storage integers are written with L
5L # 5
class(5L) # "integer"
# (Try ?class for more information on the class() function.)
# In R, every single value, like 5L, is considered a vector of length 1
length(5L) # 1
# You can have an integer vector with length > 1 too:
c(4L, 5L, 8L, 3L) # 4 5 8 3
length(c(4L, 5L, 8L, 3L)) # 4
class(c(4L, 5L, 8L, 3L)) # "integer"

# NUMERICS
# A "numeric" is a double-precision floating-point number
5 # 5
class(5) # "numeric"
# Again, everything in R is a vector;
# you can make a numeric vector with more than one element
c(3,3,3,2,2,1) # 3 3 3 2 2 1
# You can use scientific notation too
5e4 # 50000
6.02e23 # Avogadro's number
1.6e-35 # Planck length
# You can also have infinitely large or small numbers
class(Inf)  # "numeric"
class(-Inf) # "numeric"
# You might use "Inf", for example, in integrate(dnorm, 3, Inf);
# this obviates Z-score tables.

# BASIC ARITHMETIC
# You can do arithmetic with numbers
# Doing arithmetic on a mix of integers and numerics gives you another numeric
10L + 66L # 76      # integer plus integer gives integer
53.2 - 4  # 49.2    # numeric minus numeric gives numeric
2.0 * 2L  # 4       # numeric times integer gives numeric
3L / 4    # 0.75    # integer over numeric gives numeric
3 %% 2    # 1       # the remainder of two numerics is another numeric
# Illegal arithmetic yeilds you a "not-a-number":
0 / 0 # NaN
class(NaN) # "numeric"
# You can do arithmetic on two vectors with length greater than 1,
# so long as the larger vector's length is an integer multiple of the smaller
c(1,2,3) + c(1,2,3) # 2 4 6
# Since a single number is a vector of length one, scalars are applied
# elementwise to vectors
(4 * c(1,2,3) - 2) / 2 # 1 3 5
# Except for scalars, use caution when performing arithmetic on vectors with
# different lengths. Although it can be done,
c(1,2,3,1,2,3) * c(1,2) # 1 4 3 2 2 6
# Matching lengths is better practice and easier to read
c(1,2,3,1,2,3) * c(1,2,1,2,1,2)

# CHARACTERS
# There's no difference between strings and characters in R
"Horatio" # "Horatio"
class("Horatio") # "character"
class('H') # "character"
# Those were both character vectors of length 1
# Here is a longer one:
c('alef', 'bet', 'gimmel', 'dalet', 'he')
# =>
# "alef"   "bet"    "gimmel" "dalet"  "he"
length(c("Call","me","Ishmael")) # 3
# You can do regex operations on character vectors:
substr("Fortuna multis dat nimis, nulli satis.", 9, 15) # "multis "
gsub('u', 'ø', "Fortuna multis dat nimis, nulli satis.") # "Fortøna møltis dat nimis, nølli satis."
# R has several built-in character vectors:
letters
# =>
#  [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
# [20] "t" "u" "v" "w" "x" "y" "z"
month.abb # "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"

# LOGICALS
# In R, a "logical" is a boolean
class(TRUE) # "logical"
class(FALSE)    # "logical"
# Their behavior is normal
TRUE == TRUE    # TRUE
TRUE == FALSE   # FALSE
FALSE != FALSE  # FALSE
FALSE != TRUE   # TRUE
# Missing data (NA) is logical, too
class(NA)   # "logical"
# Use | and & for logic operations.
# OR
TRUE | FALSE    # TRUE
# AND
TRUE & FALSE    # FALSE
# Applying | and & to vectors returns elementwise logic operations
c(TRUE,FALSE,FALSE) | c(FALSE,TRUE,FALSE) # TRUE TRUE FALSE
c(TRUE,FALSE,TRUE) & c(FALSE,TRUE,TRUE) # FALSE FALSE TRUE
# You can test if x is TRUE
isTRUE(TRUE)    # TRUE
# Here we get a logical vector with many elements:
c('Z', 'o', 'r', 'r', 'o') == "Zorro" # FALSE FALSE FALSE FALSE FALSE
c('Z', 'o', 'r', 'r', 'o') == "Z" # TRUE FALSE FALSE FALSE FALSE

# FACTORS
# The factor class is for categorical data
# Factors can be ordered (like childrens' grade levels) or unordered (like gender)
factor(c("female", "female", "male", NA, "female"))
#  female female male   <NA>   female
# Levels: female male
# The "levels" are the values the categorical data can take
# Note that missing data does not enter the levels
levels(factor(c("male", "male", "female", NA, "female"))) # "female" "male"
# If a factor vector has length 1, its levels will have length 1, too
length(factor("male")) # 1
length(levels(factor("male"))) # 1
# Factors are commonly seen in data frames, a data structure we will cover later
data(infert) # "Infertility after Spontaneous and Induced Abortion"
levels(infert$education) # "0-5yrs"  "6-11yrs" "12+ yrs"

# NULL
# "NULL" is a weird one; use it to "blank out" a vector
class(NULL) # NULL
parakeet = c("beak", "feathers", "wings", "eyes")
parakeet
# =>
# [1] "beak"     "feathers" "wings"    "eyes"
parakeet <- NULL
parakeet
# =>
# NULL

# TYPE COERCION
# Type-coercion is when you force a value to take on a different type
as.character(c(6, 8)) # "6" "8"
as.logical(c(1,0,1,1)) # TRUE FALSE  TRUE  TRUE
# If you put elements of different types into a vector, weird coercions happen:
c(TRUE, 4) # 1 4
c("dog", TRUE, 4) # "dog"  "TRUE" "4"
as.numeric("Bilbo")
# =>
# [1] NA
# Warning message:
# NAs introduced by coercion

# Also note: those were just the basic data types
# There are many more data types, such as for dates, time series, etc.

##################################################
# Variables, loops, if/else
##################################################

# A variable is like a box you store a value in for later use.
# We call this "assigning" the value to the variable.
# Having variables lets us write loops, functions, and if/else statements

# VARIABLES
# Lots of way to assign stuff:
x = 5 # this is possible
y <- "1" # this is preferred
TRUE -> z # this works but is weird

# LOOPS
# We've got for loops
for (i in 1:4) {
  print(i)
}
# We've got while loops
a <- 10
while (a > 4) {
    cat(a, "...", sep = "")
    a <- a - 1
}
# Keep in mind that for and while loops run slowly in R
# Operations on entire vectors (i.e. a whole row, a whole column)
# or apply()-type functions (we'll discuss later) are preferred

# IF/ELSE
# Again, pretty standard
if (4 > 3) {
    print("4 is greater than 3")
} else {
    print("4 is not greater than 3")
}
# =>
# [1] "4 is greater than 3"

# FUNCTIONS
# Defined like so:
jiggle <- function(x) {
    x = x + rnorm(1, sd=.1) #add in a bit of (controlled) noise
    return(x)
}
# Called like any other R function:
jiggle(5)   # 5±ε. After set.seed(2716057), jiggle(5)==5.005043

###########################################################################
# Data structures: Vectors, matrices, data frames, and arrays
###########################################################################

# ONE-DIMENSIONAL

# Let's start from the very beginning, and with something you already know: vectors.
vec <- c(8, 9, 10, 11)
vec #  8  9 10 11
# We ask for specific elements by subsetting with square brackets
# (Note that R starts counting from 1)
vec[1]      # 8
letters[18] # "r"
LETTERS[13] # "M"
month.name[9]   # "September"
c(6, 8, 7, 5, 3, 0, 9)[3]   # 7
# We can also search for the indices of specific components,
which(vec %% 2 == 0)    # 1 3
# grab just the first or last few entries in the vector,
head(vec, 1)    # 8
tail(vec, 2)    # 10 11
# or figure out if a certain value is in the vector
any(vec == 10) # TRUE
# If an index "goes over" you'll get NA:
vec[6]  # NA
# You can find the length of your vector with length()
length(vec) # 4
# You can perform operations on entire vectors or subsets of vectors
vec * 4 # 16 20 24 28
vec[2:3] * 5    # 25 30
any(vec[2:3] == 8) # FALSE
# and R has many built-in functions to summarize vectors
mean(vec)   # 9.5
var(vec)    # 1.666667
sd(vec)     # 1.290994
max(vec)    # 11
min(vec)    # 8
sum(vec)    # 38
# Some more nice built-ins:
5:15    # 5  6  7  8  9 10 11 12 13 14 15
seq(from=0, to=31337, by=1337)
# =>
#  [1]     0  1337  2674  4011  5348  6685  8022  9359 10696 12033 13370 14707
# [13] 16044 17381 18718 20055 21392 22729 24066 25403 26740 28077 29414 30751

# TWO-DIMENSIONAL (ALL ONE CLASS)

# You can make a matrix out of entries all of the same type like so:
mat <- matrix(nrow = 3, ncol = 2, c(1,2,3,4,5,6))
mat
# =>
#      [,1] [,2]
# [1,]    1    4
# [2,]    2    5
# [3,]    3    6
# Unlike a vector, the class of a matrix is "matrix", no matter what's in it
class(mat) # => "matrix"
# Ask for the first row
mat[1,] # 1 4
# Perform operation on the first column
3 * mat[,1] # 3 6 9
# Ask for a specific cell
mat[3,2]    # 6

# Transpose the whole matrix
t(mat)
# =>
#      [,1] [,2] [,3]
# [1,]    1    2    3
# [2,]    4    5    6

# Matrix multiplication
mat %*% t(mat)
# =>
#      [,1] [,2] [,3]
# [1,]   17   22   27
# [2,]   22   29   36
# [3,]   27   36   45

# cbind() sticks vectors together column-wise to make a matrix
mat2 <- cbind(1:4, c("dog", "cat", "bird", "dog"))
mat2
# =>
#      [,1] [,2]
# [1,] "1"  "dog"
# [2,] "2"  "cat"
# [3,] "3"  "bird"
# [4,] "4"  "dog"
class(mat2) # matrix
# Again, note what happened!
# Because matrices must contain entries all of the same class,
# everything got converted to the character class
c(class(mat2[,1]), class(mat2[,2]))

# rbind() sticks vectors together row-wise to make a matrix
mat3 <- rbind(c(1,2,4,5), c(6,7,0,4))
mat3
# =>
#      [,1] [,2] [,3] [,4]
# [1,]    1    2    4    5
# [2,]    6    7    0    4
# Ah, everything of the same class. No coercions. Much better.

# TWO-DIMENSIONAL (DIFFERENT CLASSES)

# For columns of different types, use a data frame
# This data structure is so useful for statistical programming,
# a version of it was added to Python in the package "pandas".

students <- data.frame(c("Cedric","Fred","George","Cho","Draco","Ginny"),
                       c(3,2,2,1,0,-1),
                       c("H", "G", "G", "R", "S", "G"))
names(students) <- c("name", "year", "house") # name the columns
class(students) # "data.frame"
students
# =>
#     name year house
# 1 Cedric    3     H
# 2   Fred    2     G
# 3 George    2     G
# 4    Cho    1     R
# 5  Draco    0     S
# 6  Ginny   -1     G
class(students$year)    # "numeric"
class(students[,3]) # "factor"
# find the dimensions
nrow(students)  # 6
ncol(students)  # 3
dim(students)   # 6 3
# The data.frame() function converts character vectors to factor vectors
# by default; turn this off by setting stringsAsFactors = FALSE when
# you create the data.frame
?data.frame

# There are many twisty ways to subset data frames, all subtly unalike
students$year   # 3  2  2  1  0 -1
students[,2]    # 3  2  2  1  0 -1
students[,"year"]   # 3  2  2  1  0 -1

# An augmented version of the data.frame structure is the data.table
# If you're working with huge or panel data, or need to merge a few data
# sets, data.table can be a good choice. Here's a whirlwind tour:
install.packages("data.table") # download the package from CRAN
require(data.table) # load it
students <- as.data.table(students)
students # note the slightly different print-out
# =>
#      name year house
# 1: Cedric    3     H
# 2:   Fred    2     G
# 3: George    2     G
# 4:    Cho    1     R
# 5:  Draco    0     S
# 6:  Ginny   -1     G
students[name=="Ginny"] # get rows with name == "Ginny"
# =>
#     name year house
# 1: Ginny   -1     G
students[year==2] # get rows with year == 2
# =>
#      name year house
# 1:   Fred    2     G
# 2: George    2     G
# data.table makes merging two data sets easy
# let's make another data.table to merge with students
founders <- data.table(house=c("G","H","R","S"),
                       founder=c("Godric","Helga","Rowena","Salazar"))
founders
# =>
#    house founder
# 1:     G  Godric
# 2:     H   Helga
# 3:     R  Rowena
# 4:     S Salazar
setkey(students, house)
setkey(founders, house)
students <- founders[students] # merge the two data sets by matching "house"
setnames(students, c("house","houseFounderName","studentName","year"))
students[,order(c("name","year","house","houseFounderName")), with=F]
# =>
#    studentName year house houseFounderName
# 1:        Fred    2     G           Godric
# 2:      George    2     G           Godric
# 3:       Ginny   -1     G           Godric
# 4:      Cedric    3     H            Helga
# 5:         Cho    1     R           Rowena
# 6:       Draco    0     S          Salazar

# data.table makes summary tables easy
students[,sum(year),by=house]
# =>
#    house V1
# 1:     G  3
# 2:     H  3
# 3:     R  1
# 4:     S  0

# To drop a column from a data.frame or data.table,
# assign it the NULL value
students$houseFounderName <- NULL
students
# =>
#    studentName year house
# 1:        Fred    2     G
# 2:      George    2     G
# 3:       Ginny   -1     G
# 4:      Cedric    3     H
# 5:         Cho    1     R
# 6:       Draco    0     S

# Drop a row by subsetting
# Using data.table:
students[studentName != "Draco"]
# =>
#    house studentName year
# 1:     G        Fred    2
# 2:     G      George    2
# 3:     G       Ginny   -1
# 4:     H      Cedric    3
# 5:     R         Cho    1
# Using data.frame:
students <- as.data.frame(students)
students[students$house != "G",]
# =>
#   house houseFounderName studentName year
# 4     H            Helga      Cedric    3
# 5     R           Rowena         Cho    1
# 6     S          Salazar       Draco    0

# MULTI-DIMENSIONAL (ALL ELEMENTS OF ONE TYPE)

# Arrays creates n-dimensional tables
# All elements must be of the same type
# You can make a two-dimensional table (sort of like a matrix)
array(c(c(1,2,4,5),c(8,9,3,6)), dim=c(2,4))
# =>
#      [,1] [,2] [,3] [,4]
# [1,]    1    4    8    3
# [2,]    2    5    9    6
# You can use array to make three-dimensional matrices too
array(c(c(c(2,300,4),c(8,9,0)),c(c(5,60,0),c(66,7,847))), dim=c(3,2,2))
# =>
# , , 1
#
#      [,1] [,2]
# [1,]    2    8
# [2,]  300    9
# [3,]    4    0
#
# , , 2
#
#      [,1] [,2]
# [1,]    5   66
# [2,]   60    7
# [3,]    0  847

# LISTS (MULTI-DIMENSIONAL, POSSIBLY RAGGED, OF DIFFERENT TYPES)

# Finally, R has lists (of vectors)
list1 <- list(time = 1:40)
list1$price = c(rnorm(40,.5*list1$time,4)) # random
list1
# You can get items in the list like so
list1$time # one way
list1[["time"]] # another way
list1[[1]] # yet another way
# =>
#  [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
# [34] 34 35 36 37 38 39 40
# You can subset list items like any other vector
list1$price[4]

# Lists are not the most efficient data structure to work with in R;
# unless you have a very good reason, you should stick to data.frames
# Lists are often returned by functions that perform linear regressions

##################################################
# The apply() family of functions
##################################################

# Remember mat?
mat
# =>
#      [,1] [,2]
# [1,]    1    4
# [2,]    2    5
# [3,]    3    6
# Use apply(X, MARGIN, FUN) to apply function FUN to a matrix X
# over rows (MAR = 1) or columns (MAR = 2)
# That is, R does FUN to each row (or column) of X, much faster than a
# for or while loop would do
apply(mat, MAR = 2, jiggle)
# =>
#      [,1] [,2]
# [1,]    3   15
# [2,]    7   19
# [3,]   11   23
# Other functions: ?lapply, ?sapply

# Don't feel too intimidated; everyone agrees they are rather confusing

# The plyr package aims to replace (and improve upon!) the *apply() family.
install.packages("plyr")
require(plyr)
?plyr

#########################
# Loading data
#########################

# "pets.csv" is a file on the internet
# (but it could just as easily be be a file on your own computer)
pets <- read.csv("http://learnxinyminutes.com/docs/pets.csv")
pets
head(pets, 2) # first two rows
tail(pets, 1) # last row

# To save a data frame or matrix as a .csv file
write.csv(pets, "pets2.csv") # to make a new .csv file
# set working directory with setwd(), look it up with getwd()

# Try ?read.csv and ?write.csv for more information

#########################
# Statistical Analysis
#########################

# Linear regression!
linearModel <- lm(price  ~ time, data = list1)
linearModel # outputs result of regression
# =>
# Call:
# lm(formula = price ~ time, data = list1)
#
# Coefficients:
# (Intercept)         time
#      0.1453       0.4943
summary(linearModel) # more verbose output from the regression
# =>
# Call:
# lm(formula = price ~ time, data = list1)
#
# Residuals:
#     Min      1Q  Median      3Q     Max
# -8.3134 -3.0131 -0.3606  2.8016 10.3992
#
# Coefficients:
#             Estimate Std. Error t value Pr(>|t|)
# (Intercept)  0.14527    1.50084   0.097    0.923
# time         0.49435    0.06379   7.749 2.44e-09 ***
# ---
# Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
#
# Residual standard error: 4.657 on 38 degrees of freedom
# Multiple R-squared:  0.6124,  Adjusted R-squared:  0.6022
# F-statistic: 60.05 on 1 and 38 DF,  p-value: 2.44e-09
coef(linearModel) # extract estimated parameters
# =>
# (Intercept)        time
#   0.1452662   0.4943490
summary(linearModel)$coefficients # another way to extract results
# =>
#              Estimate Std. Error    t value     Pr(>|t|)
# (Intercept) 0.1452662 1.50084246 0.09678975 9.234021e-01
# time        0.4943490 0.06379348 7.74920901 2.440008e-09
summary(linearModel)$coefficients[,4] # the p-values
# =>
#  (Intercept)         time
# 9.234021e-01 2.440008e-09

# GENERAL LINEAR MODELS
# Logistic regression
set.seed(1)
list1$success = rbinom(length(list1$time), 1, .5) # random binary
glModel <- glm(success  ~ time, data = list1,
    family=binomial(link="logit"))
glModel # outputs result of logistic regression
# =>
# Call:  glm(formula = success ~ time,
#   family = binomial(link = "logit"), data = list1)
#
# Coefficients:
# (Intercept)         time
#     0.17018     -0.01321
#
# Degrees of Freedom: 39 Total (i.e. Null);  38 Residual
# Null Deviance:        55.35
# Residual Deviance: 55.12   AIC: 59.12
summary(glModel) # more verbose output from the regression
# =>
# Call:
# glm(formula = success ~ time,
#   family = binomial(link = "logit"), data = list1)

# Deviance Residuals:
#    Min      1Q  Median      3Q     Max
# -1.245  -1.118  -1.035   1.202   1.327
#
# Coefficients:
#             Estimate Std. Error z value Pr(>|z|)
# (Intercept)  0.17018    0.64621   0.263    0.792
# time        -0.01321    0.02757  -0.479    0.632
#
# (Dispersion parameter for binomial family taken to be 1)
#
#     Null deviance: 55.352  on 39  degrees of freedom
# Residual deviance: 55.121  on 38  degrees of freedom
# AIC: 59.121
#
# Number of Fisher Scoring iterations: 3

#########################
# Plots
#########################

# BUILT-IN PLOTTING FUNCTIONS
# Scatterplots!
plot(list1$time, list1$price, main = "fake data")
# Plot regression line on existing plot
abline(linearModel, col = "red")
# Get a variety of nice diagnostics
plot(linearModel)
# Histograms!
hist(rpois(n = 10000, lambda = 5), col = "thistle")
# Barplots!
barplot(c(1,4,5,1,2), names.arg = c("red","blue","purple","green","yellow"))

# GGPLOT2
# But these are not even the prettiest of R's plots
# Try the ggplot2 package for more and better graphics
install.packages("ggplot2")
require(ggplot2)
?ggplot2
pp <- ggplot(students, aes(x=house))
pp + geom_histogram()
ll <- as.data.table(list1)
pp <- ggplot(ll, aes(x=time,price))
pp + geom_point()
# ggplot2 has excellent documentation (available http://docs.ggplot2.org/current/)


########################################################
# spectrum_analysis.r                                  #
# Matheus J. Castro                                    #
# Version 2.3                                          #
# Last Modification: 11/11/2021 (month/day/year)       #
# https://github.com/MatheusJCastro/spectra_comparator #
# Licensed under MIT License                           #
########################################################

library("minpack.lm")

# Files Names
files = c("Spectrum_R=14026.csv", "Spectrum_R=6000.csv")

# Load Spectrum 1
spec_wave_1 = read.table(files[1], sep=",", skip=0, nrow=2, header=FALSE, row.names=1, check.names=FALSE)

spec_data_1 = read.table(files[1], sep="", skip=2, header=TRUE, check.names=FALSE)
spec_data_1 = spec_data_1[,1]

# Load Spectrum 2
spec_wave_2 = read.table(files[2], sep=",", skip=0, nrow=2, header=FALSE, row.names=1, check.names=FALSE)

spec_data_2 = read.table(files[2], sep="", skip=2, header=TRUE, check.names=FALSE)
spec_data_2 = spec_data_2[,1]

# Calculate wavelengths
spec_wave_1 = spec_wave_1["CRVAL_1",1] + spec_wave_1["CD1_1",1] * seq.int(0, length(spec_data_1)-1)
spec_wave_2 = spec_wave_2["CRVAL_1",1] + spec_wave_2["CD1_1",1] * seq.int(0, length(spec_data_2)-1)

# Plot Spectra
png(file="Espectra.png", width=1200, height=675)
par(mfrow=c(1, 2))

plot(spec_wave_1, spec_data_1, main="Spectra Comparison",
     xlab="Wavelength", ylab="Intensity", type="l", lty=1,
     cex.axis=2, cex.lab=1.5, cex.main=2)
lines(spec_wave_2, spec_data_2, col="blue")
labels = c(unlist(strsplit(sub(".*_", "", files[1]), "[.]"))[1])
labels = c(labels, unlist(strsplit(sub(".*_", "", files[2]), "[.]"))[1])
legend("topright", legend=c(labels),
       col=c("black", "blue"), lty=1, cex=2)
grid()

interval = 1550:1700
plot(spec_wave_1[interval], spec_data_1[interval], main="Spectra Comparison - zoom in",
     xlab="Wavelength", ylab="Intensity", type="l", lty=1,
     cex.axis=2, cex.lab=1.5, cex.main=2)
lines(spec_wave_2[interval], spec_data_2[interval], col="blue")
labels = c(unlist(strsplit(sub(".*_", "", files[1]), "[.]"))[1])
labels = c(labels, unlist(strsplit(sub(".*_", "", files[2]), "[.]"))[1])
legend("topright", legend=c(labels),
       col=c("black", "blue"), lty=1, cex=2)
grid()

# Find Peaks
find_peaks <- function(spec_data, threshold=NULL, half_window=10){
       peaks = c()

       if(is.null(threshold))
              threshold = mean(spec_data)

       lenspec = length(spec_data)
       for(i in 1:lenspec){
              imin = i - half_window
              imax = i + half_window
              if(imin < 1)
                     imin = 1
              if(imax > lenspec)
                     imax = lenspec

              if(spec_data[i] == max(spec_data[imin:imax]) & spec_data[i] > threshold)
                     peaks = c(peaks, i)
       }

       return(peaks)
}

peaks1 = find_peaks(spec_data_1)
# segments(x0=spec_wave_1[peaks1], y0=spec_data_1[peaks1]*1.1,
       #   y1=spec_data_1[peaks1]*1.1+10000, col="red")

peaks2 = find_peaks(spec_data_2)
# segments(x0=spec_wave_2[peaks2], y0=spec_data_2[peaks2]*1.1,
       #   y1=spec_data_2[peaks2]*1.1+10000, col="green")

# Find Min Max of each Peak
find_min_max_gauss <- function(spec_data, peak){
       miny_old = spec_data[peak]
       j = peak
       while(TRUE){
              miny = spec_data[j]
              if(miny <= miny_old){
                     miny_old = miny
                     j = j - 1
              } else{
                     ind_miny = j
                     break
              }
       }

       maxy_old = spec_data[peak]
       j = peak
       while(TRUE){
              maxy = spec_data[j]
              if(maxy <= maxy_old){
                     maxy_old = maxy
                     j = j + 1
              } else{
                     ind_maxy = j
                     break
              }
       }

       return(c(ind_miny, ind_maxy))
}

# Gaussian function
gauss <- function(x, a, m, s){
       G = a * exp(-1/2 * ((x-m)/s)**2)
}

# Gaussian Fit and Spectrum Analysis
gaussian_fit <- function(spec_wave, spec_data, peaks, plot=FALSE){
       stds = c()
       new_peaks = c()

       for(i in peaks){
              ind_min_max = find_min_max_gauss(spec_data, i)

              x = spec_wave[ind_min_max[1]:ind_min_max[2]]
              y = spec_data[ind_min_max[1]:ind_min_max[2]]

              if(plot){
                     png(file=paste("Fits/Fit_", format(spec_wave[i], digits=2, nsmall=2), ".png", sep=""), width=1200, height=675)
                     plot(x, y, main="Gauss Fit", xlab="Wavelength", ylab="Intensity", type="l", lty=1, lwd=5,
                          cex.axis=2, cex.lab=1.5, cex.main=2)
              }

              chi_square <- function(par){
                     y_gauss = gauss(x, par[1], par[2], par[3])
                     chi = y - y_gauss
                     if(plot) lines(x, gauss(x, par[1], par[2], par[3]), col="lightblue", lty=2)
                     return(chi)
              }

              fit = nls.lm(par=c(1, spec_wave[i], 0.1),# upper=c(280000, spec_wave[i]+100, 5),
                                 fn=chi_square, control=nls.lm.control(maxiter=500))

              if(plot){
                     x = seq(min(x), max(x), 0.01)
                     lines(x, gauss(x, fit$par[1], fit$par[2], fit$par[3]), col="red", lty=2, lwd=2)
                     graphics.off()
              }

              if(fit$par[3] <= 1 & fit$par[3] > 0){
                     stds = c(stds, fit$par[3])
                     new_peaks = c(new_peaks, i)
              }
       }
       return(list(std=stds, peak=new_peaks))
}

# Standard Devations
fit_res = gaussian_fit(spec_wave_1, spec_data_1, peaks1)
stds1 = fit_res$std
std1p = format(mean(stds1), digits=2, nsmall=2)
peaks1 = fit_res$peak

fit_res = gaussian_fit(spec_wave_2, spec_data_2, peaks2)
stds2 = fit_res$std
std2p = format(mean(stds2), digits=2, nsmall=2)
peaks2 = fit_res$peak

# Plot Stds
png(file="Desvio_padrao.png", width=1200, height=675)
par(mfrow=c(1, 2))

hist(stds1, main=paste("Standard Deviation of Original Spectrum Peaks\nwith mean", std1p),
     ylab="Frequency", xlab="Values", breaks=15, col="lightblue",
     cex.axis=2, cex.lab=1.5, cex.main=2)
abline(v=mean(stds1), lty=2, col="red")

hist(stds2, main=paste("Standard Deviation of Reduced Spectrum Peaks\nwith mean", std2p),
     ylab="Frequency", xlab="Values", breaks=15, col="lightblue",
     cex.axis=2, cex.lab=1.5, cex.main=2)
abline(v=mean(stds2), lty=2, col="red")

# Plot Correlation of Stds and Wavelength
png(file="Desvio_Padrao_por_Comp_Onda.png", width=1200, height=675)
par(mfrow=c(1, 2))

plot(spec_wave_1[peaks1], stds1, main="Original Spectrum\nMean of Peaks x Standard Deviation",
     xlab="Wavelength", ylab=expression(sigma), lty=1, col="blue",
     cex.axis=2, cex.lab=1.5, cex.main=2)

plot(spec_wave_2[peaks2], stds2, main="Reduced Spectrum\nMean of Peaks x Standard Deviation",
     xlab="Wavelength", ylab=expression(sigma), lty=1, col="red",
     cex.axis=2, cex.lab=1.5, cex.main=2)

# Change of means for each peak
cross_match <- function(spec1, spec2, radius=10){
       matchs = matrix(, nrow=0, ncol=2)
       colnames(matchs) <- c("Spec1", "Spec2")

       if(length(spec1) >= length(spec2)){
              spec_big = spec1
              spec_few = spec2
       } else{
              spec_big = spec2
              spec_few = spec1
       }

       for(i in 1:length(spec_big)){
              val1 = spec_big[i]
              for(j in 1:length(spec_few)){
                     val2 = spec_few[j]
                     if(val2-radius <= val1 & val2+radius >= val1){
                            if(i %in% matchs[,1]){
                                   ind_rep = which(matchs[,1]==i)
                                   if(abs(val1-val2) < abs(val1-spec_few[matchs[ind_rep,2]]))
                                          matchs[ind_rep,2] = j
                            } else{
                                   matchs = rbind(matchs, c(i, j))
                            }
                     }
              }
       }

       if(length(spec1) < length(spec2)){
              order = c("Spec2", "Spec1")
              matchs = matchs[,order]
       }

       return(matchs)
}

match = cross_match(spec_wave_1[peaks1], spec_wave_2[peaks2])
matchc1 = spec_wave_1[peaks1[match[,1]]]
matchc2 = spec_wave_2[peaks2[match[,2]]]

# Plot Change of Means
png(file="Mudanca_das_Medias.png", width=1200, height=675)
par(mfrow=c(1, 2))

plot(matchc1, abs(matchc1-matchc2),
     main="Wavelengths of Original Spectrum\nPeaks x Drifting from Reduced Spectrum",
     xlab="Original Spectrum Wavelength", ylab="Drifting from Reduced Spectrum Peaks",
     cex.axis=2, cex.lab=1.5, cex.main=2)
abline(h=quantile(abs(matchc1-matchc2), prob=c(.75)), lty=2, col="red")

hist(abs(matchc1-matchc2), breaks=10,
     main="Histogram of Peak Value Differences",
     xlab="Change of Means", ylab="Frequency", col="lightblue",
     cex.axis=2, cex.lab=1.5, cex.main=2)
abline(v=mean(abs(matchc1-matchc2)), lty=2, col="red")

# Quartile of Peaks Change
save_txt = "Qartile of Peaks Change"
save_txt = paste(save_txt, "\n50% =", quantile(abs(matchc1-matchc2), prob=c(.50)))
save_txt = paste(save_txt, "\n75% =", quantile(abs(matchc1-matchc2), prob=c(.75)))

# Identificacion of Blended Lines
blend_indentify <- function(spec1, spec2, radius=0.1){
       blends = matrix(, nrow=0, ncol=2)
       colnames(blends) <- c("Spec1", "Spec2")

       if(length(spec1) >= length(spec2)){
              spec_big = spec1
              spec_few = spec2
       } else{
              spec_big = spec2
              spec_few = spec1
       }

       for(i in 1:length(spec_big)){
              val1 = spec_big[i]
              actual_blend = c()
              for(j in 1:length(spec_few)){
                     val2 = spec_few[j]
                     if(val2-radius <= val1 & val2+radius >= val1){
                            actual_blend = c(actual_blend, j)
                     }

              }
              if(length(actual_blend) > 1){
                     for(j in 1:length(actual_blend))
                            blends = rbind(blends, c(i, actual_blend[j]))
              }
       }

       if(length(spec1) < length(spec2)){
              order = c("Spec2", "Spec1")
              blends = blends[,order]
       }

       return(blends)
}

blend = blend_indentify(spec_wave_1[peaks1], spec_wave_2[peaks2], radius=3*mean(abs(matchc1-matchc2)))
blends1_wave = spec_wave_1[peaks1[blend[,1]]]
blends2_wave = spec_wave_2[peaks2[blend[,2]]]
blends1_data = spec_data_1[peaks1[blend[,1]]]

# Find Correlation of Blend and Intensity
corr_blends <- function(bl1_w, bl1_d){
       intensities = c(50, 40, 25, 12.5, 6.25, 3.125, 0) * 1000

       intens_blends = list()

       for(i in 1:length(intensities)){
              blends_count = c()
              for(j in 1:length(bl1_w)){
                     if(bl1_d[j] >= intensities[i]){
                            if(i == 1)
                                   blends_count = c(blends_count, bl1_w[j])
                            else if(bl1_d[j] <= intensities[i-1])
                                   blends_count = c(blends_count, bl1_w[j])
                     }
              }
              intens_blends[[paste(intensities[i])]] = unique(blends_count)
       }

       return(intens_blends)
}

blends_correlation = corr_blends(blends1_wave, blends1_data)

# Plot Blended Lines in Spectra
png(file="Linhas_com_Blends.png", width=1200, height=675)
plot(spec_wave_1, spec_data_1, main="Blended Lines found for each Intensity level",
     xlab="Wavelength", ylab="Intensity", type="l", lty=1,
     cex.axis=2, cex.lab=1.5, cex.main=2)

for(i in names(blends_correlation)){
       y_inten = rep(as.numeric(i), length(blends_correlation[[i]]))
       points(blends_correlation[[i]], y_inten, col=1+which(i==names(blends_correlation)), pch=4, lwd=3)
}

labels = names(blends_correlation)
legend("topright", legend=labels, title="Intensities levels",
       col=2:(length(names(blends_correlation))+1), lty=1, cex=2)

# Fit Correlation of Blend and Intensity
e_func <- function(x, a, b, c){
       E = b * exp(a*x) + c
}

chi_square_e_func <- function(x, y, par){
       e_teor = e_func(x, par[1], par[2], par[3])
       chi = sum(((y - e_teor)^2)/e_teor)
       return(chi)
}

intens = as.numeric(names(blends_correlation))
fit = optim(par=c(-0.0001, 50, 1), fn=chi_square_e_func, x=as.numeric(names(blends_correlation)), y=lengths(blends_correlation))
save_txt = paste(save_txt, "\nExponential of b*e^(ax)+c")
save_txt = paste(save_txt, "\na =", fit$par[1])
save_txt = paste(save_txt, "\nb =", fit$par[2])
save_txt = paste(save_txt, "\nc =", fit$par[3])

x_inten = seq(min(intens), max(intens), length=1000)
y_count = e_func(x_inten, fit$par[1], fit$par[2], fit$par[3])

# Plot Blended Lines as Intensity function
png(file="Relacao_Blend_Intensidade.png", width=1200, height=675)

plot(intens, lengths(blends_correlation), main="Blended Lines as funtction of Intensity",
     xlab="Intensity", ylab="Blend Line Count", pch=8, cex=2, lwd=2,
     cex.axis=2, cex.lab=1.5, cex.main=2)

lines(x_inten, y_count, lty=2, col="red")

# Save Results
fl <- file("Resultados.txt")
writeLines(save_txt, fl)
close(fl)


library(SuperLearner)
source('utils.r')
source('slfunctions.r')

fitnuisance <- function(data, nfolds,
                        sl_lib = c('SL.myglmnet', 'SL.myglm', 'SL.mean')) {

    candidatesg <- candidatese <- candidatesm <- candidatesb <-
        candidatesd <- sl_lib
    ## extract data
    Y <- data[, "Y"]
    Z <- data[, substr(names(data), 1, 1) == "Z"]
    L <- data[, "L"]
    A <- data[, "A"]
    W <- data[, substr(names(data), 1, 1) == "W"]

    ## observations and cross-validation
    n <- length(A)
    valSets <- split(sample(seq_len(n)), rep(seq_len(nfolds), length = n))

    ## fit nuisance functions
    fitg <- mySL(
        Y = A,
        X = W,
        family = stats::binomial(),
        SL.library = candidatesg,
        validRows = valSets
    )
    fite <- mySL(
        Y = A,
        X = data.frame(Z, W),
        family = stats::binomial(),
        SL.library = candidatese,
        validRows = valSets
    )
    fitm <- mySL(
        Y = Y,
        X = data.frame(Z, L, A, W),
        family = binomial(),
        SL.library = candidatesm,
        validRows = valSets
    )
    fitb <- mySL(
        Y = L,
        X = data.frame(A, W),
        family = stats::binomial(),
        SL.library = candidatesb,
        validRows = valSets
    )
    fitd <- mySL(
        Y = L,
        X = data.frame(Z, A, W),
        family = stats::binomial(),
        SL.library = candidatesd,
        validRows = valSets
    )

    return(list(fitg = fitg, fite = fite, fitm = fitm, fitb = fitb,
                fitd = fitd, valSets = valSets))
}

estimators <- function(data, delta, nuisance, seed, type,
                       sl_lib = c('SL.myglmnet', 'SL.myglm', 'SL.mean')) {

    candidatesv  <- candidatess <- candidatesq <- candidatesubar <- sl_lib

    ## extract data
    Y <- data[, "Y"]
    Z <- data[, substr(names(data), 1, 1) == "Z"]
    L <- data[, "L"]
    A <- data[, "A"]
    W <- data[, substr(names(data), 1, 1) == "W"]

    n <- length(A)

    g1  <- truncate(nuisance$fitg$SL.predict[, 1])
    e1  <- truncate(nuisance$fite$SL.predict[, 1])
    b1A <- nuisance$fitb$SL.predict[, 1]
    d1A <- truncate(nuisance$fitd$SL.predict[, 1])

    g <- A * g1 + (1 - A) * (1 - g1)
    e <- A * e1 + (1 - A) * (1 - e1)
    b <- L * b1A + (1 - L) * (1 - b1A)
    d <- L * d1A + (1 - L) * (1 - d1A)

    b11  <- predict(nuisance$fitb, newdata = data.frame(A = 1, W))$pred[, 1]
    b10  <- predict(nuisance$fitb, newdata = data.frame(A = 0, W))$pred[, 1]
    d11  <- truncate(predict(nuisance$fitd, newdata = data.frame(Z, A = 1, W))$pred[, 1])
    d10  <- truncate(predict(nuisance$fitd, newdata = data.frame(Z, A = 0, W))$pred[, 1])
    m11  <- predict(nuisance$fitm, newdata = data.frame(Z, L = 1, A = 1, W))$pred[, 1]
    m10  <- predict(nuisance$fitm, newdata = data.frame(Z, L = 1, A = 0, W))$pred[, 1]
    m01  <- predict(nuisance$fitm, newdata = data.frame(Z, L = 0, A = 1, W))$pred[, 1]
    m00  <- predict(nuisance$fitm, newdata = data.frame(Z, L = 0, A = 0, W))$pred[, 1]

    m <- nuisance$fitm$SL.predict[, 1]
    m1A <- A * m11 + (1 - A) * m10
    m0A <- A * m01 + (1 - A) * m00

    uA <- m1A * b1A + m0A * (1 - b1A)
    u1 <- m11 * b11 + m01 * (1 - b11)
    u0 <- m10 * b10 + m00 * (1 - b10)

    vout <- m * b / d
    sout <- m * b / d * g / e

    if(sd(vout) < .Machine$double.eps * 10) {
        v1 <- v0 <- rep(mean(vout), length(vout))
    } else {
        fitv <- mySL(
            Y = vout,
            X = data.frame(L, A, W),
            family = stats::gaussian(),
            SL.library = candidatesv,
            validRows = nuisance$valSets
        )
        v1 <- predict(fitv, newdata = data.frame(L = 1, A, W))$pred[, 1]
        v0 <- predict(fitv, newdata = data.frame(L = 0, A, W))$pred[, 1]
    }

    if(sd(sout) < .Machine$double.eps * 10) {
        s1 <- s0 <- rep(mean(sout), length(sout))
    } else {
        fits <- mySL(
            Y = sout,
            X = data.frame(L, A, W),
            family = stats::gaussian(),
            SL.library = candidatess,
            validRows = nuisance$valSets
        )
        s1 <- predict(fits, newdata = data.frame(L = 1, A, W))$pred[, 1]
        s0 <- predict(fits, newdata = data.frame(L = 0, A, W))$pred[, 1]
    }

    if(sd(uA) < .Machine$double.eps * 10) {
        ubar1 <- ubar0 <- rep(mean(uA), length(uA))
    } else {
        fitubar <- mySL(
            Y = uA,
            X = data.frame(A, W),
            family = stats::gaussian(),
            SL.library = candidatesubar,
            validRows = nuisance$valSets
        )
        ubar1 <- predict(fitubar, newdata = data.frame(A = 1, W))$pred[, 1]
        ubar0 <- predict(fitubar, newdata = data.frame(A = 0, W))$pred[, 1]
    }

    ubarA  <- A * ubar1 + (1 - A) * ubar0
    q1    <- ubar1 - ubar0

    if(sd(u1 - u0) < .Machine$double.eps * 10) {
        q2  <- rep(mean(u1 - u0), length(u1))
    } else {
        fitq2 <- mySL(
            Y = u1 - u0,
            X = data.frame(W),
            family = stats::gaussian(),
            SL.library = candidatesq,
            validRows = nuisance$valSets
        )
        q2  <- fitq2$SL.predict[, 1]
    }

    g1delta <- gdelta1(g1, delta)
    gdelta <- A * g1delta + (1 - A) * (1 - g1delta)

    HD <- b / d * (1 - gdelta / e)
    HI <- b / d * gdelta * (1 / e -  1 / g)
    KD <- v1 - v0 - gdelta / g * (s1 - s0)
    KI <- gdelta / g * (s1 - s0 - v1 + v0)
    MD <- - g1delta * (1 - g1delta) / (g1 * (1 - g1)) * q2
    MI <- g1delta * (1 - g1delta) / (g1 * (1 - g1)) * (q2 - q1)
    J  <- - gdelta / g

    de <- ubar1 * g1 + ubar0 * (1 - g1) - (u1 * g1delta + u0 * (1 - g1delta))
    ie <- (u1 - ubar1) * g1delta + (u0 - ubar0) * (1 - g1delta)
    eifD <- HD * (Y - m) + KD * (L - b1A) + MD * (A - g1) + (uA - ubarA) + de
    eifI <- HI * (Y - m) + KI * (L - b1A) + MI * (A - g1) + J * (uA - ubarA) + ie

    osde <- mean(eifD)
    osie <- mean(eifI)
    seosde <- sd(eifD) / sqrt(n)
    seosie <- sd(eifI) / sqrt(n)

    ## now, compute the TMLE
    stopcrit <- FALSE
    iter <- 1

    ## iterative TMLE
    while (!stopcrit) {
        tiltm <- glm(Y ~ 0 + offset(qlogis(bound(m)))   + HD + HI, family = binomial())
        tiltb <- glm(L ~ 0 + offset(qlogis(bound(b1A))) + KD + KI, family = binomial())
        tiltg <- glm(A ~ 0 + offset(qlogis(bound(g1)))  + MD + MI, family = binomial())

        m   <- predict(tiltm, type = 'response')
        b1A <- predict(tiltb, type = 'response')
        g1  <- predict(tiltg, type = 'response')

        HD11 <- b11 / d11 * (1 - g1delta / e1)
        HI11 <- b11 / d11 * g1delta * (1 / e1 -  1 / g1)
        HD10 <- b10 / d10 * (1 - (1 - g1delta) / (1 - e1))
        HI10 <- b10 / d10 * (1 - g1delta) * (1 / (1 - e1) -  1 / (1 - g1))

        HD01 <- (1 - b11) / (1 - d11) * (1 - g1delta / e1)
        HI01 <- (1 - b11) / (1 - d11) * g1delta * (1 / e1 -  1 / g1)
        HD00 <- (1 - b10) / (1 - d10) * (1 - (1 - g1delta) / (1 - e1))
        HI00 <- (1 - b10) / (1 - d10) * (1 - g1delta) * (1 / (1 - e1) -  1 / (1 - g1))

        m11 <- plogis(qlogis(bound(m11)) + coef(tiltm)[1] * HD11 + coef(tiltm)[2] * HI11)
        m10 <- plogis(qlogis(bound(m10)) + coef(tiltm)[1] * HD10 + coef(tiltm)[2] * HI10)
        m01 <- plogis(qlogis(bound(m01)) + coef(tiltm)[1] * HD01 + coef(tiltm)[2] * HI01)
        m00 <- plogis(qlogis(bound(m00)) + coef(tiltm)[1] * HD00 + coef(tiltm)[2] * HI00)

        g <- A * g1 + (1 - A) * (1 - g1)
        b <- L * b1A + (1 - L) * (1 - b1A)
        g1delta <- gdelta1(g1, delta)
        gdelta <- A * g1delta + (1 - A) * (1 - g1delta)

        HD <- b / d * (1 - gdelta / e)
        HI <- b / d * gdelta * (1 / e -  1 / g)
        KD <- v1 - v0 - gdelta / g * (s1 - s0)
        KI <- gdelta / g * (s1 - s0 - v1 + v0)
        MD <- - g1delta * (1 - g1delta) / (g1 * (1 - g1)) * q2
        MI <- g1delta * (1 - g1delta) / (g1 * (1 - g1)) * (q2 - q1)

        de <- ubar1 * g1 + ubar0 * (1 - g1) - (u1 * g1delta + u0 * (1 - g1delta))
        ie <- (u1 - ubar1) * g1delta + (u0 - ubar0) * (1 - g1delta)

        eifDp <- HD * (Y - m) + KD * (L - b1A) + MD * (A - g1)
        eifIp <- HI * (Y - m) + KI * (L - b1A) + MI * (A - g1)

        ## iterate iterator
        iter <- iter + 1
        ## note: interesting stopping criterion
        stopcrit <- max(abs(c(mean(eifDp), mean(eifIp)))) <
            max(c(sd(eifDp), sd(eifIp))) * log(n) / n | iter > 6
    }

    J   <- - gdelta / g
    J1  <- - g1delta / g1
    J0  <- - (1 - g1delta) / (1 - g1)

    m1A <- A * m11 + (1 - A) * m10
    m0A <- A * m01 + (1 - A) * m00

    uA <- m1A * b1A + m0A * (1 - b1A)
    u1 <- m11 * b11 + m01 * (1 - b11)
    u0 <- m10 * b10 + m00 * (1 - b10)

    tiltu <- glm(uA ~ offset(qlogis(bound(ubarA))) + J, family = binomial())
    ubar1 <- plogis(coef(tiltu)[1] + qlogis(bound(ubar1)) + coef(tiltu)[2] * J1)
    ubar0 <- plogis(coef(tiltu)[1] + qlogis(bound(ubar0)) + coef(tiltu)[2] * J0)
    ubarA  <- A * ubar1 + (1 - A) * ubar0

    de <- ubar1 * g1 + ubar0 * (1 - g1) - (u1 * g1delta + u0 * (1 - g1delta))
    ie <- (u1 - ubar1) * g1delta + (u0 - ubar0) * (1 - g1delta)

    eifD <- HD * (Y - m) + KD * (L - b1A) + MD * (A - g1) + (uA - ubarA) + de
    eifI <- HI * (Y - m) + KI * (L - b1A) + MI * (A - g1) + J * (uA - ubarA) + ie

    tmlede <- mean(de)
    tmleie <- mean(ie)
    setmlede <- sd(eifD) / sqrt(n)
    setmleie <- sd(eifI) / sqrt(n)

    out <- data.frame(
        parameter = c('DE', 'IE', 'DE', 'IE'),
        estimator = c('OS', 'OS', 'TMLE', 'TMLE'),
        estimate  = c(osde, osie, tmlede, tmleie),
        ses       = c(seosde, seosie, setmlede, setmleie),
        n         = n,
        seed      = seed,
        type      = type)

    return(out)
}


subroutine stl(y,n,np,ns,nt,nl,isdeg,itdeg,ildeg,nsjump,ntjump,nljump,ni,no,rw,
	season,trend,work)

integer n, np, ns, nt, nl, isdeg, itdeg, ildeg, nsjump, ntjump, nljump, ni, no, k
integer newns, newnt, newnl, newnp
real y(n), rw(n), season(n), trend(n), work(n+2*np,5)
logical userw

userw = .false.
k = 0
do i = 1,n
	trend(i) = 0.0
newns = max0(3,ns)
newnt = max0(3,nt)
newnl = max0(3,nl)
newnp = max0(2,np)
if(mod(newns,2)==0) newns = newns + 1	#make odd
if(mod(newnt,2)==0) newnt = newnt + 1
if(mod(newnl,2)==0) newnl = newnl + 1
repeat {
	call onestp(y,n,newnp,newns,newnt,newnl,isdeg,itdeg,ildeg,nsjump,ntjump,nljump,
	ni,userw,rw,season, trend, work)
	k = k+1
	if(k>no) break
	do i = 1,n
		work(i,1) = trend(i)+season(i)
	call rwts(y,n,work(1,1),rw)
	userw = .true.
	}
if (no<=0)
	do i = 1,n
		rw(i) = 1.0
return
end

subroutine ess(y,n,len,ideg,njump,userw,rw,ys,res)

integer n, len, ideg, njump, newnj, nleft, nright, nsh, k, i, j
real y(n), rw(n), ys(n), res(n), delta
logical ok, userw

if(n<2) { ys(1) = y(1); return }
newnj = min0(njump, n-1)
if(len>=n) {	#len > or = n
	nleft = 1
	nright = n
	do i = 1,n,newnj {
		call est(y,n,len,ideg,float(i),ys(i),nleft,nright,res,userw,rw,ok)
		if(!ok) ys(i) = y(i)
		}
	}
else if(newnj==1) {	# newnj equal to one, len less than n
	nsh = (len+1)/2
	nleft = 1
	nright = len
	do i = 1,n {	# fitted value at i
		if(i>nsh && nright!=n) {
			nleft = nleft+1
			nright = nright+1
			}
		call est(y,n,len,ideg,float(i),ys(i),nleft,nright,res,userw,rw,ok)
		if(!ok) ys(i) = y(i)
		}
	}
else { # newnj greater than one, len less than n
	nsh = (len+1)/2
	do i = 1,n,newnj {	# fitted value at i
		if(i<nsh) {
			nleft = 1
			nright = len
			}
		else if(i>=n-nsh+1) {
			nleft = n-len+1
			nright = n
			}
		else {
			nleft = i-nsh+1
			nright = len+i-nsh
			}
		call est(y,n,len,ideg,float(i),ys(i),nleft,nright,res,userw,rw,ok)
		if(!ok) ys(i) = y(i)
		}
	}
if(newnj!=1){
	do i = 1,n-newnj,newnj {
		delta = (ys(i+newnj)-ys(i))/float(newnj)
		do j = i+1,i+newnj-1
			ys(j) = ys(i)+delta*float(j-i)
		}
	k = ((n-1)/newnj)*newnj+1
	if(k!=n) {
		call est(y,n,len,ideg,float(n),ys(n),nleft,nright,res,userw,rw,ok)
		if(!ok) ys(n) = y(n)
		if(k!=n-1) {
			delta = (ys(n)-ys(k))/float(n-k)
			do j = k+1,n-1
				ys(j) = ys(k)+delta*float(j-k)
			}
		}
	}
return
end

subroutine est(y,n,len,ideg,xs,ys,nleft,nright,w,userw,rw,ok)

integer n, len, ideg, nleft, nright, j
real y(n), w(n), rw(n), xs, ys, range, h, h1, h9, a, b, c, r
logical userw,ok

range = float(n)-float(1)
h = amax1(xs-float(nleft),float(nright)-xs)
if (len>n) h = h+float((len-n)/2)
h9 = .999*h
h1 = .001*h
# compute weights
a = 0.0
do j = nleft,nright {
	w(j) = 0.
	r = abs(float(j)-xs)
	if (r<=h9) {
		if (r<=h1) w(j) = 1.
		else w(j) = (1.0-(r/h)**3)**3
		if (userw) w(j) = rw(j)*w(j)
		a = a+w(j)
		}
	}
if (a<=0.0)
	ok = .false.
else {	# weighted least squares
	ok = .true.
	do j = nleft,nright	# make sum of w(j) == 1
		w(j) = w(j)/a
	if ((h>0.)&(ideg>0)) {	# use linear fit
		a = 0.0
		do j = nleft,nright	# weighted center of x values
			a = a+w(j)*float(j)
		b = xs-a
		c = 0.0
		do j = nleft,nright
			c = c+w(j)*(float(j)-a)**2
		if (sqrt(c)>.001*range) {
			b = b/c
# points are spread out enough to compute slope
			do j = nleft,nright
				w(j) = w(j)*(b*(float(j)-a)+1.0)
			}
		}
	ys = 0.0
	do j = nleft,nright
		ys = ys+w(j)*y(j)
	}
return
end

subroutine fts(x,n,np,trend,work)

integer n, np
real x(n), trend(n), work(n)

call ma(x,n,np,trend)
call ma(trend,n-np+1,np,work)
call ma(work,n-2*np+2,3,trend)
return
end

subroutine ma(x, n, len, ave)

integer n, len, i, j, k, m, newn
real x(n), ave(n), flen, v

newn = n-len+1
flen = float(len)
v = 0.0
# get the first average
do i = 1,len
	v = v+x(i)
ave(1) = v/flen
if (newn>1) {
	k = len
	m = 0
	do j = 2, newn {
# window down the array
		k = k+1
		m = m+1
		v = v-x(m)+x(k)
		ave(j) = v/flen
	}
}
return
end

subroutine onestp(y,n,np,ns,nt,nl,isdeg,itdeg,ildeg,nsjump,ntjump,nljump,ni,
	userw,rw,season,trend,work)

integer n,ni,np,ns,nt,nsjump,ntjump,nl,nljump,isdeg,itdeg,ildeg
real y(n),rw(n),season(n),trend(n),work(n+2*np,5)
logical userw

do j = 1,ni {
	do i = 1,n
		work(i,1) = y(i)-trend(i)
	call ss(work(1,1),n,np,ns,isdeg,nsjump,userw,rw,work(1,2),work(1,3),work(1,4),
		work(1,5),season)
	call fts(work(1,2),n+2*np,np,work(1,3),work(1,1))
	call ess(work(1,3),n,nl,ildeg,nljump,.false.,work(1,4),work(1,1),work(1,5))
	do i = 1,n
		season(i) = work(np+i,2)-work(i,1)
	do i = 1,n
		work(i,1) = y(i)-season(i)
	call ess(work(1,1),n,nt,itdeg,ntjump,userw,rw,trend,work(1,3))
	}
return
end

subroutine rwts(y,n,fit,rw)

integer mid(2), n
real y(n), fit(n), rw(n), cmad, c9, c1, r

do i = 1,n
	rw(i) = abs(y(i)-fit(i))
mid(1) = n/2+1
mid(2) = n-mid(1)+1
call psort(rw,n,mid,2)
cmad = 3.0*(rw(mid(1))+rw(mid(2)))	#6 * median abs resid
c9 = .999*cmad
c1 = .001*cmad
do i = 1,n {
	r = abs(y(i)-fit(i))
	if (r<=c1) rw(i) = 1.
	else if (r<=c9) rw(i) = (1.0-(r/cmad)**2)**2
	else rw(i) = 0.
	}
return
end

subroutine ss(y,n,np,ns,isdeg,nsjump,userw,rw,season,work1,work2,work3,work4)

integer n, np, ns, isdeg, nsjump, nright, nleft, i, j, k
real y(n), rw(n), season(n+2*np), work1(n), work2(n), work3(n), work4(n), xs
logical userw,ok

for(j=1; j<=np; j=j+1){
	k = (n-j)/np+1
	do i = 1,k
		work1(i) = y((i-1)*np+j)
	if(userw)
		do i = 1,k
			work3(i) = rw((i-1)*np+j)
	call ess(work1,k,ns,isdeg,nsjump,userw,work3,work2(2),work4)
	xs = 0
	nright = min0(ns,k)
	call est(work1,k,ns,isdeg,xs,work2(1),1,nright,work4,userw,work3,ok)
	if(!ok) work2(1) = work2(2)
	xs = k+1
	nleft = max0(1,k-ns+1)
	call est(work1,k,ns,isdeg,xs,work2(k+2),nleft,k,work4,userw,work3,ok)
	if(!ok) work2(k+2) = work2(k+1)
	do m = 1,k+2
		season((m-1)*np+j) = work2(m)
	}
return
end
subroutine stlez(y, n, np, ns, isdeg, itdeg, robust, no, rw, season, trend, work)

logical robust
integer n, i, j, np, ns, no, nt, nl, ni, nsjump, ntjump, nljump, newns, newnp
integer isdeg, itdeg, ildeg
real y(n), rw(n), season(n), trend(n), work(n+2*np,7)
real maxs, mins, maxt, mint, maxds, maxdt, difs, dift

ildeg = itdeg
newns = max0(3,ns)
if(mod(newns,2)==0) newns = newns+1
newnp = max0(2,np)
nt = (1.5*newnp)/(1 - 1.5/newns) + 0.5
nt = max0(3,nt)
if(mod(nt,2)==0) nt = nt+1
nl = newnp
if(mod(nl,2)==0) nl = nl+1
if(robust) ni = 1
else ni = 2
nsjump = max0(1,int(float(newns)/10 + 0.9))
ntjump = max0(1,int(float(nt)/10 + 0.9))
nljump = max0(1,int(float(nl)/10 + 0.9))
do i = 1,n
	trend(i) = 0.0
call onestp(y,n,newnp,newns,nt,nl,isdeg,itdeg,ildeg,nsjump,ntjump,nljump,ni,
	.false.,rw,season,trend,work)
no = 0
if(robust){
	for(j=1; j<=15; j=j+1){	#robustness iterations
		do i = 1,n{	#initialize for testing
			work(i,6) = season(i)
			work(i,7) = trend(i)
			work(i,1) = trend(i)+season(i)
			}
		call rwts(y,n,work(1,1),rw)
		call onestp(y, n, newnp, newns, nt, nl, isdeg, itdeg, ildeg, nsjump,
			ntjump, nljump, ni, .true., rw, season, trend, work)
		no = no+1
		maxs = work(1,6)
		mins = work(1,6)
		maxt = work(1,7)
		mint = work(1,7)
		maxds = abs(work(1,6) - season(1))
		maxdt = abs(work(1,7) - trend(1))
		do i = 2,n{
			if(maxs<work(i,6)) maxs = work(i,6)
			if(maxt<work(i,7)) maxt = work(i,7)
			if(mins>work(i,6)) mins = work(i,6)
			if(mint>work(i,7)) mint = work(i,7)
			difs = abs(work(i,6) - season(i))
			dift = abs(work(i,7) - trend(i))
			if(maxds<difs) maxds = difs
			if(maxdt<dift) maxdt = dift
			}
		if((maxds/(maxs-mins)<.01) & (maxdt/(maxt-mint)<.01)) break
		}
	}
if(!robust){
	do i = 1,n
		rw(i) = 1.0
	}
return
end
subroutine psort(a,n,ind,ni)
real a(n)
integer n,ind(ni),ni
integer indu(16),indl(16),iu(16),il(16),p,jl,ju,i,j,m,k,ij,l
real t,tt
if (n<0||ni<0) return #ERROR(number of items<0)
if(n<2 | ni==0) return
jl = 1
ju = ni
indl(1) = 1
indu(1) = ni
#  arrays indl, indu keep account of the portion of ind related to the
#  current segment of data being ordered.
i = 1
j = n
m = 1
repeat {
	if (i<j) go to 10
	repeat {
		m = m-1
		if (m==0) break 2
		i = il(m)
		j = iu(m)
		jl = indl(m)
		ju = indu(m)
		if (jl<=ju) {
			while (j-i>10) {
#  first order a(i),a(j),a((i+j)/2), and use median to split the data
				10  k = i
				ij = (i+j)/2
				t = a(ij)
				if (a(i)>t) {
					a(ij) = a(i)
					a(i) = t
					t = a(ij)
					}
				l = j
				if (a(j)<t) {
					a(ij) = a(j)
					a(j) = t
					t = a(ij)
					if (a(i)>t) {
						a(ij) = a(i)
						a(i) = t
						t = a(ij)
						}
					}
				repeat {
					l = l-1
					if (a(l)<=t) {
						tt = a(l)
						repeat
#  split the data into a(i to l).lt.t, a(k to j).gt.t
							k = k+1
							until(a(k)>=t)
						if (k>l) break
						a(l) = a(k)
						a(k) = tt
						}
					}
				indl(m) = jl
				indu(m) = ju
				p = m
				m = m+1
#  split the larger of the segments
				if (l-i<=j-k) {
					il(p) = k
					iu(p) = j
					j = l
					repeat {
						if (jl>ju) next 3
						if (ind(ju)<=j) break
						ju = ju-1
						}
					indl(p) = ju+1
					}
				else {
					il(p) = i
					iu(p) = l
					i = k
					repeat {
#  skip all segments not corresponding to an entry in ind
						if (jl>ju) next 3
						if (ind(jl)>=i) break
						jl = jl+1
						}
					indu(p) = jl-1
					}
				}
			if (i==1) break
			i = i-1
			repeat {
				i = i+1
				if (i==j) break
				t = a(i+1)
				if (a(i)>t) {
					k = i
					repeat {
						a(k+1) = a(k)
						k = k-1
						}
						until(t>=a(k))
					a(k+1) = t
					}
				}
			}
		}
	}
return
end