### Copyright (C) 2017 Rafael Laboissière
###
### This program is free software: you can redistribute it and/or modify it
### under the terms of the GNU General Public License as published by the
### Free Software Foundation, either version 3 of the License, or (at your
### option) any later version.
###
### This program is distributed in the hope that it will be useful, but
### WITHOUT ANY WARRANTY; without even the implied warranty of
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
### General Public License for more details.
###
### You should have received a copy of the GNU General Public License along
### with this program.  If not, see <http://www.gnu.org/licenses/>.

### * Statistical analyses

### ** Load the necessary libraries
library (lme4)
library (lmerTest)
library (HDInterval)
library (shape)
library (car)

### ** Function for computing confidence intervals of predicted values
ci.pred <- function (fit.model, new.data = NA, pred.fun = NA, nb.sim = 1000) {
    if (! is.function (pred.fun))
        pred.fun <- function (fit.model)
                        predict (fit.model, newdata = new.data, re.form = NA)
    n <- length (pred.fun (fit.model))
    b <- bootMer (fit.model, pred.fun, nsim = nb.sim)
    ci <- c ()
    for (i in seq (1, n))
        ci <- rbind (ci, hdi (b$t [, i]))
    return (list (ci = ci, t = b$t))
}

### ** Load the results
obj.stab.psycho <- read.csv ("obj-stab-psycho.csv")

### ** Transform the discrete factors chair and object into numeric
obj.stab.psycho$object.num <- c (1, -1, 0) [as.numeric(obj.stab.psycho$object)]
obj.stab.psycho$chair.num <- c (-1, 1, 0) [as.numeric (obj.stab.psycho$chair)]
obj.stab.psycho$table.side.num <- (c (-0.5, 0, 0.5)
                                   [as.numeric (obj.stab.psycho$table.side)])

### ** Boxplot parameters
obj.col <- c ("pink", "cyan", "wheat")
exp.col <- c ("aquamarine", "coral")
side.col <- c ("firebrick1", "deepskyblue")
boxplot.pars <- list (boxwex  = 0.5, bty = "n")
boxplot.ylab <- "threshold angle (degrees)"

### ** Plot labels

### *** Labels for the conditions
chair.lab <- c ("Left Tilt", "Upright", "Right Tilt")
bg.lab <- c ("Static Surround", "Rotating Surround")
scene.lab <- c ("Scene on the Left", "Scene on the Right")
table.lab <- c ("Table to the Left", "Table to the Right")
com.lab <- c ("Low COM", "Mid COM", "High COM")

### *** Labels for the axes
dsvh.xlab <- expression (paste (Delta, "TU (degrees)"))
dca.ylab = expression (paste (Delta, "CA (degrees)"))
ca.ylab <- "Critical Angle (degrees)"
svh.ylab <- "Table Uprightness (degrees)"

### ** Experiments

### *** Room 126

### **** Select the data
room.126 <- subset (obj.stab.psycho, experiment == "room-126")

### **** Drop subject S066 (it's Corinne Cian!))
room.126 <- subset (room.126, subject != "S066")

### **** Linear mixed models

## ***** Effect of chair inclination & object shape in static background
df.r126.chair.obj <- subset (room.126,
                             stimulus == "object" & background == "static")
fm.r126.chair.obj <- lmer (threshold ~ object.num * chair.num
                           + (1 | subject), df.r126.chair.obj)

anova (fm.r126.chair.obj)
fixef (fm.r126.chair.obj)
confint (fm.r126.chair.obj)

pdf (file = "room-126-chair-object.pdf")
par (mar = c (4, 5, 0.5, 0))
for (i in c (1, 2)) {
    boxplot (threshold ~ object.num * chair.num, df.r126.chair.obj,
             frame = FALSE, las = 1, xlab = "", ylab = boxplot.ylab,
             xaxt = "n", pars = boxplot.pars,
             col = rep (obj.col, 3), add = (i == 2))
    if (i == 1)
        polygon (c (3.5, 6.5, 6.5, 3.5), c (0, 0, 100, 100),
                 col = "#eeeeee", border = NA)
}
axis (1, at = c (2, 5, 8), tick = FALSE, labels = chair.lab)
legend ("topright", inset = 0.05, pch = 22, pt.cex = 2, pt.bg = obj.col,
        legend = com.lab)
dummy <- dev.off ()

### ***** Effect of object shape and background in upright position
df.r126.bg.obj <- subset (room.126,
                          stimulus == "object" & chair == "upright")
fm.r126.bg.obj <- lmer (threshold ~ background * object.num
                        + (1 | subject), df.r126.bg.obj)
anova (fm.r126.bg.obj)
fixef (fm.r126.bg.obj)
confint (fm.r126.bg.obj)

fe.r126.bg.obj <- fixef (fm.r126.bg.obj)
re.r126.bg.obj <- ranef (fm.r126.bg.obj)

pdf (file = "room-126-background-object.pdf")
par (mar = c (4, 5, 0.5, 0))
for (i in c (1, 2)) {
    boxplot (threshold ~ object.num * background, df.r126.bg.obj, frame = FALSE,
             las = 1, xlab = "", ylab = boxplot.ylab, xaxt = "n",
             pars = boxplot.pars, col = rep (obj.col, 2), add = (i == 2))
    if (i == 1)
        polygon (c (3.5, 6.5, 6.5, 3.5), c (0, 0, 100, 100),
                 col = "#eeeeee", border = NA)
}
axis (1, at = c (2, 5), tick = FALSE, labels = bg.lab)
legend ("topright", inset = 0.05, pch = 22, pt.cex = 2, pt.bg = obj.col,
        legend = com.lab)
dummy <- dev.off ()

### ***** Power analysis

### ****** Home-made simulation
### (Taken from the web somewhere.  Look at https://goo.gl/zOUgFy)
nsim <- 1000
p.value <- rep (NA, nsim)
sim.r126.bg.obj <- simulate (fm.r126.bg.obj, nsim = nsim)

cat ("Computing power effect for Exp. 1 (surround effect)\n")
flush.console ()

for (i in seq (1, nsim)) {
    df <- df.r126.bg.obj
    df$threshold <- sim.r126.bg.obj [, i]
    fm <- lmer (threshold ~ background * object.num + (1 | subject), df)
    p.value [i] <- anova (fm) [["Pr(>F)"]] [1]
    cat (sprintf ("\r%4d", i))
    flush.console ()
}

cat (sprintf ("Power for surround effect is %f\n",
              (nsim - length (which (p.value > 0.05))) / nsim))
flush.console ()

### ****** Using SIMR package
library (simr)
powerSim (fm.r126.bg.obj, test = fixed ("background"), nsim = 100)

### ***** Effect of background in upright position on horizontal estimation
df.r126.bg.hor <- subset (room.126,
                          stimulus == "horizontal" & chair == "upright")
fm.r126.bg.hor <- lmer (threshold ~ background + (1 | subject), df.r126.bg.hor)

anova (fm.r126.bg.hor)
fixef (fm.r126.bg.hor)
confint (fm.r126.bg.hor)

fe.r126.bg.hor <- fixef (fm.r126.bg.hor)
re.r126.bg.hor <- ranef (fm.r126.bg.hor)

pdf (file = "room-126-background-horizontal.pdf")
par (mar = c (4, 5, 0.5, 0))
boxplot (threshold ~ background, df.r126.bg.hor, frame = FALSE,
         las = 1, xlab = "", ylab = boxplot.ylab,
         xaxt = "n", pars = list (boxwex  = 0.2, bty = "n"))
axis (1, at = c (1, 2), tick = FALSE, labels = bg.lab)
dummy <- dev.off ()

### ***** Efect of inclination in static background on horizontal estimation
df.r126.chair.hor <- subset (room.126,
              stimulus == "horizontal" & background == "static")
df.r126.chair.hor$object <- factor (as.character (df.r126.chair.hor$object))
fm.r126.chair.hor <- lmer (threshold ~ chair.num + (0 + chair.num | subject),
                           df.r126.chair.hor)

anova (fm.r126.chair.hor)
fixef (fm.r126.chair.hor)
confint (fm.r126.chair.hor)

pdf (file = "room-126-chair-horizontal.pdf")
par (mar = c (4, 5, 0.5, 0))
boxplot (threshold ~ chair.num, df.r126.chair.hor, frame = FALSE,
         las = 1, xlab = "", ylab = boxplot.ylab,
         xaxt = "n", pars = list (boxwex  = 0.4, bty = "n"))
axis (1, at = seq (1, 3), tick = FALSE, labels = chair.lab)
dummy <- dev.off ()

### **** Plot random effects for horizontality vs. object stability models

pdf (file = "room-126-ranef-cor.pdf")
par (mar = c (4, 5, 0.5, 0))
plot (fe.r126.bg.hor [2] + re.r126.bg.hor$subject [, 1],
      fe.r126.bg.obj [2] + re.r126.bg.obj$subject [, 1],
      pch = 19, bty = "n", las = 1, xlim = c (0,7),
      xlab = dsvh.xlab, ylab = dca.ylab)
dummy <- dev.off ()

pdf (file = "room-126-ranef-cor-diag.pdf")
par (mar = c (4, 5, 0.5, 0))
plot (fe.r126.bg.hor [2] + re.r126.bg.hor$subject [, 1],
      fe.r126.bg.obj [2] + re.r126.bg.obj$subject [, 1],
      pch = 19, bty = "n", las = 1, xlim = c (0,7),
      xlab = dsvh.xlab, ylab = dca.ylab)
abline (0, 1, lty = 2, col = "gray", lwd = 2)
dummy <- dev.off ()

### **** Select representative subjects

### ***** Object stability experiment

### Get the data frame for the room-126 (background/object) experiment
### in condition "static"
df <- subset (df.r126.bg.obj, background == "static")
### Compute the differences in threshold high-mid and mid-low
ag <- aggregate (threshold ~ subject, df,
                 function (x) c(x[2] - x[3], x [3] - x [1]))
diff.t <- ag$threshold
### Get the size of the effect
diff.ca <- -fixef (fm.r126.bg.obj) [3]
### Find the subject
idx <- which.min ((diff.t [, 1] - diff.ca) ^ 2 + (diff.t [, 2] - diff.ca) ^ 2)
cat (sprintf ("Representative subject is %s\n", ag$subject [idx]))

### ***** Horizontality experiment

### Get the data frame for the room-126 (background/horizontal) experiment
### in condition "vection"
df <- subset (df.r126.bg.hor, background == "vection")
### Get the indivual thresholds
thres <- df$threshold
### Get the size of the effect
fe <- fixef (fm.r126.bg.hor) [2]
### Find the subject
idx <- which.min ((thres - fe) ^ 2)
cat (sprintf ("Representative subject is %s\n", df$subject [idx]))

### *** New screen

### **** Select the data
new.screen <- subset (obj.stab.psycho, experiment == "new-screen")
new.screen$subject <- factor (as.character (new.screen$subject))

### **** Select the same subjects from room 126 experiment
for (s in levels (new.screen$subject)) {
    new.screen <- rbind (new.screen,
                         subset (obj.stab.psycho, subject == s
                                                  & experiment == "room-126"
                                                  & stimulus == "horizontal"
                                                  & chair == "upright"))
}
new.screen$subject <- factor (as.character (new.screen$subject))
new.screen$experiment <- factor (as.character (new.screen$experiment),
                                 levels = c ("room-126", "new-screen"))

pdf (file = "room-126-new-screen.pdf")
par (mar = c (4, 5, 0.5, 0))
for (i in c (1, 2)) {
    boxplot (threshold ~ experiment * background, new.screen, frame = FALSE,
             las = 1, xlab = "", ylab = boxplot.ylab, col = rep (exp.col, 2),
             xaxt = "n", pars = list (boxwex  = 0.4, bty = "n"), add = (i == 2))
    if (i == 1)
        polygon (c (2.5, 4.5, 4.5, 2.5), c (-50, -50, 50, 50),
                 col = "#eeeeee", border = NA)
}
axis (1, at = c (1.5, 3.5), tick = FALSE, labels = bg.lab)
legend ("topleft", inset = 0.05, pch = 22, pt.cex = 2, pt.bg = exp.col,
        legend = c ("computer screen", "wall screen"))
dummy <- dev.off ()

### **** Fit model
fm <- lmer (threshold ~ experiment * background + (1 | subject), new.screen)
show (anova (fm))
show (fixef (fm))
show (ranef (fm))

### **** Results Exp. 1 (Fig. 2)

### ***** General plot paramaters
obj.pch <- c (18, 16, 15) # diamond, circle, square
obj.cex <- c (2.5, 2, 2) # diamond, circle, square
gray.box <- "#eeeeee"
pdf.wd <- 4.5
pdf.ht <- 4.5

### ***** Panel A
nd <- expand.grid (object.num  = c (-1, 0, 1),
                   background = c ("static", "vection"))
pred <- predict (fm.r126.bg.obj, nd, re.form = NA)
ci <- ci.pred (fm.r126.bg.obj, nd)$ci
y.min <- 26
y.max <- 39
pdf (file = "Fig-2-a.pdf", width = pdf.wd, height = pdf.ht)
par (mar = c (2, 4, 1, 1))
plot (0, 0, xlim = c (0.5, 6.5), bty = "n", xaxt = "n", las = 1,
      ylim = c (y.min, y.max), xlab = "", ylab = ca.ylab, type = "n")
axis (1, at = c (2, 5), tick = FALSE, labels = bg.lab)
polygon (c (3.5, 6.5, 6.5, 3.5), c (-50, -50, y.max, y.max), col = gray.box,
         border = NA)
points (pred, pch = obj.pch, cex = obj.cex)
for (i in seq (1, 6))
    lines (rep (i, 2), ci [i, ], lwd = 3)
legend ("bottomleft", inset = c (0.05, 0.05), pch = obj.pch, bty = "n",
        pt.cex = 0.75 * obj.cex, legend = com.lab)
par (xpd = NA)
text (-0.2, y.max, adj = c (0, 0), labels = "a", cex = 2)
dummy <- dev.off ()

### ***** Panel C
nd <- expand.grid (object.num  = c (-1, 0, 1), chair.num = c (-1, 0, 1))
pred <- predict (fm.r126.chair.obj, nd, re.form = NA)
ci <- ci.pred (fm.r126.chair.obj, nd)$ci
pdf (file = "Fig-2-c.pdf", width = pdf.wd, height = pdf.ht)
par (mar = c (2, 4, 1, 1))
plot (0, 0, xlim = c (0.5, 9.5), bty = "n", xaxt = "n", las = 1, type = "n",
      ylim = c (y.min, y.max), xlab = "", ylab = ca.ylab)
axis (1, at = c (2, 5, 8), tick = FALSE, labels = chair.lab)
polygon (c (3.5, 6.5, 6.5, 3.5), c (-50, -50, y.max, y.max), col = gray.box,
         border = NA)
