show with app
library(shiny)
library(parallel)
library(future)
#library(ggplot2)
#licence MIT
max_step_count <- 10^5
max_run_count <- 2000

# Define UI for application that draws
ui <- fluidPage(
    tags$head(
        tags$link(rel = "stylesheet", type = "text/css", href = "../../../assets/css/main.css")
    ),
    fluidRow(
        HTML(
            '<div class="topnav">
                <a class="active" href="../../../" target="_blank">Home</a>
                <a href="../../">Apps by Authors</a>
                <a href="../">Up</a>
            </div>'
        )
    ),
    # User input for run numbers + Summary
    fluidRow(
        column(3,
            sliderInput("stepNum",
                        h3("Random Walk # of steps:"),
                        min = 1,
                        max = max_step_count,
                        value = ceiling( max_step_count/100)),
        )
        ,
        column(3,
            sliderInput("runNum",
                        h3("Number of runs:"),
                        min = 1,
                        max = max_run_count,
                        value = 1),
        ),
        column(6,
            verbatimTextOutput("summary")
        )
    ),
    fluidRow(
        column(12,plotOutput("randomWalkPlot"))
    )
)

# Define server logic required to draw a plot
server <- function(input, output) {
    output$randomWalkPlot <- renderPlot({
        numSteps <- input$stepNum
        if (input$runNum==1) {
            # start the clock!
            ptm <- proc.time()
            #create random walk using vectors, a single walk is generated and them plotted using both plot and ggplot
            theta <- 2*pi*runif(numSteps)	#create vector of size numSteps holding random angles 0 to 360
            x <- c(0, cumsum(cos(theta)))   #cos(theta) creates distance in x for each step, cumsum() creates cumulative sum, then add starting x of 0
            y <- c(0, cumsum(sin(theta)))   #sin(theta) creates distance in y for each step, cumsum() creates cumulative sum, then add starting y of 0
            
            Distance = function(v1,v2) {
              v <- (v2-v1)^2
              sqrt(v[,1] + v[,2])
            }
            
            distanceTraveled <- Distance(
                cbind(x[1],y[1]),
                cbind(x[length(x)],y[length(y)])
            )
            processing_time <- round(proc.time()["elapsed"] - ptm["elapsed"],3)
            summary_text <- paste0("Random Walk of ",numSteps,
                                   " steps resulted \nin a final distance traveled of ",
                                   round(distanceTraveled,1), "\nin " ,processing_time,
                                   " sec"
            )
            output$summary <- renderPrint({
                cat(summary_text)
            })
            #coords <- data.frame(x,y)
            #p <- ggplot(coords,aes(x,y)) + geom_path()
            #print(p)
            #plot using base R
            plot(
                x,
                y,
                xlab=paste0("x"),
                ylab="y",
                main=paste0("Random Walk of ",numSteps,
                            " steps") , 
                type = 'l'
            )
        } else { 
            num_runs <- input$runNum
            # start the clock!
            ptm <- proc.time()
	          run_cores <- future::availableCores()-1
            #create random walk using vectors, a single walk is generated and them plotted using both plot and ggplot
            cl <- makeCluster(run_cores)
            clusterSetRNGStream(cl, iseed = 42)
            cluster_overhead_time <- proc.time()["elapsed"] - ptm["elapsed"]
            ptm <- proc.time()
            distances_traveled <- parLapply(
                cl, 
                1:num_runs, 
                fun=function(i,steps) {
                    Distance = function(v1,v2) {
                      v <- (v2-v1)^2
                      sqrt(v[,1] + v[,2])
                    }
                    theta <- 2*pi*runif(n = steps)
                    x <- c(0, cumsum(cos(theta)))   #cos(theta) creates distance in x for each step, cumsum() creates cumulative sum, then add starting x of 0
                    y <- c(0, cumsum(sin(theta)))   #sin(theta) creates distance in y for each step, cumsum() creates cumulative sum, then add starting y of 0
                    # points_run <- cbind(x,y)
                    # colnames(points_run) <- c("x","y")
                    # points_run                    
		    # This is the total distance traveled this run
                    distanceTraveled <- Distance(
                        cbind(x[1],y[1]),
                         cbind(x[length(x)],y[length(y)])
                    )
                    distanceTraveled <- round(distanceTraveled,3)
                },
                steps=numSteps
            )
            processing_time <- proc.time()["elapsed"] - ptm["elapsed"]
            ptm <- proc.time()
            stopCluster(cl)
            cluster_overhead_time <- cluster_overhead_time +  proc.time()["elapsed"] - ptm["elapsed"]
            summary_text <- paste0("On ",
    	    	  run_cores,
  	  	      " cores ",
		          num_runs, " runs of Random Walk at ",numSteps,
              " steps resulted in : \n",
    	  	    "A minimum distance of ",min(unlist(distances_traveled)),"\n",
    	  	    "A median distance of ",summary(unlist(distances_traveled))["Median"],"\n",
    	  	    "A max distance of ",max(unlist(distances_traveled)),"\n",
    	  	    "in " ,round(processing_time,3),
              " sec, with a cluster overhead time of: ",
        		  round(cluster_overhead_time,3) 
            )

            output$summary <- renderPrint({
                cat(summary_text)
            })
            hist(unlist(distances_traveled))
        }
    })

}

# Run the appsummarylication 
shinyApp(ui = ui, server = server)