diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 7ac45b88b..3ced37848 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -12,6 +12,7 @@ ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## ## Copyright 2023 by Maximilian Löffler +## Copyright 2024 by Thomas Bock ## All Rights Reserved. name: Build Status @@ -29,17 +30,17 @@ permissions: jobs: build: name: Build - + # change to 'runs-on: self-hosted' to run on self-hosted runners (https://docs.github.com/en/actions/using-jobs/choosing-the-runner-for-a-job) runs-on: ubuntu-latest - + strategy: fail-fast: false matrix: - r-version: ['3.6', '4.0', '4.1', '4.2', 'latest'] + r-version: ['3.6', '4.0', '4.1', '4.2', '4.3', 'latest'] steps: - - name: Checkout Repo + - name: Checkout Repo uses: actions/checkout@v3 - name: Update system @@ -56,7 +57,7 @@ jobs: uses: r-lib/actions/setup-r@v2 with: r-version: ${{ matrix.r-version }} - + - name: Install dependencies run: Rscript install.R diff --git a/NEWS.md b/NEWS.md index 8192e6c05..a54b974bf 100644 --- a/NEWS.md +++ b/NEWS.md @@ -6,10 +6,11 @@ ### Added -- Add issue-based artifact-networks (PR #244, 98a93ee721a293410623aafe46890cfba9d81e72, 771bcc8d961d419b53a1e891e9dc536371f1143b) +- Add issue-based artifact-networks (PR #244, 98a93ee721a293410623aafe46890cfba9d81e72, 771bcc8d961d419b53a1e891e9dc536371f1143b, 368e79264adf5a5358c04518c94ad2e1c13e212b) - Add a new `split.data.by.bins` function (not to be confused with a previously existing function that had the same name and was renamed in this context), which splits data based on given activity-based bins (PR #244, ece569ceaf557bb38cd0cfad437b69b30fe8a698, ed5feb214a123b605c9513262f187cfd72b9e1f4) - Add new `assert.sparse.matrices.equal` function to compare two sparse matrices for equality for testing purposes (PR #248, 9784cdf12d1497ee122e2ae73b768b8c334210d4, d9f1a8d90e00a634d7caeb5e7f8f262776496838) - Add tests for file `util-networks.misc.R` for issue #242 (PR #248, f3202a6f96723d11c170346556d036cf087521c8, 030574b9d0f3435db4032d0e195a3d407fb7244b, 380b02234275127297fcd508772c69db21c216de, 8b803c50d60fc593e4e527a08fd4c2068d801a48, 7335c3dd4d0302b024a66d18701d9800ed3fe806, 6b600df04bec1fe70c272604f274ec5309840e65) +- Add the possibility to simplify edges of multiple-relation networks into a single edge at all instead of a single edge per relation (PR #250, 2105ea89b5227e7c9fa78fea9de1977f2d9e8faa) ### Changed/Improved @@ -20,6 +21,7 @@ - Change `util-tensor.R` to correctly use the new output format of `get.author.names.from.network` (PR #248, 72b663ebf7169c0da5c687fe215529f3be0c08c5) - Throw an error in `convert.adjacency.matrix.list.to.array` if the function is called with wrong parameters (PR #248, ece2d38b4972745af3a83e06f32317a06465a345, 1a3e510df15f5fa4e920e9fce3e0e162c27cd6d1) - Rename `compare.networks` to `assert.networks.equal` to better match the purpose of the function (PR #248, d9f1a8d90e00a634d7caeb5e7f8f262776496838) +- Explicitly add R version 4.3 to the CI test pipeline (9f346d5bc3cfc553f01e5e80f0bbe51e1dc2b53e) ### Fixed @@ -30,6 +32,8 @@ - Fix `get.expanded.adjacency` to work if the provided author list does not contain all authors from network and add a warning when that happens since it causes some authors from the network to be lost in the resulting matrix (PR #248, ff59017e114b10812dcfb1704a19e01fc1586a13) - Fix `get.expanded.adjacency.matrices` to have correct names for the columns and rows (PR #248, e72eff864a1cb1a4aecd430e450d4a6a5044fdf2) - Fix `get.expanded.adjacency.cumulated` so that it works if `weighted` parameter is set to `FALSE` (PR #248, 2fb9a5d446653f6aee808cbfc87c2dafeb9a749a) +- Fix broken error loggingin `metrics.smallworldness` (03e06881f06abf30d44b69d7988873f20b95232d) +- Fix multi-network construction to work with igraph version 2.0.1.1, which does not allow to add an empty list of vertices (PR #250, 5547896faa279f6adaae4b2b77c7ab9623ddf256) ## 4.3 diff --git a/README.md b/README.md index 3ebd1bf92..62c029b33 100644 --- a/README.md +++ b/README.md @@ -632,7 +632,7 @@ Updates to the parameters can be done by calling `NetworkConf$update.variables(. * possible values: [*`"cochange"`*, `"callgraph"`, `"mail"`, `"issue"`] - `artifact.directed` * The directedness of edges in an artifact network - * **Note**: This parameter does not take effect for now, as the `cochange` relation is always undirected, while the `callgraph` relation is always directed. For the other relations (`mail` and `issue`), we currently do not have data available to exhibit edge information. + * **Note**: This parameter does only affect the `issue` relation, as the `cochange` relation is always undirected, while the `callgraph` relation is always directed. For the `mail`, we currently do not have data available to exhibit edge information. * [`TRUE`, *`FALSE`*] - `edge.attributes` * The list of edge-attribute names and information @@ -654,6 +654,10 @@ Updates to the parameters can be done by calling `NetworkConf$update.variables(. - `simplify` * Perform edge contraction to retrieve a simplified network * [`TRUE`, *`FALSE`*] +- `simplify.multiple.relations` + * Whether the simplified network should contract edges of multiple relations into a single edge or not (if not, there will be one edge for each relation, resulting in possibly more than one edge between a pair of vertices) + * **Note** This parameter does not take effect if ``simplify = FALSE``! + * [`TRUE`, *`FALSE`*] - `skip.threshold` * The upper bound for total amount of edges to build for a subset of the data, i.e., not building any edges for the subset exceeding the limit * any positive integer diff --git a/util-conf.R b/util-conf.R index f05c2b924..0031771a4 100644 --- a/util-conf.R +++ b/util-conf.R @@ -18,7 +18,7 @@ ## Copyright 2020-2021 by Christian Hechtl ## Copyright 2017 by Felix Prasse ## Copyright 2017-2019 by Thomas Bock -## Copyright 2021, 2023 by Thomas Bock +## Copyright 2021, 2023-2024 by Thomas Bock ## Copyright 2018 by Barbara Eckl ## Copyright 2018-2019 by Jakob Kronawitter ## Copyright 2019 by Anselm Fehnker @@ -863,6 +863,12 @@ NetworkConf = R6::R6Class("NetworkConf", inherit = Conf, allowed = c(TRUE, FALSE), allowed.number = 1 ), + simplify.multiple.relations = list( + default = FALSE, + type = "logical", + allowed = c(TRUE, FALSE), + allowed.number = 1 + ), skip.threshold = list( default = Inf, type = "numeric", diff --git a/util-networks-metrics.R b/util-networks-metrics.R index faa7c4f69..5111ef5e3 100644 --- a/util-networks-metrics.R +++ b/util-networks-metrics.R @@ -12,7 +12,7 @@ ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## ## Copyright 2015, 2019 by Thomas Bock -## Copyright 2021, 2023 by Thomas Bock +## Copyright 2021, 2023-2024 by Thomas Bock ## Copyright 2017 by Raphael Nömmer ## Copyright 2017-2019 by Claus Hunsen ## Copyright 2017-2018 by Christian Hechtl @@ -167,7 +167,7 @@ metrics.smallworldness = function(network) { if (!is.simple(network)) { ## if this is not the case, raise an error and stop the execution error.message = "The input network has too many edges. Try again with a simplified network." - logging::error(error.message) + logging::logerror(error.message) stop(error.message) } diff --git a/util-networks.R b/util-networks.R index 7fa76f4f6..e21b40791 100644 --- a/util-networks.R +++ b/util-networks.R @@ -15,7 +15,7 @@ ## Copyright 2017 by Raphael Nömmer ## Copyright 2017-2018 by Christian Hechtl ## Copyright 2017-2019 by Thomas Bock -## Copyright 2021, 2023 by Thomas Bock +## Copyright 2021, 2023-2024 by Thomas Bock ## Copyright 2018 by Barbara Eckl ## Copyright 2018-2019 by Jakob Kronawitter ## Copyright 2020 by Anselm Fehnker @@ -958,8 +958,10 @@ NetworkBuilder = R6::R6Class("NetworkBuilder", ## to be consistent with bipartite networks artifacts.to.add.kind[artifacts.to.add.kind == "IssueEvent"] = "Issue" - artifacts.net = artifacts.net + igraph::vertices(artifacts.to.add, type = TYPE.ARTIFACT, - kind = artifacts.to.add.kind) + if (length(artifacts.to.add) > 0) { + artifacts.net = artifacts.net + igraph::vertices(artifacts.to.add, type = TYPE.ARTIFACT, + kind = artifacts.to.add.kind) + } ## check directedness and adapt artifact network if needed if (igraph::is.directed(authors.net) && !igraph::is.directed(artifacts.net)) { @@ -1260,7 +1262,8 @@ construct.network.from.edge.list = function(vertices, edge.list, network.conf, d ## transform multiple edges to edge weights if (network.conf$get.value("simplify")) { - net = simplify.network(net) + net = simplify.network(net, + simplify.multiple.relations = network.conf$get.value("simplify.multiple.relations")) } logging::logdebug("construct.network.from.edge.list: finished.") @@ -1536,16 +1539,19 @@ add.attributes.to.network = function(network, type = c("vertex", "edge"), attrib #' @param network the given network #' @param remove.multiple whether to contract multiple edges between the same pair of vertices [default: TRUE] #' @param remove.loops whether to remove loops [default: TRUE] +#' @param simplify.multiple.relations whether to combine edges of multiple relations into +#' one simplified edge [default: FALSE] #' #' @return the simplified network -simplify.network = function(network, remove.multiple = TRUE, remove.loops = TRUE) { +simplify.network = function(network, remove.multiple = TRUE, remove.loops = TRUE, + simplify.multiple.relations = FALSE) { logging::logdebug("simplify.network: starting.") logging::loginfo("Simplifying network.") ## save network attributes, otherwise they get lost network.attributes = igraph::get.graph.attribute(network) - if (length(unique(igraph::get.edge.attribute(network, "relation"))) > 1) { + if (!simplify.multiple.relations && length(unique(igraph::get.edge.attribute(network, "relation"))) > 1) { ## data frame of the network edge.data = igraph::as_data_frame(network, what = "edges") vertex.data = igraph::as_data_frame(network, what = "vertices") @@ -1587,9 +1593,12 @@ simplify.network = function(network, remove.multiple = TRUE, remove.loops = TRUE #' @param networks the list of networks #' @param remove.multiple whether to contract multiple edges between the same pair of vertices [default: TRUE] #' @param remove.loops whether to remove loops [default: TRUE] +#' @param simplify.multiple.relations whether to combine edges of multiple relations into +#' one simplified edge [default: FALSE] #' #' @return the simplified networks -simplify.networks = function(networks, remove.multiple = TRUE, remove.loops = TRUE) { +simplify.networks = function(networks, remove.multiple = TRUE, remove.loops = TRUE, + simplify.multiple.relations = FALSE) { logging::logdebug("simplify.networks: starting.") logging::loginfo( "Simplifying networks (names = [%s]).", @@ -1597,7 +1606,7 @@ simplify.networks = function(networks, remove.multiple = TRUE, remove.loops = TR ) nets = parallel::mclapply(networks, simplify.network, remove.multiple = remove.multiple, - remove.loops = remove.loops) + remove.loops = remove.loops, simplify.multiple.relations = simplify.multiple.relations) logging::logdebug("simplify.networks: finished.") return(nets)