points (pred, pch = obj.pch, cex = obj.cex)
for (i in seq (1, 9))
    lines (rep (i, 2), ci [i, ], lwd = 3)
par (xpd = NA)
text (-0.2, y.max, adj = c (0, 0), labels = "c", cex = 2)
dummy <- dev.off ()

### ***** Panel B
nd <- expand.grid (background = c ("static", "vection"))
pred <- predict (fm.r126.bg.hor, nd, re.form = NA)
ci <- ci.pred (fm.r126.bg.hor, nd)$ci
y.min <- -5
y.max <- 8
pdf (file = "Fig-2-b.pdf", width = pdf.wd, height = 0.8 * pdf.ht)
par (mar = c (4.5, 4, 2.0, 1))
plot (0, 0, xlim = c (0.5, 6.5), bty = "n", xaxt = "n", las = 1,
      ylim = c (y.min, y.max), xlab = "", ylab = svh.ylab, type = "n")
axis (1, at = c (2, 5), tick = FALSE, labels = bg.lab)
polygon (c (3.5, 6.5, 6.5, 3.5), c (-50, -50, 38, 38), col = gray.box,
         border = NA)
for (i in seq (1, 2))
    lines (rep ((i - 1) * 3 + 2, 2), ci [i, ], lwd = 3)
points (c (2, 5), pred, pch = 21, cex = 1.8, bg = "white")
par (xpd = NA)
text (-0.2, y.max + 1.2, adj = c (0, -0.2), labels = "b", cex = 2)
dummy <- dev.off ()

### ***** Panel D
nd <- expand.grid (chair.num = c (-1, 0, 1))
pred <- predict (fm.r126.chair.hor, nd, re.form = NA)
ci <- ci.pred (fm.r126.chair.hor, nd)$ci
pdf (file = "Fig-2-d.pdf", width = pdf.wd, height = 0.8 * pdf.ht)
par (mar = c (4.5, 5, 2.0, 1))
plot (0, 0, xlim = c (0.5, 9.5), bty = "n", xaxt = "n", las = 1,
      ylim = c (y.min, y.max), xlab = "", ylab = svh.ylab, type = "n")
axis (1, at = c (2, 5, 8), tick = FALSE, labels = chair.lab)
polygon (c (3.5, 6.5, 6.5, 3.5), c (-50, -50, 38, 38), col = gray.box,
         border = NA)
for (i in seq (1, 3))
    lines (rep ((i - 1) * 3 + 2, 2), ci [i, ], lwd = 3)
points (c (2, 5, 8), pred, pch = 21, cex = 1.8, bg = "white")
par (xpd = NA)
text (-0.2, y.max + 1.2, adj = c (0, -0.2), labels = "d", cex = 2)
dummy <- dev.off ()

### ***** Compose Figure
system (paste ("pdfjam Fig-2-a.pdf Fig-2-c.pdf Fig-2-b.pdf Fig-2-d.pdf",
               "--no-landscape --frame true --nup 2x2 --frame false",
               "--outfile tmp.pdf"))
system ("pdfcrop --margins 10 tmp.pdf Fig-2.pdf")

### **** Correlation figure (Fig. 3)
df.hor <- subset(room.126, stimulus == "horizontal" & chair == "upright")
delta.hor <- aggregate (threshold ~ subject, df.hor, diff)
df.ca <- subset(room.126, stimulus == "object" & chair == "upright")
delta.ca <- aggregate (threshold ~ subject,
                       aggregate (threshold ~ subject * background, df.ca, mean),
                       diff)
pdf (file = "Fig-3.pdf", width = pdf.wd, height = pdf.ht)
par (mar = c (5, 4, 0, 0))
plot (delta.hor$threshold, delta.ca$threshold, bty = "n", las = 1, pch = 19,
      xlab = dsvh.xlab, ylab = dca.ylab, type = "n")
abline (0, 1, col = "gray", lwd = 2)
points (delta.hor$threshold, delta.ca$threshold, pch = 19)
points (mean (delta.hor$threshold), mean (delta.ca$threshold), pch = 18,
        col = "#ff000080", cex = 3)
dummy <- dev.off ()

### *** Scene mirror

### **** Select the data
df.scene.mirror <- subset (obj.stab.psycho, experiment == "scene-mirror")
df.scene.mirror$subject <- factor (as.character (df.scene.mirror$subject))

### **** Effect of object CG height and secene side

### ***** Extract the data
df.scene.mirror.obj <- subset (df.scene.mirror, stimulus == "object")

### ***** Plot the raw results
pdf (file = "scene-mirror-object.pdf")
par (mar = c (4, 5, 0.5, 0))
for (i in c (1, 2)) {
    boxplot (threshold ~ object.num * object.side, df.scene.mirror.obj,
             frame = FALSE, las = 1, xlab = "", ylab = boxplot.ylab,
             xaxt = "n", pars = boxplot.pars,
             col = rep (obj.col, 2), add = (i == 2))
    if (i == 1)
        polygon (c (3.5, 6.5, 6.5, 3.5), c (0, 0, 100, 100),
                 col = gray.box, border = NA)
}
axis (1, at = c (2, 5), tick = FALSE, labels = scene.lab)
legend ("topright", inset = 0.05, pch = 22, pt.cex = 2, pt.bg = obj.col,
        legend = com.lab)
dummy <- dev.off ()

### ***** Fit the model
fm.scene.mirror.obj <- lmer (threshold ~ object.num * table.side.num
                                         + (1 | subject)
                                         + (0 + table.side.num | subject),
                             df.scene.mirror.obj)
show (anova (fm.scene.mirror.obj))
show (fixef (fm.scene.mirror.obj))
show (ranef (fm.scene.mirror.obj))

fm.no.Intercept <- lmer (threshold ~ object.num * table.side.num
                                     + (0 + table.side.num | subject),
                         df.scene.mirror.obj)
fm.no.table.side.num <- lmer (threshold ~ object.num * table.side.num
                                          + (1 | subject),
                              df.scene.mirror.obj)
show (anova (fm.no.Intercept, fm.scene.mirror.obj))
show (anova (fm.no.table.side.num, fm.scene.mirror.obj))

### ***** Plot the results
nd <- expand.grid (object.num = c (-1, 0, 1), table.side.num = c (-0.5, 0.5))
pred <- predict (fm.scene.mirror.obj, nd, re.form = NA)
ci <- ci.pred (fm.scene.mirror.obj, nd)$ci
y.min <- min (ci [, 1])
y.max <- max (ci [, 2])
pdf (file = "Fig-5-a.pdf", width = pdf.wd, height = pdf.ht)
par (mar = c (4.5, 5, 2.0, 0))
plot (0, 0, type = "n", xlim = c (0.5, 6.5), bty = "n", xaxt = "n", las = 1,
      ylim = c (y.min, y.max), xlab = "", ylab = ca.ylab)
axis (1, at = c (2, 5), tick = FALSE, labels = scene.lab)
polygon (c (3.5, 6.5, 6.5, 3.5), c (-50, -50, 42, 42), col = gray.box,
         border = NA)
for (i in seq (1, 6))
    lines (rep (i, 2), ci [i, ], lwd = 3)
points (pred, pch = obj.pch, cex = obj.cex)
legend ("bottomleft", inset = 0.05, pch = obj.pch, pt.cex = 0.75 * obj.cex,
        bty = "n", legend = com.lab)
par (xpd = NA)
text (-0.2, y.max + 0.8, adj = c (0, -0.2), labels = "a", cex = 2)
dummy <- dev.off ()

### ***** Plot the BLUP
re <- ranef (fm.scene.mirror.obj)$subject
n <- nrow (re)
fe <- fixef (fm.scene.mirror.obj)

pdf (file = "Fig-5-b.pdf", width = pdf.wd, height = pdf.ht)
par (mar = c (5, 5.5, 2, 0.1))
x <- re [,1] + fe [1]
y <- - (re [,2]  + fe [3])
show (max (y))
y.min <- min (y)
y.max <- 18
plot (x, y, pch = 19, cex = 1.5, las = 1,  xlim = c (20, 40), col = "#00000080",
      bty = "n", xlab = "Mean Critical Angle (degrees)",
      ylab = "Left/Right Side Effect (degrees)")
abline (h = -fe [3], col = "#00000080", lwd = 2, lty = "21")
abline (v = fe [1], col = "#00000080", lwd = 2, lty = "21")
par (xpd = NA)
text (20, 14.5, adj = c (1, 0), labels = "b", cex = 2)
dummy <- dev.off ()

### ***** Compose the Fig. 5
system (paste ("pdfjam Fig-5-a.pdf Fig-5-b.pdf",
               "--no-landscape --frame true --nup 2x1 --frame false",
               "--outfile tmp.pdf"))
system ("pdfcrop --margins 10 tmp.pdf Fig-5.pdf")

### **** Check age effect on the random factors

### ****** Plot the ranef with age as size of points
subjects <- read.csv ("cohort-info.csv")
age <- sapply (row.names (re),
               function (x)
                   subjects$age [which (x == as.character (subjects$subject))])
pdf (file = "scene-mirror-ranef-age.pdf")
par (xpd = NA)
plot (fe [1] + re [, 1], -(fe [3] + re [, 2]), bty = "n",
      las = 1, col = "#00000080", pch = 19,
      cex = 1 + 5 * (age - min (age)) / (max (age) - min (age)),
      xlab = "individual intercept effect (degrees)",
      ylab = "individual table-sode effect (degrees)")
legend.years <- c (20, 30)
legend.cex <- 1 + 5 * (legend.years - min (age)) / (max (age) - min (age))
legend ("topleft", inset = 0.2, pt.cex = legend.cex, pch = 1, cex = 1.8,
        legend = sapply (legend.years, function (x) sprintf ("%.0f years", x)),
        text.col = "#bbbbbb")
Arrows (19, 0, 19, -5, lwd = 2, col = "red")
text (19.5, -2.5, label = "- gravity", adj = c (0.5, 1), srt = 90, col = "red",
      cex = 1.2)
Arrows (19, 8, 19, 13, lwd = 2, col = "red")
text (19.5, 10.5, label = "+ gravity", adj = c (0.5, 1), srt = 90, col = "red",
      cex = 1.2)
Arrows (24, 15, 20, 15, lwd = 2, col = "red")
text (22, 15.5, label = "cautious", adj = c (0.5, 0), col = "red", cex = 1.2)
Arrows (32, 15, 36, 15, lwd = 2, col = "red")
text (34, 15.5, label = "risky", adj = c (0.5, 0), col = "red", cex = 1.2)
dummy <- dev.off ()

### ****** Pilai statistical test
fm.scene.mirror.age <- lm (cbind (fe [1] + re [, 1], -(fe [3] + re [, 2])) ~ age)
Manova (fm.scene.mirror.age)

### **** Effect of background on horizontal detection
df.scene.mirror.hor <- subset (df.scene.mirror, stimulus == "horizontal")
idx <- which (df.scene.mirror.hor$table.side == "right")
df.scene.mirror.hor$threshold [idx] <- -df.scene.mirror.hor$threshold [idx]

pdf (file = "scene-mirror-horizontal.pdf")
par (mar = c (4, 5, 0.5, 0))
for (i in c (1, 2)) {
    boxplot (threshold ~ table.side * background, df.scene.mirror.hor,
             frame = FALSE, las = 1, xlab = "", ylab = boxplot.ylab,
             col = rep (side.col, 2), xaxt = "n",
             pars = list (boxwex  = 0.4, bty = "n"), add = (i == 2))
    if (i == 1)
        polygon (c (2.5, 4.5, 4.5, 2.5), c (-50, -50, 50, 50),
                 col = gray.box, border = NA)
}
axis (1, at = c (1.5, 3.5), tick = FALSE, labels = bg.lab)
legend ("topleft", inset = 0.05, pch = 22, pt.cex = 2, pt.bg = side.col,
        legend = table.lab)
dummy <- dev.off ()

fm.scene.mirror.hor <- lmer (threshold ~ table.side.num * background
                                         + (1 | subject),
                             df.scene.mirror.hor)
show (anova (fm.scene.mirror.hor))
show (fixef (fm.scene.mirror.hor))
show (ranef (fm.scene.mirror.hor))

### *** Flip table

### **** Select the data
flip.table <- subset (obj.stab.psycho, experiment == "flip-table")
flip.table$subject <- factor (as.character (flip.table$subject))

### **** Effect of scene side and background on object stability
flip.table.obj <- subset (flip.table, stimulus == "object")

pdf (file = "flip-table-object.pdf")
par (mar = c (4, 5, 0.5, 0))
for (i in c (1, 2)) {
    boxplot (threshold ~ table.side * background, flip.table.obj,
             frame = FALSE, las = 1, xlab = "", ylab = boxplot.ylab,
             col = rep (side.col, 2), xaxt = "n",
             pars = list (boxwex  = 0.4, bty = "n"), add = (i == 2))
    if (i == 1)
        polygon (c (2.5, 4.5, 4.5, 2.5), c (-50, -50, 50, 50),
                 col = gray.box, border = NA)
}
axis (1, at = c (1.5, 3.5), tick = FALSE, labels = bg.lab)
legend ("bottomleft", inset = 0.05, pch = 22, pt.cex = 2, pt.bg = side.col,
        legend = c ("table to the left", "table to the right"))
dummy <- dev.off ()

fm <- lmer (threshold ~ background * table.side + (1 | subject),
            flip.table.obj)
show (anova (fm))
show (fixef (fm))
show (ranef (fm))

### **** Effect of scene side and background on horizontal detection
flip.table.hor <- subset (flip.table, stimulus == "horizontal")
idx <- which (flip.table.hor$table.side == "right")
flip.table.hor$threshold [idx] <- -flip.table.hor$threshold [idx]

pdf (file = "flip-table-horizontal.pdf")
par (mar = c (4, 5, 0.5, 0))
for (i in c (1, 2)) {
    boxplot (threshold ~ background * table.side, flip.table.hor,
             frame = FALSE, las = 1, xlab = "", ylab = boxplot.ylab,
             col = rep (side.col, 2), xaxt = "n",
             pars = list (boxwex  = 0.4, bty = "n"), add = (i == 2))
    if (i == 1)
        polygon (c (2.5, 4.5, 4.5, 2.5), c (-50, -50, 50, 50),
                 col = gray.box, border = NA)
}
axis (1, at = c (1.5, 3.5), tick = FALSE,
      labels = c ("table to the left", "table to the right"))
legend ("topleft", inset = 0.05, pch = 22, pt.cex = 2, pt.bg = side.col,
        legend = bg.lab)
dummy <- dev.off ()

fm <- t.test (threshold ~ background, paired = TRUE,
              data = subset (flip.table.hor, table.side == "left"))
show (fm)

fm <- t.test (threshold ~ background, paired = TRUE,
              data = subset (flip.table.hor, table.side == "right"))
show (fm)

### *** No table

### **** Select the data
df.no.table <- subset (obj.stab.psycho, experiment == "no-table")

