## Trabajo final MAPP Otoño. Métodos cuantitativos.
## Integrantes:
## Guadalupe Álvarez
## Ángel Carrillo
## Eduardo Muñiz

Sys.setlocale("LC_ALL", "es_ES.UTF-8") # Cambiar locale para prevenir problemas con caracteres especiales
options(scipen=999) # Prevenir notación científica
rm(list=ls()) #Limpia todas las variables y objetos creados

##### Paquetería ----
library(tidyverse)
library(ggplot2)
library(ggcorrplot)
library(ggthemes)

library(cluster)
library(dplyr)
library(pacman)
library(factoextra)
library(dendextend)
library(purrr)

#PAQUETERÍA PARA ANOVA Y REGRESIÓN LINEAL
library(lme4)
library(lmerTest)

##### Base de datos ----
computoeinegi <- read.csv("2021 computoeinegi.csv")
str(computoeinegi)
head(computoeinegi)
# View(computoeinegi)

###################################
####### Indice de cosas por hacer:
###################################

# FECHA DE ENTREGA: 13 Y 14 DE DICIEMBRE

# Limpiar la base
# Estadistica descriptiva LALO
# ANOVA LUPITA
# Regresión lineal con variables explicativas CARILLO
# Hito 1: DEBE ESTAR LISTO EL  25-NOV EN LA NOCHE
# Ahí cordinarnos por mensajería sobre lo siguiente.

# Usar variables explicativas para analisis de componentes principales
# crear subconjunto de variables
# utilizar estas variables explicativas para:
# Conglomerados
# Nuevo grupos
# con nuevos grupos analisis jerárquico.

##### Estadística descriptiva ----

gr_participacion <- ggplot( computoeinegi,
                   aes(x=distrito , y=participacion) )+
              geom_point() +
              labs(title="Participación electoral",
                  subtitle="Proceso Electoral Federal 2021.",
                  x="Distrito electoral federal",
                  y="Porcentaje de participación",
                  caption="Elaboración propia con datos de INE(2021).") +
              theme_economist()+
              theme(axis.text.x=element_text(angle=50,size=12))

plot(gr_participacion)

########
      ##  ANOVA  ##

#Creamos una base con la variable categórica complejidad que nos indicará el número de grupos
# y la variable de interés será el porcentaje de participación

Anova_part <- computoeinegi [, -c(1,2,3,4,5,6,8,9,11,12,13,14,15,16,17)]

# Gráfica simple
ggplot(data = Anova_part, aes(x = 1:nrow(Anova_part), y = participacion)) +
  geom_point() +
  theme_bw()

# Gráfica por complejidad
ggplot(data = Anova_part, aes(x = 1:nrow(Anova_part),
                              y = participacion, colour = complejidad)) +
                              geom_point() +
                              theme_bw()

# Grafica de la gran media
ggplot(data = Anova_part, aes(x = 1:nrow(Anova_part), y = participacion, colour = complejidad)) +
  geom_point() +
  geom_hline(yintercept = mean(Anova_part$participacion), colour = "purple", size = 1) +
  theme_bw()

