diff --git a/.Rbuildignore b/.Rbuildignore new file mode 100644 index 0000000000000000000000000000000000000000..91114bf2f2bba5e0c5252e75018da19b869776f1 --- /dev/null +++ b/.Rbuildignore @@ -0,0 +1,2 @@ +^.*\.Rproj$ +^\.Rproj\.user$ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..f4f606b08247414e98fdb3ffca335cef87e17e7d --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.Rproj.user +.Rhistory +.RData +.Ruserdata +*.Rproj diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..4f9e7da87f1ca9ec3ba840966c18ec8d3a51d487 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,44 @@ +image: rocker/rstudio +stages: +- build +- test +- deploy +building: + stage: build + script: + - Rscript -e 'install.packages("remotes")' + - Rscript -e 'install.packages("devtools")' + - R -e "remotes::install_deps(dependencies = TRUE)" + - R -e 'devtools::check()' + +testing: + stage: test + allow_failure: true + when: on_success + only: + - master + coverage: '/coverage: \d+.\d+% of statements/' + script: + - Rscript -e 'install.packages("testthat")' + - Rscript -e 'install.packages("DT")' + - Rscript -e 'install.packages("covr")' + - Rscript -e 'covr::gitlab(quiet = FALSE)' + artifacts: + paths: + - public +# To produce a code coverage report as a GitLab page see +# https://about.gitlab.com/2016/11/03/publish-code-coverage-report-with-gitlab-pages/ +pages: + stage: deploy + dependencies: + - testing + script: + - mkdir .public + - cp -r * .public + - mv .public public + artifacts: + paths: + - public + expire_in: 30 days + only: + - master \ No newline at end of file diff --git a/DESCRIPTION b/DESCRIPTION new file mode 100644 index 0000000000000000000000000000000000000000..f4d51532443268b7121f1046c60cdc36f6b8d0fc --- /dev/null +++ b/DESCRIPTION @@ -0,0 +1,17 @@ +Package: lab +Type: Package +Title: Advanced R Group Cooperation +Version: 1.0 +Date: 2024-09-12 +Author: Liuxi Mei,Xiaochen Liu +Maintainer: Liuxi Mei <liume102@student.liu.se>,Xiaochen Liu<xiali125@student.liu.se> +Description: This is a exercise package for advanced R . +License: GPL (>= 2) +RoxygenNote: 7.3.2 +Encoding: UTF-8 +Depends: + R (>= 2.10) +LazyData: true +Suggests: + testthat (>= 3.0.0) +Config/testthat/edition: 3 diff --git a/NAMESPACE b/NAMESPACE new file mode 100644 index 0000000000000000000000000000000000000000..6ae926839dd1829f1016a96f766d970ff184ad97 --- /dev/null +++ b/NAMESPACE @@ -0,0 +1,2 @@ +# Generated by roxygen2: do not edit by hand + diff --git a/R/lab_3_submission.R b/R/lab_3_submission.R new file mode 100644 index 0000000000000000000000000000000000000000..8af145a27e53d641d3d527a0b96283a0516d6d2a --- /dev/null +++ b/R/lab_3_submission.R @@ -0,0 +1,135 @@ + + +#' Euclidian algorithm to find the +#' greatest common divisor of two numbers +#' @title euclidean algorithm +#' @param x first number +#' @param y second number + +euclidean <- function(x,y) { + x <- abs(x) + y <- abs(y) + if (!is.numeric(x) | length(x) != 1){ + stop('pls check your input x') + } + if (!is.numeric(y) | length(y) != 1){ + stop('pls check your input y') + } + a <- ifelse(x < y, y, x) + b <- ifelse(x < y, x, y) + repeat{ + mode = a %% b + if (mode == 0) { + return (b) + } + a <- b + b <- mode + } + return (b) +} + + +#' @description init the detail table +#' @title initial the detail frame +#' @param init_node the start node to find the shortest path +#' @param graph the structure of the graph, +#' eg:wiki_graph <- data.frame(v1=c(1,1,1,2,2,2,3,3,3,3,4,4,4,5,5,6,6,6), +#' v2=c(2,3,6,1,3,4,1,2,4,6,2,3,5,4,6,1,3,5), +#' w=c(7,9,14,7,10,15,9,10,11,2,15,11,6,6,9,14,2,9)) +init_node_distance_list <- function (init_node, graph) { + node_distance_list <- list(init_node = 0) + # first, get all unqiue nodes + all_nodes <- unique(append(graph[,'v1'],graph[,'v2'])) + if (!init_node %in% all_nodes) { + stop('node is not in graph') + } + detail_frame <- data.frame(matrix(ncol=length(all_nodes),nrow = 3)) + names(detail_frame) <- all_nodes + row.names(detail_frame) <- c('is_best_node','node_distance','previous_node') + detail_frame['node_distance', ]<- Inf + detail_frame['node_distance',init_node] <- 0 + detail_frame['is_best_node',init_node] <- TRUE + checked_nodes <- list(init_node) + unchecked_nodes <- all_nodes[-which( all_nodes == init_node)] + return (list(detail_frame=detail_frame, checked_nodes=checked_nodes, unchecked_nodes=unchecked_nodes)) +} + + +#' @description +#' the update method for detail table to record the shortest path +#' @title update the detail frame when traversing to a new node +#' @param node the current the node when traversing all the nodes to find the best way +#' @param init_node the start node in the algorithm +#' @param checked_nodes the nodes that having found the shortest path +#' @param unchecked_nodes the nodes that having not found the shortest path +#' @param detail_frame to store the shorest path , if it is the best node and the related distance +#' @param graph the graph indicates the relationship of different nodes + +update_detail_path <- function(node,init_node,detail_frame,graph,checked_nodes,unchecked_nodes) { + #get connected nodes to node + if (length(unchecked_nodes) == 0){ + # browser() + return (detail_frame) + } + connected_nodes <- graph[graph$v1 == node,]$v2 + next_node <- NULL + min_path <- Inf + for (c_node in connected_nodes){ + current_distance <- graph[graph$v1 == node & graph$v2 == c_node,]$w + if (node == init_node) { + detail_frame['node_distance',c_node] <- current_distance + detail_frame['previous_node',c_node] <- init_node + if(current_distance < min_path) { + min_path <- current_distance + next_node <- c_node + # detail_frame['best_node',c_node] <-TRUE + } + }else{ + # browser() + if (c_node %in% checked_nodes) next + + previous_distance <- detail_frame['node_distance',node] + source_distance <- previous_distance + current_distance + exist_distance <- detail_frame['node_distance',c_node] + #差更新å‰ç½®èŠ‚ç‚¹ + if (source_distance < exist_distance) { + + # update source distance + detail_frame['node_distance',c_node] <- source_distance + # update previous node + detail_frame['previous_node',c_node] <- node + }else{ + source_distance <- exist_distance + } + if (source_distance < min_path) { + min_path <- source_distance + next_node <- c_node + } + } + } + + checked_nodes <- append(checked_nodes,next_node) + unchecked_nodes <- unchecked_nodes[-which(unchecked_nodes==next_node)] + detail_frame['is_best_node',next_node] <-TRUE + return (update_detail_path(next_node,init_node,detail_frame,graph,checked_nodes,unchecked_nodes)) +} + +#' @description +#' the dijkstra algorithm to find the shortest path in the graph +#' @title the entrance of the dijkstra algorithm +#' @param graph a graph to find the shortest path +#' @param init_node the start node to find the shortest path in the graph +dijkstra <- function(graph, init_node) { + + res<- init_node_distance_list(init_node,graph) + detail_frame <- res$detail_frame + checked_nodes <- res$checked_nodes + unchecked_nodes <- res$unchecked_nodes + updated_detail_frame <- update_detail_path(init_node,init_node,detail_frame,graph,checked_nodes,unchecked_nodes) + return (unname(unlist(updated_detail_frame['node_distance',]))) +} + + + + + diff --git a/R/wiki_graph.R b/R/wiki_graph.R new file mode 100644 index 0000000000000000000000000000000000000000..d480674eade0fe0389e6e04556cf74b99f6450db --- /dev/null +++ b/R/wiki_graph.R @@ -0,0 +1,10 @@ + +#' graph +#' @format A data frame with 18 rows and 3 columns: +#' \describe{ +#' \item{v1}{node name} +#' \item{v2}{node name} +#' \item{w}{the weight between node v1 and node v2} +#' ... +#' } +"wiki_graph" \ No newline at end of file diff --git a/data-raw/.gitkeep b/data-raw/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/data-raw/wiki_graph.R b/data-raw/wiki_graph.R new file mode 100644 index 0000000000000000000000000000000000000000..bf14777b4f98387ad5a98acfd0e823013850c113 --- /dev/null +++ b/data-raw/wiki_graph.R @@ -0,0 +1,12 @@ +library(dplyr, warn.conflicts = FALSE) +library(rvest) +library(tidyr) +library(readr) +library(usethis) + +wiki_graph <-data.frame(v1=c(1,1,1,2,2,2,3,3,3,3,4,4,4,5,5,6,6,6), + v2=c(2,3,6,1,3,4,1,2,4,6,2,3,5,4,6,1,3,5), + w=c(7,9,14,7,10,15,9,10,11,2,15,11,6,6,9,14,2,9)) + +write_csv(wiki_graph, "data-raw/wiki_graph.csv") +usethis::use_data(wiki_graph, overwrite = TRUE) \ No newline at end of file diff --git a/data-raw/wiki_graph.csv b/data-raw/wiki_graph.csv new file mode 100644 index 0000000000000000000000000000000000000000..8a673824f7bdf1b61c863af9ee966ea1349e84bc --- /dev/null +++ b/data-raw/wiki_graph.csv @@ -0,0 +1,19 @@ +v1,v2,w +1,2,7 +1,3,9 +1,6,14 +2,1,7 +2,3,10 +2,4,15 +3,1,9 +3,2,10 +3,4,11 +3,6,2 +4,2,15 +4,3,11 +4,5,6 +5,4,6 +5,6,9 +6,1,14 +6,3,2 +6,5,9 diff --git a/data/wiki_graph.rda b/data/wiki_graph.rda new file mode 100644 index 0000000000000000000000000000000000000000..b9513341241f425a3aece1bb3c043a2cb7efc6f4 Binary files /dev/null and b/data/wiki_graph.rda differ diff --git a/man/dijkstra.Rd b/man/dijkstra.Rd new file mode 100644 index 0000000000000000000000000000000000000000..74004cc6837dc5872c7a0ebedbe259cbf697cb78 --- /dev/null +++ b/man/dijkstra.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lab_3_submission.R +\name{dijkstra} +\alias{dijkstra} +\title{the entrance of the dijkstra algorithm} +\usage{ +dijkstra(graph, init_node) +} +\arguments{ +\item{graph}{a graph to find the shortest path} + +\item{init_node}{the start node to find the shortest path in the graph} +} +\description{ +the dijkstra algorithm to find the shortest path in the graph +} diff --git a/man/euclidean.Rd b/man/euclidean.Rd new file mode 100644 index 0000000000000000000000000000000000000000..c3c30c97ffd649b8ac4ca3e0b8488db467e2a55a --- /dev/null +++ b/man/euclidean.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lab_3_submission.R +\name{euclidean} +\alias{euclidean} +\title{euclidean algorithm} +\usage{ +euclidean(x, y) +} +\arguments{ +\item{x}{first number} + +\item{y}{second number} +} +\description{ +Euclidian algorithm to find the +greatest common divisor of two numbers +} diff --git a/man/init_node_distance_list.Rd b/man/init_node_distance_list.Rd new file mode 100644 index 0000000000000000000000000000000000000000..af02e37f6e9a6551219d2f174ea91003c63ec349 --- /dev/null +++ b/man/init_node_distance_list.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lab_3_submission.R +\name{init_node_distance_list} +\alias{init_node_distance_list} +\title{initial the detail frame} +\usage{ +init_node_distance_list(init_node, graph) +} +\arguments{ +\item{init_node}{the start node to find the shortest path} + +\item{graph}{the structure of the graph, +eg:wiki_graph <- data.frame(v1=c(1,1,1,2,2,2,3,3,3,3,4,4,4,5,5,6,6,6), + v2=c(2,3,6,1,3,4,1,2,4,6,2,3,5,4,6,1,3,5), + w=c(7,9,14,7,10,15,9,10,11,2,15,11,6,6,9,14,2,9))} +} +\description{ +init the detail table +} diff --git a/man/update_detail_path.Rd b/man/update_detail_path.Rd new file mode 100644 index 0000000000000000000000000000000000000000..b7013cc4139d3e0454e5b3906a1b68194e75a90b --- /dev/null +++ b/man/update_detail_path.Rd @@ -0,0 +1,31 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lab_3_submission.R +\name{update_detail_path} +\alias{update_detail_path} +\title{update the detail frame when traversing to a new node} +\usage{ +update_detail_path( + node, + init_node, + detail_frame, + graph, + checked_nodes, + unchecked_nodes +) +} +\arguments{ +\item{node}{the current the node when traversing all the nodes to find the best way} + +\item{init_node}{the start node in the algorithm} + +\item{detail_frame}{to store the shorest path , if it is the best node and the related distance} + +\item{graph}{the graph indicates the relationship of different nodes} + +\item{checked_nodes}{the nodes that having found the shortest path} + +\item{unchecked_nodes}{the nodes that having not found the shortest path} +} +\description{ +the update method for detail table to record the shortest path +} diff --git a/man/wiki_graph.Rd b/man/wiki_graph.Rd new file mode 100644 index 0000000000000000000000000000000000000000..23c0a343b4384d33105f36c6ef9ff27f1bf8db12 --- /dev/null +++ b/man/wiki_graph.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/wiki_graph.R +\docType{data} +\name{wiki_graph} +\alias{wiki_graph} +\title{graph} +\format{ +A data frame with 18 rows and 3 columns: +\describe{ + \item{v1}{node name} + \item{v2}{node name} + \item{w}{the weight between node v1 and node v2} + ... +} +} +\usage{ +wiki_graph +} +\description{ +graph +} +\keyword{datasets} diff --git a/tests/testthat.R b/tests/testthat.R new file mode 100644 index 0000000000000000000000000000000000000000..480670efebea35a2ea53e93eab972825ff6ff824 --- /dev/null +++ b/tests/testthat.R @@ -0,0 +1,12 @@ +# This file is part of the standard setup for testthat. +# It is recommended that you do not modify it. +# +# Where should you do additional test configuration? +# Learn more about the roles of various files in: +# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview +# * https://testthat.r-lib.org/articles/special-files.html + +library(testthat) +library(lab) + +test_check("lab") diff --git a/tests/testthat/test.dijkstra.R b/tests/testthat/test.dijkstra.R new file mode 100644 index 0000000000000000000000000000000000000000..f49d110330679e06c1302dc3b1d70be5155ec0ef --- /dev/null +++ b/tests/testthat/test.dijkstra.R @@ -0,0 +1,23 @@ +# context("dijkstra") +library(testthat) + +wiki_graph <- + data.frame(v1=c(1,1,1,2,2,2,3,3,3,3,4,4,4,5,5,6,6,6), + v2=c(2,3,6,1,3,4,1,2,4,6,2,3,5,4,6,1,3,5), + w=c(7,9,14,7,10,15,9,10,11,2,15,11,6,6,9,14,2,9)) + +test_that("outputs are correct in the Dijkstra algorithm.", { + expect_equal(dijkstra(wiki_graph,1), c(0,7,9,20,20,11)) + expect_equal(dijkstra(wiki_graph,3), c(9,10,0,11,11,2)) +}) + + +test_that("Error messages are returned for erronous input in the Dijkstra algorithm.", { + wiki_wrong_graph <- wiki_graph + names(wiki_wrong_graph) <- c("v1, v3, w") + expect_error(dijkstra(wiki_wrong_graph, 3)) + wiki_wrong_graph <- wiki_graph[1:2] + expect_error(dijkstra(wiki_wrong_graph, 3)) + expect_error(dijkstra(wiki_graph, 7)) + expect_error(dijkstra(as.matrix(wiki_graph), 3)) +}) diff --git a/tests/testthat/test_euclidean.R b/tests/testthat/test_euclidean.R new file mode 100644 index 0000000000000000000000000000000000000000..98138cdf3d88b3dae8f2683bde6ca94d40d1a319 --- /dev/null +++ b/tests/testthat/test_euclidean.R @@ -0,0 +1,15 @@ +library(testthat) + + +test_that("GDC is calculated correctly.", { + expect_equal(euclidean(123612, 13892347912), 4) + expect_equal(euclidean(100, 1000), 100) + expect_equal(euclidean(-100, 1000), 100) +}) + + +test_that("Wrong input throws an error.", { + expect_error(euclidean("100", 1000)) + expect_error(euclidean(100, "1000")) + expect_error(euclidean(TRUE, "1000")) +}) \ No newline at end of file