### **** Plot the raw results
pdf (file = "no-table-object.pdf")
par (mar = c (4, 5, 0.5, 0))
for (i in c (1, 2)) {
    boxplot (threshold ~ object.num * background * table.side, df.no.table,
             frame = FALSE, las = 1, xlab = "", ylab = boxplot.ylab,
             xaxt = "n", pars = boxplot.pars,
             col = rep (obj.col, 2), add = (i == 2))
    if (i == 1)
        polygon (c (3.5, 6.5, 6.5, 3.5), c (0, 0, 100, 100),
                 col = gray.box, border = NA)
}
axis (1, at = c (2, 5), tick = FALSE, labels = bg.lab)
legend ("topright", inset = 0.05, pch = 22, pt.cex = 2, pt.bg = obj.col,
        legend = com.lab)
dummy <- dev.off ()

fm.no.table <- lmer (threshold ~ background * object.num * table.side
                                 + (1 | subject),
                     df.no.table)
show (anova (fm.no.table))
show (fixef (fm.no.table))
show (ranef (fm.no.table))
show (confint (fm.no.table))

fe <- fixef (fm.no.table)

### **** Rudimentary plot of results
pdf (file = "no-table-object.pdf", width = 4, height = 5)
par (mar = c (4, 5, 0.5, 0))
plot (c (1, 1, 2, 2),
      c (fe[1], fe [1] + fe [2], fe [1] + fe [4],
         fe [1] + fe [2] + fe [4] + fe [6]),
      pch = 19, col = rep (c ("blue", "red"), 2), bty = "n",
      xlim = c (0.7, 2.3), cex = 1.3,
      las = 1, xaxt = "n", xlab = "", ylab = ca.ylab)
lines (c (1, 2), c (fe[1], fe [1] + fe [4]), col = "blue")
lines (c (1, 2), c (fe [1] + fe [2], fe [1] + fe [2] + fe [4] + fe [6]),
       col = "red")
axis (1, at = c (1, 2), labels = c ("table", "no table"))
legend ("right", col = c ("red", "blue"), legend = c ("rotating", "static"),
        pch = 19)
dummy <- dev.off ()

### ***** Plot the results
nd <- expand.grid (object.num = c (-1, 0, 1),
                   background = c ("static", "vection"),
                   table.side = c ("left", "none"))
pred <- predict (fm.no.table, nd, re.form = NA)
ci <- ci.pred (fm.no.table, nd)$ci
y.min <- min (ci [, 1])
y.max <- max (ci [, 2])
pdf (file = "Fig-6.pdf", width = 7, height = 5)
par (mar = c (4.5, 5, 4.5, 0), xpd = FALSE)
plot (0, 0, type = "n", xlim = c (0.5, 12.5), bty = "n", xaxt = "n", las = 1,
      ylim = c (y.min, y.max), xlab = "", ylab = ca.ylab)
group.axis <- function (pos, at, lab) {
    axis (pos, at = at, labels = rep ("", 2), line = 1)
    axis (pos, at = mean (at), tick = FALSE, line = 0.5, labels = lab)
}
for (i in c (1, 2)) {
    polygon (6 * (i - 1) + c (3.5, 6.5, 6.5, 3.5),
             c (0, 0, 100, 100), col = gray.box, border = NA)
    group.axis (3, at = 6 * (i - 1) + c (1, 3), "Static")
    group.axis (3, at = 6 * (i - 1) + c (4, 6), "Rotating")
}
group.axis (1, c (1, 6), "With Table")
group.axis (1, c (7, 12), "Without Table")
for (i in seq (1, 12))
    lines (rep (i, 2), ci [i, ], lwd = 3)
points (pred, pch = obj.pch, cex = obj.cex)
legend ("topleft", inset = c (0.05, 0), pch = obj.pch, pt.cex = 0.75 * obj.cex,
        bty = "n", legend = com.lab)
dummy <- dev.off ()

### ** Verify age effects for background effect in Exp. 1 and Exp. 3

df.age <- subset (obj.stab.psycho,
                  experiment %in% c ("room-126", "no-table")
                  & table.side == "left" & chair == "upright"
                  & subject != "S066" & stimulus == "object")
fm.age <- lmer (threshold ~ background * object + (background | subject),
                df.age)
re <- ranef (fm.age)$subject
age <- sapply (row.names (re),
               function (x)
                   subjects$age [which (x == as.character (subjects$subject))])
cor.test (re [, 1], age)
cor.test (re [, 2], age)


subroutine rqfnb(n,p,a,y,rhs,d,u,beta,eps,wn,wp,nit,info)
integer n,p,info,nit(3)
double precision a(p,n),y(n),rhs(p),d(n),u(n),wn(n,9),wp(p,p+3)
double precision one,beta,eps
parameter( one = 1.0d0)
call lpfnb(n,p,a,y,rhs,d,u,beta,eps,wn(1,1),wn(1,2),
        wp(1,1),wn(1,3),wn(1,4),wn(1,5),wn(1,6),
        wp(1,2),wn(1,7),wn(1,8),wn(1,9),wp(1,3),wp(1,4),nit,info)
return
end
# This is a revised form of my primal-dual log barrier form of the
# interior point LP solver based on Lustig, Marsten and Shanno ORSA J Opt 1992.
# It is a projected Newton primal-dual logarithmic barrier method which uses
# the predictor-corrector approach of Mehrotra for the mu steps.
# For the sake of brevity we will call it a Frisch-Newton algorithm.
# Problem:
# 	min c'x s.t. Ax=b, 0<=x<=u
#
# Denote dx,dy,dw,ds,dz as the steps for the respective variables x,y,w,s,z
#
subroutine lpfnb(n,p,a,c,b,d,u,beta,eps,x,s,y,z,w,
	dx,ds,dy,dz,dw,dr,rhs,ada,nit,info)

integer n,p,pp,i,info,nit(3),maxit
double precision a(p,n),c(n),b(p)
double precision zero,one,mone,big,ddot,dmax1,dmin1,dxdz,dsdw
double precision deltap,deltad,beta,eps,mu,gap,g
double precision x(n),u(n),s(n),y(p),z(n),w(n),d(n),rhs(p),ada(p,p)
double precision dx(n),ds(n),dy(p),dz(n),dw(n),dr(n)

parameter( zero  = 0.0d0)
parameter( one   = 1.0d0)
parameter( mone  = -1.0d0)
parameter( big  = 1.0d+20)
parameter( maxit  = 500)

# Initialization:  We follow the notation of LMS
# On input we require:
#
# 	c = n-vector of marginal costs (-y in the rq problem)
# 	a = p by n matrix of linear constraints (x' in rq)
# 	b = p-vector of rhs ((1-tau)x'e in rq)
#       u = upper bound vector ( e in rq)
# 	beta = barrier parameter, LMS recommend .99995
# 	eps = convergence tolerance, LMS recommend 10d-8
#
# 	the integer vector nit returns iteration counts
# 	the integer info contains an error code from the Cholesky in stepy
# 		info = 0 is fine
# 		info < 0 invalid argument to dposv
# 		info > 0 singular matrix
nit(1)=0
nit(2)=0
nit(3)=n
pp=p*p
# Start at the OLS estimate for the dual vector y
call dgemv('N',p,n,one,a,p,c,1,zero,y,1)
do i=1,n
	d(i)=one
call stepy(n,p,a,d,y,ada,info)
if(info != 0) return
# put current residual vector in s (temporarily)
call dcopy(n,c,1,s,1)
call dgemv('T',p,n,mone,a,p,y,1,one,s,1)
# Initialize remaining variables
do i=1,n{
	if(dabs(s(i))<eps){
		z(i)=dmax1(s(i), zero) + eps
		w(i)=dmax1(-s(i),zero) + eps
		}
	else {
		z(i)=dmax1(s(i), zero)
		w(i)=dmax1(-s(i),zero)
		}
	s(i)=u(i)-x(i)
	}
gap = ddot(n,z,1,x,1)+ddot(n,w,1,s,1)
while(gap > eps && nit(1)<maxit) {
	nit(1)=nit(1)+1
	do i = 1,n{
		d(i) = one/(z(i)/x(i) + w(i)/s(i))
		ds(i)=z(i)-w(i)
		dz(i)=d(i)*ds(i)
		}
	call dcopy(p,b,1,dy,1)#save rhs
	call dgemv('N',p,n,mone,a,p,x,1,one,dy,1)
	call dgemv('N',p,n,one,a,p,dz,1,one,dy,1)
	call dcopy(p,dy,1,rhs,1)#save rhs
	call stepy(n,p,a,d,dy,ada,info)
	if(info != 0) return
	call dgemv('T',p,n,one,a,p,dy,1,mone,ds,1) #ds -> A'dy - ds
	deltap=big
	deltad=big
	do i=1,n{
		dx(i)=d(i)*ds(i)
		ds(i)=-dx(i)
		dz(i)=-z(i)*(dx(i)/x(i) + one)
		dw(i)=-w(i)*(ds(i)/s(i) + one)
		if(dx(i)<0)deltap=dmin1(deltap,-x(i)/dx(i))
		if(ds(i)<0)deltap=dmin1(deltap,-s(i)/ds(i))
		if(dz(i)<0)deltad=dmin1(deltad,-z(i)/dz(i))
		if(dw(i)<0)deltad=dmin1(deltad,-w(i)/dw(i))
		}
	deltap=dmin1(beta*deltap,one)
	deltad=dmin1(beta*deltad,one)
	if(min(deltap,deltad) < one){
		nit(2)=nit(2)+1
		# Update mu
		mu = ddot(n,x,1,z,1)+ddot(n,s,1,w,1)
		g = mu + deltap*ddot(n,dx,1,z,1)+
			deltad*ddot(n,dz,1,x,1) +
			deltap*deltad*ddot(n,dz,1,dx,1)+
			deltap*ddot(n,ds,1,w,1)+
			deltad*ddot(n,dw,1,s,1) +
			deltap*deltad*ddot(n,ds,1,dw,1)
		mu = mu * ((g/mu)**3) /dfloat(2*n)
		# Compute modified step
		do i=1,n{
			dr(i)=d(i)*(mu*(1/s(i)-1/x(i))+
				dx(i)*dz(i)/x(i)-ds(i)*dw(i)/s(i))
			}
		call dswap(p,rhs,1,dy,1)
		call dgemv('N',p,n,one,a,p,dr,1,one,dy,1)# new rhs
		call dpotrs('U',p,1,ada,p,dy,p,info)# backsolve for dy
		call dgemv('T',p,n,one,a,p,dy,1,zero,u,1)#ds=A'ddy
		deltap=big
		deltad=big
		do i=1,n{
			dxdz =  dx(i)*dz(i)
			dsdw =  ds(i)*dw(i)
			dx(i)=  d(i)*(u(i)-z(i)+w(i))-dr(i)
			ds(i)= -dx(i)
			dz(i)= -z(i)+(mu - z(i)*dx(i) - dxdz)/x(i)
			dw(i)= -w(i)+(mu - w(i)*ds(i) - dsdw)/s(i)
			if(dx(i)<0)deltap=dmin1(deltap,-x(i)/dx(i))
			if(ds(i)<0)deltap=dmin1(deltap,-s(i)/ds(i))
			if(dz(i)<0)deltad=dmin1(deltad,-z(i)/dz(i))
			if(dw(i)<0)deltad=dmin1(deltad,-w(i)/dw(i))
			}
		deltap=dmin1(beta*deltap,one)
		deltad=dmin1(beta*deltad,one)
		}
	call daxpy(n,deltap,dx,1,x,1)
	call daxpy(n,deltap,ds,1,s,1)
	call daxpy(p,deltad,dy,1,y,1)
	call daxpy(n,deltad,dz,1,z,1)
	call daxpy(n,deltad,dw,1,w,1)
	gap = ddot(n,z,1,x,1)+ddot(n,w,1,s,1)
	}
# return residuals in the vector x
call daxpy(n,mone,w,1,z,1)
call dswap(n,z,1,x,1)
return
end
subroutine stepy(n,p,a,d,b,ada,info)
integer n,p,pp,i,info
double precision a(p,n),b(p),d(n),ada(p,p),zero
parameter( zero = 0.0d0)
# Solve the linear system ada'x=b by Choleski -- d is diagonal
# Note that a isn't altered, and on output ada returns the upper
# triangle Choleski factor, which can be reused, eg with blas dtrtrs
pp=p*p
do j=1,p
	do k=1,p
		ada(j,k)=zero
do i=1,n
	call dsyr('U',p,d(i),a(1,i),1,ada,p)
call dposv('U',p,1,ada,p,b,p,info)
return
end


# ......................................................................................
# ........................Cvičení 3 - Diskrétní náhodná veličina........................
# ..................Martina Litschmannová, Adéla Vrtková, Michal Béreš..................
# ......................................................................................

# Nezobrazuje-li se vám text korektně, nastavte File \ Reopen with Encoding... na UTF-8
# Pro zobrazení obsahu skriptu použijte CTRL+SHIFT+O
# Pro spouštění příkazů v jednotlivých řádcích použijte CTRL+ENTER

#  Příklady ####
# * Příklad 1. ####
# Majitel servisního střediska nabídl prodejně automobilů, která si zřídila autopůjčovnu
# své
# služby. Za každý automobil zapůjčený jeho prostřednictvím obdrží od autopůjčovny 500,-
# Kč.
# Zároveň se však zavázal, že každý den investuje do údržby zapůjčených automobilů 800,-
# Kč.
# Počet automobilů zapůjčených prostřednictvím servisního střediska za 1 den je popsán
# následující pravděpodobnostní funkcí:
# Obrázek viz sbírka úloh.
# ** 1. a) ####
# Hodnota pravděpodobnostní funkce pro 5 automobilů byla špatně čitelná. Určete ji:

x = c(0,1,2,3,4,5,6)
p = c(0.01,0.40,0.25,0.15,0.10,0,0.03)
1 - sum(p) # počítačová aritmetika zde může zlobit
round(1 - sum(p), digits=2) # zaokrouhlíme na setiny
p[6] = round(1 - sum(p), digits=2) # zápis pro x=5 je 6-tá pozice
p

plot(x, p)

plot(x, p, type="h")

# Začínáme s grafikou -> graf dále upravujeme - používáme další parametry
plot(x, p,
     ylim=c(0,0.5),                    # parametr pro rozsah osy y
     ylab="p(x)",                      # parametr pro popis osy y
     main="Pravděpodobnostní funkce",  # parametr pro název grafu
     type="p",                         # určuje o jaký typ grafu se jedná (p -> points, bodový)
     pch=19,                           # parametr pro vzhled zobrazovaných bodů
     col=c("blue","red","green"),      # barvy
     cex=2,                            # parametr pro upravení velikosti celého grafu (ve smyslu zvětší 2x)
     cex.lab=1.3,                      # parametr zvlášť pro velikost názvů os
     cex.axis=1.3,                     # parametr zvlášť pro velikost hodnot na osách
     cex.main=1.3)                     # parametr pro velikost názvu grafu