# Graficar la gran media y las medias de los grupos
ggplot(data = Anova_part, aes(x = 1:nrow(Anova_part), y = participacion, colour = complejidad)) +
  geom_point() +
  geom_hline(yintercept = mean(Anova_part$participacion), colour = "purple", size = 1) +
  geom_hline(yintercept = mean(Anova_part$participacion[Anova_part$complejidad=="
Altamente Concentrado 1"]),
             colour = "orangered1", size = 1) +
  geom_hline(yintercept = mean(Anova_part$participacion[Anova_part$complejidad=="
Altamente Concentrado 2"]),
             colour = "orange", size = 1) +
  geom_hline(yintercept = mean(Anova_part$participacion[Anova_part$complejidad=="Concentración Media"]),
             colour = "olivedrab", size = 1) +
  geom_hline(yintercept = mean(Anova_part$participacion[Anova_part$complejidad=="Concentrado 1"]),
             colour = "green", size = 1) +
  geom_hline(yintercept = mean(Anova_part$participacion[Anova_part$complejidad=="Concentrado 2"]),
             colour = "turquoise2", size = 1) +
  geom_hline(yintercept = mean(Anova_part$participacion[Anova_part$complejidad=="Disperso 1"]),
             colour = "blue", size = 1) +
  geom_hline(yintercept = mean(Anova_part$participacion[Anova_part$complejidad=="Disperso 2"]),
             colour = "royalblue", size = 1) +
  geom_hline(yintercept = mean(Anova_part$participacion[Anova_part$complejidad=="Muy Disperso 1"]),
             colour = "violet", size = 1) +
  geom_hline(yintercept = mean(Anova_part$participacion[Anova_part$complejidad=="Muy Disperso 2"]),
             colour = "deeppink", size = 1) +
  theme_bw()

###
### ANOVA
### Hipótesis Nula = las medias son iguales
### Hipótesis Alternativa = No todas las medias son iguales

anova(lm(participacion ~ complejidad, data = Anova_part))


model_snowmelt <- function (ps = 0.0,
         M = 0.0){
    #'- Name: SnowMelt -Version: 1.0, -Time step: 1
    #'- Description:
    #'            * Title: Snow Melt
    #'            * Author: STICS
    #'            * Reference: doi:http://dx.doi.org/10.1016/j.agrformet.2014.05.002
    #'            * Institution: INRA
    #'            * Abstract: Snow melt
    #'- inputs:
    #'            * name: ps
    #'                          ** description : density of snow cover
    #'                          ** inputtype : variable
    #'                          ** variablecategory : state
    #'                          ** datatype : DOUBLE
    #'                          ** default : 0.0
    #'                          ** min : 0.0
    #'                          ** max : 5000.0
    #'                          ** unit : kg/m**3
    #'                          ** uri :
    #'            * name: M
    #'                          ** description : snow in the process of melting
    #'                          ** inputtype : variable
    #'                          ** variablecategory : rate
    #'                          ** datatype : DOUBLE
    #'                          ** default : 0.0
    #'                          ** min :
    #'                          ** max :
    #'                          ** unit : mmW/d
    #'                          ** uri :
    #'- outputs:
    #'            * name: Snowmelt
    #'                          ** description : Snow melt
    #'                          ** variablecategory : state
    #'                          ** datatype : DOUBLE
    #'                          ** min : 0.0
    #'                          ** max : 500.0
    #'                          ** unit : m
    #'                          ** uri :
    Snowmelt <- 0.0
    if (ps > 1e-8)
    {
        Snowmelt <- M / ps
    }
    return (list('Snowmelt' = Snowmelt))
}


#       __  ___
#      /  |/  /___ _______________
#     / /|_/ / __ `/ ___/ ___/ __ \
#    / /  / / /_/ / /  / /__/ /_/ /
#   /_/  /_/\__,_/_/   \___/\____/
#  _       ___      __  __    ___
#  | |     / (_)____/ /_/ /_  / (_)___
#  | | /| / / / ___/ __/ __ \/ / / __ \
#  | |/ |/ / / /  / /_/ / / / / / / / /
#  |__/|__/_/_/   \__/_/ /_/_/_/_/ /_/-------------------------------------------------------------------------

#S2876507

# Running instructions: Press Ctrl+A, then Ctrl+Enter. "plyr" package must be installed.
# If you zoom in on the graph, drag the window a bit to the right, until the plots are roughly of quadratic shape (nicer that way).

library("plyr")

# exp_dict according to Taatgen, van Rijn and Anderson (2004)
exp_dict <- list(
    tick_increment = 1.1,
    b = 0.015,
    tick_base = 11,
    decay = -0.75, #decay parameter, default 0.5
    amount_subjects = 5, # subjects per interval
    amount_trials = 500, # amount of trials per subject and per interval
    subject_data = data.frame(matrix(ncol = 4, nrow = 0)),
    parm_t = 20
)

# act-r noise
noise <- function(number)
{
    random <- runif(1, min = 0.0001, max = 0.9999)
    number * log( (1 - random ) / random)
}

# function which converts time in ms to an internal representation in pulses
msecs_to_pulses <- function(msecs)
{
    pulse_counter = 0 # number of accumulated pulses
    time_counter <- 0 # passed time
    pulse <- exp_dict$tick_base # length of the initial pulse

    while (time_counter < msecs)
    {
        pulse <- exp_dict$tick_increment * pulse + noise(exp_dict$b * exp_dict$tick_increment * pulse) # generate next pulse
        pulse_counter <- pulse_counter + 1
        time_counter <- time_counter + pulse
    }

    pulse_counter
}

# function which produces time in ms based on an internal representation in pulses
pulse_to_msces <- function(pulses_input)
{

    time_counter <- 0 # passed time
    pulse_counter <- 0 # number of pulses
    pulse <- exp_dict$tick_base # length of the initial pulse

    while (pulse_counter < pulses_input)
    {
        pulse <- exp_dict$tick_increment * pulse + noise(exp_dict$b * exp_dict$tick_increment * pulse) # generate next pulse
        pulse_counter <- pulse_counter + 1
        time_counter <- time_counter + pulse
    }

    time_counter
}

experiment_setup <- function(current_subject) #I want setup the experiment parameters for each subject, once
{
    real_time <- 0 #this is the subjects objective time in ms. this will stay with the subject for the duration of the experiment
    DecMem <- matrix(NA, 35, 900)
    #simuli for the trials get determined:
    short_condition_values <- seq(494, 847, length=11) #values of the short interval get determined
    short_condition_sample <- sample(short_condition_values, exp_dict$amount_trials, replace = TRUE)
    medium_condition_values <- seq(671, 1023, length=11) #values of the short interval get determined
    medium_condition_sample <- sample(medium_condition_values, exp_dict$amount_trials, replace = TRUE)
    long_condition_values <- seq(847, 1200, length=11) #values of the short interval get determined
    long_condition_sample <- sample(long_condition_values, exp_dict$amount_trials, replace = TRUE)

    condition_order <- sample(c(1, 2, 3)) #randomization of experimental condition order (1=short, 2=medium, 3=long)

    list(real_time = real_time, subject_nr = current_subject,
        DecMem = DecMem,
        short_condition_sample = short_condition_sample,
        medium_condition_sample = medium_condition_sample,
        long_condition_sample = long_condition_sample,
        condition_order = condition_order
    )
}

encounter_add <- function(subject_setup, sample_int_pulse)
{
    tmp <- sum(!is.na(subject_setup$DecMem[sample_int_pulse, ])) + 1
    subject_setup$DecMem[sample_int_pulse, tmp] <- subject_setup$real_time
    subject_setup$real_time <- subject_setup$real_time + 50
    subject_setup
}

encounters_get <- function(subject_setup, current_row)
{
    tmp <- subject_setup$DecMem[current_row,]

    if (length(tmp[!is.na(tmp)]) == 0){
        return(NA)
    }else{
        return(tmp[!is.na(tmp)])
    }

}

chunk_activation <- function(encounters, curtime)
{
    if (curtime < min(encounters)) {
        return(NA)
    } else {
        sum((curtime - encounters[encounters<curtime])^exp_dict$decay)
    }
}

prob_calc <- function(current_activation, total_activation)
{
    dividend = sum(current_activation) / exp_dict$parm_t
    divisor = total_activation / exp_dict$parm_t

    retrieval_prob = dividend / divisor
}

blending <- function(subject_setup)
{
    total_activation <- 0
    blended_response <- 0

    for (current_row in seq(1, nrow(subject_setup$DecMem)))
    {
        amount_presentations <- sum(!is.na(subject_setup$DecMem[current_row, ]))

        if (amount_presentations > 0)
        {
            encounters <- encounters_get(subject_setup, current_row)

            current_activation <- chunk_activation(encounters, subject_setup$real_time)

            total_activation <- total_activation + current_activation # ACTIVATION OF THE DECLARATIVE MEMORY
        }
    }

    for (current_row in seq(1, nrow(subject_setup$DecMem)))
    {
        amount_presentations <- sum(!is.na(subject_setup$DecMem[current_row, ]))

        if (amount_presentations > 0)
        {

        encounters <- encounters_get(subject_setup, current_row)

        current_activation <- chunk_activation(encounters, subject_setup$real_time)

        retrieval_prob <- prob_calc(current_activation, total_activation)
        blended_response <- blended_response + (retrieval_prob * current_row)

        }
    }

    blended_response
}

trial <- function(current_condition, subject_setup)
{
    if(current_condition == 1){
        current_condition_sample <- subject_setup$short_condition_sample} else if(current_condition == 2){
            current_condition_sample <- subject_setup$medium_condition_sample} else if(current_condition == 3){
                current_condition_sample <- subject_setup$long_condition_sample}

    for (.. in seq(1, length(current_condition_sample))) #length = amount_trials (default: 500)
    {
        ts <- current_condition_sample[..] # sample interval (ts) for the current trial
        subject_setup$real_time <- subject_setup$real_time + 1.000 + sample(seq(0.250, 0.850), 1) + 0.100 + ts + 0.50

        # presentation of central fixation point (+1000), + variable delay ranging from 0.25–0.85s
        # + "READY?" flash for 100 ms + actual time of the sample interval
        # + "SET!" flash (lasted 100ms, but tp was recorded alrady after 50ms)

        sample_int_pulse <- msecs_to_pulses(ts) # the sample interval gets converted into pulses

        subject_setup <- encounter_add(subject_setup, sample_int_pulse)

        blended_response <- blending(subject_setup)
        tp <- pulse_to_msces(blended_response)

        subject_setup$subject_data <- rbind(subject_setup$subject_data, c(subject_setup$subject_nr, current_condition, ts, tp))
    }

    subject_setup
}

train <- function(current_condition, subject_setup)
{
    train_amount <- 250
    if(current_condition == 1){
        current_condition_sample <- subject_setup$short_condition_sample} else if(current_condition == 2){
            current_condition_sample <- subject_setup$medium_condition_sample} else if(current_condition == 3){
                current_condition_sample <- subject_setup$long_condition_sample}

    for (.. in seq(1, train_amount))
    {
        ts <- current_condition_sample[..] # sample interval (ts) for the current trial
        subject_setup$real_time <- subject_setup$real_time + 1 + sample(seq(0.250, 0.850), 1) + 0.100 + ts + 0.50
        sample_int_pulse <- msecs_to_pulses(ts) # the sample interval gets converted into pulses
        subject_setup <- encounter_add(subject_setup, sample_int_pulse)
    }
    subject_setup
}

main <- function()
{
    simulated_data <- data.frame(matrix(ncol = 4, nrow = 0))

    for (.. in seq(1, exp_dict$amount_subjects)) #loop for subjects
    {
        current_subject <- ..
        subject_setup <- experiment_setup(current_subject)

        for (.. in subject_setup$condition_order) # loop containing all conditions
        {
            current_condition <- ..
            subject_setup$DecMem <- matrix(NA, 35, 900) #new DM each day(condition)
            subject_setup <- train(current_condition, subject_setup)
            subject_setup$real_time <- subject_setup$real_time + 1
            subject_setup <- trial(current_condition, subject_setup) #here the trials happen (another loop inside)

        }

        simulated_data <- rbind(simulated_data, subject_setup$subject_data)
    }

    colnames(subject_setup$subject_data) <- c("Subject_Nr ", "Cond", "Ts", "Tp")
    subject_data <- data.frame(subject_setup$subject_data)
    subject_data$Response[is.nan(subject_data$Response)] <- subject_data$Prior[is.nan(subject_data$Response)]
    subject_data
}

plotting <- function(dataframe)
{

    brown <- "#8b4513";
    red <- "#ff1100";
    black <- "#000000";
    brownT <- "#8b451322";
    redT <- "#ff110022";
    blackT <- "#00000022";

    ## ---
    datJS <- dataframe
    par(mfrow=c(1,1))

    plotDatJS <- with(datJS,aggregate(list(Tp=Tp),list(Ts=Ts,Cond=Cond),mean))
    agregJS <- ddply(datJS, c("Cond", "Ts"), summarise, Ts_mean = mean(Ts), Tp_mean = mean(Tp))
    yrange <- range(plotDatJS$Ts)*c(.95,1.05)

    with(plotDatJS[plotDatJS$Cond==3,],plot(Ts,Tp,type="b",col=red,lwd=2,ylim=yrange,xlim=yrange,main="J&S All"))
    with(plotDatJS[plotDatJS$Cond==2,],lines(Ts,Tp,type="b",col=brown,lwd=2,ylim=yrange,xlim=yrange))
    with(plotDatJS[plotDatJS$Cond==1,],lines(Ts,Tp,type="b",col=black,lwd=2,ylim=yrange,xlim=yrange))

    lines(c(yrange[1],yrange[2]),c(yrange[1],yrange[2]),col="darkgrey",lty=2)

    with(datJS[datJS$Cond==3,],points(jitter(Ts),Tp,col=redT,pch=".",cex=3))
    with(datJS[datJS$Cond==2,],points(jitter(Ts),Tp,col=brownT,pch=".",cex=3))
    with(datJS[datJS$Cond==1,],points(jitter(Ts),Tp,col=blackT,pch=".",cex=3))
}

plotting(main())


permutation.test.discrete <-
function (x, y=NULL, scores, alternative="greater", trials=1000)
{
	# set up x and y properly
	if(length(y)) {
		n <- length(y)
		if(length(x) != n) stop("x and y have different lengths")
	} else {
		if(ncol(x) != 2)
			stop("x does not have 2 columns and y is missing")
		y <- x[, 2]
		x <- x[, 1]
		n <- length(y)
	}
	x <- as.character(x)
	y <- as.character(y)

	# set up alternative
	if(length(alternative) != 1 || !is.character(alternative))
		stop("alternative must be a single character string")
	altnum <- pmatch(alternative, c("greater", "less"), nomatch=NA)
	if(is.na(altnum))
		stop("alternative must partially match 'greater' or 'less'")
	alternative <- c("greater", "less")[altnum]

	# set up scores properly
	orig.tab <- table(x, y)
	otd <- dim(orig.tab)
	odnam <- dimnames(orig.tab)
	scnam <- dimnames(scores)
	if(!is.matrix(scores) || length(scnam) != 2 || !is.numeric(scores))
		stop("scores must be a numeric matrix with dimnames")
	scd <- dim(scores)
	if(any(scd != otd) && any(rev(scd) != otd)) {
		stop(paste("scores is not the proper size, should be",
			otd[1], "by", otd[2]))
	}
	if(any(scd != otd)) {
		scores <- t(scores)
		scd <- dim(scores)
		scnam <- dimnames(scores)
		reverse <- TRUE
	} else {
		reverse <- FALSE
	}
	rownum <- match(scnam[[1]], odnam[[1]], nomatch=NA)
	if(any(is.na(rownum))) {
		if(reverse || otd[1] != otd[2])
			stop("bad dimnames for scores")
		scores <- t(scores)
		scd <- dim(scores)
		scnam <- dimnames(scores)
		rownum <- match(scnam[[1]], odnam[[1]], nomatch=NA)
		if(any(is.na(rownum))) stop("bad dimnames for scores")
	}
	colnum <- match(scnam[[2]], odnam[[2]], nomatch=NA)
	if(any(is.na(colnum))) stop("bad dimnames for scores")
	scores <- scores[rownum, colnum]

	# the main event
	ranseed <- .Random.seed
	orig.score <- sum(orig.tab * scores)
	perm.scores <- numeric(trials)
	for(i in 1:trials) {
		perm.scores[i] <- sum(table(x, sample(y)) * scores)
	}

	if(alternative == "greater") {
		extreme <- sum(perm.scores >= orig.score)
	} else {
		extreme <- sum(perm.scores <= orig.score)
	}
	ans <- list(original.score=orig.score, perm.scores=perm.scores,
		stats=c(nobs=n, trials=trials, extreme=extreme),
		alternative=alternative, random.seed=ranseed, call=match.call())
	class(ans) <- "permtstBurSt"
	ans
}
permutation.test.fun <-
function (x, y=NULL, fun=function(x, y) sum(x * y), alternative="greater",
	trials=1000)
{
	# set up x and y properly
	if(length(y)) {
		n <- length(y)
		if(length(x) != n) stop("x and y have different lengths")
		if(!is.numeric(y)) stop("y must be numeric")
	} else {
		if(ncol(x) != 2)
			stop("x does not have 2 columns and y is missing")
		x <- as.matrix(x)
		if(!is.numeric(x)) stop("x must be numeric")
		y <- x[, 2]
		x <- x[, 1]
		n <- length(y)
	}

	# set up alternative
	if(length(alternative) != 1 || !is.character(alternative))
		stop("alternative must be a single character string")
	altnum <- pmatch(alternative, c("greater", "less"), nomatch=NA)
	if(is.na(altnum))
		stop("alternative must partially match 'greater' or 'less'")
	alternative <- c("greater", "less")[altnum]

	# the main event
	ranseed <- .Random.seed
	orig.score <- fun(x, y)
	if(length(orig.score) != 1) stop("fun must return a single number")

	perm.scores <- numeric(trials)
	for(i in 1:trials) {
		perm.scores[i] <- fun(x, sample(y))
	}

	if(alternative == "greater") {
		extreme <- sum(perm.scores >= orig.score)
	} else {
		extreme <- sum(perm.scores <= orig.score)
	}
	ans <- list(original.score=orig.score, perm.scores=perm.scores,
		stats=c(nobs=n, trials=trials, extreme=extreme),
		alternative=alternative, random.seed=ranseed, call=match.call())
	class(ans) <- "permtstBurSt"
	ans
}
plot.permtstBurSt <-
function (x, col=c("black", "red"), width=10, uniqlim=40, main="",
	xlab="Scores", col.hist="yellow", ...)
{
	orig.score <- x$original.score
	ulen <- length(unique(x$perm.scores))
	if(ulen > uniqlim) {
		hist(x$perm.scores, xlim=range(x$perm.scores, orig.score),
			 main=main, xlab=xlab, col=col.hist,  ...)
		box()
		abline(v=orig.score, col=col[2])
	} else {
		ptab <- table(x$perm.scores)
		vals <- as.numeric(names(ptab))
		if(x$alternative == "greater") {
			extreme <- vals >= orig.score
		} else {
			extreme <- vals <= orig.score
		}
		if(all(vals > orig.score) || all(vals < orig.score)) {
			xrng <- range(vals, orig.score)
		} else {
			xrng <- range(vals)
		}
		plot(vals, as.vector(ptab), type="n", xlab=xlab, ylab="Count",
			xlim=xrng, ...)
		points(vals[!extreme], ptab[!extreme], type="h",
			col=col[1], lwd=width, ...)
		points(vals[extreme], ptab[extreme], type="h",
			col=col[2],  lwd=width, ...)
		if(nchar(main)) title(main=main)
	}
}
print.permtstBurSt <-
function (x, digits=4, ...)
{
	cat("Call:\n")
	print(x$call)
	cat("\nOriginal value:", x$original.score, "  Number of observations:",
		x$stats["nobs"], "\n")
	cat("Number of random permutations:", x$stats["trials"],
		"  Alternative:", x$alternative, "  p-value:",
		round(x$stats["extreme"] / x$stats["trials"], digits), "\n")
	invisible(x)
}
superscore <-
structure(c(1, 0, 0, 1), .Dim = c(2L, 2L), .Dimnames = list(c("Up",
"Down"), c("National", "American")))


#' f_h1
#'
#' Construct the $K_\tau K_1$ vector $h_1$
#'
#' @param n1 matrix n1 output from f_n1
#' @param g1 $G_1$ diagonal matrix
#' @param g2 $G_2$ diagonal matrix
#' @param sigmatau $\Sigma_tau$ diagonal matrix
#'
#'
#' @return $K_\tau K_1$ vector $H_1$
#'
#' @examples
#' \dontrun{
#' v_taustar <- f_tausearch(y, n1, til_beta, m_sigma, ktau, mtau)
#' m_ntaustar <- f_ntaustar(v_taustar, ktau, mtau)
#' m_s <- f_mats(ktau + mtau, k1 + m1, rep(1, 3))
#' m_g1 <- f_g1(ktau, mtau)
#' m_g2 <- f_g2(ktau, mtau)
#' m_sigmatau <- f_sigmatau(ktau + mtau)
#' m_h1 <- f_h1(n1, m_g1, m_g2, m_sigmatau)
#' m_h2 <- f_h2(n1, m_ntaustar, m_g1, m_sigmatau)
#' }
f_h1 <- function(n1, g1, g2, sigmatau) {
    #form N^{m_tau+2}(\tau)|_0^1
    nm2 <- rep(0, nrow(sigmatau)); nm2[nrow(sigmatau)] <- 1
    #Calculate $H_1$
    h_1 <- tcrossprod(g1, sigmatau) %*% tcrossprod(g2, sigmatau)
    h_1 <- -h_1 %*% nm2
    h_1 <- kronecker(h_1, t(n1))
    h_1 <- rowSums(h_1)
    return(h_1)
}

#' f_h2
#'
#' Construct the $K_\tauK_1$ vector $H_2$
#'
#' @param n1 matrix n1 output from f_n1
#' @param ntaustar matrix ntau output from f_ntaustar
#' @param g1 $G_1$ diagonal matrix
#' @param sigmatau $\Sigma_tau$ diagonal matrix
#'
#'
#' @return $K_\tau K_1$ vector $H_2$
#'
#' @import mgcv
#'
#' @examples
#' \dontrun{
#' v_taustar <- f_tausearch(y, n1, til_beta, m_sigma, ktau, mtau)
#' m_ntaustar <- f_ntaustar(v_taustar, ktau, mtau)
#' m_s <- f_mats(ktau + mtau, k1 + m1, rep(1, 3))
#' m_g1 <- f_g1(ktau, mtau)
#' m_g2 <- f_g2(ktau, mtau)
#' m_sigmatau <- f_sigmatau(ktau + mtau)
#' m_h1 <- f_h1(n1, m_g1, m_g2, m_sigmatau)
#' m_h2 <- f_h2(n1, m_ntaustar, m_g1, m_sigmatau)
#' }
f_h2 <- function(n1, ntaustar, g1, sigmatau) {
    h_2 <- tcrossprod(g1, sigmatau) %*% t(ntaustar)
#ptm <- proc.time()# Start the clock!
    h_2 <- mgcv::tensor.prod.model.matrix(list(t(h_2), n1))
    h_2 <- colSums(h_2)
#print(proc.time() - ptm)# Stop the clock

    return(h_2)
}

#' f_lossderiv
#'
#' Construct the $K_\tau K_1$ gradient vector for the loss
#'
#' @param til_beta the current estimation fro $\tilde{\beta}$
#' @param v_dim vector contain the dimension of covariates
#'             $(K_\tau, K_1, K_2, K_3, \cdots)$
#'
#' @param m_sigma $K_\tau K_1K_2 \times K_1K_2 \Sigma$ diagonal block matix.
#' @param h1 $K_\tau K_1K_2$ spline vector for the first covariate
#' @param h2 $K_\tau K_1K_2$ spline vector for the tau covariate
#'
#'
#' @return the $K_\tau K_1$ gradient vector for the loss
#'
#' @examples
#' \dontrun{
#' v_taustar <- f_tausearch(y, n1, til_beta, m_sigma, ktau, mtau)
#' m_ntaustar <- f_ntaustar(v_taustar, ktau, mtau)
#' m_s <- f_mats(ktau + mtau, k1 + m1, rep(1, 3))
#' m_g1 <- f_g1(ktau, mtau)
#' m_g2 <- f_g2(ktau, mtau)
#' m_sigmatau <- f_sigmatau(ktau + mtau)
#' m_h1 <- f_h1(n1, m_g1, m_g2, m_sigmatau)
#' m_h2 <- f_h2(n1, m_ntaustar, m_g1, m_sigmatau)
#' v_lossderiv <- f_lossderiv(til_beta, c(ktau + mtau, k1 + m1), m_sigma, m_h1, m_h2)
#' }
f_lossderiv <- function(til_beta, v_dim, m_sigma, h1, h2) {
    m_c <- f_matc(v_dim, til_beta)
    lossderiv <- - m_c %*% crossprod(m_sigma, (h1 + h2))
    return(c(lossderiv))
}

#' f_grad
#'
#' Construct the $K_\tau K_1K_2$ gradient vector for $\beta$
#'
#' @param beta the current estimation fro $\beta$
#' @param loss_deriv the derivative of the loss
#' @param s $K_\tau K_1K_2 \times K_1K_2$ $S$ matrix
#'
#'
#' @return the $K_\tau K_1K_2$ gradient vector for $\beta$
#'
#' @examples
#' \dontrun{
#' v_taustar <- f_tausearch(y, n1, til_beta, m_sigma, ktau, mtau)
#' m_ntaustar <- f_ntaustar(v_taustar, ktau, mtau)
#' m_s <- f_mats(ktau + mtau, k1 + m1, rep(1, 3))
#' m_g1 <- f_g1(ktau, mtau)
#' m_g2 <- f_g2(ktau, mtau)
#' m_sigmatau <- f_sigmatau(ktau + mtau)
#' m_h1 <- f_h1(n1, m_g1, m_g2, m_sigmatau)
#' m_h2 <- f_h2(n1, m_ntaustar, m_g1, m_sigmatau)
#' v_lossderiv <- f_lossderiv(til_beta, c(ktau + mtau, k1 + m1), m_sigma, m_h1, m_h2)
#' f_grad(beta, v_lossderiv, m_s)
#' }
f_grad <- function(beta, loss_deriv, s) {
    loss_deriv + c(s %*% beta)
}

#' f_hess
#'
#' Construct the $K_\tau K_1K_2 \times K_\tau K_1K_2$ Hessian matrix for $\beta$
#'
#' @param loss_deriv the derivative of the loss
#' @param v_dim vector contain the dimension of covariates
#'             $(K_\tau, K_1, K_2, K_3, \cdots)$
#' @param s $K_\tau K_1K_2 \times K_\tau K_1K_2$ $S$ matrix
#'
#'
#' @return the $K_\tau K_1K_2$ gradient vector for $\beta$
#'
#' @examples
#' \dontrun{
#' v_taustar <- f_tausearch(y, n1, til_beta, m_sigma, ktau, mtau)
#' m_ntaustar <- f_ntaustar(v_taustar, ktau, mtau)
#' m_s <- f_mats(ktau + mtau, k1 + m1, rep(1, 3))
#' m_g1 <- f_g1(ktau, mtau)
#' m_g2 <- f_g2(ktau, mtau)
#' m_sigmatau <- f_sigmatau(ktau + mtau)
#' n_m2 <- rep(0, ktau + mtau)
#' n_m2[ktau + mtau] <- 1
#' m_h1 <- f_h1(n1, m_g1, m_g2, m_sigmatau, n_m2)
#' m_h2 <- f_h2(n1, m_ntaustar, m_g1, m_sigmatau)
#' v_lossderiv <- f_lossderiv(til_beta, c(ktau + mtau, k1 + m1), m_sigma, m_h1, m_h2)
#' f_grad(beta, v_lossderiv, m_s)
#' m_hess <- f_hess(v_lossderiv, c(ktau + mtau, k1 + m1), m_s)
#' }
f_hess <- function(loss_deriv, v_dim, s) {
    v_idx <- seq_len(v_dim[2])
    loss_deriv[v_idx] <- 0
    return(diag(loss_deriv) + s)
}


# Copyright 2017 Province of British Columbia
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and limitations under the License.

###############################################################################
# Fit a Bayesian model for the replicated observations at the same species
# using data cloning.
#
# This function can be used for different distributions
# by selectively extracting the code with the tag number at the right

model {
  # Input data for logConc - log-concentration
  #                SpeciesNum - species number to link replicate observations
  #                NData - number of data values
  #                NSpecies - number of unique species
  #
  # Parameters for distributions vary depending on the distribution
  #    lnorm   -   mu, sigma - intercept and slope (on log scale) - lognormal

  # Parameters for observal error
  #       sigma_obs - sd of observational error
  #

  # observed data comes from underlying mean with a lognormal distribution
  # this is true regardless of the distribution of the mu_species whose
  # distributions can change
  # We want separate latent variables for each clone because this sample size
  # is NOT increasing as we increase the number of chemicals tested.
  for(k in 1:K){
     for(i in 1:NData){
        logConc[i,k]  ~ dnorm(log_mu_species[SpeciesNum[i],k], tau_obs)
     }
  }
  # Contributions to the likelihood from the observed data#
#  for(i in 1:NData){
#     likc.data[i] <- dnorm(logConc[i,1], mu_species[SpeciesNum[i]], tau_obs)
#  }
#  lik.data <- prod(likc.data[])  # total contribuiton to the likelihood from data
  # priors and derived variables for the observation process
  tau_obs <- 1/(sigma_obs*sigma_obs)
  sigma_obs ~dunif(.01, 5)

  #--------------------------------------------------------------------
  # LOGNORMAL distribution for the "mean" of each species
  # fit a distribution to the mean of each observation
  for(k in 1:K){
     for(i in 1:NSpecies){
        mu_species[i,k] ~ dlnorm(mu, tau)
        log_mu_species[i,k] <- log(mu_species[i,k])
#        likc.latent[i] <- dlnorm(mu_species[i], mu, tau) # contribution from the likelihoo
     }
  }
#  lik.latent <- prod(likc.latent[])  # total contribution to the likelihood from latent species value
  tau <- 1/(sigma*sigma)
  sigma ~ dunif(.01,5)

  mu ~ dnorm(0, .001)

  # estimate the average ranking of the species for each clone
  for(k in 1:K){
     rank_mu_species[1:NSpecies,k] <- rank(mu_species[1:NSpecies,k])
  }

  # estimate the HC[5]
  hc     <- qlnorm(.05, mu, tau)  # the HC[5]
  hc.log <- log(hc)
  #------------------------------------------------------------------

  # total complete-data likelihood
#  lik <- lik.data * lik.latent
}  # end of model.jags


library("animation")
library("plyr")
library("MASS")
#
# ################################################################################
# #   0
# ################################################################################
#
# library("ElemStatLearn")
# require("class")
# mixture.example$xnew
# x <- mixture.example$x
# g <- mixture.example$y
# xnew <- mixture.example$xnew
# mod15 <- knn(x, xnew, g, k=15, prob=TRUE)
# prob <- attr(mod15, "prob")
# prob <- ifelse(mod15=="1", prob, 1-prob)
# px1 <- mixture.example$px1
# px2 <- mixture.example$px2
# prob15 <- matrix(prob, length(px1), length(px2))
# par(mar=rep(2,4))
# contour(px1, px2, prob15, levels=0.5, labels="", xlab="", ylab="", main=
#         "15-nearest neighbour", axes=FALSE)
# points(x, col=ifelse(g==1, "coral", "cornflowerblue"))
# gd <- expand.grid(x=px1, y=px2)
# points(gd, pch=".", cex=1.2, col=ifelse(prob15>0.5, "coral", "cornflowerblue"))
# box()

# spirals
spiral <- function (radius, theta, sequence, col) {
    r <- radius(sequence)
    t <- theta(sequence)
    x <- r * sin(t)
    y <- r * cos(t)
    return(data.frame(x=x, y=y))
    # points(x, y, col=col)
}
sigmoid <- function (n) 1/(1 + exp(-n))

computeLayer <- function (input, weights) {
    sums <- colSums(input * weights)
    return(sigmoid(sums))
}

computeAll <- function (input, weights) {
    numberOfLayers <- length(weights)
    output <- list()
    output[[1]] <- input
    for (i in 1:numberOfLayers) {
        output[[i + 1]] <- computeLayer(output[[i]], weights[[i]])
    }
    return(output)
}

classify <- function (input, weights) {
    numberOfLayers <- length(weights)
    output <- input
    for (i in 1:numberOfLayers) {
        output <- computeLayer(output, weights[[i]])
    }
    return(output)
}

mse <- function (target, output) {
    diff <- target - output
    return(sum(diff * diff)/2)
}

learn <- function (weights, input, target, learningRate = 0.5) {

    outputs <- computeAll(input, weights)
    numberOfLayers <- length(weights)

    # linear programming, tabulate deltas
    deltas <- list()

    # tabulate the output layer first
    output <- outputs[[numberOfLayers + 1]]
    deltas[[numberOfLayers]] <- (target - output) * output * (1 - output)
    # tabulate the rest
    if (numberOfLayers > 1) {
        for (layer in (numberOfLayers - 1):1) {
            output <- outputs[[layer + 1]]
            weight <- weights[[layer + 1]]

            sums <- rowSums(deltas[[layer + 1]] * weights[[layer + 1]])
            deltas[[layer]] <- sums * output * (1 - output)
        }
    }

    for (layer in 1:numberOfLayers) {
        weights[[layer]] <- weights[[layer]] + outputs[[layer]] %o% deltas[[layer]] * learningRate
    }

    return(list(
        weights = weights,
        error = mse(target, outputs[[numberOfLayers + 1]])
        ))
    # return(weights)
}

plotErrors <- function (errors) {
    if (length(errors) > 0) {
        plot(errors, xlab="iteration", ylab="error", type="h")
        title("error / iteration")
    }
}

reconstruct <- function (weights) {
    structure <- c()
    for (i in 1:length(weights)) {
        structure <- c(structure, nrow(weights[[i]]))
    }
    structure <- c(structure, ncol(weights[[i]]))
    return(structure)
}

identityWeights <- function (nodes) {
    weights <- list()
    for (i in 1:(length(nodes) - 1)) {
        rows <- nodes[i]
        cols <- nodes[i + 1]
        weights[[i]] <- matrix(0, rows, cols)
    }
    return(weights)
}

initializeWeights <- function (nodes) {
    weights <- list()
    for (i in 1:(length(nodes) - 1)) {
        rows <- nodes[i]
        cols <- nodes[i + 1]
        size <- rows * cols
        weights[[i]] <- matrix(sigmoid(rexp(size)), rows, cols)
    }
    return(weights)
}

accumulateWeights <- function (acc, x) {
    for (i in 1:length(acc)) {
        acc[[i]] <- acc[[i]] + x[[i]]
    }
    return(acc)
}

train <- function (weights, callback, iteration = 100000, until = 0.1, every = 1000) {

    errors <- c()
    learningRate <- 1

    for (i in 1:iteration) {
        accumulatedError <- 0

        # class 0
        size <- length(class0$x)
        for (j in 1:size) {
            data <- class0[j, ]
            result <- learn(weights, c(data$x, data$y, 1), c(1, 0), learningRate)
            weights <- result$weights
            accumulatedError <- accumulatedError + result$error
        }
        # class 1
        size <- length(class1$x)
        for (j in 1:size) {
            data <- class1[j, ]
            result <- learn(weights, c(data$x, data$y, 1), c(0, 1), learningRate)
            weights <- result$weights
            accumulatedError <- accumulatedError + result$error
        }
        errors <- c(errors, accumulatedError)

        if (accumulatedError < until) {
            print(i)
            break
        }

        if (i %% every == 0) {
            callback(i, weights, errors)
        }
    }
    return(list(
        weights = weights,
        errors = errors
        ))
}

drawGrid <- function (weights) {
    grid <- expand.grid(x=seq(-8, 8, by=0.2), y=seq(-8, 8, by=0.2))
    gridResult <- aaply(grid, 1, function (data) {
            result <- classify(c(data$x, data$y, 1), weights)
            return(ifelse(result[1] > result[2], "cornflowerblue", "coral"))
        })
    points(grid, pch=".", cex=3, col=gridResult)
}

################################################################################
#   1
################################################################################

plot(NA, NA, xlim=c(-8,8), ylim=c(-8,8),
    xlab="x", ylab="y",
    axes=FALSE, asp=1)
axis(side=1, at=seq(-8, 8, by=2), cex.axis=0.8)
axis(side=2, at=seq(-8, 8, by=2), cex.axis=0.8)
title("Two Spiral Problem")

# class0 <- spiral(function (i) (6.5 * (104 - i) / 104),
#     function (i) (pi * i / 8),
#     40:52)
#
# class1 <- spiral(function (i) (6.5 * (104 - i) / -104),
#     function (i) (pi * i / 8),
#     40:52)
# class0 <- spiral(function (i) (6.5 * (104 - i) / 104),
#     function (i) (pi * i / 8),
#     0:10)
#
# class1 <- spiral(function (i) (6.5 * (104 - i) / -104),
#     function (i) (pi * i / 8),
#     0:10)
class0 <- data.frame(x=c(-5), y=c(-2))
class1 <- data.frame(x=c(1), y=c(-1))

# class0 <- data.frame(x=c(-4, -4, 4, 0), y=c(-4, 4, 4, 0))
# class1 <- data.frame(x=c(4), y=c(-4))

# class0 <- data.frame(x=c(-4, -4, 4, 0), y=c(-4, 4, -4, 0))
# class1 <- data.frame(x=c(4, -2, 0, 2, 4), y=c(4, -2, -2, -2, -2))
# class0 <- data.frame(x=c(-4, 4), y=c(4, -4))
# class1 <- data.frame(x=c(4, -4), y=c(4, -4))

points(class0, col="cornflowerblue", cex=2)
points(class1, col="coral", cex=2)

layers <- c(3, 5, 2)
# weights <- initializeWeights(layers)

weights <- list()
weights[[1]] <- matrix(
    c(1.716595448658756, 1.1764761912424921, 1.557118196208473, 1.7041037817911824, 1.6406029506187856,
     0.6146408255673677, 1.2674559523877986, 0.8036832609525906, 0.4969173598004548, 0.7056984961660893,
     0.978526932134667, 0.3158700142016504, 0.7265454504592824, 0.6660428783020633, 0.6623111268153622),
     3, 5, byrow = TRUE)
weights[[2]] <- matrix(
    c(-1.3136394181316513, 1.0616230793282784,
     -0.1289445413211639, 1.0017360756800076,
     -0.9759845197492095, 1.0231283450037518,
     -1.276113700799778, 1.1112948075375635,
     -1.325443401614583, 1.1986825244676422), 5, 2, byrow = TRUE)

# print(computeLayer(c(1, -1, 1), weights[[1]]))

result <- train(weights, function (i, weights, errors) {
    print(errors[i])
    }, 10000)
print(result$weights)
drawGrid(result$weights)
plotErrors(result$errors)


covZ <- function(t_seq, Y, C, sigma2)
{
  #########################################################################
  #     covZ: calculate the covariance matrix of paired-y product
  #
  #     Input
  #     t_seq: defined grid point m-by-1
  #     Y: response vector m-by-1
  #     C: covariance matrix of X m-by-m
  #     sigma2: variance of random error
  #
  #     Output
  #     CovZZ: covariance matrix of paired-y product m^2-by-m^2
  #     Z.info: vectorized Z.tri and  the corresponding grid points
  #     Z.tri: upper triangle matrix of paired-y product m-by-m
  #
  #########################################################################
  temp <- expand.grid(Y,Y)
  t.pair <- expand.grid(t_seq,t_seq)
  d <- length(Y)
  id <- expand.grid(1:d,1:d)
  m <- d

  Z <- apply(temp, 1, function(z) prod(z))
  Z.info <- as.matrix(cbind(Z,t.pair,id))
  Z.info <- Z.info[Z.info[,5] <= Z.info[,4],]

#   Z.mat <- matrix(Z,nrow=length(Y),ncol=length(Y),byrow=T)
#   Z.tri <- Z.mat
#   Z.tri[lower.tri(Z.tri)] <- NA

  Z.tri <- matrix(NA,nrow=length(Y),ncol=length(Y))
  Z.tri[lower.tri(Z.tri, diag=T)] <- Z.info[,1]
  Z.tri <- t(Z.tri)

  # Quick-n-dirty implementation (for testing only)
#   CovZZ <- matrix(NA,nrow=length(Z),ncol=length(Z))
#   time.start <- proc.time()
#   for (i in 1:m)
#   {
#     for (j in 1:m)
#     {
#       row.id <- d * (i - 1) + j
#       for (k in 1:m)
#       {
#         for (l in 1:m)
#         {
#           col.id <- d * (k - 1) + l
#           if (row.id <= col.id)
#           {
#             CovZZ[row.id,col.id] = C[i,k] * C[j,l] + C[i,l] * C[j,k] +
#               (i==k) * (j==l) *sigma2^2 + (i==l) * (j==k) *sigma2^2 +
#               (C[i,k] * (j==l) + C[i,l] * (j==k) + C[j,k] * (i==l)
#                + C[j,l] * (i==k)) * sigma2
#           }
#
#         }
#       }
#     }
#   }
#   print((proc.time()-time.start)[3])
#
#   # Avoid loops (even slower, for testing only)
#   time.start <- proc.time()
#   id1 <- as.matrix(expand.grid(1:d,1:d,1:d,1:d))
#   id2 <- as.matrix(expand.grid(1:d^2,1:d^2))
#   id.tab <- as.matrix(cbind(id1,id2))
#   id.tab <- id.tab[id.tab[,5] <= id.tab[,6],]
#   CovZZ2.vec = apply(id.tab,1,function(x)
#     C[x[2],x[4]] * C[x[1],x[3]] + C[x[2],x[3]] * C[x[1],x[4]] +
#     (x[2]==x[4]) * (x[1]==x[3]) *sigma2^2 +
#     (x[2]==x[3]) * (x[1]==x[4]) *sigma2^2 +
#     (C[x[2],x[4]] * (x[1]==x[3]) + C[x[2],x[3]] * (x[1]==x[4]) +
#        C[x[1],x[4]] * (x[2]==x[3]) + C[x[1],x[3]] * (x[2]==x[4])) * sigma2)
#
#   CovZZ2 <- matrix(NA,nrow=length(Z),ncol=length(Z))
#   CovZZ2[upper.tri(CovZZ2, diag=T)] <- CovZZ2.vec
#   print((proc.time()-time.start)[3])

  # Alternative vectorizing
  #time.start <- proc.time()
  id1 <- as.matrix(expand.grid(1:d,1:d,1:d,1:d))
  id2 <- as.matrix(expand.grid(1:d^2,1:d^2))
  id.tab <- as.matrix(cbind(id1,id2))
  id.tab <- id.tab[id.tab[,5] <= id.tab[,6],] # symmetric
  # kronecker delta terms
  # \delta_{jk},\delta_{j'k'},\delta_{jk'},\delta_{j'k}
  k.del <- cbind(id.tab[,1]==id.tab[,3],id.tab[,2]==id.tab[,4],
                 id.tab[,1]==id.tab[,4],id.tab[,2]==id.tab[,3])
  # Cov operator terms
  # C_{jk},C_{j'k'},C_{jk'},C_{j'k}
  c.term <- cbind(C[cbind(id.tab[,1],id.tab[,3])],
                  C[cbind(id.tab[,2],id.tab[,4])],
                  C[cbind(id.tab[,1],id.tab[,4])],
                  C[cbind(id.tab[,2],id.tab[,3])])
  # Form a matrix with pre-calculated terms
  id.tab <- cbind(id.tab,k.del,c.term)
  # CovZZ = C_{jk}C_{j'k'} + C_{jk'}C_{j'k}
  # + (\delta_{jk}\delta_{j'k'} + \delta_{jk'}\delta_{j'k})\sigma_2^2 +
  # (C_{jk}\delta_{j'k'} + C_{jk'}\delta_{j'k} + C_{j'k}\delta_{jk'} +
  # C_{j'k'}\delta_{jk})\sigma_2
  CovZZ3.vec = id.tab[,12] * id.tab[,11] + id.tab[,14] * id.tab[,13] +
      (id.tab[,8] * id.tab[,7] + id.tab[,10] * id.tab[,9]) *sigma2^2 +
      (id.tab[,12] * id.tab[,7] + id.tab[,14] * id.tab[,9] +
         id.tab[,13] * id.tab[,10] + id.tab[,11] * id.tab[,8]) * sigma2
  # CovZZ.vec = vech(CovZZ)
  CovZZ3 <- matrix(NA,nrow=length(Z),ncol=length(Z))
  CovZZ3[upper.tri(CovZZ3, diag=T)] <- CovZZ3.vec
  #print((proc.time()-time.start)[3])

  return (list(CovZZ = CovZZ3,CovZZ.vech = CovZZ3.vec,
               Z.info = Z.info,Z.tri = Z.tri))

}


"
This document provide functions for spatial heterogenetiy analysis
@author: Haoyang Mi
"

library(spatstat)
library(dplyr)
library(flexclust)
library(plyr)
library(rjson)
library(spatstat)
library(pracma)

fac2num <- function(x){

  x <- as.numeric(as.character(x))
  return(x)
}

ShannonE <- function(types, coreData){

    #types <- ctype_tensor
    type.count <- length(types)

    Total <- nrow(coreDat) # total number of cells

    # all int/ext data
    ctype_stat_all <- data.frame(matrix(nrow =  0, ncol = 0))

    for (cseq in seq_len(type.count)) {   # outer loop, calcualte interior stats
        #cseq <- 1
        ctype_int <- 0
        ctype_ext <- 0
        p <- 0 # ratio

        # current cell type
        ctype <- types[cseq]

        # coordinates data for the current core, current cell type

        ctype.Dat <- coreDat[coreDat$ctype_no == ctype, c('Xcoord', 'Ycoord')]

        p <- nrow(ctype.Dat)/Total

        # interior score
        ctype_int <- mean(as.matrix(dist(ctype.Dat[c('Xcoord', 'Ycoord')])))

        # other cell types
        ctype_other <- types[-cseq]

        ctype_stat <- cbind(p, ctype_int)

        for (cseq_other in ctype_other) {

            ctype_other.Dat <- coreDat[coreDat$ctype_no == cseq_other, c('Xcoord', 'Ycoord')]

            # exterior score

            ctype_ext <- ctype_ext +  mean(dist2(ctype.Dat, ctype_other.Dat))

        }
        # number of computations = No. cell types - 1
        ctype_stat <- cbind(ctype_stat, ctype_ext / (type.count - 1))

        colnames(ctype_stat) <- c('p', 'int', 'ext')

        ctype_stat_all <- rbind(ctype_stat_all ,cbind(ctype_stat, ctype))

    }

    ShannonH <- 0
    # combine row data

    for (dat in seq_len(type.count)) {
      p <- as.numeric(as.character(ctype_stat_all[dat, 1]))
      d_int <- as.numeric(as.character(ctype_stat_all[dat, 2]))

      d_ext <- as.numeric(as.character(ctype_stat_all[dat, 3]))
      d_final <- d_int / d_ext

      if(isTRUE(d_int*d_ext == 0)){
        d_final <- 0
      }
      if(isTRUE(p != 0)){
        ShannonH <- -d_final*p*log2(p) + ShannonH
      }
    }

    return(ShannonH)
}

# convet graph to covariance matrix
#@ input: g -> graph
#         null_matrix -> an empty matrix

graph2covMatrix <- function(Community_edges, node_type){

  from_types <- node_type[match(Community_edges$from, node_type$X1),]
  to_types <- node_type[match(Community_edges$to, node_type$X1),]

  nt_types <- data.frame(cbind(as.character(from_types$X2), as.character(to_types$X2)))

  # create covariance matrix
  covar_Matrix <- matrix(nrow = 17, ncol = 17)

  colnames(covar_Matrix) <- ctype_names
  rownames(covar_Matrix) <- ctype_names

  for(row in seq_len(17)){

    # from
    row_name <- ctype_names[row]
    for (col in seq_len(17)) {

      col_name <- ctype_names[col]
      covar_Matrix[row, col] <- nrow(nt_types[nt_types$X1 == row_name & nt_types$X2 == col_name,])+
        nrow(nt_types[nt_types$X1 == col_name & nt_types$X2 == row_name,])

    }
  }
  return(covar_Matrix)
}

GNN <- function(Community_edges, NodeFeature){

  # re-index
  NodeFeature$reindex <- seq_len(nrow(NodeFeature)) - 1
  edges <- list()
  features <- list()

  ## merge
  from_oldNode <- data.frame(Community_edges$from)
  colnames(from_oldNode) <- 'id'
  to_oldNode <- data.frame(Community_edges$to)
  colnames(to_oldNode) <- 'id'

  newNode <- data.frame(cbind(NodeFeature$members, NodeFeature$reindex))
  colnames(newNode) <- c('id', 'new_id')

  from_new <- vector()
  for(row in seq_len(nrow(from_oldNode))){

    old <- from_oldNode$id[row]
    new <- newNode[newNode$id == old, 2]

    from_new <- c(from_new, new)
  }

  to_new <- vector()
  for(row in seq_len(nrow(to_oldNode))){

    old <- to_oldNode$id[row]
    new <- newNode[newNode$id == old, 2]

    to_new <- c(to_new, new)
  }

  newEdge <- data.frame(cbind(from_new, to_new))
  # edges to list

  for(lid in seq_len(nrow(newEdge))) {
    edges[[lid]] <- as.numeric(newEdge[lid,])
  }

  F <- NodeFeature[,c(1,68, 69)]
  F$ctype_int <- as.character(F$ctype_int)

  # features to list

  for(fid in seq_len(nrow(NodeFeature))) {
    features[[fid]] <- F[fid,]$ctype_int
    names(features)[fid] <- F[fid, 3]
  }

  # combine features and edges to one list
  list_final <- list(edges = edges, features = features)
  return(list_final)
}

cor.network <- function(gct_file, allCore){

  #allCore <- NR_core
  R_intercor <- data.frame(matrix(nrow = 0, ncol = 0))

  for (core in allCore) {

    #core <- 2
    # core - dendrogram
    Core_dendro <- gct_file[gct_file$id == core,]
    Core_dendro <- Core_dendro[order(Core_dendro$Community_id, decreasing = FALSE),]

    GNN_vec <- read.csv(paste('./Data/Features/', core, '/nci.csv', sep = ''), row.names = 1)
    intercor <- outer(1:nrow(GNN_vec),1:nrow(GNN_vec), FUN = Vectorize( function(i,j) cor.test(t(GNN_vec[i,]), t(GNN_vec[j,]), method = 'spearman')$p.value) )

    colnames(intercor) <- Core_dendro$dendrogram_cut
    rownames(intercor) <- Core_dendro$dendrogram_cut
    diag(intercor) <- -10

    # melt matrix
    melt_intercor <- melt(intercor)
    melt_intercor <- melt_intercor[!(melt_intercor$value == -10),]
    R_intercor <- rbind(R_intercor, melt_intercor)

  }

  Cor_network <- data.frame(matrix(nrow = 0, ncol = 0))
  for(row in seq_len(8)){
    #row <- 1
    #col <- 1
    for(col in row:8){

      dat <- R_intercor[R_intercor$Var1 == row & R_intercor$Var2 == col,]

      if(nrow(dat) >= 5){
        strength <- nrow(dat[dat$value < 0.05,])/nrow(dat)

      } else {
        strength <- 0
      }
      #hist(dat$value)

      #value <- p.adjust(dat$value, method = 'fdr')

      # normalized communication strength
      #strength <- length(value[value < 0.05])/length(value)
      Cor_network <- rbind(Cor_network, cbind(row, col, strength))

    }
  }
  Cor_network <- Cor_network[complete.cases(Cor_network$strength),]

  Cor_network <- Cor_network[Cor_network$strength > 0,]

  #test <- graph_from_data_frame(Cor_network[,1:2])
  #plot(test)

  return(Cor_network)
}

#######################
# Kcross function #####
#######################

bivarAnalysis.Kcross <- function(type1, type2){

  #type1 <- typeA
  #type2 <- typeB

  colnames(type1) <- c('x', 'y')

  colnames(type2) <- c('x', 'y')

  if(nrow(type1)*nrow(type2) != 0){

    # read pts dat

    type1$attr <- 'ctypeA'

    type2$attr <- 'ctypeB'

    # create multitype df
    pts_OI <- rbind(type1, type2)

    # define the type
    species <- factor(pts_OI$attr)

    # create multitype ppp

    # check if empty
    ppp1 <- ppp(type1$x, type1$y, owin(c(0,800), c(0, 800)))
    ppp2 <- ppp(type2$x, type2$y, owin(c(0,800), c(0, 800)))

    # prevent NA

    if(is.empty(ppp1) == 'FALSE' & is.empty(ppp2) == 'FALSE'){

      multitype_ppp <- ppp(pts_OI$x, pts_OI$y, marks = species, owin(c(0, 800), c(0, 800)))
      K.cross <- data.frame(Kcross(multitype_ppp, i = 'ctypeA', j = 'ctypeB', r = seq(0,20,0.1), correction = 'Ripley'))

      #plot(Gihc)
      # relocat DF

      K.cross <- K.cross[complete.cases(K.cross),]

      # calculate the area (positive - negative )
      K.cross$rs <- K.cross$iso - K.cross$theo

      A.to.B.diff.area <- trapz(K.cross$r, K.cross$iso)

      # j to i

      K.cross <- data.frame(Kcross(multitype_ppp, i = 'ctypeB', j = 'ctypeA', r = seq(0,20,0.1), correction = 'Ripley'))

      K.cross <- K.cross[complete.cases(K.cross),]

      K.cross$iso <- K.cross$iso - K.cross$theo
      K.cross <- K.cross[complete.cases(K.cross),]
      B.to.A.diff.area <- trapz(K.cross$r, K.cross$iso)

    } else {

      A.to.B.diff.area <- NA
      B.to.A.diff.area <- NA

    }
  } else {
    A.to.B.diff.area <- NA
    B.to.A.diff.area <- NA
  }
  return(list(A.to.B.diff.area, B.to.A.diff.area))
}

#----------------------------------------------------#
# generate poisson distribution ppp from a given ppp #
#----------------------------------------------------#

poisp <- function(pos_Target, nsim){

  #pos_Target <- tPos

  n <- nrow(pos_Target)

  simpp <- runifpoint(n = n, win = owin(c(0, 800), c(0, 800)), nsim = nsim)

  # return the result
  return(simpp)
}

#-----------------------------#
# Find number of interactions #
#-----------------------------#

nnIntrxn <- function(sDF, simDF){ # sDF: the coordiantes for the source point pattern

  #sDF <- sPos
  if(nrow(sDF) == 0 | nrow(simDF) == 0){
    simInt <- 0
  } else{
    dist <- nn2(simDF, query = sDF, k = nrow(simDF), treetype = 'kd', searchtype = 'radius', radius = 20)

    nn.idx <- data.frame(dist$nn.idx)

    nn.idx$source <- seq_len(nrow(sDF))

    nn.merge <- melt(nn.idx, id.vars = 'source')

    # clear non-valid rows
    nn.merge <- nn.merge[nn.merge$value != 0, -2]

    # remove itself

    nn.merge$diff <- nn.merge$source - nn.merge$value
    nn.merge <- nn.merge[nn.merge$diff != 0, -3]

    simInt <- nrow(nn.merge)
  }

  # replace by real cell type
  return(simInt)
}

#-----------------------------#
#           cor.mtest         #
#-----------------------------#

cor.mtest <- function(mat, ...) {
  mat <- as.matrix(mat)
  n <- ncol(mat)
  p.mat<- matrix(NA, n, n)
  diag(p.mat) <- 0
  for (i in 1:(n - 1)) {
    for (j in (i + 1):n) {
      tmp <- cor.test(mat[, i], mat[, j], ...)
      p.mat[i, j] <- p.mat[j, i] <- tmp$p.value
    }
  }
  colnames(p.mat) <- rownames(p.mat) <- colnames(mat)
}


# fit_robust_linear_model.r
#
# Copyright (c) 2020 VIB (Belgium) & Babraham Institute (United Kingdom)
#
# Software written by Carlos P. Roca, as research funded by the European Union.
#
# This software may be modified and distributed under the terms of the MIT
# license. See the LICENSE file for details.

# Returns a matrix by rows, with the intercept and p-value, and coefficient and
# p-value, of a robust linear model fitted to the input data.
#
# Reverts to a standard linear model in case of no convergence.

fit.robust.linear.model <- function( x.data, y.data, x.name, y.name, asp )
{
    xy.data <- data.frame( x = x.data, y = y.data )

    xy.model <- rlm( y ~ x, xy.data, maxit = asp$rlm.iter.max )

    if ( xy.model$converged )
    {
        xy.coef <- xy.model$coefficients
        xy.t <- summary( xy.model )$coefficients[ , 3 ]
        xy.df <- summary( xy.model )$df[ 2 ]
        xy.pval <- 2*( pt( abs( xy.t ), xy.df, lower.tail = FALSE ) )
    }
    else
    {
        cat( sprintf( "WARNING: rlm of %s ~ %s did not converge - then using ols\n",
            y.name, x.name ), file = stderr() )

        xy.model <- lm( y ~ x, xy.data )

        xy.coef <- xy.model$coefficients
        xy.pval <- summary( xy.model )$coefficients[ , 4 ]
    }

    res <- cbind( xy.coef, xy.pval )
    dimnames( res ) <- NULL
    res
}


# ST3068/ST2054 -- tutorial -- 21 October 2016
# Summer Exam 2009 in the course ST2054
# Question 2

sample_dist_1 = function() {
  n = sample(x = c(0,1), 1, replace = FALSE, prob = c(0.2, 0.8));
  return(n)
}

sample_dist_2 = function() {
  n = sample(x = c(0,1), 1, replace = FALSE, prob = c(0.3, 0.7));
  return(n)
}

sample_dist_3 = function() {
  n = sample(x = c(0,1), 1, replace = FALSE, prob = c(0.4, 0.6));
  return(n)
}

x_count = 0;
run_count = 10000;

for (i in 1:run_count) {

  player_1 = sample_dist_1();
  player_2 = sample_dist_2();
  player_3 = sample_dist_3();

  if ((player_1 == 1) || (player_2 == 1) || (player_3 == 1)) {
    if (player_3 == 1){x_count = x_count + 1}
  }
}
print (x_count/run_count)


nextState <- function(x, y, wx, wy, inp) {
    cmd <- substring(inp, 1, 1)
    val <- strtoi(substring(inp, 2, nchar(inp)))

    result <- switch(cmd,
        "N" = move_w(x, y, wx, wy, "N", val),
        "S" = move_w(x, y, wx, wy, "S", val),
        "E" = move_w(x, y, wx, wy, "E", val),
        "W" = move_w(x, y, wx, wy, "W", val),
        "F" = move_f(x, y, wx, wy, val),
        "R" = rotate_v(x, y, wx, wy, -val),
        "L" = rotate_v(x, y, wx, wy, val))

    result
}

move_w <- function(x, y, wx, wy, moveDir, val) {
    switch(moveDir,
        "N" = c(x, y, wx, wy + val),
        "S" = c(x, y, wx, wy - val),
        "E" = c(x, y, wx + val, wy),
        "W" = c(x, y, wx - val, wy))
}

move_f <- function(x, y, wx, wy, count) {
    c(x + wx * count, y + wy * count, wx, wy)
}

rotate_v <- function(x, y, wx, wy, d) {
    r <- d * (pi / 180)

    c(x, y, wx * cos(r) - wy * sin(r), wx * sin(r) + wy * cos(r))
}

fileName <- "input.txt"

x <- 0
y <- 0

wx <- 10
wy <- 1

inp <- file(fileName, "r")

for (line in readLines(inp)) {
    s <- nextState(x, y, wx, wy, line)

    x <- round(as.double(s[1]))
    y <- round(as.double(s[2]))
    wx <- round(as.double(s[3]))
    wy <- round(as.double(s[4]))
}

close(inp)

print(abs(x) + abs(y))


# Simulate VB tag-recapture, otolith and length-frequency growth data
# =====================================================================

# Specify VB parameters common to all datasets(noting that Linf ~ Norm(mu.Linf, sigma.Linf) )
k <- 0.2
a0 <- 0
mu.Linf <- 100
sigma.Linf <- 5

# a)tag-recapture data:
# ----------------------
set.seed(1)
n <- 500

# generate log-normal release ages (relative to a0)
par1.A <- 0.5
par2.A <- 0.3
A <- rlnorm(n,par1.A,par2.A)

# generate times at liberty assuming gamma distribution
dt <- rgamma(n,3,.5)

# generate release lengths and recapture lengths assuming random Linf and measurement error
Linf <- rnorm(n,mu.Linf,sigma.Linf)
sig.tag <- 5
L1 <- Linf*(1-exp(-k*A)) + rnorm(n,0,sig.tag)
L2 <- Linf*(1-exp(-k*(A+dt))) + rnorm(n,0,sig.tag)

# Note that the code allows for a different measurement error for scientist-measured recapture lengths
# versus fisherman-measured recapture lengths, so need to specify whether L2 was measured by
# a scientist (=0) or a fisherman (=1).  Here I'll specify all as scientist (0) since I generated L2
# assuming the same measurement error for all observations.
L2measurer <- rep(0,n)

tagdat <- cbind(L1,L2,rep(0,n),dt,L2measurer)
plot(c(A,A+dt),c(L1,L2),xlab="age",ylab="length")
points(A,L1,col=2)

# b) otolith data:
# ----------------------
set.seed(1)
n.oto <- 200

# generate random uniform ages
age <- runif(n.oto,.5,20)
# generate corresponding lengths with measurement error
Linf <- rnorm(n.oto,mu.Linf,sigma.Linf)
sig.oto <- 5
len <- Linf*(1-exp(-k*(age-a0))) + rnorm(n.oto,0,sig.oto)

otodat <- cbind(age,len)
points(age,len,pch=2,col=3)

# c) length-frequency data:
# -------------------------
set.seed(1)

# Note: the LF component assumes that a model decomposition has already been applied to the
# raw data, such that the dataset input to the growth analysis is the ages and lengths corresponding to
# the modes in the LF data, along with the standard error estimates for each modal length estimate

# generate ages and lengths corresponding to modes in the LF data, assuming we have monthly LF data for
# fish of ages 1-5, and we have this data for 5 years
mode.age <- rep(seq(1,5,1/12),times=5)
n.lf <- length(mode.age)
# recall we are not including a random Linf parameter for the LF data
sig.lf <- 5
mode.len <- mu.Linf*(1-exp(-k*(mode.age-a0))) + rnorm(n.lf,0,sig.lf)

# Specify standard error estimates corresponding to each of the modal length estimates
se.mode <- rlnorm(n.lf,.01,.5)

lfdat <- cbind(mode.age,mode.len,se.mode)
points(mode.age,mode.len,pch=3,col=4)

# Source the R code with the likelihood and a range of growth functions:
# -----------------------------------------------------------------------
source("/Users/stephenscherrer/Google Drive/Weng Lab/Data/Bottomfish/Okamoto's 1990s Mark Recapture Data/src/Laslett Functions/joint_lkhd.r")
source("/Users/stephenscherrer/Google Drive/Weng Lab/Data/Bottomfish/Okamoto's 1990s Mark Recapture Data/src/Laslett Functions/growth_functions.r")

# Fit a VB model WITHOUT seasonal growth:
# -----------------------------------------
growth.ssnl.f<- growthvb.f
npf <- 1  #number of parameters passed to growth.ssnl.f (in this case k)
npA <- 2  #number of parameters in distribution of release ages for tag model

# specify starting parameters, as well as upper and lower bounds
#        mu.L, sig.L,   k,  mu.A, sig.A, sig.sci, sig.f, a0, sig.oto, sig.lf
p0 <- c(  70,   5.0, .10,   1.0,   .10,    5.0,      0,  0,   10.0,   10.0)
lb <- c(   50,   1.0, .05,    .1,   .05,    1.0,      0, -2,    0.0,    0.0)
ub <- c(  100,  15.0, .40,   1.5,   .50,   10.0,      0,  1,   15.0,   15.0)
fit.vb <- nlminb(p0,joint.logl.f,lower=lb,upper=ub,npf=npf,npA=npA,tagdat=tagdat,otodat=otodat,lfdat=lfdatz)
fit.vb

# Fit a VB model *WITH* seasonal growth:
# -----------------------------------------
growth.ssnl.f<- growthvb.ssnl.f
npf <- 3  #number of parameters passed to growth.ssnl.f (in this case k, u, w)
npA <- 2  #number of parameters in distribution of release ages for tag model

# specify starting parameters, as well as upper and lower bounds
#        mu.L, sig.L,   k,  u,   w, mu.A, sig.A, sig.sci, sig.f, a0, sig.oto, sig.lf
p0 <- c(  110,   5.0, .10, .1,   0,  1.0,   .10,    5.0,      0,  0,   10.0,   10.0)
lb <- c(   70,   1.0, .05,  0, -.5,   .1,   .05,    1.0,      0, -2,    0.0,    0.0)
ub <- c(  130,  15.0, .40,  1,  .5,  1.5,   .50,   10.0,      0,  1,   15.0,   15.0)
fit.ssnl.vb <- nlminb(p0,joint.logl.f,lower=lb,upper=ub,npf=npf,npA=npA,tagdat=tagdat,otodat=otodat,lfdat=lfdat)
fit.ssnl.vb


#' @title calcHMPwr
#'
#' @description Calculate instantaneous main engine power (kW) using the Holtrop & Mennen method.
#'
#' @param totalInstalledPwr Total installed main engine power (vector of numericals, kW) (maximum
#' continuous rated power)
#' @param shipSpeed Ship actual speed (vector of numericals, m/s) (see
#'  \code{\link{calcSpeedUnitConversion}})
#' @param actualDraft Actual draft (vector of numericals, m)
#' @param maxDraft Maximum summer load line draft (vector of numericals, m)
#' @param shipType Ship type (vector of strings, see \code{\link{calcShipType}}).
#' Must align with \code{tankerBulkCarrierShipTypes}, \code{tugShipTypes},
#' \code{roroPaxShipTypes}, \code{gCargoShipTypes},
#' \code{containerShipTypes} groupings
#' @param lwl Waterline length (vector of numericals, m) (see \code{\link{calclwl}})
#' @param breadth Moulded breadth (vector of numericals, m)
#' @param maxDisplacement Maximum ship displacement (vector of numericals, m^3)
#' @param Cb Maximum block coefficient (vector of numericals, dimensionless) (see
#' \code{\link{calcCb}})
#' @param nProp Number of propellers (vector of numericals, see \code{\link{calcPropNum}})
#' @param serviceMargin A service margin to account for weather and sea effects:
#' \itemize{\item At-sea operations = 15 (Default) \item Coastal operations = 10} Can
#' supply either a vector of numericals, a single number, or rely on the default
#' @param shaftEff Shaft efficiency (dimensionless). Default = 0.98.
#'  Ratio of power delivered to the propeller and the brake power delivered by
#'  the engine. Can supply either a vector of numericals, a single number, or rely on the default.
#' @param relRotationEff Relative rotational efficiency (dimensionless).
#'  Default = 1. Accounts for effect of rotational flow of water around propeller.
#' Can supply either a vector of numericals, a single number, or rely on the default
#' @param seawaterTemp Sea water temperature. Default = 15 (degrees Celsius). Can
#' supply either a vector of numericals, a single number, or rely on the default
#' @param seawaterDensity Sea water density. Default = 1.025 (g/cm^3). Can
#' supply either a vector of numericals, a single number, or rely on the default
#' @param pwrUpperBoundPercent Percent of total installed power at which
#' required power is capped. Default = 1, which indicates required power cannot
#' exceed \code{totalInstalledPwr}. Can supply either a vector of numericals, a
#' single number, or rely on the default
#' @param pwrLowerBoundPercent Percent of total installed power to act as lower
#' bound for required power. Default = 0.02, which indicates required power
#' cannot go below 2\% of \code{totalInstalledPwr}. Can supply either a vector
#' of numericals, a single number, or rely on the default
#' @param CmEquationType Type of equation to estimate the midship section
#' coefficient (see \code{\link{calcCm}}): \itemize{
#' \item"kristensen (Default)"
#' \item"benford"
#' \item"schneekluth"}
#' This argument is not vectorized, as it takes only a single string
#' @param tankerBulkCarrierShipTypes Ship types specified in input
#' \code{shipTypes} to be modeled as tankers and bulk carriers
#' @param tugShipTypes Ship types specified in input \code{shipTypes} to be
#' modeled as tugs (vector of strings)
#' @param roroPaxShipTypes Ship types specified in input \code{shipTypes} to be
#' modeled as RORO and passenger ships (vector of strings)
#' @param gCargoShipTypes Ship types specified in input \code{shipTypes} to be
#' modeled as general cargo (vector of strings)
#' @param containerShipTypes Ship types specified in input \code{shipTypes} to
#' be modeled as container ships (vector of strings)
#' @param Cstern Afterbody form coefficient: \itemize{\item V-shaped Hull = -10
#'         \item U-Shaped Hull =  10
#'         \item Normal Hull = 0 (default)}
#' Can supply either a vector of numericals, a single number, or rely on the default
#' @param forwardDraft Forward draft (deviation from actual draft indicates trim)
#' (vector of numericals, m)
#' @param aftDraft Aft draft (deviation from actual draft indicates trim)
#' (vector of numericals, m)
#' @param appendagesList List of appendages on ship (vector of strings) \itemize{
#'  \item"rudder behind skeg"
#'  \item"rudder behind stern"
#'  \item"twin-screw balance rudders"
#'  \item"shaft brackets"
#'  \item"skeg"
#'  \item"strut bossings"
#'  \item"hull bossings"
#'  \item"shafts"
#'  \item"stabilizer fins"
#'  \item"dome"
#'  \item"bilge keels"}
#' @param wettedAppSAList List of wetted surface areas corresponding to list of
#' appendages (vector of numericals, m^2)
#'
#' @details
#' Primary method from Holtrop & Mennen (1982). Updated equations for high speed
#' operations (Froude number > 0.55) from Holtrop & Mennen (1984). Estimation of
#' some inputs use methodology from Rakke (2016).
#'
#' This method this requires ship types to be grouped. Use the
#' \code{tankerBulkCarrierShipTypes}, \code{tugShipTypes}, \code{roroPaxShipTypes},
#' \code{gCargoShipTypes}, \code{containerShipTypes} grouping parameters to
#' provide these ship type groupings. Any ship types not included in these groupings
#' will be considered as miscellaneous vessels.
#'
#' Ship speed and actual draft are typically obtained from sources such as AIS
#' messages or ship records.
#'
#' @return power (vector of numericals, kW)
#'
#' @references
#'Holtrop, J. and Mennen, G. G. J. 1982. "An approximate power prediction
#'method." International Shipbuilding Progress 29.
#'
#'Holtrop, J. and Mennen, G. G. J. 1984. "A Statistical Re-Analysis of Resistance
#'and Propulsion Data'.
#'
#'\href{http://hdl.handle.net/11250/2410741}{Rakke, S. G. 2016. "Ship Emissions
#'Calculation from AIS." NTNU.}
#'
#'@seealso \itemize{
#'\item \code{\link{calcSpeedUnitConversion}}
#'\item \code{\link{calclwl}}
#'\item \code{\link{calcCb}}
#'\item \code{\link{calcPropNum}}
#'\item \code{\link{calcCm}}
#'\item \code{vignette("OverviewOfPowerModels", package="ShipPowerModel")}
#'\item \code{vignette("HoltropMennen.Example", package="ShipPowerModel")}
#'}
#'
#' @family Holtrop-Mennen Calculations
#'
#' @examples
#' calcHMPwr(
#' totalInstalledPwr=rep(9363,2),,
#' shipSpeed=seq(0,1,1),
#' actualDraft=rep(12.48,2),
#' maxDraft=rep(13.57,2),
#' shipType=rep("bulk.carrier",2),
#' lwl=rep(218.75,2),
#' breadth=rep(32,2),
#' maxDisplacement=rep(80097,2),
#' Cb=rep(0.8099003,2),
#' nProp=rep(1,2),
#' serviceMargin=15,
#' shaftEff=0.98,
#' relRotationEff=1,
#' seawaterTemp=15,
#' seawaterDensity=1.025,
#' Cstern=0,
#' CmEquationType="kristensen",
#' forwardDraft=rep(13.57,2),
#' aftDraft=rep(13.57,2),
#' appendagesList=c(""),
#' wettedAppSAList=NA
#' )
#'
#' @export

  calcHMPwr<- function(
  totalInstalledPwr,
  shipSpeed,
  actualDraft,
  maxDraft,
  shipType,
  lwl,
  breadth,
  maxDisplacement,
  Cb,
  nProp,
  serviceMargin=15,
  shaftEff=0.98,
  relRotationEff=1,
  seawaterTemp=15,
  seawaterDensity=1.025,
  pwrUpperBoundPercent=1,
  pwrLowerBoundPercent=0.02,
  CmEquationType="kristensen",
  tankerBulkCarrierShipTypes=c("tanker","chemical.tanker","liquified.gas.tanker","oil.tanker","other.tanker","bulk.carrier"),
  tugShipTypes=c("service.tug","tug"),
  roroPaxShipTypes=c("passenger","ferry.pax","ferry.ro.pax","cruise","cruise.ed","yacht","ro.ro"),
  gCargoShipTypes=c("general.cargo"),
  containerShipTypes=c("container.ship"),
  Cstern=0,
  forwardDraft=NULL,
  aftDraft=NULL,
  appendagesList=c(""),
  wettedAppSAList=NA
 ){
#===========================================
if(is.null(forwardDraft)){forwardDraft<-maxDraft}
if(is.null(aftDraft)){aftDraft<-maxDraft}

#Inputs
    Cbw<-calcCbw(Cb, actualDraft, maxDraft)
    Cm<-calcCm(shipType,Cbw,maxDraft,actualDraft,CmEquationType,tankerBulkCarrierShipTypes,tugShipTypes,roroPaxShipTypes)
    Cp<-calcCp(Cm, Cbw,shipType, bounds="holtrop mennen", roroPaxContainerShipTypes=union(roroPaxShipTypes,containerShipTypes),gCargoShipTypes,tankerBulkCarrierShipTypes)
    Cwp<-calcCwp(Cbw, CwpEquationType="kristensen")
    froudeNum<-calcFroudeNum(shipSpeed, lwl)
    At<-calcAt(Cm, breadth, maxDraft)
    hb<-calchb(maxDraft)
    Abt<-calcAbt(Cm, breadth, maxDraft)
    propDiam<-calcPropDia(shipType, maxDraft,tankerBulkCarrierGCargoShipTypes=union(tankerBulkCarrierShipTypes,gCargoShipTypes),containerShipTypes)
    lcb<-calclcb(lwl)
#===========================================
Cf<-calcCf(shipSpeed,
           lwl,
           seawaterTemp,
           seawaterDensity)
#=============================================
Rapp<-calcHMAppendageRes(shipSpeed,
                          Cf,
                          appendagesList,
                          wettedAppSAList,
                          seawaterDensity)
#=============================================
Rw<-calcHMWaveMakingRes(lwl,
                         breadth,
                        Cp,
                        Cwp,
                        Cm,
                         maxDisplacement,
                         maxDraft,
                         froudeNum,
                        At,
                        hb,
                        Abt,
                         seawaterDensity,
                         forwardDraft,
                        lcb)
#========================================

FormFactor<-calcHMFormFactor(maxDraft,
                              lwl,
                              breadth,
                              maxDisplacement,
                             Cp,
                              Cstern,
                             lcb)
#==========================================

wettedSA<-calcHMWettedSA(lwl,
                          actualDraft,
                          breadth,
                          Cm,
                          Cbw,
                          Cwp,
                          Abt)
#==============================================
Rtr<-calcHMImmersedTransomRes(shipSpeed,
                               breadth,
                               Cwp,
                               maxDraft,
                             At,
                             seawaterDensity)
#==============================================
Rb<-calcHMBulbousBowRes(shipSpeed,
                         maxDraft,
                         forwardDraft,
                         Abt,
                         hb,
                         seawaterDensity)
#=============================================================
Ca<-calcHMCa(maxDraft,
                         lwl,
                         Cbw,
                         breadth,
                         forwardDraft,
                        Abt,
                         hb)
#=============================================================
w<-calcHMWakeFraction(breadth,
                      wettedSA,
                       maxDraft,
                       nProp,
                       lwl,
                      propDiam,
                      FormFactor,
                      Cf,
                      Ca,
                     Cbw,
                      Cp,
                      Cm,
                       aftDraft,
                      Cstern,
                      lcb)

t<-calcHMThrustFactor(breadth,
                       lwl,
                       maxDraft,
                       maxDisplacement,
                       nProp,
                       Cp,
                       propDiam,
                       Cbw,
                       Cstern,
                       lcb,
                       seawaterDensity)
#=============================================================

R<- calcHMTotalRes(Rapp,Rw,Rb,Rtr,seawaterDensity,wettedSA,shipSpeed,
                   Cf,FormFactor,Ca,serviceMargin)

#=============================================================
no<- calcOpenWaterEff(R,t,nProp,w,propDiam,shipSpeed)

#=============================================================
power<-calcResistanceShipPwr(R,shipSpeed, (1-t)/(1-w), no,totalInstalledPwr, shaftEff,relRotationEff, pwrUpperBoundPercent, pwrLowerBoundPercent)

 return(power)
}


subroutine dirseg(dirsgs,ndir,nadj,madj,npd,x,y,ntot,rw,eps,nerror)

# Output the endpoints of the segments of boundaries of Dirichlet
# tiles.  (Do it economically; each such segment once and only once.)
# Called by master.

implicit double precision(a-h,o-z)
logical collin, adjace, intfnd, bptab, bptcd, goferit, rwu
dimension nadj(-3:ntot,0:madj), x(-3:ntot), y(-3:ntot)
dimension dirsgs(10,ndir), rw(4)

nerror = -1

# Add in some dummy corner points, outside the actual window.
# Far enough out so that no resulting tile boundaries intersect the
# window.

# Note that these dummy corners are needed by the routine `dirout'
# but will screw things up for `delseg' and `delout'.  Therefore
# this routine (`dirseg') must be called ***before*** dirout, and
# ***after*** delseg and delout.

# Dig out the corners of the rectangular window.
xmin = rw(1)
xmax = rw(2)
ymin = rw(3)
ymax = rw(4)

a = xmax-xmin
b = ymax-ymin
c = sqrt(a*a+b*b)

npd  = ntot-4
nstt = npd+1
i = nstt
x(i) = xmin-c
y(i) = ymin-c
i = i+1
x(i) = xmax+c
y(i) = ymin-c
i = i+1
x(i) = xmax+c
y(i) = ymax+c
i = i+1
x(i) = xmin-c
y(i) = ymax+c

do j = nstt,ntot {
	call addpt(j,nadj,madj,x,y,ntot,eps,nerror)
	if(nerror > 0) return
}

# Put the segments into the array dirsgs.

# For each distinct pair of (genuine) data points, find out if they are
# adjacent.  If so, find the circumcentres of the triangles lying on each
# side of the segment joining them.
kseg = 0
do i = 2,npd {
        do j = 1,i-1 {
                call adjchk(i,j,adjace,nadj,madj,ntot,nerror)
		if(nerror > 0) return
                if(adjace) {
                        call pred(k,i,j,nadj,madj,ntot,nerror)
			if(nerror > 0) return
                        call circen(i,k,j,a,b,x,y,ntot,eps,collin,nerror)
			if(nerror > 0) return
                        if(collin) {
				nerror = 12
				return
			}
                        call succ(l,i,j,nadj,madj,ntot,nerror)
			if(nerror > 0) return
                        call circen(i,j,l,c,d,x,y,ntot,eps,collin,nerror)
			if(nerror > 0) return
                        if(collin) {
				nerror = 12
				return
			}
                        # If a circumcentre is outside the rectangular window
                        # of interest, draw a line joining it to the other
                        # circumcentre.  Find the intersection of this line with
                        # the boundary of the window; for (a,b) and call the point
                        # of intersection (ai,bi).  For (c,d), call it (ci,di).
                        # Note: rwu = "right way up".
                        xi = x(i)
                        xj = x(j)
                        yi = y(i)
                        yj = y(j)
                        if(yi!=yj) {
                            slope = (xi - xj)/(yj - yi)
                            rwu   = .true.
                        } else {
                            slope = 0.d0
                            rwu = .false.
                        }
                        call dldins(a,b,slope,rwu,ai,bi,rw,intfnd,bptab,nedgeab)
			if(!intfnd) {
				nerror = 16
				return
			}
                        call dldins(c,d,slope,rwu,ci,di,rw,intfnd,bptcd,nedgecd)
			if(!intfnd) {
				nerror = 16
				return
			}
			goferit = .false.
			if(bptab & bptcd) {
				xm = 0.5*(ai+ci)
				ym = 0.5*(bi+di)
				if(xmin<xm&xm<xmax&ymin<ym&ym<ymax) {
					goferit = .true.
				}
			}
			if((!bptab)|(!bptcd)) goferit = .true.
			if(goferit) {
				kseg = kseg + 1
				if(kseg > ndir) {
					nerror = 15
					return
				}
				dirsgs(1,kseg) = ai
				dirsgs(2,kseg) = bi
				dirsgs(3,kseg) = ci
				dirsgs(4,kseg) = di
				dirsgs(5,kseg) = i
				dirsgs(6,kseg) = j
				if(bptab) dirsgs(7,kseg) = 1.d0
				else dirsgs(7,kseg) = 0.d0
				if(bptcd) dirsgs(8,kseg) = 1.d0
				else dirsgs(8,kseg) = 0.d0
                                if(bptab) dirsgs(9,kseg) = -nedgeab
                                else dirsgs(9,kseg) = k
                                if(bptcd) dirsgs(10,kseg) = -nedgecd
                                else dirsgs(10,kseg) = l
			}
                }
        }
}
ndir = kseg

return
end


#!/usr/bin/env Rscript
#
# Fisher Exact Test p-values from 2x2 contingency table
#
args <- commandArgs(TRUE)
infile = paste("", args[1], sep="")
outfile = paste("", args[2], sep="")
if(nchar(infile) >= 1 && !infile == "NA" && nchar(outfile) >= 1 && !outfile == "NA") {
    x = read.table(infile, sep="\t", header=F)
    dx = data.matrix(x)
    n = dim(dx)[1]
    if(n >= 1) {
        p = rep(1, n)
        for(i in 1:n) {d=matrix(dx[i,],nrow=2); p[i]=fisher.test(d, alternative = "greater",conf.int=F)$p}
        fdr = p.adjust(p)
        dxp = data.frame(dx,p,fdr)
        names(dxp) = c("a","b","c","d","p-value","fdr")
        if(nchar(outfile) >= 1) {
            write.table(dxp, outfile, quote=F, sep="\t", row.names=F, col.names=T)
        } else {
            print(dxp)
        }
    }
} else {
    warning("Usage: fisher-pvals.r [input table (a,b,c,d)] [output table (a,b,c,d,p-value,fdr)]")
}


  # ---------------------------------------------------------------------
  # predict weights of individuals that do not have weights recorded from groundfish surveys
  # (for the moment, obtain weight-cw relationship from groundfish surveys and apply to cw from
  # snowcrab surveys
  # ------------------------------------------------------------------

  predictweights = function( Y, parameterisation="bio") {

    # sex codes
    male = 0
    female = 1
    sex.unknown = 2

    # maturity codes
    immature = 0
    mature = 1
    mat.unknown = 2

    # fill in missing weights from historical data as they used regression to do this ..
    # a slight variation is that the model chosen in 2007 includes shell condition as well

    if (parameterisation=="bio") {
      # develop regression relationships for each of: using cw, sex, maturity, shell, weighted by sa

      x = Y

      x$log.mass = log(x$mass)
      x$log.cw = log(x$cw)
      x$log.chela = log(x$chela)
      x$log.abdom =log(x$abdomen)
      x0 = x
      ii = which( x$sex%in% c(male, female) )
      x$sex = factor(x$sex, levels=c(male,female) )

      mod = glm( log.mass ~ log.cw + log.cw:sex, weights=sa, data=x, na.action='na.exclude')
      x$predictedmass = predict( mod, x )
      x$rstand =  abs( x$log.mass - x$predictedmass )
      x$rstand =   x$rstand  / sqrt(var(x$rstand, na.rm=T))

      jj = which(x$rstand  > 3 )
      x$log.mass [ jj ] = x$predictedmass [ jj ]
      kk = which( !is.finite( x$log.mass ) )
      x$log.mass [ kk ] = x$predictedmass [ kk ]

      # still a few NA's: fill in with a simpler model dependent only upon cw ~ 500 cases
      mod = glm( log.mass ~ log.chela, weights=sa, data=x, na.action='na.exclude')
      x$predictedmass = predict( mod, x )
      kk = which( !is.finite( x$log.mass ) )
      x$log.mass [ kk ] = x$predictedmass [ kk ]

      # still a few NA's: fill in with a simpler model dependent only upon cw ~ 500 cases
      mod = glm( log.mass ~ log.abdom, weights=sa, data=x, na.action='na.exclude' )
      x$predictedmass = predict( mod, x )
      kk = which( !is.finite( x$log.mass ) )
      x$log.mass [ kk ] = x$predictedmass [ kk ]

      Y$mass = exp(x$log.mass)

      return(Y)

# summary(mod);Anova(mod) from 2007 data

#Call:
#lm(formula = mass ~ cw + cw:sex + shell, subset = ii, weights = sa,
#    na.action = "na.exclude")

#Residuals:
#      Min        1Q    Median        3Q       Max
#-0.174287 -0.003357 -0.000181  0.003389  0.141542

#Coefficients:
#             Estimate Std. Error t value Pr(>|t|)
#(Intercept) -7.464833   0.024413 -305.78  < 2e-16 ***
#cw           2.890774   0.003796  761.55  < 2e-16 ***
#shell2       0.053130   0.017581    3.02   0.0025 **
#shell3       0.125508   0.017627    7.12  1.1e-12 ***
#shell4       0.154578   0.018308    8.44  < 2e-16 ***
#shell5       0.164819   0.039400    4.18  2.9e-05 ***
#cw:sex2     -0.023230   0.000649  -35.81  < 2e-16 ***
#---

#Residual standard error: 0.00838 on 13236 degrees of freedom
#  (36127 observations deleted due to missingness)
#Multiple R-Squared: 0.985,	Adjusted R-squared: 0.985
#F-statistic: 1.46e+05 on 6 and 13236 DF,  p-value: <2e-16

#Anova Table (Type II tests)

#Response: mass
#          Sum Sq    Df  F value Pr(>F)
#cw         49.76     1 708761.9 <2e-16 ***
#shell       0.05     4    186.7 <2e-16 ***
#cw:sex      0.09     1   1282.6 <2e-16 ***
#Residuals   0.93 13236
#---
#Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

#> summary(mod);Anova(mod)

#Call:
#lm(formula = mass ~ cw + cw:sex, data = newdata, weights = sa,     na.action = "na.exclude")

#Residuals:
#       Min         1Q     Median         3Q        Max
#-0.0840392 -0.0021296 -0.0000281  0.0019451  0.1309121

#Coefficients:
#              Estimate Std. Error t value Pr(>|t|)
#(Intercept) -7.7028530  0.0014793   -5207   <2e-16 ***
#cw           2.9630510  0.0003513    8435   <2e-16 ***
#cw:sex2     -0.0150139  0.0000779    -193   <2e-16 ***
#---
#Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

#Residual standard error: 0.00379 on 205565 degrees of freedom
#  (1109 observations deleted due to missingness)
#Multiple R-Squared: 0.997,	Adjusted R-squared: 0.997
#F-statistic: 3.96e+07 on 2 and 205565 DF,  p-value: <2e-16

#Anova Table (Type II tests)

#Response: mass
#          Sum Sq     Df  F value Pr(>F)
#cw        1135.4      1 79181818 <2e-16 ***
#cw:sex       0.5      1    37130 <2e-16 ***
#Residuals    2.9 205565
#---
#Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

      }

      if (parameterisation == "moncton") {
        m.soft = filter.class(x, "m.soft")
        m.hard = filter.class(x, "m.hard")
        x$mass[m.hard] = x$cw[m.hard]^ 3.098 *  0.0002665
        x$mass[m.soft] = x$cw[m.soft]^ 3.524 *  0.00002995

        #  use same equations as for male ... must fix this
        f.soft = filter.class(x, "f.soft")
        f.hard = filter.class(x, "f.hard")
        x$mass[f.hard] = x$cw[f.hard]^ 3.098 *  0.0002665
        x$mass[f.soft] = x$cw[f.soft]^ 3.524 *  0.00002995
      }

      return(x)
  }


#' Generate prior distributions for k using stream geometry
#'
#' @details Generates means and standard deviations for half-normal priors for k600. This
#' function uses the 7 equations from Raymond et al 2012. Which equation to use is a user
#' choice, though there are some recommendations from Raymond to guide the choice (see below,
#' and see Raymond et al 2012).
#'
#' Rayment et al provide standard deviations for the parameters, but do NOT provide information
#' on correlations among parameters; therefore this function treats them as independent (which
#' will generally produce larger prior standard deviations). The standard deviation is chosen
#' by simulating across independent parameter combinations.
#'
#' Slope and velocity are required for all equations. Discharge and depth are required for
#' equations 6 & 7 (discharge) and 1, 2, and 7 (depth); for equations 3-5 they can safely be
#' left set to NA.
#'
#' Guidelines for k:
#' Best for small streams:
#' includes depth, more preditive, but less general, not in accordance with theory
#' 		eq 1, 2
#'
#' More general (includes only slope & velocity), but maybe less precise
#' 		eq 3-5
#'
#' Equation 6 also includes discharge, predictability is lower, an alt to 3-5
#' Equation 7 includes depth and discharge; theoretically problematic, but
#' 		prediction might be better for small streams
#'
#' @param slope Stream slope (unitless; meters of height/meters of length)
#' @param velocity In meters/second
#' @param discharge In m^3/sec
#' @param depth In meters
#' @param eqn Which equation(s) to use
#' @param nsim Number of simulations used for the standard deviation
#'
#' @return If a single equations is given, a 2-column matrix giving the mean and standard
#'   deviation for k for each value in slope, velocity, etc. Otherwise a list of such matrices,
#'   one for each equation in eqn. Units for k are meters/day
#' @references Raymond, P.A. et al. (2012). Scaling the gas transfer velocity and hydraulic
#' 		 geometry in streams and small rivers. Limnol. Oceanogr., 2, 41–53.
#' @examples
#' sl = 0.05
#' v = 0.5
#' q = 1
#' d = 0.5
#' eq1 = k_prior(sl, v, q, d, eqn = 1, nsim=3) ## normally run thousands of sims
#' @export
k_prior = function(slope, velocity, depth = NA, discharge = NA, eqn = 1:7, nsim = 5000) {
	if(!all(eqn %in% 1:7))
		stop("Unknown equation; ensure all values in eqn are in 1:7")
	if(length(eqn) > 1) {
		lapply(eqn, function(e) k_prior(slope, velocity, depth, discharge, e, nsim))
	} else {
		params = .k_parameters()
		simpars = .k_generate_pars(params$pars[[eqn]], params$pars_se[[eqn]], 5000)
		sds = .k_sd_sim(slope, velocity, depth, discharge, simpars, eqn)
		means = .k_compute(slope, velocity, depth, discharge, params$pars[[eqn]], eqn)
		cbind(mean = means, stdev = sds)
	}
}

#' generate parameter sets (assuming independence) for k sims
#' @keywords internal
.k_generate_pars = function(par, se, n) {
	mapply(function(mu, stdev, N) rnorm(N, mu, stdev), par, se, n)
}

#' generate standard dev of k for a given set of stream variables
#' @keywords internal
.k_sd_sim = function(S, V, D, Q, pars, eqn) {
	getsd = function(S, V, D, Q, p, eqn) sd(apply(p, 1, function(x)
		.k_compute(S, V, D, Q, x, eqn)))
	if(requireNamespace("parallel")) {
		parallel::mcmapply(FUN = getsd, S = S, V = V, D = D,
			Q = Q, MoreArgs = list(p = pars, eqn = eqn))
	} else {
		mapply(FUN = getsd, S = S, V = V, D = D,
			Q = Q, MoreArgs = list(p = pars, eqn = eqn))
	}
}

# compute k
#' @keywords internal
.k_compute = function(S, V, D, Q, pars, eq) {
	eq = paste0('eq', eq)
	# magic number is gravitational acceleration
	fr = V / sqrt(9.806*D)
	switch(eq,
		eq1 = (V*S)^(pars[1]) * D^(pars[2]) * pars[3],
		eq2 = pars[1] * (1 - pars[2] * fr^2) * (V*S)^(pars[3]) * D^(pars[4]),
		eq3 = pars[1] * S^pars[2] * V^pars[3],
		eq4 = (V*S)^pars[1] * pars[2],
		eq5 = V*S*pars[1] + pars[2],
		eq6 = pars[1] * (V*S)^(pars[2]) * Q^pars[3],
		eq7 = pars[1] * (V*S)^(pars[2]) * Q^pars[3] * D^pars[4]
	)
}

#' Constant for k parameters
#' @keywords internal
.k_parameters = function() {
	## parameters from Raymond
	pars = list(
		eq1 = c(0.89, 0.54, 5037),
		eq2 = c(5937, 2.54, 0.89, 0.58),
		eq3 = c(1162, 0.77, 0.85),
		eq4 = c(0.76, 951.5),
		eq5 = c(2841, 2.02),
		eq6 = c(929, 0.75, 0.011),
		eq7 = c(4725, 0.86, -0.14, 0.66))
	pars_se = list(
		eq1 = c(0.020, 0.030, 604),
		eq2 = c(606, 0.223, 0.017, 0.027),
		eq3 = c(192, 0.028, 0.045),
		eq4 = c(0.027, 144),
		eq5 = c(107, 0.209),
		eq6 = c(141, 0.027, 0.016),
		eq7 = c(445, 0.016, 0.012, 0.029))
	list(pars = pars, pars_se = pars_se)
}