text(0.5,0.0,"X ... počet zapůjčených automobilů", cex=1.3, col="blue", adj=c(0,0))

# Pravděpodobnostní funkce
pravd.f = function(x,p){
    plot(x, p, # plná kolečka - v skutečných hodnotách
        ylab='p(x)',xaxt='n',pch=19,ylim=c(0,max(p)),main="Pravdepodobnostni funkce")
    lines(c(min(x)-100,max(x)+100),c(0, 0))
    for(i in 1:length(x)){
        lines(c(min(x)-100,max(x)+100), c(p[i],p[i]),
              type = 'l', lty = 3, lwd=0.5) # horizontální grid
        lines(c(x[i],x[i]), c(-0.1,1.1),
              type = 'l', lty = 3, lwd=0.5) # vertikální grid
    }
    par(new=TRUE) # že chceme kreslit do jednoho grafu
    plot(x, p*0, # prázdná kolečka - tam kde je definovaná nenulová hodnota
        ylab='p(x)', xaxt='n', ylim=c(0,max(p)))
    axis(1, at=x,labels=x) # nastavení hodnot na X
    axis(4, at=p,labels=p, las=2, cex.axis=0.7, tck=-.01) # a Y
}

pravd.f(x, p)

#  Poznámky k úvodu do grafiky
#  základem jsou tzv. high-level funkce, které vytvoří graf (tj. otevřou grafické okno a
# vykreslí dle zadaných parametrů)
#  na ně navazují tzv. low-level funkce, které něco do aktviního grafického okna
# přidají, samy o sobě neotevřou nové
#  výše použitá funkce "text" je low-level funkce - přidá text do stávajícího aktivního
# grafického okna
#  další low-level funkce - např. abline, points, lines, legend, title, axis ... které
# přidají přímku, body, legendu...
#  tzn. před použitím "low-level" funkce je potřeba, volat "high-level" funkci (např.
# plot, boxplot, hist, barplot, pie,...)
#
#  další grafické parametry naleznete v nápovědě
#  nebo např. zde http://www.statmethods.net/advgraphs/parameters.html
#  nebo zde https://flowingdata.com/2015/03/17/r-cheat-sheet-for-graphical-parameters/
#  nebo http://bcb.dfci.harvard.edu/~aedin/courses/BiocDec2011/2.Plotting.pdf

# ** 1. b) ####
# Určete a zakreslete distribuční funkci náhodné veličiny X, která je definována jako
# počet
# zapůjčených automobilů.

p
F = cumsum(p)
F

plot(x, F, type="s") # zjednodušený graf distribuční funkce

# Funkce pro výpočet a vykreslení distribuční funkce
dist.f = function(x,p){
    F = cumsum(p)
    F_ext = c(0, F) # natáhneme F o 0 na začátku
    x_ext = c(x[1]-1, x, x[length(x)]+1) # a x z obou stran

    plot(x, F, ylab="F(x)", xaxt='n', ylim=c(0,1), # prazdná kolečka
         type='p', main="Distribucni funkce")
    par(new=TRUE) # že chceme kreslit do jednoho grafu
    plot(x, F_ext[1:(length(F_ext)-1)], # plná kolečka
         ylab="F(x)", xaxt='n', ylim=c(0,1), type='p', pch=19)

    for(i in 1:(length(x_ext)-1)){
        lines(c(min(x)-100,max(x)+100), c(F_ext[i],F_ext[i]),
              type = 'l', lty = 3, lwd=0.5) # horizontální grid
        lines(c(x_ext[i],x_ext[i]), c(-0.1,1.1),
              type = 'l', lty = 3, lwd=0.5) # vertikální grid
        lines(x_ext[i:(i+1)], c(F_ext[i],F_ext[i])) # graf - čáry
    }
    axis(1, at=x,labels=x) # nastavení hodnot na X
    axis(4, at=F,labels=F, las=2, cex.axis=0.7, tck=-.01) # a Y
    return(F)
}

dist.f(x,p)

# ** 1. c)  ####
# Určete střední hodnotu, rozptyl, směrodatnou odchylku a modus počtu zapůjčených
# automobilů během jednoho dne.

# Střední hodnota
x*p
EX = sum(x*p)
EX

# Rozptyl
EX2 = sum(x*x*p)  # druhý obecný moment
DX = EX2 - EX^2
DX

# Směrodatná odchylka
sigma.X = sqrt(DX)
sigma.X

# Funkce pro výpočet základních číselných charakteristik
souhrn=function(x,p){
  EX = sum(x*p)
  EX2 = sum(x*x*p)
  DX = EX2-EX^2
  sigma.X = sqrt(DX)
  # zápis výsledků do tabulky
  tab = rbind(EX, DX, sigma.X)
  tab.popis = c("str. hodnota","rozptyl","smer. odchylka")
  rownames(tab) = tab.popis
  return(tab)
}

souhrn(x, p)

# ** 1. d) ####
# Určete pravděpodobnostní funkci a distribuční funkci náhodné veličiny Y, která je
# definována jako denní příjem majitele servisu.

y = 500*x
y

pravd.f(y, p)

# Distribuční funkce
dist.f(y,p)

# ** 1. e)  ####
# Určete střední hodnotu, směrodatnou odchylku a modus příjmu majitele servisu ze
# zapůjčených automobilů během jednoho dne.

souhrn(y,p)

# ** 1. f)  ####
# Určete pravděpodobnost, že příjem majitele servisu (náhodná veličina Y) z půjčování
# automobilů převýší jeho výdaje.

# zisk
z=500*x-800
z

# příjem převýší výdaje, když je zisk kladný
z > 0

p
sum(p[z>0])

# ** 1. g)  ####
# Určete střední hodnotu, směrodatnou odchylku a modus náhodné veličiny Z, která je
# definována jako zisk majitele servisu ze zapůjčených automobilů během jednoho dne.

souhrn(z, p)

# * Příklad č. 2 ####
# Pro distribuční funkci náhodné veličiny X platí:
#
# $F(x)=\begin{cases}
# 0   &      x \leq -1 \\
# 0.3 & -1 < x \leq  0 \\
# 0.7 &  0 < x \leq  1 \\
# 1   & -1 < x
# \end{cases}$
#
# ** 2. a)  ####
# Určete pravděpodobnostní funkci náhodné veličiny X, její střední hodnotu a směrodatnou
# odchylku.

F = c(0, 0.3, 0.7, 1)
F
x = c(-1,0,1)
x

diff(F)

p = diff(F)
x
p

pravd.f(x,p)

dist.f(x,p)

souhrn(x,p)

# ** 2. b)  ####
# Náhodná veličina Y = 1 − 3X, určete P(y), F(y), E(Y), D(Y).

y = 1 - 3*x
pravd.f(y,p)

dist.f(y,p)   # Nesmyslný výstup - čím je to způsobeno?
y
p

y
sort(y)
idx_sorted = order(y) # funkce order vrátí indexy setřízeného pořadí
idx_sorted
y = y[idx_sorted]
p_y = p[idx_sorted]
p_y

dist.f(y,p_y)

souhrn(y, p_y)

# ** 2. c)  ####
# Náhodná veličina W = $3X^2$, určete P(w), F(w), E(W), D(W).

w = 3*x*x
w

pravd.f(w,p)
dist.f(w,p)

w
w_uniq = unique(w)
w_uniq
w_sorted = sort(w_uniq)
w_sorted

p_w = w_sorted*0 # inicializace pole o stejné velikosti
for(i in 1:length(w_sorted)){
    p_w[i] = sum(p[w == w_sorted[i]])
}
p_w

pravd.f(w_sorted,p_w)
dist.f(w_sorted,p_w)
souhrn(w_sorted,p_w)

# * Příklad 3. ####
# V dílně jsou dva stroje pracující nezávisle na sobě. Pravděpodobnost poruchy prvního
# stroje
# je 0,2, pravděpodobnost poruchy druhého stroje je 0,3. Náhodná veličina X je
# definována jako
# počet současně porouchaných strojů. Určete:
# ** 3. a)  ####
# pravděpodobnostní funkci náhodné veličiny X,

x = c(0, 1, 2)
x
p1 = 0.2
p2 = 0.3

p = x*0
# spočteme jednotlivé pravděpodobnosti počtu porouchaných strojů
p[1] = (1 - p1)*(1 - p2) # 0 porouchaných tedy oba v provozu
p[3] = p1*p2 # 2 tedy porouchané oba
p
1 - sum(p)
p[2] = (1 - p1)*p2 + p1*(1 - p2) # právě jeden - buď první nebo druhý
p

sum(p)

pravd.f(x,p)

# ** 3. b) ####
# distribuční funkci náhodné veličiny X,

dist.f(x,p)

# ** 3. c) ####
# střední hodnotu a rozptyl náhodné veličiny X.

souhrn(x,p)


#' @title
#' Nested reduced-rank regression with given ranks
#'
#' @description
#' This function implements the blockwise coordinate descent algorithm
#' to get the nested reduced-rank regression estimator with
#' given rank values \code{(r, rx, ry)}.
#'
#' @usage
#' NRRR.est(Y, X, Ag0 = NULL, Bg0 = NULL,
#'          rini, r, rx, ry, jx, jy, p, d, n,
#'          maxiter = 100, conv = 1e-4,
#'          method = c("RRR", "RRS")[1], lambda = 0)
#'
#'
#' @param Y response matrix of dimension n-by-jy*d.
#' @param X design matrix of dimension n-by-jx*p.
#' @param Ag0 an initial estimator of matrix U. If \code{Ag0 = NULL} then generate it
#'            by \code{\link{NRRR.ini}}. Default is NULL.
#' @param Bg0 an initial estimator of matrix V. If \code{Bg0 = NULL} then generate it
#'            by \code{\link{NRRR.ini}}. Default is NULL.
#' @param rini,r rank of the local reduced-rank structure. \code{rini} is used
#'               in \code{\link{NRRR.ini}} to get the initial
#'               estimators of U and V.
#' @param rx number of latent predictors.
#' @param ry number of latent responses.
#' @param jx number of basis functions to expand the functional predictor.
#' @param jy number of basis functions to expand the functional response.
#' @param p number of predictors.
#' @param d number of responses.
#' @param n sample size.
#' @param maxiter the maximum iteration number of the
#'                blockwise coordinate descent algorithm. Default is 100.
#' @param conv the tolerance level used to control the convergence of the
#'             blockwise coordinate descent algorithm. Default is 1e-4.
#' @param method 'RRR' (default): no additional ridge penalty; 'RRS': add an
#'               additional ridge penalty.
#' @param lambda the tuning parameter to control the amount of ridge
#'               penalization. It is only used when \code{method = 'RRS'} and
#'               a positive value should be provided.
#'               Default is 0.
#'
#' @return The function returns a list:
#'   \item{Ag}{the estimated U.}
#'   \item{Bg}{the estimated V.}
#'   \item{Al}{the estimated A.}
#'   \item{Bl}{the estimated B.}
#'   \item{C}{the estimated coefficient matrix C.}
#'   \item{df}{degrees of freedom of the model.}
#'   \item{sse}{sum of squared errors.}
#'   \item{ic}{a vector containing values of BIC, BICP, AIC, GCV.}
#   \item{obj}{a vector contains all objective function (sse) values along iteration.}
#'   \item{iter}{the number of iterations needed to converge.}
#'
#' @details
#' The \emph{nested reduced-rank regression (NRRR)} is proposed to solve
#' a multivariate functional linear regression problem where both the response and
#' predictor are multivariate and functional (i.e., \eqn{Y(t)=(y_1(t),...,y_d(t))^T}
#' and \eqn{X(s)=(x_1(s),...,y_p(s))^T}). To control the complexity of the
#' problem, NRRR imposes a nested reduced-rank structure on the regression
#' surface \eqn{C(s,t)}. Specifically, a global dimension reduction makes use of the
#' correlation within the components of multivariate response and multivariate
#' predictor. Matrices U (d-by-ry) and V (p-by-rx) provide weights to form ry latent
#' functional responses and rx latent functional predictors, respectively.
#' Dimension reduction is achieved
#' once \eqn{ry < d} or \eqn{rx < p}. Then, a local dimension reduction is
#' conducted by restricting the latent regression surface \eqn{C^*(s,t)} to be of low-rank.
#' After basis expansion and truncation, also by applying proper rearrangement to
#' columns and rows of the resulting data matrices and coefficient matrices, we
#' have the nested reduced-rank problem:
#' \deqn{ \min_{C} || Y - XC ||_F^2, s.t., C = (I_{jx} \otimes V) BA^T (I_{jy} \otimes U)^T,}
#' where \eqn{BA^T} is a full-rank decomposition to control the local
#' rank and \eqn{jx, jy} are the number of basis functions. Beyond the functional
#' setup, this structure can also be applied to multiple scenarios, including
#' multivariate time series autoregression analysis and tensor-on-tensor regression.
#' This problem is non-convex and has no explicit solution, thus we use a
#' blockwise coordinate descent algorithm to find a local solution. The convergence
#' is decided by the change in objective values between two neighboring iterations.
#'
#'
#'
#'
#'
#' @references Liu, X., Ma, S., & Chen, K. (2020).
#' Multivariate Functional Regression via Nested Reduced-Rank Regularization.
#' arXiv: Methodology.
#' @examples
#' library(NRRR)
#' simDat <- NRRR.sim(n = 100, ns = 200, nt = 200, r = 5, rx = 3, ry = 3,
#'                    jx = 15, jy = 15, p = 10, d = 6, s2n = 1, rho_X = 0.5,
#'                    rho_E = 0, Sigma = "CorrAR")
#' fit_init <- with(simDat, NRRR.est(Y = Yest, X = Xest,
#'                  Ag0 = NULL, Bg0 = NULL, rini = 5, r = 5,
#'                  rx = 3, ry = 3, jx = 15, jy = 15,
#'                  p = 10, d = 6, n = 100))
#' fit_init$Ag
#' @importFrom MASS ginv
#' @export
NRRR.est <- function(Y, X, Ag0 = NULL, Bg0 = NULL, rini, r, rx, ry, jx, jy, p, d, n,
                    maxiter = 100, conv = 1e-4,
                    method = c("RRR", "RRS")[1], lambda = 0) {
  if (rini == 0) stop("rini cannot be 0")
  if (r == 0) stop("r cannot be 0")
  if(p < rx) stop("rx cannot be greater than p")
  if(d < ry) stop("ry cannot be greater than d")

  if (method == "RRS" & lambda != 0) { # RRS is reduced rank ridge regression.
    Y <- rbind(Y, matrix(nrow = p * jx, ncol = d * jy, 0.0))
    X <- rbind(X, sqrt(lambda) * diag(nrow = p * jx, ncol = p * jx))
    n <- n + p * jx
  }

  # require(rrpack)
  # compute initial values of U and V
  if (is.null(Ag0) | is.null(Bg0)) {
    ini <- NRRR.ini(Y, X, rini, rx, ry, jx, jy, p, d, n)
    Ag0 <- ini$Ag
    Bg0 <- ini$Bg
  }

  if (d == ry) {
    Yl0 <- Y
  } else {
    Yl0 <- Y %*% kronecker(diag(jy), Ag0)
  }
  if (p == rx) {
    Xl0 <- X
  } else {
    Xl0 <- X %*% kronecker(diag(jx), Bg0)
  }

  # Given Ag (U) and Bg (V), compute Al and Bl
  if (r > min(dim(Yl0)[2])) stop("r cannot be greater than jy*ry")
  fitRR <- RRR(Yl0, Xl0, nrank = r)
  Bl0 <- fitRR$C_ls %*% fitRR$A
  Al0 <- fitRR$A

  obj <- vector() # collect all objective function (sse) values
  obj[1] <- Obj(Y, X, Ag0, Bg0, Al0, Bl0, jx, jy)$obj
  objnow <- obj[1] + 10
  iter <- 1
  while (iter < maxiter & abs(obj[iter] - objnow) > conv) { # use sse to control convergence.

    ### For updating Ag (U)###
    if (d == ry) {
      Ag1 <- diag(nrow = ry, ncol = ry) # an identity matrix
      Yl0 <- Y
    } else {
      Xg <- Xl0 %*% Bl0 %*% t(Al0)
      Yg0 <- matrix(nrow = d, ncol = ry, 0)
      for (j in 1:jy) {
        a1 <- d * (j - 1) + 1
        b1 <- d * j

        a2 <- ry * (j - 1) + 1
        b2 <- ry * j

        Yg0 <- Yg0 + t(Y[, a1:b1]) %*% (Xg[, a2:b2])
      }
      svdYg0 <- svd(Yg0)
      Ag1 <- svdYg0$u %*% t(svdYg0$v)
      Yl0 <- Y %*% kronecker(diag(jy), Ag1)
    }

    ### For updating Bg (V)###
    if (p == rx) {
      Bg1 <- diag(nrow = rx, ncol = rx)
      Xl0 <- X
    } else {
      yB <- as.vector(Yl0 %*% Al0)
      XB <- matrix(nrow = n * r, ncol = rx * p, 0)
      for (j in 1:jx) {
        a1 <- rx * (j - 1) + 1
        b1 <- rx * j

        a2 <- p * (j - 1) + 1
        b2 <- p * j

        XB <- XB + kronecker(matrix(t(Bl0)[, a1:b1], nrow = r, ncol = rx), X[, a2:b2])
      }
      Bg1 <- matrix(nrow = p, ncol = rx, byrow = FALSE, MASS::ginv(t(XB) %*% XB +
                   0.0000001 * diag(1, rx * p, rx * p)) %*% t(XB) %*% yB)

      Bg1 <- qr.Q(qr(Bg1))
      Xl0 <- X %*% kronecker(diag(jx), Bg1)
    }

    ### For updating Al (A) and Bl (B)###
    fitRR <- RRR(Yl0, Xl0, nrank = r)
    Bl1 <- fitRR$C_ls %*% fitRR$A
    Al1 <- fitRR$A

    iter <- iter + 1
    Objiter <- Obj(Y, X, Ag1, Bg1, Al1, Bl1, jx, jy)
    obj[iter] <- Objiter$obj
    objnow <- obj[iter - 1]
    C <- Objiter$C

    Al0 <- Al1
    Bl0 <- Bl1
    Ag0 <- Ag1
    Bg0 <- Bg1
  }

  # compute rank of X
  xr <- sum(svd(X)$d > 1e-2)
  # compute degrees of freedom of NRRR
  df <- ifelse(xr / jx > rx, rx * (xr / jx - rx), 0) + ry * (d - ry) + (jy * ry + jx * rx - r) * r
  # obtain sse
  sse <- ifelse(Objiter$sse < 0.1, 0, Objiter$sse)
  # compute information criterion
  BIC <- log(sse) + log(d * jy * n) / d / jy / n * df
  BICP <- log(sse) + 2 * log(d * jy * p * jx) / d / jy / n * df
  AIC <- log(sse) + 2 / d / jy / n * df
  GCV <- sse / d / jy / n / (1 - df / d / jy / n)^2

  if (method == "RRS") sse <- sse - lambda * sum(Objiter$C^2)

  # if (!quietly) {
  #   cat("SSE = ", sse, "DF = ", df, "\n", sep = "")
  # }
  return(list(
    Ag = Ag1, Bg = Bg1, Al = as.matrix(Al1), Bl = as.matrix(Bl1), C = C, df = df,
    sse = sse, ic = c(BIC, BICP, AIC, GCV), obj = obj, iter = iter
  ))
}


# Day 9: Smoke Basin

get_day9_input_path <- function() {
    paste(getwd(), "/2021/Day 9/Day9_input.txt", sep = "")
}

part1 <- function() {
    readings <- readLines(get_day9_input_path())

    basin_rows <- length(readings)
    basin_cols <- nchar(readings[1])
    basin <- matrix(ncol = basin_cols)[-1, ]

    for (i in seq_len(length(readings))) {
        basin <- rbind(basin, strtoi(unlist(strsplit(readings[i], ""))))
    }

    total_risk_level <- 0

    for (r in seq_len(basin_rows)) {
        for (c in seq_len(basin_cols)) {
            total_risk_level <- total_risk_level +
                calc_risk_level(basin, r, c, basin_rows, basin_cols)
        }
    }

    print(total_risk_level)
}

part2 <- function() {
    readings <- readLines(get_day9_input_path())

    basin_rows <- length(readings)
    basin_cols <- nchar(readings[1])
    basin <- matrix(ncol = basin_cols)[-1, ]
    low_points <- matrix(ncol = 2)[-1, ]
    basin_sizes <- c()

    for (i in seq_len(length(readings))) {
        basin <- rbind(basin, strtoi(unlist(strsplit(readings[i], ""))))
    }

    for (r in seq_len(basin_rows)) {
        for (c in seq_len(basin_cols)) {
            if (calc_risk_level(basin, r, c, basin_rows, basin_cols) > 0) {
                low_points <- rbind(low_points, c(r, c))
            }
        }
    }

    for (i in seq_len(length(low_points) / 2)) {
        # Sprawl from low points to make basins
        ind_basin <- get_basin_from_low_point(
                        basin,
                        low_points[i, 1],
                        low_points[i, 2],
                        basin_rows,
                        basin_cols)

        # Get size of individual basin
        ind_basin_size <- length(ind_basin) / 2
        basin_sizes <- append(basin_sizes, ind_basin_size)
    }

    basin_sizes <- sort(basin_sizes, decreasing = TRUE)

    # Multiply sizes of 3 largest basins
    print(prod(basin_sizes[1:3]))
}

calc_risk_level <- function(basin, row, col, max_row, max_col) {
    point_val <- basin[row, col]
    risk_level <- 0
    adj_point_vals <- c()

    # Up Value
    if (row > 1) {
        adj_point_vals <- append(adj_point_vals, basin[row - 1, col])
    }

    # Down Value
    if (row < max_row) {
        adj_point_vals <- append(adj_point_vals, basin[row + 1, col])
    }

    # Left Value
    if (col > 1) {
        adj_point_vals <- append(adj_point_vals, basin[row, col - 1])
    }

    # Right Value
    if (col < max_col) {
        adj_point_vals <- append(adj_point_vals, basin[row, col + 1])
    }

    if (sum(adj_point_vals > point_val) == length(adj_point_vals)) {
        risk_level <- point_val + 1
    }

    risk_level
}

get_basin_from_low_point <- function(basin, row, col, max_row, max_col) {
    basin_points <- matrix(ncol = 2)[-1, ]
    new_points <- matrix(ncol = 2)[-1, ]

    basin_points <- rbind(basin_points, c(row, col))
    new_points <- rbind(new_points, c(row, col))

    while (length(new_points) > 0) {
        adj_points <- get_adj_points(basin,
                                    new_points[1, 1],
                                    new_points[1, 2],
                                    max_row, max_col)
        new_points <- new_points[-1, ]
        new_points <- rbind(new_points)

        for (i in seq_len(length(adj_points) / 2)) {
            adj_point_r <- adj_points[i, 1]
            adj_point_c <- adj_points[i, 2]
            point_val <- basin[adj_point_r, adj_point_c]
            if (point_val < 9) {
                match <- FALSE
                for (p in seq_len(length(basin_points) / 2)) {
                    match <- (basin_points[p, 1] == adj_point_r &&
                                basin_points[p, 2] == adj_point_c)
                    if (match) break
                }

                if (!match) {
                    basin_points <- rbind(basin_points,
                                        c(adj_point_r, adj_point_c))
                    new_points <- rbind(new_points,
                                        c(adj_point_r, adj_point_c))
                }
            }
        }
    }
    basin_points
}

get_adj_points <- function(basin, row, col, max_row, max_col) {
    adj_points <- matrix(ncol = 2)[-1, ]

    # Up Value
    if (row > 1) {
        adj_points <- rbind(adj_points, c(row - 1, col))
    }

    # Down Value
    if (row < max_row) {
        adj_points <- rbind(adj_points, c(row + 1, col))
    }

    # Left Value
    if (col > 1) {
        adj_points <- rbind(adj_points, c(row, col - 1))
    }

    # Right Value
    if (col < max_col) {
        adj_points <- rbind(adj_points, c(row, col + 1))
    }

    adj_points
}

part1()
part2()


subroutine collincheck(nadj,madj,npts,x,y,ntot,eps)

# Collinearity check --- experimental.  Runs through the adjacency
# list to see if any of the putative triangles in the triangulation
# that has so far been created are "degenerate", i.e. are actually
# just three points lying on a straight line.

implicit double precision(a-h,o-z)
dimension x(-3:ntot), y(-3:ntot)
dimension nadj(-3:ntot,0:madj)
logical collin, changed

nerror  = -1
changed = .false.
repeat {
    do j = 1,npts {
       nj = nadj(j,0)
       do k = 1,nj {
           k1 = nadj(j,k)
           call succ(k2,j,k1,nadj,madj,ntot,nerror)
           if(nerror > 0) {
               call intpr("Error number =",-1,nerror,1)
               call rexit("Error in succ, called from collincheck.")
           }

# Check whether triangle j, k1, k2 is really a triangle.
           call crossutil(j,k1,k2,x,y,ntot,eps,collin)

# If collinear, remove the triangle from the mix.
           if(collin) {
               changed = .true.
# First determine which of k1 and k2 is closer to j.  It
# *should* be k1, but y'never know in these chaotic
# circumstances.
           sd1 = (x(k1) - x(j))**2 + (y(k1) - y(j))**2
           sd2 = (x(k2) - x(j))**2 + (y(k2) - y(j))**2
           if(sd1 < sd2) {
               kr = k2
           } else {
               kr = k1
           }
# Delete kr ("r" for "remove") from the adjacency list of j and j
# from the adjacency list of kr.
               call delet(j,kr,nadj,madj,ntot,nerror)
               if(nerror > 0) {
                   call intpr("Error number =",-1,nerror,1)
                   call rexit("Error in collincheck.")
               }
               break
           }
       }
       if(changed) break
    }
}
until(!changed)
return
end


# 4. faza: Napredna analiza podatkov

source("lib/libraries.r")

################################################################################
# RAZVRŠČANJE V SKUPINE -
# Razvrščanje držav v skupine glede na to, kakšne rezultate dosegajo

### Najprej k-means:

# Tabela s podatki o državah:
# | država | točke DH | točke SG | točke GS | točke SL | povprečen YB |

# Najprej spremenimo kratice držav, da lahko združimo z zemljevidom
prave.kratice <- REZULTATI.VREME %>%
  mutate(NSA = str_replace_all(REZULTATI.VREME$NSA, pattern = "SLO", replacement = "SVN"))
prave.kratice <- prave.kratice %>%
  mutate(NSA = str_replace_all(prave.kratice$NSA, pattern = "GER", replacement = "DEU"))
prave.kratice <- prave.kratice %>%
  mutate(NSA = str_replace_all(prave.kratice$NSA, pattern = "CRO", replacement = "HRV"))
prave.kratice <- prave.kratice %>%
  mutate(NSA = str_replace_all(prave.kratice$NSA, pattern = "SUI", replacement = "CHE"))
prave.kratice <- prave.kratice %>%
  mutate(NSA = str_replace_all(prave.kratice$NSA, pattern = "NED", replacement = "NLD"))
prave.kratice <- prave.kratice %>%
  mutate(NSA = str_replace_all(prave.kratice$NSA, pattern = "BUL", replacement = "BGR"))
prave.kratice <- prave.kratice %>%
  mutate(NSA = str_replace_all(prave.kratice$NSA, pattern = "GRE", replacement = "GRC"))
prave.kratice <- prave.kratice %>%
  mutate(NSA = str_replace_all(prave.kratice$NSA, pattern = "MON", replacement = "MCO"))
prave.kratice <- prave.kratice %>%
  mutate(NSA = str_replace_all(prave.kratice$NSA, pattern = "RSF", replacement = "RUS"))
prave.kratice

DH.analiza <- prave.kratice %>% filter(Disciplina == "DH") %>% group_by(NSA) %>%
  summarise(tocke.DH = sum(tocke_30))
SG.analiza <- prave.kratice %>% filter(Disciplina == "SG") %>% group_by(NSA) %>%
  summarise(tocke.SG = sum(tocke_30))
GS.analiza <- prave.kratice %>% filter(Disciplina == "GS") %>% group_by(NSA) %>%
  summarise(tocke.GS = sum(tocke_30))
SL.analiza <- prave.kratice %>% filter(Disciplina == "SL") %>% group_by(NSA) %>%
  summarise(tocke.SL = sum(tocke_30))
YB.analiza <- prave.kratice %>% group_by(NSA) %>% summarise(YB.povprecen = mean(YB))

drzave <- left_join(prave.kratice, DH.analiza, by = "NSA")
drzave <- left_join(drzave, SG.analiza, by = "NSA")
drzave <- left_join(drzave, GS.analiza, by = "NSA")
drzave <- left_join(drzave, SL.analiza, by = "NSA")
drzave <- left_join(drzave, YB.analiza, by = "NSA")

drzave <- drzave %>%
  dplyr::select(YB.povprecen, NSA, tocke.DH, tocke.SG, tocke.GS, tocke.SL)

drzave$tocke.DH[is.na(drzave$tocke.DH)] <- 0
drzave$tocke.SG[is.na(drzave$tocke.SG)] <- 0
drzave$tocke.GS[is.na(drzave$tocke.GS)] <- 0
drzave$tocke.SL[is.na(drzave$tocke.SL)] <- 0
drzave <- unique(drzave)

# Clustering s k-means
set.seed(123)

skupine <- drzave[,-2] %>%
  kmeans(centers = 5) %>%
  getElement("cluster") %>%
  as.ordered()
print(skupine)

tabela.skupine <- drzave %>%
  transform(NSA = as.factor(NSA)) %>%
  mutate(Skupine = as.numeric(skupine))

zemljevid.za.skupine <-
  uvozi.zemljevid(
    "http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/50m/cultural/ne_50m_admin_0_countries.zip",
    "ne_50m_admin_0_countries",
    mapa = "zemljevidi",
    pot.zemljevida = "",
    encoding = "UTF-8"
  ) %>%
  fortify() %>% filter(long < 170 & long > -170 & lat > 0 & lat < 85)

zemljevid.po.skupinah <- ggplot() +
  aes(x = long, y = lat, group = group, fill = Skupine) +
  geom_polygon(data=tabela.skupine %>% right_join(zemljevid.za.skupine,
                                                  by = c("NSA" = "ADM0_A3"))) +
  xlab("") +
  ylab("") +
  ggtitle("Države s podobno strukturo smučarjev 2020/21") +
  coord_fixed(ratio = 2) +
  guides(fill=guide_legend(title="Skupina")) +
  theme(legend.title = element_text(color = "black", size = 11),
        legend.background = element_rect(colour ="#006699", fill = "white"),
        plot.title = element_text(color = "#006699", hjust = 0.5, size = 15))
zemljevid.po.skupinah

### Še hierarhično razvrščanje:
dendrogram <- drzave[,-2] %>%
  dist() %>%
  hclust()

plot(dendrogram,
     labels = drzave$NSA,
     ylab = "višina",
     main = NULL)

hc.kolena <- function(dendrogram, od = 1, do = NULL, eps = 0.5) {
  # število primerov in nastavitev parametra do
  n = length(dendrogram$height) + 1
  if (is.null(do)) {
    do = n - 1
  }
  k.visina = tibble(
    k = as.ordered(od:do),
    visina = dendrogram$height[do:od]
  ) %>%
    mutate(
      dvisina = visina - lag(visina)
    ) %>%
    mutate(
      koleno = lead(dvisina) - dvisina > eps
    )
  k.visina
}

# iz tabele k.visina vrne seznam vrednosti k, pri katerih opazujemo koleno
hc.kolena.k <- function(k.visina) {
  k.visina %>%
    filter(koleno) %>%
    dplyr::select(k) %>%
    unlist() %>%
    as.character() %>%
    as.integer()
}

# tabela s koleni za dendrogram
r <- hc.kolena(dendrogram)

diagram.kolena <- function(k.visina) {
  k.visina %>% ggplot() +
    geom_point(
      mapping = aes(x = k, y = visina),
      color = "red"
    ) +
    geom_line(
      mapping = aes(x = as.integer(k), y = visina),
      color = "red"
    ) +
    geom_point(
      data = k.visina %>% filter(koleno),
      mapping = aes(x = k, y = visina),
      color = "#006699", size = 2
    ) +
    ggtitle(paste("Kolena:", paste(hc.kolena.k(k.visina), collapse = ", "))) +
    xlab("število skupin (k)") +
    ylab("razdalja pri združevanju skupin") +
    theme_classic()
}

diagram.kolena(r)

################################################################################
# NAPOVEDNI MODEL
# Napovemo uvrstitev, ki jo pričakujemo od smučarja glede na to, katere smuči uporablja,
# v kateri disciplini tekmuje in glede na snežno podlago

# spemenimo imenske spremenljivke v numerične
one_hot = function(pod, spr) {
  domena = pod %>%
    dplyr::select({{spr}}) %>%
    unlist() %>%
    unique()
  for (v in domena) {
    pod = pod %>%
      mutate(
        "{{spr}}.{v}" := ifelse({{spr}} == v, 1, 0)
      )
  }
  pod %>% dplyr::select(-{{spr}})
}

smuci <- levels(REZULTATI.VREME$Ski)[-c(9)]

# Podatki, na katerih bom delala napovedi:
podatki <- REZULTATI.VREME %>%
  dplyr::select(Rank, Ski, Disciplina, sneg) %>%
  filter(Ski %in% smuci) %>%
  one_hot(Ski) %>% one_hot(Disciplina) %>% one_hot(sneg)

set.seed(123)
# linearna regresija, da napovemo uvrstitve tekmovalca glede na:
# smuči (1. MODEL)
lin.reg.smuci = lm(
  Rank ~ Ski.Atomic + Ski.Fischer + Ski.Head + Ski.Kaestle + Ski.Nordica + Ski.Rossignol +
    Ski.Salomon + Ski.Stoeckli + Ski.Voelkl + Ski.Dynastar + Ski.Blizzard,
  data = podatki)
print(lin.reg.smuci)

# smuči in disciplino (2.MODEL)
lin.reg.smuci.disc = lm(
  Rank ~  Disciplina.DH + Disciplina.SG + Disciplina.GS + Disciplina.SL +
    Ski.Atomic + Ski.Fischer + Ski.Head + Ski.Kaestle + Ski.Nordica + Ski.Rossignol +
    Ski.Salomon + Ski.Stoeckli  + Ski.Dynastar + Ski.Voelkl+ Ski.Blizzard,
  data = podatki)
print(lin.reg.smuci.disc)

# smuči in snežno podlago (3. MODEL)
lin.reg.smuci.sneg = lm(
  Rank ~ Ski.Atomic + Ski.Fischer + Ski.Head + Ski.Kaestle + Ski.Nordica + Ski.Rossignol +
    Ski.Salomon + Ski.Stoeckli + Ski.Blizzard + Ski.Dynastar + Ski.Voelkl + sneg.HARD +
    `sneg.SPRING CONDITIONS` + sneg.COMPACT + sneg.SOFT + sneg.PACKED,
  data = podatki)
print(lin.reg.smuci.sneg)

# Še model, ki vključuje tako smuči kot tudi disciplino in snežno podlago (4. MODEL):
lin.reg.skupaj = lm(
  Rank ~ Ski.Atomic + Ski.Fischer + Ski.Head + Ski.Kaestle + Ski.Nordica + Ski.Rossignol +
    Ski.Salomon + Ski.Stoeckli + Ski.Blizzard + Ski.Dynastar + Ski.Voelkl +
    Disciplina.DH + Disciplina.SG + Disciplina.GS + Disciplina.SL + sneg.HARD +
    `sneg.SPRING CONDITIONS` + sneg.COMPACT + sneg.SOFT + sneg.PACKED,
  data = podatki)
print(lin.reg.skupaj)

# prečno preverjanje
napaka.cv <- function(podatki, formula, k) {
  set.seed(123)
  n <- nrow(podatki)
  # naključno premešamo primere
  r <- sample(1:n)
  # razrez na k intervalov
  razrez <- cut(seq_along(r), k, labels = FALSE)
  # razbijemo vektor na k seznamov na osnovi razreza intervalov
  razbitje = split(r, razrez)
  # zdaj imamo dane indekse za vsakega od k-tih delov
  pp.napovedi = rep(0, nrow(podatki))
  # prečno preverjanje
  for (i in 1:length(razbitje)) {
    train.data = podatki[-razbitje[[i]],]  # učni podatki
    test.data = podatki[razbitje[[i]],]    # testni podatki
    # naučimo model
    model = lm(data = train.data, formula = formula)
    # napovemo za testne podatke
    napovedi = predict(model, newdata = test.data)
    pp.napovedi[razbitje[[i]]] = napovedi
  }
  # izračunamo MSE
  napaka = mean((pp.napovedi - podatki$Rank) ^ 2)
  return(napaka)
}

# formule za napovedi
formula.smuci <-
  Rank ~ Ski.Atomic + Ski.Fischer + Ski.Head + Ski.Kaestle + Ski.Nordica + Ski.Rossignol +
  Ski.Salomon + Ski.Stoeckli + Ski.Voelkl + Ski.Dynastar + Ski.Blizzard
formula.smuci.disc <-
  Rank ~  Disciplina.DH + Disciplina.SG + Disciplina.GS + Disciplina.SL +
  Ski.Atomic + Ski.Fischer + Ski.Head + Ski.Kaestle + Ski.Nordica + Ski.Rossignol +
  Ski.Salomon + Ski.Stoeckli  + Ski.Dynastar + Ski.Voelkl+ Ski.Blizzard
formula.smuci.sneg <-
  Rank ~ Ski.Atomic + Ski.Fischer + Ski.Head + Ski.Kaestle + Ski.Nordica + Ski.Rossignol +
  Ski.Salomon + Ski.Stoeckli + Ski.Blizzard + Ski.Dynastar + Ski.Voelkl + sneg.HARD +
  `sneg.SPRING CONDITIONS` + sneg.COMPACT + sneg.SOFT + sneg.PACKED
formula.skupaj <-
  Rank ~ Ski.Atomic + Ski.Fischer + Ski.Head + Ski.Kaestle + Ski.Nordica + Ski.Rossignol +
  Ski.Salomon + Ski.Stoeckli + Ski.Blizzard + Ski.Dynastar + Ski.Voelkl +
  Disciplina.DH + Disciplina.SG + Disciplina.GS + Disciplina.SL + sneg.HARD +
  `sneg.SPRING CONDITIONS` + sneg.COMPACT + sneg.SOFT + sneg.PACKED

napaka.smuci <- napaka.cv(podatki, formula.smuci, 10)
napaka.smuci.disc <- napaka.cv(podatki, formula.smuci.disc, 10)
napaka.smuci.sneg <- napaka.cv(podatki, formula.smuci.sneg, 10)
napaka.skupaj <- napaka.cv(podatki, formula.skupaj, 10)
print(c(napaka.smuci, napaka.smuci.disc, napaka.smuci.sneg, napaka.skupaj))
# --> najboljši model je tisti s smučmi in disciplino (2. model)

# Prikaz za 1. model:
uvrstitev <- c(1:length(smuci)) * 0
napovedi.za.smuci <- tibble(smuci, uvrstitev)

for (i in 1:length(smuci)){
  vzorec = podatki[1,2:12]
  vzorec[1,] = c(rep(0,i-1), 1, rep(0, length(smuci)-i))
  napovedi.za.smuci[i,2] <- predict(lin.reg.smuci, newdata = vzorec)
}
napovedi.za.smuci[2]

barve <- c("#FF0000", "#FF6633","#00CCCC", "#FFFF00", "#FFF7A9", "#009966",
           "#330000", "#FF3300", "#000066", "#990000", "#CCCC00")

graf.napovedi <-
  ggplot(napovedi.za.smuci) +
  aes(x = smuci, y = uvrstitev) +
  geom_bar(stat = "identity", aes(fill = smuci)) +
  scale_fill_manual(values = barve) +
  xlab("Smuči") +
  ylab("Uvrstitev") +
  ggtitle("Napovedane uvrstitve glede na smuči v sezoni 2020/21") +
  theme(legend.position = "none",
        plot.title = element_text(color = "#006699", hjust = 0.5, size = 15),
        axis.text.x = element_text(angle = 25))
graf.napovedi

# Primeri za v poročilo, delam jih na podlagi 2. modela, ker ima najmanjšo napako:
vzorec.2 = podatki[1, 2:16]
# Opazujmo smuči znamke Atomic, za katere smo ugotovili, da so najbolj vsestranske,
# torej primerne z tekmovanje v vseh disciplinah:
vzorec.2[1,] = c(rep(0,3), 1, rep(0, 7), 1, rep(0, 3))
pred.atomic.dh <- predict(lin.reg.smuci.disc, newdata = vzorec.2)
vzorec.2[1,] = c(rep(0,3), 1, rep(0, 8), 1, rep(0, 2))
pred.atomic.sg <- predict(lin.reg.smuci.disc, newdata = vzorec.2)
vzorec.2[1,] = c(rep(0,3), 1, rep(0, 9), 1, 0)
pred.atomic.gs <- predict(lin.reg.smuci.disc, newdata = vzorec.2)
vzorec.2[1,] = c(rep(0,3), 1, rep(0, 10), 1)
pred.atomic.sl <- predict(lin.reg.smuci.disc, newdata = vzorec.2)

Uvrstitev <- c(pred.atomic.dh, pred.atomic.sg, pred.atomic.gs, pred.atomic.sl)
Disciplina <- c("Smuk", "Superveleslalom", "Veleslalom", "Slalom")
# Tabela za v poročilo:
atomic <- t(tibble(Disciplina, Uvrstitev))


# -*- encoding: utf-8 -*-

# 目的: 实现基于网格的SVM近邻聚类算法(GCASK)，同时进行数值模拟以及复杂度分析

##########################################################
# 设置工作路径
##########################################################
setwd('E:/projects/grid_svm_knn/data')
# setwd('D:/个人/坚果云同步/我的坚果云/论文/grid_svm_knn/data')
###########################################################
# 基于网格的SVM近邻聚类算法相关代码
###########################################################

# 对数据空间进行网格化，返回各个维度上网格化的边界
Gridding <- function(X,l_grid=0){
    # 得到X的属性个数
    p <- ncol(X)
    # 得到X样本点个数
    n <- nrow(X)
    # 计算得到各个属性维度的最大值和最小值，确定数据空间的范围
    X_range <- matrix(ncol=2,nrow=p)
    # X_range的第一列为每个维度上的最大值
    X_range[,1] <- apply(X,2,max)
    # X_range的第二列为每个维度上的最小值
    X_range[,2] <- apply(X,2,min)
    # 若X_range的第一列和第二列相同，说明该属性取值都相同，应该删除该属性
    # Index <- (X_range[,1] == X_range[,2])
    # X <- X[,!Index]
    # X_range <- X_range[!Index,]
    # p <- ncol(X)
    # 计算整个空间的体积
    V <- cumprod(X_range[,1]-X_range[,2])[p]
    # 计算小网格的边长
    if (l_grid == 0){
        l_grid <- (V/n) ** (1/p)
    }
    # 计算每个维度上网格的个数
    n_grid <- ceiling((X_range[,1]-X_range[,2]) / l_grid)
    # 用DividingLine来存放各个维度上网格的划分边界线
    DivdingLine <- matrix(ncol=p,nrow=max(n_grid)+1)
    for(i in 1:p){
        DivdingLine[1:(n_grid[i]+1),i] <- X_range[i,2] + ((0:n_grid[i]) * l_grid)
    }
    Lst <- list(DivdingLine=DivdingLine,n_grid=n_grid)
    return(Lst)
}

# 判断格子里有没有点
box_point <- function(X,border){
    Index <- 1:nrow(X)
    p <- ncol(X)
    for(i in 1:p){
        new_X <- X[Index,]
        new_X <- matrix(new_X,ncol=p)
        Index <- which( (new_X[,i]>=border[i,1]) & (new_X[,i]<=border[i,2]) )
        if(length(Index) == 0){
            return(1)
        }
    }
    return(0)
}

# 生成小格子边界的索引
get_combinations <- function(n_grid,Index_matrix,Index = 1,row=1){
    for(i in 1:n_grid[Index]){
        if(Index == length(n_grid)){
            for(j in 1:n_grid[Index]){
                Index_matrix[which(is.na(Index_matrix[,Index]))[1],Index] <- j
                row <- row + 1
            }
            return(list(Index_matrix=Index_matrix, row=row))
        }else{
            Index_matrix[row:nrow(Index_matrix),Index] <- i
            Index <- Index + 1
            Lst <- get_combinations(n_grid,Index_matrix,Index,row)
            Index <- Index - 1
            row <- Lst$row
            Index_matrix <- Lst$Index_matrix
        }
    }
    return(Lst)
}

# 对稀疏区域进行插点
get_nothing_point <- function(X,l_grid=0){
    # 得到网格边界
    Lst <- Gridding(X,l_grid)
    DivdingLine <- Lst$DivdingLine
    n_grid <- Lst$n_grid
    # 得到网格索引矩阵
    Index_matrix <- matrix(ncol=length(n_grid),nrow=cumprod(n_grid)[length(n_grid)])
    Lst <- get_combinations(n_grid,Index_matrix,Index = 1,row=1)
    Index_matrix <- Lst$Index_matrix
    # 生成一个插点矩阵
    point_matrix <- matrix(nrow=nrow(Index_matrix),ncol=1)
    # 生成小格子border，并进行判别
    border <- matrix(ncol=2,nrow=ncol(X))
    for(i in 1:nrow(Index_matrix)){
        for(j in 1:ncol(Index_matrix)){
            border[j,1] <- DivdingLine[Index_matrix[i,j],j]
            border[j,2] <- DivdingLine[Index_matrix[i,j]+1,j]
        }
        point_matrix[i] <- box_point(X,border)
    }
    Index_matrix <- cbind(Index_matrix,point_matrix)
    # 得到稀疏区域点的坐标
    Index_matrix <- Index_matrix[Index_matrix[,ncol(Index_matrix)]==1 ,]
    nothing_point <- matrix(ncol=ncol(X),nrow=nrow(Index_matrix))
    for(i in 1:nrow(Index_matrix)){
        for(j in 1:ncol(X)){
            nothing_point[i,j] <- (DivdingLine[Index_matrix[i,j],j] + DivdingLine[Index_matrix[i,j]+1,j]) / 2
        }
    }
    return(nothing_point)
}

# 生成有监督学习的数据
get_newdata <- function(X,l_grid=0){
    nothing_point <- get_nothing_point(X,l_grid)
    label0 <- matrix(0,nrow=nrow(nothing_point),ncol=1)
    X1 <- cbind(nothing_point,label0)
    label1 <- matrix(1,nrow = nrow(X),ncol=1)
    X2 <- cbind(X,label1)
    newdata <- rbind(X1,X2)
    return(newdata)
}

# 找到最近的k个点
nearest_k_point <- function(x,X,C_S,k){
    x <- matrix(rep(x,nrow(X)), byrow = TRUE, ncol = ncol(X))
    dis_matrix <- diag((x-X) %*% t(x-X))
    dis_matrix[C_S] <- max(dis_matrix)+1
    Index <- c()
    kk <- sum(!((1:nrow(X)) %in% C_S))
    k <- min(k,kk)
    if(k==0){return(Index)}
    for(i in 1:k){
        Index <- c(Index,which.min(dis_matrix))
        dis_matrix[Index[i]] <- max(dis_matrix)+1
    }
    return(Index) # Index中最后的那个就是最远的那个
}

# 判断最近的k个点中有几个要生成新类
new_class_point <- function(x,X,Index,model){
    x <- matrix(rep(x,length(Index)), byrow = TRUE, ncol = ncol(X))
    med <- as.data.frame((x + X[Index,])/2)
    colnames(med) <- colnames(X)
    pred <- predict(model,med)
    # 需要生成新类的点
    newclass_point <- Index[!(as.logical(as.numeric(pred)-1))]
    # 不需要生成新类的点
    oldclass_point <- Index[as.logical(as.numeric(pred)-1)]
    point <- list(newclass_point=newclass_point, oldclass_point=oldclass_point)
    return(point)
}

NewClass <- function(class_list,k,Index){
    # k表示当前有几个类
    class_list[[k]] <- Index
    return(class_list)
}

# 函数：合并到上一类
CombindClass <- function(class_list,k,Index){
    # k表示当前类的个数
    class_list[[k]] <- c(class_list[[k]],Index)
    return(class_list)
}

# 融合形成新类
Combind <- function(X,C,C_S,model,class_list,k,k_class=0,Index1=1){
    # 若是第一个点，先生成一个类
    if(k_class == 0){
        k_class <- k_class+1
        class_list <- list()
        class_list[k_class] <- C[Index1]
        C_S <- c(C_S,C[Index1])
        #print(X[Index1,])
        #points(X[Index1,1],X[Index1,2],col=k_class,pch=18)
        #pause()
    }

    # 有了类之后可以进行判别聚类了
    # 只要还有点没有分类就执行代码
    while(length(C_S) <= length(C)){
        #readline('请按回车')
        # 找到聚类点
        #if(exists('new_center')){
        #    x <- new_center
        #}else{
        #    x <- X[C[Index1],]
        #}
        x <- X[C[Index1],]
        # 找到最近的k个点
        Index <- nearest_k_point(x,X,C_S,k)
        if(is.null(Index)){return(class_list)}
        # 对是否每个k近邻点需要生成新类进行分析
        point <- new_class_point(x,X,Index,model)
        # 判断是不是所有的点都需要生成新类
        if(length(point$newclass_point) == length(Index)){ # 所有点都要生成新类
            # 找到最近的那个点
            Index2 <- Index[1]
            C_S <- c(C_S,C[Index2])
            # 生成新类
            k_class <- k_class + 1
            class_list <- NewClass(class_list,k_class,C[Index2])
            #points(X[Index2,1],X[Index2,2],pch=20,col=k_class)
            #pause()
            Index1 <- Index2
        }else{
            Index2 <- point$oldclass_point
            C_S <- c(C_S,C[Index2])
            # 合并类
            class_list <- CombindClass(class_list,k_class,C[Index2])
            #points(X[Index2,1],X[Index2,2],pch=20,col=k_class)
            #pause()
            #Index1 <- Index2[length(Index2)] # 选择最远的同类点作为下一个迭代点
            #this_class_points <- X[class_list[[length(class_list)]],]
            #new_center <- apply(this_class_points, 2, mean)
            Index1 <- Index2[1] # 选择最近的同类点作为下一个迭代点
        }
    }
    return(class_list)
}

# 噪声点识别
get_noise_point<- function(dat,pred){
    index_1 <- sum(dat$g==0)
    noise_index <- dat$g == 1 & pred != dat$g
    noise_point <- dat[noise_index,]
    row.names(noise_point) <- as.numeric(row.names(noise_point)) - index_1
    not_noise_point_index <- dat$g == 1 & pred == dat$g
    not_noise_point <- dat[not_noise_point_index,]
    row.names(not_noise_point) <- as.numeric(row.names(not_noise_point)) - index_1
    res <- list(noise_point=noise_point, not_noise_point=not_noise_point)
    return(res)
}

grid_svm_knn <- function(newdata, gamma ,cost, k, Index1){
    # 若是没有加载e1071则加载该包
    if(!('e1071' %in% (.packages()))){library(e1071)}
    mydata <- get_newdata(newdata,l_grid = 0)
    dat <- as.data.frame(mydata)
    colnames(dat)[ncol(dat)] <- 'g'
    dat$g<- as.factor(dat$g)
    gamma <- 50
    model <- svm(g~.,data = dat,type='C',kernel='radial',gamma=gamma,cost=cost)
    #plot(model,dat)
    pred <- predict(model,dat[,-ncol(dat)])
    X <- as.matrix(newdata[,1:2])
    res <- get_noise_point(dat,pred)
    X <- as.matrix(res$not_noise_point[,1:2])
    index_X <- as.numeric(row.names(res$not_noise_point))
    C <- 1:nrow(X)
    C_S <- c()
    class_list <- list()
    class_list <- Combind(X,C,C_S,model,class_list,k = k, Index1=Index1)
    noise_point <- as.numeric(row.names(res$noise_point))
    #clusters_result <- list(class_list = class_list, noise_point = noise_point)
    # 对结果进行整理
    pred <- rep(0, dim(newdata)[1])
    for(i in 1:length(class_list)){
        pred[index_X[class_list[[i]]]] <- i
    }
    return(pred)
}

#########################################################################################
# 动态分位数Kmeans算法
#########################################################################################
Radius.KMeans <- function(x,p,q=0.5,t=1.5){
    lst <- FILTER(x,11,q,t)
    C <- lst$C
    R <- lst$R
    k <- COMBINE(C,R)
    km <- kmeans(x,k)
    plot(x,col=km$cluster,main = 'Radius.KMeans result')
    return(list(k = k,km = km))
}

# 中心筛选——对应2.3中的算法2
FILTER <- function(x,p,q=0.5,t=1.5){
    C <- matrix(nrow = 1,ncol = dim(x)[2])
    R <- c()
    # 生成中心点集合C以及对应的半径集合R
    for(k in 2:p){
        # 进行Kmeans聚类
        km <- kmeans(x,k)
        for (i in 1:k) {
            # 返回本次聚类属于第i类的样本
            samples <- x[km$cluster==i,]
            # 计算样本到对应聚类中心的距离
            d <- dist(km$centers[i,],samples)
            # 得到当前类聚类中心对应的半径
            r <- as.numeric(quantile(d,q))
            R <- c(R,r)
            # 聚类中心
            C <- rbind(C,km$centers[i,])
        }
    }
    # 绘制图像
    #plot(C,pch=19,col=2,xlim = c(-30,30),ylim = c(-30,30),main = 'Sizeable radiuses(中心筛选前)')
    library(plotrix)
    for(i in 1:length(R)){
        draw.circle(C[i,1],C[i,2],R[i])
    }
    C <- C[-1,]
    COL <- c()
    for (i in 1:length(R)) {
        for (j in 1:length(R)) {
            # 计算Condition1
            d_i_j <- sqrt(sum((C[i,] - C[j,])^2))
            MIN_i_j <- min(R[i],R[j])
            MAX_i_j <- max(R[i],R[j])
            Condition1 <- (d_i_j + MIN_i_j < (t * MAX_i_j))
            if ((i!=j) && Condition1) {
                col <- c(i,j)[which.max(R[c(i,j)])]
                COL <- c(COL,col)
            }
        }
    }
    COL <- unique(COL)
    C <- C[-COL,]
    R <- R[-COL]
    # 绘制图像
    #plot(C,pch=19,col=2,xlim = c(-5,20),ylim = c(-5,20),main = 'Sizeable radiuses(中心筛选后)')
    library(plotrix)
    for(i in 1:length(R)){
        draw.circle(C[i,1],C[i,2],R[i])
    }
    return(list(C=C,R=R))
}

# 中心融合——对应2.3中的算法3
COMBINE <- function(C,R){
    L_C <- length(R)
    # 生成pointer矩阵
    pointer <- matrix(0,nrow = L_C,ncol = L_C)
    s <- c()
    c_s <- 1:L_C
    for(i in 1:L_C){
        for(j in 1:L_C){
            d_i_j <- sqrt(sum((C[i,1:2] - C[j,1:2])^2))
            Condition2 <- d_i_j<(R[i]+R[j])
            if((i!=j) & Condition2){
                pointer[i,j] <- 1
                pointer[j,i] <- 1
            }
        }
    }
    k <- 0
    while (length(c_s) != 0) {
        lst <- RECURSION(pointer,s,c_s,c_s[1])
        s <- lst$s
        c_s <- lst$c_s
        k <- k + 1
    }
    return(k)
}

# 递归函数，完成类的寻找工作——对应2.3中的算法4
RECURSION <- function(pointer,s,c_s,ini_co){
    corrdin <- which(pointer[ini_co,] == 1)
    s <- c(s,ini_co)
    c_s <- c_s[which(c_s!=ini_co)]
    if(length(corrdin) != 0){
        for(i in 1:length(corrdin)){
            if(corrdin[i] %in% s){
                next
            }else{
                ini_co <- corrdin[i]
                lst <- RECURSION(pointer,s,c_s,ini_co)
                s <- lst$s
                c_s <- lst$c_s
            }
        }
    }
    return(list(s=s,c_s=c_s))
}

# 定义distance函数，计算类内所有点到聚类中心距离的排序
dist <- function(centers,X){
    d <- sqrt(diag((X - centers) %*% t(X - centers)))
    return(d)
}

######################################################################################
# 生成模拟数据
#####################################################################################
# 导入用到的包
library(MASS)
# 多图绘制
par(mfrow=c(2,2))
# =============================================案例1：三圆环数据=========================================
set.seed(123)
n1 <- 500  # 内部圆的样本点数量
n2 <- 500  # 中间圆环的样本点数量
n3 <- 500  # 外部圆环的样本点数量
X1 <- matrix(nrow = n1,ncol = 2)
mu <- c(0,0)
sigma <- matrix(c(1,0,0,1),nrow = 2,ncol = 2)
for(i in 1:n1){
    x <- mvrnorm(1,mu,sigma)
    while(TRUE){
        if((x[1]^2 + x[2]^2) >= 0 & (x[1]^2 + x[2]^2) <= 1){
            X1[i,] <- x
            break()
        }else{
            x <- mvrnorm(1,mu,sigma)
        }
    }

}

X2 <- matrix(nrow = n2,ncol = 2)
mu <- c(0,0)
sigma <- matrix(c(9,0,0,9),nrow = 2,ncol = 2)
for(i in 1:n2){
    x <- mvrnorm(1,mu,sigma)
    while(TRUE){
        if((x[1]^2 + x[2]^2) >= 2 & (x[1]^2 + x[2]^2) <= 3){
            X2[i,] <- x
            break()
        }else{
            x <- mvrnorm(1,mu,sigma)
        }
    }
}
X3 <- matrix(nrow = n3,ncol = 2)
mu <- c(0,0)
sigma <- matrix(c(36,0,0,36),nrow = 2,ncol = 2)
for(i in 1:n2){
    x <- mvrnorm(1,mu,sigma)
    while(TRUE){
        if((x[1]^2 + x[2]^2) >= 5 & (x[1]^2 + x[2]^2) <= 6){
            X3[i,] <- x
            break()
        }else{
            x <- mvrnorm(1,mu,sigma)
        }
    }
}
# 合并数据
X <- rbind(X1,X2,X3)
g <- c(rep(1,n1),rep(2,n2),rep(3,n3))
# 无标签绘图
plot(X,pch=20,col='blue',main='DataSet1',xlab = expression(X[1]),ylab=expression(X[2]))
# 有标签绘图
plot(X,col=g,pch=20,main='圆环数据',xlab = expression(X[1]),ylab=expression(X[2]))
# 保存数据
dataset1 <- cbind(X,g)
colnames(dataset1) <- c('X1','X2','g')
write.csv(dataset1, 'dataset1.csv', fileEncoding = 'utf-8', row.names = FALSE)
# ============================================案例2：块状数据===============================================
n <- 300
mu1 <- c(0,0)
mu2 <- c(0,-3)
mu3 <- c(3,-3)
mu4 <- c(3,3)
mu5 <- c(-3,3)
sigma <- matrix(c(0.1,0,0,0.1),nrow = 2,ncol = 2)
X1 <- mvrnorm(n,mu1,sigma)
X2 <- mvrnorm(n,mu2,sigma)
X3 <- mvrnorm(n,mu3,sigma)
X4 <- mvrnorm(n,mu4,sigma)
X5 <- mvrnorm(n,mu5,sigma)
X <- rbind(X1,X2,X3,X4,X5)
g <- rep(1:5,each=n)
# 无标签绘图
plot(X,pch=20,col='blue',main='DataSet2',xlab = expression(X[1]),ylab=expression(X[2]))
# 有标签绘图
plot(X,col=g,pch=20,main='块状数据',xlab = expression(X[1]),ylab=expression(X[2]))
# 保存数据
dataset2 <- cbind(X,g)
colnames(dataset2) <- c('X1','X2','g')
write.csv(dataset2, 'dataset2.csv', fileEncoding = 'utf-8', row.names = FALSE)
# ======================================案例3：块状数据+噪声==================================================
n <- 300
mu1 <- c(0,0)
mu2 <- c(0,-3)
mu3 <- c(3,-2)
mu4 <- c(2,2)
mu5 <- c(-1.5,3)
sigma <- matrix(c(0.1,0,0,0.1),nrow = 2,ncol = 2)
X1 <- mvrnorm(n,mu1,sigma)
X2 <- mvrnorm(n,mu2,sigma)
X3 <- mvrnorm(n,mu3,sigma)
X4 <- mvrnorm(n,mu4,sigma)
X5 <- mvrnorm(n,mu5,sigma)
X <- rbind(X1,X2,X3,X4,X5)
g <- rep(1:5,each=n)
n_noise <- 100
X_noise <- matrix(ncol=2,nrow = n_noise)
for(i in 1:n_noise){
    min_dist <- 0
    while(min_dist < 0.5){
        noise_x<- runif(1,-4,4)
        noise_y <- runif(1,-4,4)
        noise_one <- matrix(rep(c(noise_x, noise_y), times=dim(X)[1]), ncol = 2,byrow = TRUE)
        min_dist <- min(dist(noise_one, X))
    }
    X_noise[i,] <- noise_one[1,]
}
X <- rbind(X,X_noise)
g <- c(g,rep(6,n_noise))
# 无标签绘图
plot(X,pch=20,col='blue',main='DataSet3',xlab = expression(X[1]),ylab=expression(X[2]))
# 有标签绘图
plot(X,col=g,pch=20,main='带噪声的块状数据',xlab = expression(X[1]),ylab=expression(X[2]))
# 保存数据
dataset3 <- cbind(X,g)
colnames(dataset3) <- c('X1','X2','g')
write.csv(dataset3, 'dataset3.csv', fileEncoding = 'utf-8', row.names = FALSE)
# ==========================================案例4：圆弧数据+噪声==============================================
set.seed(123)
n1 <- 1000  # 上圆弧的样本点数量
n2 <- 1000  # 下圆弧的样本点数量
X1 <- matrix(nrow = n1,ncol = 2)
mu <- c(-0.5,0)
sigma <- matrix(c(1,0,0,1),nrow = 2,ncol = 2)
for(i in 1:n1){
    x <- mvrnorm(1,mu,sigma)
    while(TRUE){
        if(((x[1]+0.5)^2 + x[2]^2) >= 1 & ((x[1]+0.5)^2 + x[2]^2) <= 2 & x[2] > -0.5){
            X1[i,] <- x
            break()
        }else{
            x <- mvrnorm(1,mu,sigma)
        }
    }
}
X2 <- matrix(nrow = n2,ncol = 2)
mu <- c(0.5,0)
sigma <- matrix(c(1,0,0,1),nrow = 2,ncol = 2)
for(i in 1:n1){
    x <- mvrnorm(1,mu,sigma)
    while(TRUE){
        if(((x[1]-0.5)^2 + x[2]^2) >= 1 & ((x[1]-0.5)^2 + x[2]^2) <= 2 & x[2] < 0.5){
            X2[i,] <- x
            break()
        }else{
            x <- mvrnorm(1,mu,sigma)
        }
    }
}
# 合并数据
X <- rbind(X1,X2)
g <- c(rep(1,n1),rep(2,n2))
# 噪声数据
n_noise <- 100
X_noise <- matrix(ncol=2,nrow = n_noise)
for(i in 1:n_noise){
    min_dist <- 0
    while(min_dist < 0.1){
        noise_x<- runif(1,-2,2)
        noise_y <- runif(1,-2,2)
        noise_one <- matrix(rep(c(noise_x, noise_y), times=dim(X)[1]), ncol = 2,byrow = TRUE)
        min_dist <- min(dist(noise_one, X))
    }
    X_noise[i,] <- noise_one[1,]
}
X <- rbind(X,X_noise)
g <- c(g,rep(3,n_noise))
# 无标签绘图
plot(X,pch=20,col='blue',main='DataSet4',xlab = expression(X[1]),ylab=expression(X[2]))
# 有标签绘图
plot(X,col=g,pch=20,main='带噪声的弧形数据',xlab = expression(X[1]),ylab=expression(X[2]))
# 保存数据
dataset4 <- cbind(X,g)
colnames(dataset4) <- c('X1','X2','g')
write.csv(dataset4, 'dataset4.csv', fileEncoding = 'utf-8', row.names = FALSE)

# ==========================================案例3：混合数据+噪声==============================================
set.seed(123)
n1 <- 300  # 左边块的样本点数量
n2 <- 200  # 右边块的样本点数量
n3 <- 1000  # 圆弧的样本点数量
# 生成左边的块
X1 <- matrix(nrow = n1,ncol = 2)
mu1 <- c(-2,2)
sigma1 <- matrix(c(0.2,0,0,0.2),nrow = 2,ncol = 2)
X1 <- mvrnorm(n1,mu1,sigma1)
# 生成右边的块
X2 <- matrix(nrow = n2,ncol = 2)
mu2 <- c(2,2)
sigma2 <- matrix(c(0.2,0,0,0.2),nrow = 2,ncol = 2)
X2 <- mvrnorm(n2,mu2,sigma2)
# 生成圆弧
X3 <- matrix(nrow = n3,ncol = 2)
mu3 <- c(0,0)
sigma3 <- matrix(c(3,0,0,3),nrow = 2,ncol = 2)
for(i in 1:n3){
    x <- mvrnorm(1,mu3,sigma3)
    while(TRUE){
        if(((x[1])^2 + x[2]^2) >= 1 & ((x[1])^2 + x[2]^2) <= 1.5 & x[2] <= 0){
            X3[i,] <- x
            break()
        }else{
            x <- mvrnorm(1,mu3,sigma3)
        }
    }
}
# 添加噪声
n_noise <- 40
X_noise <- matrix(ncol=2,nrow = n_noise)
for(i in 1:n_noise){
    min_dist <- 0
    while(min_dist < 0.1){
        noise_x<- runif(1,-2,2)
        noise_y <- runif(1,-2,2)
        noise_one <- matrix(rep(c(noise_x, noise_y), times=dim(X)[1]), ncol = 2,byrow = TRUE)
        min_dist <- min(dist(noise_one, X))
    }
    X_noise[i,] <- noise_one[1,]
}

X <- rbind(X1,X2, X3,X_noise)
plot(X,pch=20,col='blue',main='DataSet4',xlab = expression(X[1]),ylab=expression(X[2]))

#################################################################################
# 利用各种方法进行聚类
#################################################################################
# 绘制聚类结果图
plot_clustering <- function(X, res, main){
    pch_set=c(1,2,3,5,7,8,9)
    plot(X[,1], X[,2],xlab = expression(X[1]),ylab=expression(X[2]),main=main, col='white')
    for(i in 1:length(res_grid_svm_knn)){
        if(res[i] == 0){
            points(x = X[i,1], y = X[i,2], col=res[i]+1, pch=15)
        }else{
            points(x = X[i,1], y = X[i,2], col=res[i]+1, pch=pch_set[res[i]])
        }
    }
}

# 加载一些包
library(fpc)
library(dbscan)
library(ellipse)
X <- dataset1[,1:2]; g <- dataset1[,3]
# X <- dataset2[,1:2]; g <- dataset2[,3]
# X <- dataset3[,1:2]; g <- dataset3[,3]
# X <- dataset4[,1:2]; g <- dataset4[,3]
# grid_SVM_knn
res_grid_svm_knn <- grid_svm_knn(X, gamma=10 ,cost=10, k=18, Index1=1213)  # dataset1
#res_grid_svm_knn <- grid_svm_knn(X, gamma=5 ,cost=0.36, k=18, Index1=1)
res_grid_svm_knn <- grid_svm_knn(X, gamma=20,cost=0.01, k=18, Index1=1213)
res_grid_svm_knn <- grid_svm_knn(X, gamma=10, cost=0.02265, k=25, Index1=1213)
res_grid_svm_knn <- grid_svm_knn(X, gamma=10, cost=0.023, k=18, Index1=1213)
# 绘制聚类结果
plot_clustering(X, res_grid_svm_knn, 'DataSet1')
# dbscan
kNNdistplot(X,k = 20)  # 找最优eps
res_db <- dbscan(X,eps=0.2,minPts=8)
res_db <- res_db$cluster
plot_clustering(X, res_db, 'DataSet4聚类效果图')
# DP-Kmeans
res_DP_Kmeans <- Radius.KMeans(X,1213,q=0.5,t=1.2)
res_DP_Kmeans <- res_DP_Kmeans$km$cluster
plot_clustering(X, res_DP_Kmeans,'DataSet4聚类效果图')
# 汇总上面的结果并保存
res1 <- cbind(res_grid_svm_knn, res_db, res_DP_Kmeans)
write.csv(res1, 'res1.csv', row.names = FALSE, fileEncoding = 'utf-8')

res2 <- cbind(res_grid_svm_knn, res_db, res_DP_Kmeans)
write.csv(res2, 'res2.csv', row.names = FALSE, fileEncoding = 'utf-8')

res3 <- cbind(res_grid_svm_knn, res_db, res_DP_Kmeans)
write.csv(res3, 'res3.csv', row.names = FALSE, fileEncoding = 'utf-8')

res4 <- cbind(res_grid_svm_knn, res_db, res_DP_Kmeans)
write.csv(res4, 'res4.csv', row.names = FALSE, fileEncoding = 'utf-8')
# birch用python处理

# 解除多图绘制
par(mfrow=c(1,1))
###############################################################################
# 聚类效果评估
###############################################################################
library(NMI)
NMI(res_db$cluster, g)

###############################################################################
# 对算法的时间复杂度进行分析
###############################################################################
library(MASS)
create_data <- function(n){
    n <- n/2
    mu1 <- c(0,2)
    mu2 <- c(0,-2)
    sigma <- matrix(c(0.1,0,0,0.1),nrow = 2,ncol = 2)
    X1 <- mvrnorm(n,mu1,sigma)
    X2 <- mvrnorm(n,mu2,sigma)
    X <- rbind(X1,X2)
    return(X)
}
X <- create_data(500)
# 无标签绘图
plot(X,pch=20,col='blue',xlab = expression(X[1]),ylab=expression(X[2]))
res_grid_svm_knn <- grid_svm_knn(X, gamma=1,cost=1, k=5, Index1=1213)

# 随n增大的时间消耗情况
n_set <- (1:20)*50
time_set <- matrix(nrow = length(n_set), ncol = 1)
for(i in 1:length(n_set)){
    print(i)
    n <- n_set[i]
    X <- create_data(n)
    t1 <- proc.time()
    res_grid_svm_knn <- grid_svm_knn(X, gamma=1,cost=1, k=5, Index1=1213)
    t2 <- proc.time()
    t <- t2 - t1
    time_set[i] <- t[3][[1]]
}
plot(x = n_set, y = time_set, type = 'b', main='the influence of n to running time', ylab = 'Time', xlab='n')

# 随k增大的时间消耗情况
time_set <- matrix(nrow = length(k_set), ncol = 10)
for(j in 1:10){
    k_set <- 5:30
    for(i in 1:length(k_set)){
        print(paste0('正在处理 行',i,' 列',j))
        k <- k_set[i]
        X <- create_data(1000)
        t1 <- proc.time()
        res_grid_svm_knn <- grid_svm_knn(X, gamma=1,cost=1, k=k, Index1=1213)
        t2 <- proc.time()
        t <- t2 - t1
        time_set[i,j] <- t[3][[1]]
    }
}
time_set_mean <- apply(time_set, 1, mean)
plot(x = k_set, y = time_set_mean, type = 'b', main='the influence of k to running time', ylab = 'Time', xlab='k')

k_set <- 1:30
time_set1 <- matrix(nrow = length(k_set), ncol = 1)
for(i in 1:length(k_set)){
    print(paste0('正在处理 行',i))
    k <- k_set[i]
    set.seed(1213)
    X <- create_data(2000)
    t1 <- proc.time()
    res_grid_svm_knn <- grid_svm_knn(X, gamma=1,cost=1, k=k, Index1=1213)
    t2 <- proc.time()
    t <- t2 - t1
    time_set1[i] <- t[3][[1]]
}
plot(x = k_set, y = time_set1, type = 'b', main='the influence of k to running time', ylab = 'Time', xlab='k')

# 随gamma增大的时间消耗情况
gamma_set <- 10**(-6:6)
time_set <- matrix(nrow = length(gamma_set), ncol = 1)
for(i in 1:length(gamma_set )){
    print(i)
    gamma <- gamma_set[i]
    X <- create_data(1000)
    t1 <- proc.time()
    res_grid_svm_knn <- grid_svm_knn(X, gamma=gamma,cost=1, k=20, Index1=1213)
    t2 <- proc.time()
    t <- t2 - t1
    time_set[i] <- t[3][[1]]
}
plot(x = gamma_set, y = time_set, type = 'b', main='gamma对算法运行时间的影响', ylab = '消耗时间', xlab='gamma')

# 随cost增大的时间消耗情况
cost_set <- 10**(-4:4)
time_set <- matrix(nrow = length(cost_set), ncol = 1)
for(i in 1:length(cost_set )){
    print(i)
    cost <- cost_set[i]
    X <- create_data(3000)
    t1 <- proc.time()
    res_grid_svm_knn <- grid_svm_knn(X, gamma=1,cost=cost, k=20, Index1=1213)
    t2 <- proc.time()
    t <- t2 - t1
    time_set[i] <- t[3][[1]]
}
plot(x = cost_set, y = time_set, type = 'b', main='cost对算法运行时间的影响', ylab = '消耗时间', xlab='cost')