From f20f5696cfbfbfd71fbf9e756fc1a331cdec9b54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Sat, 17 Sep 2016 13:17:54 -0700 Subject: [PATCH 01/25] randomly generate graphs with max given indegree --- .gitignore | 2 + tps-core/src/main/scala/tps/ArgHandling.scala | 2 - tps-core/src/main/scala/tps/Graphs.scala | 20 +++---- .../tps/simulation/RandomGraphGenerator.scala | 53 +++++++++++++++++++ .../src/test/scala/tps/SolverOutputTest.scala | 9 +--- .../src/test/scala/tps/TestResourceUtil.scala | 12 +++++ .../simulation/RandomGraphGeneratorTest.scala | 22 ++++++++ 7 files changed, 98 insertions(+), 22 deletions(-) create mode 100644 tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala create mode 100644 tps-core/src/test/scala/tps/TestResourceUtil.scala create mode 100644 tps-core/src/test/scala/tps/simulation/RandomGraphGeneratorTest.scala diff --git a/.gitignore b/.gitignore index c6254490..8111fa95 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ *.swp +*.iml +.idea .DS_Store sbt project/project diff --git a/tps-core/src/main/scala/tps/ArgHandling.scala b/tps-core/src/main/scala/tps/ArgHandling.scala index b7ee04aa..f59df7fd 100644 --- a/tps-core/src/main/scala/tps/ArgHandling.scala +++ b/tps-core/src/main/scala/tps/ArgHandling.scala @@ -2,8 +2,6 @@ package tps import tps.util.LogUtils -import java.io.File - object ArgHandling { def parseOptions(args: Array[String]) = { val opts = new Options() diff --git a/tps-core/src/main/scala/tps/Graphs.scala b/tps-core/src/main/scala/tps/Graphs.scala index 0395ccc7..cb4b5cce 100644 --- a/tps-core/src/main/scala/tps/Graphs.scala +++ b/tps-core/src/main/scala/tps/Graphs.scala @@ -1,7 +1,5 @@ package tps -import tps.util.LogUtils._ - object Graphs { case class Vertex(id: String) extends Serializable { @@ -88,20 +86,18 @@ object Graphs { distances += v -> 0 } - while (!toProcess.isEmpty) { + while (toProcess.nonEmpty) { distance += 1 - val nextStep = toProcess.flatMap{ v => + val nextStep = toProcess.flatMap { v => this.neighbors(v) - }.filter{ v => - !alreadySeen.contains(v) - } + }.diff(alreadySeen) - for (v <- nextStep) { - distances += v -> distance - } + for (v <- nextStep) { + distances += v -> distance + } - alreadySeen ++= nextStep - toProcess = nextStep + alreadySeen ++= nextStep + toProcess = nextStep } distances diff --git a/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala b/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala new file mode 100644 index 00000000..9514b271 --- /dev/null +++ b/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala @@ -0,0 +1,53 @@ +package tps.simulation + +import tps.Graphs.{Edge, UndirectedGraph} + +/** + * Generates a random graph of given size through a random walk on a given + * [[UndirectedGraph]], starting from its sources. + */ +object RandomGraphGenerator { + + private val RANDOM_SEED = 131161511 + private val MAX_NODE_DEGREE = 3 + + object CannotExtendException extends Exception + + def generateRandomGraph(sourceGraph: UndirectedGraph, + maxNodeLimit: Int): UndirectedGraph = { + assert(sourceGraph.sources.size <= maxNodeLimit) + + val random = new scala.util.Random(RANDOM_SEED) + var generatedGraph = UndirectedGraph(sourceGraph.sources, Set.empty, + sourceGraph.sources) + + try { + while (generatedGraph.V.size < maxNodeLimit) { + // find a random incident edge to add while respecting max degree limit. + val candidates = extensionCandidates(generatedGraph, sourceGraph) + if (candidates.isEmpty) throw CannotExtendException + + val edgeToAdd = candidates.toIndexedSeq(random.nextInt(candidates.size)) + generatedGraph = UndirectedGraph( + generatedGraph.V ++ Set(edgeToAdd.v1, edgeToAdd.v2), + generatedGraph.E + edgeToAdd, + generatedGraph.sources) + } + generatedGraph + } catch { + case CannotExtendException => generatedGraph + } + } + + private def extensionCandidates(graphToExtend: UndirectedGraph, + sourceGraph: UndirectedGraph): Set[Edge] = { + graphToExtend.V.flatMap { v => + sourceGraph.incidentEdges(v).filter { e => + // only take edges that do not exist and that won't exceed max indegree + !graphToExtend.E.contains(e) && + graphToExtend.incidentEdges(e.v1).size < MAX_NODE_DEGREE && + graphToExtend.incidentEdges(e.v2).size < MAX_NODE_DEGREE + } + } + } +} diff --git a/tps-core/src/test/scala/tps/SolverOutputTest.scala b/tps-core/src/test/scala/tps/SolverOutputTest.scala index 2a2cd13d..5bef0394 100644 --- a/tps-core/src/test/scala/tps/SolverOutputTest.scala +++ b/tps-core/src/test/scala/tps/SolverOutputTest.scala @@ -1,5 +1,4 @@ package tps -package test import org.scalatest.FunSuite import org.scalatest.Matchers @@ -7,16 +6,10 @@ import org.scalatest.Matchers import Graphs._ import tps.synthesis.SynthesisOptions -import java.io.File +import TestResourceUtil.testFile class SolverOutputTest extends FunSuite with Matchers { - private val resourceBaseFolder = "/simple-example" - private def testFile(name: String): File = { - val url = getClass.getResource(s"$resourceBaseFolder/$name") - new File(url.getFile()) - } - test("output of solvers match") { val network = UndirectedGraphParser.run(testFile("network.tsv")) val timeSeries = TimeSeriesParser.run(testFile("time-series.tsv")) diff --git a/tps-core/src/test/scala/tps/TestResourceUtil.scala b/tps-core/src/test/scala/tps/TestResourceUtil.scala new file mode 100644 index 00000000..8f0559de --- /dev/null +++ b/tps-core/src/test/scala/tps/TestResourceUtil.scala @@ -0,0 +1,12 @@ +package tps + +import java.io.File + +object TestResourceUtil { + private val RESOURCE_BASE_FOLDER = "/simple-example" + + def testFile(name: String): File = { + val url = getClass.getResource(s"$RESOURCE_BASE_FOLDER/$name") + new File(url.getFile()) + } +} diff --git a/tps-core/src/test/scala/tps/simulation/RandomGraphGeneratorTest.scala b/tps-core/src/test/scala/tps/simulation/RandomGraphGeneratorTest.scala new file mode 100644 index 00000000..508afdd7 --- /dev/null +++ b/tps-core/src/test/scala/tps/simulation/RandomGraphGeneratorTest.scala @@ -0,0 +1,22 @@ +package tps.simulation + +import org.scalatest.FunSuite +import org.scalatest.Matchers +import tps.Graphs.Vertex +import tps.UndirectedGraphParser +import tps.TestResourceUtil.testFile + +class RandomGraphGeneratorTest extends FunSuite with Matchers { + + test("random graph of desired size can be generated") { + val sourceGraph = UndirectedGraphParser.run(testFile("network.tsv")).copy( + sources = Set(Vertex("A"))) + val maxNodeLimit = 3 + val generated = RandomGraphGenerator.generateRandomGraph( + sourceGraph, + maxNodeLimit) + + generated.V.size should equal (3) + } + +} From cd5fd7e56713faafd4ad89101e3e4a86a195b0ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Sat, 17 Sep 2016 15:34:58 -0700 Subject: [PATCH 02/25] random time series data generation --- .../RandomTimeSeriesGenerator.scala | 63 +++++++++++++++++++ .../simulation/RandomGraphGeneratorTest.scala | 3 +- 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala diff --git a/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala b/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala new file mode 100644 index 00000000..95ef5a5c --- /dev/null +++ b/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala @@ -0,0 +1,63 @@ +package tps.simulation + +import tps.Graphs.UndirectedGraph +import tps.{Profile, TimeSeries} + +/** + * Generates random time series data for a given [[tps.Graphs.UndirectedGraph]] + */ +object RandomTimeSeriesGenerator { + + private val RANDOM_SEED = 0 + private val random = new scala.util.Random(RANDOM_SEED) + + private val MAX_PROFILE_VALUE = 10 + + private val NB_TIME_POINTS = 10 + + // probability of a node having time series data + private val COVERAGE_RATIO = 0.8 + + /** + * Generates random time series data for the given graph. + * + * Data is generated for a subset of the nodes in the graph. + */ + def generateRandomTimeSeries(graph: UndirectedGraph): TimeSeries = { + var profiles: Set[Profile] = Set.empty + for (v <- graph.V) { + if (random.nextDouble() < COVERAGE_RATIO) { + profiles += generateProfile(v.id) + } + } + TimeSeries(generateLabels(), profiles.toSeq) + } + + /** + * Generates trivial significance scores for the given time series data, + * depending on whether values are defined at each time point. + */ + def generateSignificanceScores( + timeSeries: TimeSeries + ): Map[String, Seq[Double]] = { + val pairs = for (p <- timeSeries.profiles) yield { + val sigScores = p.values.map { v => + if (v.isDefined) 0.0 else 1.0 + } + p.id -> sigScores + } + pairs.toMap + } + + private def generateLabels(): Seq[String] = { + (1 to NB_TIME_POINTS).map(i => s"t$i") + } + + private def generateProfile(id: String): Profile = { + // all profile values are defined + val values = (0 until NB_TIME_POINTS).map(i => + Some(random.nextDouble() * MAX_PROFILE_VALUE)) + Profile(id, values) + } + +} diff --git a/tps-core/src/test/scala/tps/simulation/RandomGraphGeneratorTest.scala b/tps-core/src/test/scala/tps/simulation/RandomGraphGeneratorTest.scala index 508afdd7..931d2eaa 100644 --- a/tps-core/src/test/scala/tps/simulation/RandomGraphGeneratorTest.scala +++ b/tps-core/src/test/scala/tps/simulation/RandomGraphGeneratorTest.scala @@ -8,7 +8,7 @@ import tps.TestResourceUtil.testFile class RandomGraphGeneratorTest extends FunSuite with Matchers { - test("random graph of desired size can be generated") { + test("random graph contains source and has right size") { val sourceGraph = UndirectedGraphParser.run(testFile("network.tsv")).copy( sources = Set(Vertex("A"))) val maxNodeLimit = 3 @@ -17,6 +17,7 @@ class RandomGraphGeneratorTest extends FunSuite with Matchers { maxNodeLimit) generated.V.size should equal (3) + generated.V should contain (Vertex("A")) } } From a8a68435f3f58fbe7282a1f0367cfa78f5c0e0fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Sat, 17 Sep 2016 16:12:16 -0700 Subject: [PATCH 03/25] harness to run scalability analysis --- scripts/run-scalability-analysis | 7 +++ .../tps/evaluation/ScalabilityAnalysis.scala | 51 +++++++++++++++++++ .../RandomTimeSeriesGenerator.scala | 3 +- 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100755 scripts/run-scalability-analysis create mode 100644 tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala diff --git a/scripts/run-scalability-analysis b/scripts/run-scalability-analysis new file mode 100755 index 00000000..0eabd6b9 --- /dev/null +++ b/scripts/run-scalability-analysis @@ -0,0 +1,7 @@ +#!/bin/bash + +sbt "project tps-core" "run-main tps.evaluation.ScalabilityAnalysis \ + --network data/networks/directed-pin-with-resource-edges.tsv \ + --source EGF_HUMAN \ + --threshold 0.01 +" diff --git a/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala new file mode 100644 index 00000000..576c2635 --- /dev/null +++ b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala @@ -0,0 +1,51 @@ +package tps.evaluation + +import java.io.File + +import tps.Graphs.UndirectedGraph +import tps._ +import tps.simulation.{RandomGraphGenerator, RandomTimeSeriesGenerator} +import tps.synthesis.{Synthesis, SynthesisOptions} +import tps.util.Stopwatch + +/** + * Evaluates solver running time on randomly simulated data. + */ +object ScalabilityAnalysis { + + private val MIN_GRAPH_SIZE = 5000 + private val MAX_GRAPH_SIZE = 100000 + private val GRAPH_SIZE_STEP = 5000 + + def main(args: Array[String]): Unit = { + val resultReporter = new NoopReporter() + + val sourceGraph = UndirectedGraphParser.run( + new File("data/networks/directed-pin-with-resource-edges.tsv")) + val sources = Set("EGF_HUMAN") + val threshold = 0.01 + + for (size <- Range(MIN_GRAPH_SIZE, MAX_GRAPH_SIZE, GRAPH_SIZE_STEP)) { + val g = RandomGraphGenerator.generateRandomGraph(sourceGraph, size) + val ts = RandomTimeSeriesGenerator.generateRandomTimeSeries(g) + val scores = RandomTimeSeriesGenerator.generateSignificanceScores(ts) + + val sw = new Stopwatch(s"Graph size: V = ${g.V.size}, E = ${g.E.size}", + verbose = true) + sw.start + Synthesis.run( + g, + ts, + scores, + scores, + Set.empty, + Map.empty, + sources, + threshold, + SynthesisOptions(), + resultReporter + ) + sw.stop + } + } +} diff --git a/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala b/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala index 95ef5a5c..39ba85bd 100644 --- a/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala +++ b/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala @@ -41,7 +41,8 @@ object RandomTimeSeriesGenerator { timeSeries: TimeSeries ): Map[String, Seq[Double]] = { val pairs = for (p <- timeSeries.profiles) yield { - val sigScores = p.values.map { v => + // compute scores for all time points except the first + val sigScores = p.values.tail.map { v => if (v.isDefined) 0.0 else 1.0 } p.id -> sigScores From 392be4afbbe04c90ea18125b13ca4d08484a2c3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Sat, 17 Sep 2016 16:21:35 -0700 Subject: [PATCH 04/25] fix PIN parsing --- tps-core/src/main/scala/tps/UndirectedGraphOps.scala | 9 +++++++++ .../main/scala/tps/evaluation/ScalabilityAnalysis.scala | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tps-core/src/main/scala/tps/UndirectedGraphOps.scala b/tps-core/src/main/scala/tps/UndirectedGraphOps.scala index 1a0eff9c..30c777ba 100644 --- a/tps-core/src/main/scala/tps/UndirectedGraphOps.scala +++ b/tps-core/src/main/scala/tps/UndirectedGraphOps.scala @@ -26,4 +26,13 @@ object UndirectedGraphOps { } def emptyGraph: UndirectedGraph = UndirectedGraph(Set.empty, Set.empty, Set.empty) + + def fromDirectedGraph(g: DirectedGraph): UndirectedGraph = { + var V: Set[Vertex] = Set.empty + val E = g.keySet + for (e <- E) { + V ++= Set(e.v1, e.v2) + } + UndirectedGraph(V, E, Set.empty) + } } diff --git a/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala index 576c2635..2fcded82 100644 --- a/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala +++ b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala @@ -20,8 +20,9 @@ object ScalabilityAnalysis { def main(args: Array[String]): Unit = { val resultReporter = new NoopReporter() - val sourceGraph = UndirectedGraphParser.run( + val pin = PINParser.run( new File("data/networks/directed-pin-with-resource-edges.tsv")) + val sourceGraph = UndirectedGraphOps.fromDirectedGraph(pin) val sources = Set("EGF_HUMAN") val threshold = 0.01 From 378eba889c4bea5262726f9d56c91bcc2a820c75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Sat, 17 Sep 2016 16:41:21 -0700 Subject: [PATCH 05/25] add source vertex to random graph gen --- .../src/main/scala/tps/evaluation/ScalabilityAnalysis.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala index 2fcded82..9ac3e14c 100644 --- a/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala +++ b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala @@ -2,7 +2,7 @@ package tps.evaluation import java.io.File -import tps.Graphs.UndirectedGraph +import tps.Graphs.{UndirectedGraph, Vertex} import tps._ import tps.simulation.{RandomGraphGenerator, RandomTimeSeriesGenerator} import tps.synthesis.{Synthesis, SynthesisOptions} @@ -22,8 +22,9 @@ object ScalabilityAnalysis { val pin = PINParser.run( new File("data/networks/directed-pin-with-resource-edges.tsv")) - val sourceGraph = UndirectedGraphOps.fromDirectedGraph(pin) val sources = Set("EGF_HUMAN") + val sourceGraph = UndirectedGraphOps.fromDirectedGraph(pin).copy( + sources = sources.map(Vertex(_))) val threshold = 0.01 for (size <- Range(MIN_GRAPH_SIZE, MAX_GRAPH_SIZE, GRAPH_SIZE_STEP)) { From d98847819e47833863a1a69140da5a8343f04e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Sat, 17 Sep 2016 16:55:04 -0700 Subject: [PATCH 06/25] cached graph neighbor computation --- tps-core/src/main/scala/tps/Graphs.scala | 19 ++++++++++--------- .../tps/evaluation/ScalabilityAnalysis.scala | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/tps-core/src/main/scala/tps/Graphs.scala b/tps-core/src/main/scala/tps/Graphs.scala index cb4b5cce..1cce0d76 100644 --- a/tps-core/src/main/scala/tps/Graphs.scala +++ b/tps-core/src/main/scala/tps/Graphs.scala @@ -31,23 +31,24 @@ object Graphs { assert(v1.id <= v2.id) } + private var neighborMap = Map[Vertex, Set[Vertex]().withDefaultValue( + Set.empty[Vertex]) + for (e <- E) { + neighborMap += e.v1 -> (neighborMap(e.v1) + e.v2) + neighborMap += e.v2 -> (neighborMap(e.v2) + e.v1) + } + override def toString = { V.mkString("V = {", ", ", "}") + "\n" + E.mkString("E = {", ", ", "}") + "\n" + sources.mkString("SRC = {", ", ", "}") } - def neighbors(v: Vertex): Set[Vertex] = { - E collect { - case Edge(v1, v2) if v1 == v => v2 - case Edge(v1, v2) if v2 == v => v1 - } - } + def neighbors(v: Vertex): Set[Vertex] = neighborMap(v) def incidentEdges(v: Vertex): Set[Edge] = { - E filter { - case Edge(v1, v2) => v1 == v || v2 == v - } + val ns = neighbors(v) + ns.map(n => GraphParsing.lexicographicEdge(n.id, v.id)) } def contains(e: Edge): Boolean = { diff --git a/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala index 9ac3e14c..1857bd25 100644 --- a/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala +++ b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala @@ -2,7 +2,7 @@ package tps.evaluation import java.io.File -import tps.Graphs.{UndirectedGraph, Vertex} +import tps.Graphs.Vertex import tps._ import tps.simulation.{RandomGraphGenerator, RandomTimeSeriesGenerator} import tps.synthesis.{Synthesis, SynthesisOptions} From cdadc20c289bbb5503637b6d41fa80e3355ee90a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Sat, 17 Sep 2016 16:56:17 -0700 Subject: [PATCH 07/25] fix --- tps-core/src/main/scala/tps/Graphs.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tps-core/src/main/scala/tps/Graphs.scala b/tps-core/src/main/scala/tps/Graphs.scala index 1cce0d76..a34b2538 100644 --- a/tps-core/src/main/scala/tps/Graphs.scala +++ b/tps-core/src/main/scala/tps/Graphs.scala @@ -31,7 +31,7 @@ object Graphs { assert(v1.id <= v2.id) } - private var neighborMap = Map[Vertex, Set[Vertex]().withDefaultValue( + private var neighborMap = Map[Vertex, Set[Vertex]]().withDefaultValue( Set.empty[Vertex]) for (e <- E) { neighborMap += e.v1 -> (neighborMap(e.v1) + e.v2) From b37f4bd531877255bb3a74cf78ff5c022c8e9b77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Sat, 17 Sep 2016 23:32:32 -0700 Subject: [PATCH 08/25] purely random graph generation for efficiency --- tps-core/src/main/scala/tps/Graphs.scala | 5 ++- tps-core/src/main/scala/tps/PINParser.scala | 9 ++--- .../src/main/scala/tps/ReferenceParser.scala | 8 ++--- .../scala/tps/SignedDirectedGraphParser.scala | 2 +- .../tps/evaluation/ScalabilityAnalysis.scala | 14 +++++--- .../tps/simulation/RandomGraphGenerator.scala | 36 +++++++++++++++++-- .../simulation/RandomGraphGeneratorTest.scala | 14 ++++++-- 7 files changed, 69 insertions(+), 19 deletions(-) diff --git a/tps-core/src/main/scala/tps/Graphs.scala b/tps-core/src/main/scala/tps/Graphs.scala index a34b2538..f9c01720 100644 --- a/tps-core/src/main/scala/tps/Graphs.scala +++ b/tps-core/src/main/scala/tps/Graphs.scala @@ -48,7 +48,7 @@ object Graphs { def incidentEdges(v: Vertex): Set[Edge] = { val ns = neighbors(v) - ns.map(n => GraphParsing.lexicographicEdge(n.id, v.id)) + ns.map(n => lexicographicEdge(n, v)) } def contains(e: Edge): Boolean = { @@ -142,6 +142,9 @@ object Graphs { } } + def lexicographicEdge(v1: Vertex, v2: Vertex): Edge = + GraphParsing.lexicographicEdge(v1.id, v2.id) + private def reverseDirection(d: EdgeDirection): EdgeDirection = d match { case Forward => Backward case Backward => Forward diff --git a/tps-core/src/main/scala/tps/PINParser.scala b/tps-core/src/main/scala/tps/PINParser.scala index 36b5453e..f3c2c5a1 100644 --- a/tps-core/src/main/scala/tps/PINParser.scala +++ b/tps-core/src/main/scala/tps/PINParser.scala @@ -1,7 +1,6 @@ package tps import Graphs._ -import GraphParsing._ object PINParser { def run(f: java.io.File): DirectedGraph = { @@ -10,11 +9,13 @@ object PINParser { val Seq(id1, id2, weight, orientation) = tuple orientation match { case "U" => - lexicographicEdge(id1, id2) -> Set[EdgeDirection](Forward, Backward) + GraphParsing.lexicographicEdge(id1, id2) -> Set[EdgeDirection]( + Forward, Backward) case "D" => - lexicographicEdge(id1, id2) -> Set[EdgeDirection](lexicographicForwardDirection(id1, id2)) + GraphParsing.lexicographicEdge(id1, id2) -> Set[EdgeDirection]( + GraphParsing.lexicographicForwardDirection(id1, id2)) } } - aggregateLabels(pairs) + GraphParsing.aggregateLabels(pairs) } } diff --git a/tps-core/src/main/scala/tps/ReferenceParser.scala b/tps-core/src/main/scala/tps/ReferenceParser.scala index bf1c6af1..b85dd133 100644 --- a/tps-core/src/main/scala/tps/ReferenceParser.scala +++ b/tps-core/src/main/scala/tps/ReferenceParser.scala @@ -1,7 +1,6 @@ package tps import Graphs._ -import GraphParsing._ object ReferenceParser { def run(f: java.io.File): (SignedDirectedGraph, Map[Edge, String]) = { @@ -12,7 +11,7 @@ object ReferenceParser { val tuples = data.tuples.collect{ case tuple if tuple.size >= 7 => val Seq(src, tgt, lra, lri, rla, rli, rest @ _*) = tuple - val edge = lexicographicEdge(src, tgt) + val edge = GraphParsing.lexicographicEdge(src, tgt) assert(!evidencePerEdge.isDefinedAt(edge)) evidencePerEdge += edge -> rest.mkString(", ") @@ -28,11 +27,12 @@ object ReferenceParser { if (labelValue(rla)) originalLabels += ActiveEdge(Backward, Activating) if (labelValue(rli)) originalLabels += ActiveEdge(Backward, Inhibiting) - val lexicOrientedLabels = originalLabels map { l => lexicographicLabel(src, tgt, l) } + val lexicOrientedLabels = originalLabels map { l => + GraphParsing.lexicographicLabel(src, tgt, l) } (edge, lexicOrientedLabels) } - (aggregateLabels(tuples), evidencePerEdge) + (GraphParsing.aggregateLabels(tuples), evidencePerEdge) } } diff --git a/tps-core/src/main/scala/tps/SignedDirectedGraphParser.scala b/tps-core/src/main/scala/tps/SignedDirectedGraphParser.scala index 9acb2361..ccc2c9bf 100644 --- a/tps-core/src/main/scala/tps/SignedDirectedGraphParser.scala +++ b/tps-core/src/main/scala/tps/SignedDirectedGraphParser.scala @@ -8,7 +8,7 @@ object SignedDirectedGraphParser { val data = new TSVSource(f, noHeaders = true).data val pairs = data.tuples map { tuple => val Seq(id1, tpe, id2) = tuple - val edge = lexicographicEdge(id1, id2) + val edge = GraphParsing.lexicographicEdge(id1, id2) tpe match { case "N" => edge -> Set( lexicographicActivation(id1, id2), diff --git a/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala index 1857bd25..ff75c0c1 100644 --- a/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala +++ b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala @@ -13,22 +13,26 @@ import tps.util.Stopwatch */ object ScalabilityAnalysis { - private val MIN_GRAPH_SIZE = 5000 - private val MAX_GRAPH_SIZE = 100000 - private val GRAPH_SIZE_STEP = 5000 + private val MIN_GRAPH_SIZE = 1000 + private val MAX_GRAPH_SIZE = 10000 + private val GRAPH_SIZE_STEP = 1000 def main(args: Array[String]): Unit = { val resultReporter = new NoopReporter() + /* val pin = PINParser.run( new File("data/networks/directed-pin-with-resource-edges.tsv")) val sources = Set("EGF_HUMAN") val sourceGraph = UndirectedGraphOps.fromDirectedGraph(pin).copy( sources = sources.map(Vertex(_))) + */ val threshold = 0.01 for (size <- Range(MIN_GRAPH_SIZE, MAX_GRAPH_SIZE, GRAPH_SIZE_STEP)) { - val g = RandomGraphGenerator.generateRandomGraph(sourceGraph, size) + println(s"Evaluating with size $size") + + val g = RandomGraphGenerator.generateRandomGraph(size) val ts = RandomTimeSeriesGenerator.generateRandomTimeSeries(g) val scores = RandomTimeSeriesGenerator.generateSignificanceScores(ts) @@ -42,7 +46,7 @@ object ScalabilityAnalysis { scores, Set.empty, Map.empty, - sources, + g.sources map (_.id), threshold, SynthesisOptions(), resultReporter diff --git a/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala b/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala index 9514b271..307d77c6 100644 --- a/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala +++ b/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala @@ -1,6 +1,7 @@ package tps.simulation -import tps.Graphs.{Edge, UndirectedGraph} +import tps.Graphs +import tps.Graphs.{Edge, UndirectedGraph, Vertex} /** * Generates a random graph of given size through a random walk on a given @@ -9,11 +10,42 @@ import tps.Graphs.{Edge, UndirectedGraph} object RandomGraphGenerator { private val RANDOM_SEED = 131161511 + + // for creating graphs from a source graph private val MAX_NODE_DEGREE = 3 + // for creating purely random graphs + private val NODE_CREATION_PROBABILITY = 0.5 + object CannotExtendException extends Exception - def generateRandomGraph(sourceGraph: UndirectedGraph, + def generateRandomGraph(nbEdges: Int): UndirectedGraph = { + val random = new scala.util.Random(RANDOM_SEED) + + val src = Vertex("src") + var V = Set[Vertex](src) + var E = Set[Edge]() + + var i = 0 + while (E.size < nbEdges) { + val srcVertex = V.toIndexedSeq(random.nextInt(V.size)) + val tgtVertex = if (random.nextDouble() < NODE_CREATION_PROBABILITY) { + // add a new node + i += 1 + Vertex(s"v_$i") + } else { + // add an edge to an existing node + val targetCandidates = V - srcVertex + targetCandidates.toIndexedSeq(random.nextInt(targetCandidates.size)) + } + V += tgtVertex + E += Graphs.lexicographicEdge(srcVertex, tgtVertex) + } + + UndirectedGraph(V, E, Set(src)) + } + + def generateRandomGraphFromSourceGraph(sourceGraph: UndirectedGraph, maxNodeLimit: Int): UndirectedGraph = { assert(sourceGraph.sources.size <= maxNodeLimit) diff --git a/tps-core/src/test/scala/tps/simulation/RandomGraphGeneratorTest.scala b/tps-core/src/test/scala/tps/simulation/RandomGraphGeneratorTest.scala index 931d2eaa..fc7ef293 100644 --- a/tps-core/src/test/scala/tps/simulation/RandomGraphGeneratorTest.scala +++ b/tps-core/src/test/scala/tps/simulation/RandomGraphGeneratorTest.scala @@ -8,11 +8,21 @@ import tps.TestResourceUtil.testFile class RandomGraphGeneratorTest extends FunSuite with Matchers { - test("random graph contains source and has right size") { + test("completely random graph has one source and right number of edges") { + val generated = RandomGraphGenerator.generateRandomGraph(5) + + // Check that there is only one source, and it is in the vertex set. + generated.sources.size should equal (1) + generated.V should contain (generated.sources.head) + + generated.E.size should equal (5) + } + + test("random graph from existing graph contains source and has right size") { val sourceGraph = UndirectedGraphParser.run(testFile("network.tsv")).copy( sources = Set(Vertex("A"))) val maxNodeLimit = 3 - val generated = RandomGraphGenerator.generateRandomGraph( + val generated = RandomGraphGenerator.generateRandomGraphFromSourceGraph( sourceGraph, maxNodeLimit) From 26ff80d1923597fe9b2e4a5b37f163c9ccb10290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Sun, 18 Sep 2016 11:42:39 -0700 Subject: [PATCH 09/25] basic graph metrics to match simulated data to real data --- .../scala/tps/evaluation/GraphStats.scala | 20 +++++++++++++++++++ .../src/main/scala/tps/util/MathUtils.scala | 16 +++++++++++++++ .../test/scala/tps/util/MathUtilsTest.scala | 16 +++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 tps-core/src/main/scala/tps/evaluation/GraphStats.scala diff --git a/tps-core/src/main/scala/tps/evaluation/GraphStats.scala b/tps-core/src/main/scala/tps/evaluation/GraphStats.scala new file mode 100644 index 00000000..4cc2664b --- /dev/null +++ b/tps-core/src/main/scala/tps/evaluation/GraphStats.scala @@ -0,0 +1,20 @@ +package tps.evaluation + +import tps.Graphs.UndirectedGraph +import tps.util.MathUtils + +/** + * Computes basic graph statistics + */ +object GraphStats { + def computeGraphStats(g: UndirectedGraph): Unit = { + // # nodes, # edges, avg degree, median degree + println(s"# vertices: ${g.V.size}") + println(s"# edges : ${g.E.size}") + + val vertexDegrees = g.V.map(v => g.neighbors(v).size.toDouble) + println(s"Average vertex degree: ${MathUtils.mean(vertexDegrees)}") + println(s"Median vertex degree : ${MathUtils.median(vertexDegrees)}") + + } +} diff --git a/tps-core/src/main/scala/tps/util/MathUtils.scala b/tps-core/src/main/scala/tps/util/MathUtils.scala index ddb9ec56..4909ed8c 100644 --- a/tps-core/src/main/scala/tps/util/MathUtils.scala +++ b/tps-core/src/main/scala/tps/util/MathUtils.scala @@ -8,6 +8,22 @@ object MathUtils { def max(xs: Seq[Double]): Double = xs.reduceLeft(Math.max) def min(xs: Seq[Double]): Double = xs.reduceLeft(Math.min) + def mean(vs: Iterable[Double]): Double = { + assert(vs.nonEmpty) + vs.sum / vs.size + } + + def median(vs: Iterable[Double]): Double = { + assert(vs.nonEmpty) + val med = vs.size / 2 + val sorted = vs.toIndexedSeq.sorted + if (vs.size % 2 == 0) { + (sorted(med - 1) + sorted(med)) / 2.0 + } else { + sorted(med) + } + } + def log2(x: Double) = scala.math.log(x) / scala.math.log(2) def foldChanges(vs: Seq[Double]): Seq[Double] = { diff --git a/tps-core/src/test/scala/tps/util/MathUtilsTest.scala b/tps-core/src/test/scala/tps/util/MathUtilsTest.scala index 9954b55a..cef5aaec 100644 --- a/tps-core/src/test/scala/tps/util/MathUtilsTest.scala +++ b/tps-core/src/test/scala/tps/util/MathUtilsTest.scala @@ -27,4 +27,20 @@ class MathUtilsTest extends FunSuite with Matchers { val c = MathUtils.combination(list, 0) c should equal (List(Nil)) } + + test("mean of list") { + val l1 = List(1.0) + MathUtils.mean(l1) should equal (1.0) + + val l2 = List(8.0, 2.0, 6.0, 4.0) + MathUtils.mean(l2) should equal (10.0) + } + + test("median of list") { + val l1 = List(1.0) + MathUtils.median(l1) should equal (1.0) + + val l2 = List(8.0, 2.0, 6.0, 4.0) + MathUtils.median(l2) should equal (5.0) + } } From 5a5ae7cdc1287ae4740c5defd9a60b0faca3cc74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Sun, 18 Sep 2016 11:46:14 -0700 Subject: [PATCH 10/25] harness to run stats --- tps-core/src/main/scala/tps/evaluation/GraphStats.scala | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tps-core/src/main/scala/tps/evaluation/GraphStats.scala b/tps-core/src/main/scala/tps/evaluation/GraphStats.scala index 4cc2664b..f55bb045 100644 --- a/tps-core/src/main/scala/tps/evaluation/GraphStats.scala +++ b/tps-core/src/main/scala/tps/evaluation/GraphStats.scala @@ -1,6 +1,9 @@ package tps.evaluation +import java.io.File + import tps.Graphs.UndirectedGraph +import tps.UndirectedGraphParser import tps.util.MathUtils /** @@ -15,6 +18,11 @@ object GraphStats { val vertexDegrees = g.V.map(v => g.neighbors(v).size.toDouble) println(s"Average vertex degree: ${MathUtils.mean(vertexDegrees)}") println(s"Median vertex degree : ${MathUtils.median(vertexDegrees)}") + } + def main(args: Array[String]): Unit = { + val graphName = args(0) + val graph = UndirectedGraphParser.run(new File(graphName)) + computeGraphStats(graph) } } From 86e93f41d67559bbd4c0e98921cb6c5cc3f616d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Sun, 18 Sep 2016 11:48:55 -0700 Subject: [PATCH 11/25] fix test --- tps-core/src/test/scala/tps/util/MathUtilsTest.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tps-core/src/test/scala/tps/util/MathUtilsTest.scala b/tps-core/src/test/scala/tps/util/MathUtilsTest.scala index cef5aaec..7d1d346e 100644 --- a/tps-core/src/test/scala/tps/util/MathUtilsTest.scala +++ b/tps-core/src/test/scala/tps/util/MathUtilsTest.scala @@ -33,7 +33,7 @@ class MathUtilsTest extends FunSuite with Matchers { MathUtils.mean(l1) should equal (1.0) val l2 = List(8.0, 2.0, 6.0, 4.0) - MathUtils.mean(l2) should equal (10.0) + MathUtils.mean(l2) should equal (5.0) } test("median of list") { From e0b451648f9e69a589404193399dc1cd8b80d90f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Sun, 18 Sep 2016 12:29:46 -0700 Subject: [PATCH 12/25] add measurement significance probability parameter --- .../RandomTimeSeriesGenerator.scala | 16 +++++++------- .../main/scala/tps/synthesis/Synthesis.scala | 21 ++++++++++++------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala b/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala index 39ba85bd..09209d37 100644 --- a/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala +++ b/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala @@ -16,7 +16,10 @@ object RandomTimeSeriesGenerator { private val NB_TIME_POINTS = 10 // probability of a node having time series data - private val COVERAGE_RATIO = 0.8 + private val COVERAGE_RATIO = 0.5 + + // probability of a measurement being significaint + private val SIGNIFICANCE_RATIO = 0.2 /** * Generates random time series data for the given graph. @@ -34,8 +37,7 @@ object RandomTimeSeriesGenerator { } /** - * Generates trivial significance scores for the given time series data, - * depending on whether values are defined at each time point. + * Generates random significance scores for the given time series data. */ def generateSignificanceScores( timeSeries: TimeSeries @@ -43,7 +45,7 @@ object RandomTimeSeriesGenerator { val pairs = for (p <- timeSeries.profiles) yield { // compute scores for all time points except the first val sigScores = p.values.tail.map { v => - if (v.isDefined) 0.0 else 1.0 + if (random.nextDouble() < SIGNIFICANCE_RATIO) 0.0 else 1.0 } p.id -> sigScores } @@ -55,9 +57,9 @@ object RandomTimeSeriesGenerator { } private def generateProfile(id: String): Profile = { - // all profile values are defined - val values = (0 until NB_TIME_POINTS).map(i => - Some(random.nextDouble() * MAX_PROFILE_VALUE)) + val values = (0 until NB_TIME_POINTS) map { i => + Some(random.nextDouble() * MAX_PROFILE_VALUE) + } Profile(id, values) } diff --git a/tps-core/src/main/scala/tps/synthesis/Synthesis.scala b/tps-core/src/main/scala/tps/synthesis/Synthesis.scala index 3f1de4d8..f95a6c7c 100644 --- a/tps-core/src/main/scala/tps/synthesis/Synthesis.scala +++ b/tps-core/src/main/scala/tps/synthesis/Synthesis.scala @@ -3,6 +3,8 @@ package tps.synthesis import tps.Graphs._ import tps.SignedDirectedGraphOps._ import tps._ +import tps.evaluation.GraphStats +import tps.util.TimingUtil object Synthesis { def run( @@ -71,26 +73,29 @@ object Synthesis { ) } + // debug and stats printing printCollapsedInterpretation() + println("Expanded graph stats:") + GraphStats.computeGraphStats(expandedNetwork) // dispatch solver val solver = opts.solver match { - case "dataflow" => + case "dataflow" => new DataflowSolver( - expandedNetwork, - expandedPartialModel, - opts, + expandedNetwork, + expandedPartialModel, + opts, interpretation, resultReporter ) - case "naive" => + case "naive" => new NaiveSymbolicSolver( expandedNetwork, expandedPartialModel, opts, interpretation ) - case "bilateral" => + case "bilateral" => new BilateralSolver( expandedNetwork, expandedPartialModel, @@ -99,7 +104,9 @@ object Synthesis { ) } - val expandedSol = solver.summary() + val expandedSol = TimingUtil.time("solver") { + solver.summary() + } collapseSolution(expandedSol, ppmWithData) } From e6fe95438f37cc3408232f4ee1258ce6b3a19dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Sun, 18 Sep 2016 12:33:29 -0700 Subject: [PATCH 13/25] add missing file --- tps-core/src/main/scala/tps/util/TimingUtil.scala | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tps-core/src/main/scala/tps/util/TimingUtil.scala diff --git a/tps-core/src/main/scala/tps/util/TimingUtil.scala b/tps-core/src/main/scala/tps/util/TimingUtil.scala new file mode 100644 index 00000000..1d7ec282 --- /dev/null +++ b/tps-core/src/main/scala/tps/util/TimingUtil.scala @@ -0,0 +1,15 @@ +package tps.util + +/** + * Provides utility functions to measure running time. + */ +object TimingUtil { + def time[R](label: String)(block: => R): R = { + val t0 = System.nanoTime() + val result = block // call-by-name + val t1 = System.nanoTime() + val s = (t1 - t0) / 1000000000.0 + println(s"[${label}] Elapsed time: ${s}s") + result + } +} From a1f550518441a77e50a3480e6f46298ea68cde01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Sun, 18 Sep 2016 13:34:13 -0700 Subject: [PATCH 14/25] time series data coverage stats --- .../src/main/scala/tps/evaluation/GraphStats.scala | 14 +++++++++++++- .../tps/simulation/RandomTimeSeriesGenerator.scala | 2 +- .../src/main/scala/tps/synthesis/Synthesis.scala | 1 + 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/tps-core/src/main/scala/tps/evaluation/GraphStats.scala b/tps-core/src/main/scala/tps/evaluation/GraphStats.scala index f55bb045..c2460dbd 100644 --- a/tps-core/src/main/scala/tps/evaluation/GraphStats.scala +++ b/tps-core/src/main/scala/tps/evaluation/GraphStats.scala @@ -3,7 +3,7 @@ package tps.evaluation import java.io.File import tps.Graphs.UndirectedGraph -import tps.UndirectedGraphParser +import tps.{TimeSeries, UndirectedGraphParser} import tps.util.MathUtils /** @@ -20,6 +20,18 @@ object GraphStats { println(s"Median vertex degree : ${MathUtils.median(vertexDegrees)}") } + /** + * + * @param g + * @param ts + */ + def computeDataCoverageStats(g: UndirectedGraph, ts: TimeSeries): Unit = { + val profileIds = ts.profiles.map(_.id).toSet + val verticesWithData = g.V.map(_.id).intersect(profileIds) + val coverageRatio = verticesWithData.size.toDouble / g.V.size + println(s"Ratio of vertices with data: ${coverageRatio}") + } + def main(args: Array[String]): Unit = { val graphName = args(0) val graph = UndirectedGraphParser.run(new File(graphName)) diff --git a/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala b/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala index 09209d37..d4371baa 100644 --- a/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala +++ b/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala @@ -16,7 +16,7 @@ object RandomTimeSeriesGenerator { private val NB_TIME_POINTS = 10 // probability of a node having time series data - private val COVERAGE_RATIO = 0.5 + private val COVERAGE_RATIO = 0.6 // probability of a measurement being significaint private val SIGNIFICANCE_RATIO = 0.2 diff --git a/tps-core/src/main/scala/tps/synthesis/Synthesis.scala b/tps-core/src/main/scala/tps/synthesis/Synthesis.scala index f95a6c7c..47447b44 100644 --- a/tps-core/src/main/scala/tps/synthesis/Synthesis.scala +++ b/tps-core/src/main/scala/tps/synthesis/Synthesis.scala @@ -77,6 +77,7 @@ object Synthesis { printCollapsedInterpretation() println("Expanded graph stats:") GraphStats.computeGraphStats(expandedNetwork) + GraphStats.computeDataCoverageStats(expandedNetwork, expandedTimeSeries) // dispatch solver val solver = opts.solver match { From 4ff379df8671300118641e162ad4a5968efe27c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Sun, 18 Sep 2016 14:31:08 -0700 Subject: [PATCH 15/25] measure performance w/ replicates --- .../tps/evaluation/ScalabilityAnalysis.scala | 43 ++++++++----------- .../tps/simulation/RandomGraphGenerator.scala | 14 +++--- .../src/main/scala/tps/util/TimingUtil.scala | 25 +++++++++-- 3 files changed, 48 insertions(+), 34 deletions(-) diff --git a/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala index ff75c0c1..92eb0c55 100644 --- a/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala +++ b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala @@ -1,12 +1,9 @@ package tps.evaluation -import java.io.File - -import tps.Graphs.Vertex import tps._ import tps.simulation.{RandomGraphGenerator, RandomTimeSeriesGenerator} import tps.synthesis.{Synthesis, SynthesisOptions} -import tps.util.Stopwatch +import tps.util.{Stopwatch, TimingUtil} /** * Evaluates solver running time on randomly simulated data. @@ -32,26 +29,24 @@ object ScalabilityAnalysis { for (size <- Range(MIN_GRAPH_SIZE, MAX_GRAPH_SIZE, GRAPH_SIZE_STEP)) { println(s"Evaluating with size $size") - val g = RandomGraphGenerator.generateRandomGraph(size) - val ts = RandomTimeSeriesGenerator.generateRandomTimeSeries(g) - val scores = RandomTimeSeriesGenerator.generateSignificanceScores(ts) - - val sw = new Stopwatch(s"Graph size: V = ${g.V.size}, E = ${g.E.size}", - verbose = true) - sw.start - Synthesis.run( - g, - ts, - scores, - scores, - Set.empty, - Map.empty, - g.sources map (_.id), - threshold, - SynthesisOptions(), - resultReporter - ) - sw.stop + TimingUtil.timeReplicates(s"Scalability analysis for $size", 5) { + val g = RandomGraphGenerator.generateRandomGraph(size) + val ts = RandomTimeSeriesGenerator.generateRandomTimeSeries(g) + val scores = RandomTimeSeriesGenerator.generateSignificanceScores(ts) + + Synthesis.run( + g, + ts, + scores, + scores, + Set.empty, + Map.empty, + g.sources map (_.id), + threshold, + SynthesisOptions(), + resultReporter + ) + } } } } diff --git a/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala b/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala index 307d77c6..2f283dd2 100644 --- a/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala +++ b/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala @@ -10,6 +10,7 @@ import tps.Graphs.{Edge, UndirectedGraph, Vertex} object RandomGraphGenerator { private val RANDOM_SEED = 131161511 + private val random = new scala.util.Random(RANDOM_SEED) // for creating graphs from a source graph private val MAX_NODE_DEGREE = 3 @@ -20,8 +21,6 @@ object RandomGraphGenerator { object CannotExtendException extends Exception def generateRandomGraph(nbEdges: Int): UndirectedGraph = { - val random = new scala.util.Random(RANDOM_SEED) - val src = Vertex("src") var V = Set[Vertex](src) var E = Set[Edge]() @@ -35,11 +34,13 @@ object RandomGraphGenerator { Vertex(s"v_$i") } else { // add an edge to an existing node - val targetCandidates = V - srcVertex - targetCandidates.toIndexedSeq(random.nextInt(targetCandidates.size)) + V.toIndexedSeq(random.nextInt(V.size)) + } + // do not add self edges + if (srcVertex != tgtVertex) { + V += tgtVertex + E += Graphs.lexicographicEdge(srcVertex, tgtVertex) } - V += tgtVertex - E += Graphs.lexicographicEdge(srcVertex, tgtVertex) } UndirectedGraph(V, E, Set(src)) @@ -49,7 +50,6 @@ object RandomGraphGenerator { maxNodeLimit: Int): UndirectedGraph = { assert(sourceGraph.sources.size <= maxNodeLimit) - val random = new scala.util.Random(RANDOM_SEED) var generatedGraph = UndirectedGraph(sourceGraph.sources, Set.empty, sourceGraph.sources) diff --git a/tps-core/src/main/scala/tps/util/TimingUtil.scala b/tps-core/src/main/scala/tps/util/TimingUtil.scala index 1d7ec282..be423ab6 100644 --- a/tps-core/src/main/scala/tps/util/TimingUtil.scala +++ b/tps-core/src/main/scala/tps/util/TimingUtil.scala @@ -5,11 +5,30 @@ package tps.util */ object TimingUtil { def time[R](label: String)(block: => R): R = { + val (result, time) = computeAndTime(block _) + println(s"[${label}] Elapsed time: ${time}s") + result + } + + def timeReplicates[R](label: String, replicates: Int)(block: => R): Unit = { + var times = Set[Double]() + for (i <- 1 to replicates) { + val (_, time) = computeAndTime(block _) + times += time + } + val min = times.min + val max = times.max + val mean = MathUtils.mean(times) + val median = MathUtils.median(times) + println(s"[$label] Elapsed: min = $min, max = $max, mean = $mean, median " + + s"= $median") + } + + private def computeAndTime[R](block: () => R): (R, Double) = { val t0 = System.nanoTime() - val result = block // call-by-name + val result = block() // call-by-name val t1 = System.nanoTime() val s = (t1 - t0) / 1000000000.0 - println(s"[${label}] Elapsed time: ${s}s") - result + (result, s) } } From b457e8335f31345599ef45e3f49da8bfe983bfb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Sun, 18 Sep 2016 14:35:20 -0700 Subject: [PATCH 16/25] random seed --- .../main/scala/tps/simulation/RandomTimeSeriesGenerator.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala b/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala index d4371baa..16e66c93 100644 --- a/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala +++ b/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala @@ -8,7 +8,7 @@ import tps.{Profile, TimeSeries} */ object RandomTimeSeriesGenerator { - private val RANDOM_SEED = 0 + private val RANDOM_SEED = 2483967 private val random = new scala.util.Random(RANDOM_SEED) private val MAX_PROFILE_VALUE = 10 From 5454b993b35b48f5b06cd8a8eca49740444addd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Mon, 19 Sep 2016 11:33:18 -0700 Subject: [PATCH 17/25] print time series-specific stats --- .../main/scala/tps/evaluation/GraphStats.scala | 15 +++++++++++++++ .../src/main/scala/tps/synthesis/Synthesis.scala | 14 +++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/tps-core/src/main/scala/tps/evaluation/GraphStats.scala b/tps-core/src/main/scala/tps/evaluation/GraphStats.scala index c2460dbd..c319796e 100644 --- a/tps-core/src/main/scala/tps/evaluation/GraphStats.scala +++ b/tps-core/src/main/scala/tps/evaluation/GraphStats.scala @@ -3,6 +3,7 @@ package tps.evaluation import java.io.File import tps.Graphs.UndirectedGraph +import tps.synthesis.Synthesis import tps.{TimeSeries, UndirectedGraphParser} import tps.util.MathUtils @@ -32,6 +33,20 @@ object GraphStats { println(s"Ratio of vertices with data: ${coverageRatio}") } + def computeProfileStats( + ts: TimeSeries, + firstScores: Map[String, Seq[Double]], + prevScores: Map[String, Seq[Double]], + threshold: Double + ): Unit + = { + val nbSigMeasurements = ts.profiles map { p => + Synthesis.nbSignificantMeasurements(p, firstScores, prevScores, threshold) + } + val med = MathUtils.median(nbSigMeasurements.map(_.toDouble)) + println(s"Median number of significant time points: $med") + } + def main(args: Array[String]): Unit = { val graphName = args(0) val graph = UndirectedGraphParser.run(new File(graphName)) diff --git a/tps-core/src/main/scala/tps/synthesis/Synthesis.scala b/tps-core/src/main/scala/tps/synthesis/Synthesis.scala index 47447b44..c847d212 100644 --- a/tps-core/src/main/scala/tps/synthesis/Synthesis.scala +++ b/tps-core/src/main/scala/tps/synthesis/Synthesis.scala @@ -78,6 +78,8 @@ object Synthesis { println("Expanded graph stats:") GraphStats.computeGraphStats(expandedNetwork) GraphStats.computeDataCoverageStats(expandedNetwork, expandedTimeSeries) + GraphStats.computeProfileStats(expandedTimeSeries, expandedFirstScores, + expandedPrevScores, significanceThreshold) // dispatch solver val solver = opts.solver match { @@ -117,13 +119,23 @@ object Synthesis { prevScores: Map[String, Seq[Double]], threshold: Double ): Boolean = { + nbSignificantMeasurements(p, firstScores, prevScores, threshold) > 0 + } + + // TODO move + def nbSignificantMeasurements( + p: Profile, + firstScores: Map[String, Seq[Double]], + prevScores: Map[String, Seq[Double]], + threshold: Double + ): Int = { val fs = firstScores(p.id) val ps = prevScores(p.id) val toEval = p.values.tail val filteredValues = for ((v, (f, p)) <- toEval zip (fs zip ps)) yield { if (f < threshold || p < threshold) v else None } - filteredValues.exists(_.isDefined) + filteredValues.filter(_.isDefined).size } } From cf049e9ae7263b33fac5b74e61d68a605c4c0a99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Mon, 3 Oct 2016 13:40:36 -0700 Subject: [PATCH 18/25] multiple phosphosite simulation --- project/Build.scala | 12 ++++- .../scala/tps/evaluation/GraphStats.scala | 31 +++++++++-- .../tps/evaluation/ScalabilityAnalysis.scala | 16 ++---- .../RandomTimeSeriesGenerator.scala | 51 +++++++++++++------ .../main/scala/tps/synthesis/Synthesis.scala | 14 +++++ 5 files changed, 90 insertions(+), 34 deletions(-) diff --git a/project/Build.scala b/project/Build.scala index b2423aa8..46830ad2 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -15,7 +15,14 @@ object ApplicationBuild extends Build { showSuccess := false, - resolvers += "sonatype-public" at "https://oss.sonatype.org/content/groups/public" + resolvers ++= Seq( + "sonatype-public" at + "https://oss.sonatype.org/content/groups/public", + "Sonatype Snapshots" at + "https://oss.sonatype.org/content/repositories/snapshots/", + "Sonatype Releases" at + "https://oss.sonatype.org/content/repositories/releases/" + ) ) val coreSettings = commonSettings ++ Seq( @@ -25,7 +32,8 @@ object ApplicationBuild extends Build { libraryDependencies ++= Seq( "org.scalatest" % "scalatest_2.11" % "2.2.4" % "test", - "com.github.scopt" %% "scopt" % "3.3.0" + "com.github.scopt" %% "scopt" % "3.3.0", + "org.scalanlp" %% "breeze" % "0.12" ), mainClass in (Compile, run) := Some("tps.Main"), diff --git a/tps-core/src/main/scala/tps/evaluation/GraphStats.scala b/tps-core/src/main/scala/tps/evaluation/GraphStats.scala index c319796e..429e6f8b 100644 --- a/tps-core/src/main/scala/tps/evaluation/GraphStats.scala +++ b/tps-core/src/main/scala/tps/evaluation/GraphStats.scala @@ -21,11 +21,6 @@ object GraphStats { println(s"Median vertex degree : ${MathUtils.median(vertexDegrees)}") } - /** - * - * @param g - * @param ts - */ def computeDataCoverageStats(g: UndirectedGraph, ts: TimeSeries): Unit = { val profileIds = ts.profiles.map(_.id).toSet val verticesWithData = g.V.map(_.id).intersect(profileIds) @@ -33,6 +28,30 @@ object GraphStats { println(s"Ratio of vertices with data: ${coverageRatio}") } + /** + * Prints the mean number of phosphosites per protein in the given graph. + * + * The graph and time series data are not expanded. + */ + def printMeanNbPhosphosites( + g: UndirectedGraph, ts: TimeSeries, ppm: Map[String, Set[String]] + ): Unit = { + // TODO remove this for the case where there is no mapping. + assert(g.V.map(_.id).intersect(ts.profiles.map(_.id).toSet).isEmpty) + val phosphositeCardinalities = g.V.toSeq map { v => + // get peptides that map to the protein + val matchingPeptides = ppm.filter{ case (pep, prots) => + prots contains v .id }.keySet + val matchingProfiles = ts.profiles.filter{ p => + matchingPeptides contains p.id + } + matchingProfiles.size + } + + val mean = MathUtils.mean(phosphositeCardinalities.map(_.toDouble)) + println(s"Mean number of phosphosites: $mean") + } + def computeProfileStats( ts: TimeSeries, firstScores: Map[String, Seq[Double]], @@ -45,6 +64,8 @@ object GraphStats { } val med = MathUtils.median(nbSigMeasurements.map(_.toDouble)) println(s"Median number of significant time points: $med") + val mean = MathUtils.mean(nbSigMeasurements.map(_.toDouble)) + println(s"Mean number of significant time points: $mean") } def main(args: Array[String]): Unit = { diff --git a/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala index 92eb0c55..74efd9a1 100644 --- a/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala +++ b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala @@ -14,24 +14,18 @@ object ScalabilityAnalysis { private val MAX_GRAPH_SIZE = 10000 private val GRAPH_SIZE_STEP = 1000 + private val SIGNIFICANCE_THRESHOLD = 0.01 + def main(args: Array[String]): Unit = { val resultReporter = new NoopReporter() - /* - val pin = PINParser.run( - new File("data/networks/directed-pin-with-resource-edges.tsv")) - val sources = Set("EGF_HUMAN") - val sourceGraph = UndirectedGraphOps.fromDirectedGraph(pin).copy( - sources = sources.map(Vertex(_))) - */ - val threshold = 0.01 - for (size <- Range(MIN_GRAPH_SIZE, MAX_GRAPH_SIZE, GRAPH_SIZE_STEP)) { println(s"Evaluating with size $size") TimingUtil.timeReplicates(s"Scalability analysis for $size", 5) { val g = RandomGraphGenerator.generateRandomGraph(size) - val ts = RandomTimeSeriesGenerator.generateRandomTimeSeries(g) + val ppm = RandomTimeSeriesGenerator.generateRandomPeptideProteinMap(g) + val ts = RandomTimeSeriesGenerator.generateRandomTimeSeries(ppm.keySet) val scores = RandomTimeSeriesGenerator.generateSignificanceScores(ts) Synthesis.run( @@ -42,7 +36,7 @@ object ScalabilityAnalysis { Set.empty, Map.empty, g.sources map (_.id), - threshold, + SIGNIFICANCE_THRESHOLD, SynthesisOptions(), resultReporter ) diff --git a/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala b/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala index 16e66c93..cb44cbdc 100644 --- a/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala +++ b/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala @@ -1,6 +1,8 @@ package tps.simulation +import breeze.stats.distributions.Poisson import tps.Graphs.UndirectedGraph +import tps.PeptideExpansion.PeptideProteinMap import tps.{Profile, TimeSeries} /** @@ -13,27 +15,40 @@ object RandomTimeSeriesGenerator { private val MAX_PROFILE_VALUE = 10 - private val NB_TIME_POINTS = 10 + private val NB_TIME_POINTS = 8 - // probability of a node having time series data - private val COVERAGE_RATIO = 0.6 + // probability of a measurement being significant + private val SIGNIFICANCE_RATIO = 0.25 - // probability of a measurement being significaint - private val SIGNIFICANCE_RATIO = 0.2 + // Poisson parameter for drawing number of phosphosites + private val NB_SITES_POISSON_PARAMETER = 1.7 + private val nbSitesDistribution = Poisson.distribution( + NB_SITES_POISSON_PARAMETER) - /** - * Generates random time series data for the given graph. - * - * Data is generated for a subset of the nodes in the graph. - */ - def generateRandomTimeSeries(graph: UndirectedGraph): TimeSeries = { - var profiles: Set[Profile] = Set.empty + private val NB_SIGNIFICANT_TIME_POINTS_POISSON_PARAMETER = 0.55 + private val nbSignificantTimePointsDistribution = Poisson.distribution( + NB_SIGNIFICANT_TIME_POINTS_POISSON_PARAMETER) + + def generateRandomPeptideProteinMap( + graph: UndirectedGraph + ): PeptideProteinMap = { + var mapping: PeptideProteinMap = Map.empty for (v <- graph.V) { - if (random.nextDouble() < COVERAGE_RATIO) { - profiles += generateProfile(v.id) + val nbSites = nbSitesDistribution.draw() + for (i <- 0 until nbSites) { + val siteName = s"${v.id}#site${i}" + assert(!mapping.isDefinedAt(siteName)) + mapping += siteName -> Set(v.id) } } - TimeSeries(generateLabels(), profiles.toSeq) + mapping + } + + def generateRandomTimeSeries(pepIDs: Set[String]): TimeSeries = { + val profiles = pepIDs.toSeq map { id => + generateProfile(id) + } + TimeSeries(generateLabels(), profiles) } /** @@ -43,9 +58,13 @@ object RandomTimeSeriesGenerator { timeSeries: TimeSeries ): Map[String, Seq[Double]] = { val pairs = for (p <- timeSeries.profiles) yield { + // decide how many points should be significant + val nbSignificantTimePoints = nbSignificantTimePointsDistribution.draw() + val significanceProb = nbSignificantTimePoints.toDouble / NB_TIME_POINTS + // compute scores for all time points except the first val sigScores = p.values.tail.map { v => - if (random.nextDouble() < SIGNIFICANCE_RATIO) 0.0 else 1.0 + if (random.nextDouble() < significanceProb) 0.0 else 1.0 } p.id -> sigScores } diff --git a/tps-core/src/main/scala/tps/synthesis/Synthesis.scala b/tps-core/src/main/scala/tps/synthesis/Synthesis.scala index c847d212..4657ea17 100644 --- a/tps-core/src/main/scala/tps/synthesis/Synthesis.scala +++ b/tps-core/src/main/scala/tps/synthesis/Synthesis.scala @@ -75,6 +75,20 @@ object Synthesis { // debug and stats printing printCollapsedInterpretation() + println("Non-expanded graph stats:") + println("Unfiltered data:") + GraphStats.printMeanNbPhosphosites(networkWithSources, timeSeries, + peptideProteinMap) + GraphStats.computeProfileStats(timeSeries, firstScores, prevScores, + significanceThreshold) + println("Filtered, significant data:") + GraphStats.printMeanNbPhosphosites(networkWithSources, + significantTimeSeries, ppmWithData) + GraphStats.computeProfileStats(significantTimeSeries, firstScores, + prevScores, significanceThreshold) + println("Ratio of significant profiles: " + + (significantTimeSeries.profiles.size.toDouble / timeSeries.profiles.size)) + println("Expanded graph stats:") GraphStats.computeGraphStats(expandedNetwork) GraphStats.computeDataCoverageStats(expandedNetwork, expandedTimeSeries) From 9708cb563564bb40b918eb41d7ef2c8b8630c32c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Mon, 3 Oct 2016 13:52:01 -0700 Subject: [PATCH 19/25] test scalability with exponentially growing sizes --- .../scala/tps/evaluation/ScalabilityAnalysis.scala | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala index 74efd9a1..7f5e7f7b 100644 --- a/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala +++ b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala @@ -11,15 +11,15 @@ import tps.util.{Stopwatch, TimingUtil} object ScalabilityAnalysis { private val MIN_GRAPH_SIZE = 1000 - private val MAX_GRAPH_SIZE = 10000 - private val GRAPH_SIZE_STEP = 1000 + private val MAX_GRAPH_SIZE = 100000 private val SIGNIFICANCE_THRESHOLD = 0.01 def main(args: Array[String]): Unit = { val resultReporter = new NoopReporter() - for (size <- Range(MIN_GRAPH_SIZE, MAX_GRAPH_SIZE, GRAPH_SIZE_STEP)) { + var size = MIN_GRAPH_SIZE + do { println(s"Evaluating with size $size") TimingUtil.timeReplicates(s"Scalability analysis for $size", 5) { @@ -40,7 +40,11 @@ object ScalabilityAnalysis { SynthesisOptions(), resultReporter ) + + println("Nb. phosphosites: " + ppm.keySet.size) } - } + + size = size * 2 + } while (size <= MAX_GRAPH_SIZE) } } From 3456716057615ac42f3ac888bcdafff39fb0a88f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Mon, 3 Oct 2016 14:00:40 -0700 Subject: [PATCH 20/25] use peptide mapping in scalability analysis runs --- .../src/main/scala/tps/evaluation/ScalabilityAnalysis.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala index 7f5e7f7b..6a3f2082 100644 --- a/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala +++ b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala @@ -34,7 +34,7 @@ object ScalabilityAnalysis { scores, scores, Set.empty, - Map.empty, + ppm, g.sources map (_.id), SIGNIFICANCE_THRESHOLD, SynthesisOptions(), @@ -43,7 +43,7 @@ object ScalabilityAnalysis { println("Nb. phosphosites: " + ppm.keySet.size) } - + size = size * 2 } while (size <= MAX_GRAPH_SIZE) } From 95306aba74065bea9120d6b1a6f222466ff967d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Mon, 3 Oct 2016 14:37:08 -0700 Subject: [PATCH 21/25] remove invalid invariant and prune dead code --- .gitignore | 1 + tps-core/src/main/scala/tps/evaluation/GraphStats.scala | 2 -- .../main/scala/tps/simulation/RandomTimeSeriesGenerator.scala | 3 --- tps-core/src/main/scala/tps/synthesis/Synthesis.scala | 2 -- 4 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 8111fa95..2eb0cc02 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ sbt project/project project/target target +logs diff --git a/tps-core/src/main/scala/tps/evaluation/GraphStats.scala b/tps-core/src/main/scala/tps/evaluation/GraphStats.scala index 429e6f8b..9c1a011c 100644 --- a/tps-core/src/main/scala/tps/evaluation/GraphStats.scala +++ b/tps-core/src/main/scala/tps/evaluation/GraphStats.scala @@ -36,8 +36,6 @@ object GraphStats { def printMeanNbPhosphosites( g: UndirectedGraph, ts: TimeSeries, ppm: Map[String, Set[String]] ): Unit = { - // TODO remove this for the case where there is no mapping. - assert(g.V.map(_.id).intersect(ts.profiles.map(_.id).toSet).isEmpty) val phosphositeCardinalities = g.V.toSeq map { v => // get peptides that map to the protein val matchingPeptides = ppm.filter{ case (pep, prots) => diff --git a/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala b/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala index cb44cbdc..db2993af 100644 --- a/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala +++ b/tps-core/src/main/scala/tps/simulation/RandomTimeSeriesGenerator.scala @@ -17,9 +17,6 @@ object RandomTimeSeriesGenerator { private val NB_TIME_POINTS = 8 - // probability of a measurement being significant - private val SIGNIFICANCE_RATIO = 0.25 - // Poisson parameter for drawing number of phosphosites private val NB_SITES_POISSON_PARAMETER = 1.7 private val nbSitesDistribution = Poisson.distribution( diff --git a/tps-core/src/main/scala/tps/synthesis/Synthesis.scala b/tps-core/src/main/scala/tps/synthesis/Synthesis.scala index 4657ea17..d8bd1dbf 100644 --- a/tps-core/src/main/scala/tps/synthesis/Synthesis.scala +++ b/tps-core/src/main/scala/tps/synthesis/Synthesis.scala @@ -92,8 +92,6 @@ object Synthesis { println("Expanded graph stats:") GraphStats.computeGraphStats(expandedNetwork) GraphStats.computeDataCoverageStats(expandedNetwork, expandedTimeSeries) - GraphStats.computeProfileStats(expandedTimeSeries, expandedFirstScores, - expandedPrevScores, significanceThreshold) // dispatch solver val solver = opts.solver match { From 2a2543573a7bd19151136a685845e62b97e082d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Mon, 3 Oct 2016 17:54:14 -0700 Subject: [PATCH 22/25] run 3 simulation replicates, and change input size limit --- .../src/main/scala/tps/evaluation/ScalabilityAnalysis.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala index 6a3f2082..2d349b14 100644 --- a/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala +++ b/tps-core/src/main/scala/tps/evaluation/ScalabilityAnalysis.scala @@ -11,7 +11,7 @@ import tps.util.{Stopwatch, TimingUtil} object ScalabilityAnalysis { private val MIN_GRAPH_SIZE = 1000 - private val MAX_GRAPH_SIZE = 100000 + private val MAX_GRAPH_SIZE = 128000 private val SIGNIFICANCE_THRESHOLD = 0.01 @@ -22,7 +22,7 @@ object ScalabilityAnalysis { do { println(s"Evaluating with size $size") - TimingUtil.timeReplicates(s"Scalability analysis for $size", 5) { + TimingUtil.timeReplicates(s"Scalability analysis for $size", 3) { val g = RandomGraphGenerator.generateRandomGraph(size) val ppm = RandomTimeSeriesGenerator.generateRandomPeptideProteinMap(g) val ts = RandomTimeSeriesGenerator.generateRandomTimeSeries(ppm.keySet) From fdcff1572c3712a6657358c1654bdadc998ab824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Sun, 25 Jun 2017 12:58:56 -0700 Subject: [PATCH 23/25] clean up unused random graph generation code --- .../tps/simulation/RandomGraphGenerator.scala | 36 ------------------- .../simulation/RandomGraphGeneratorTest.scala | 12 ------- 2 files changed, 48 deletions(-) diff --git a/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala b/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala index 2f283dd2..cb274845 100644 --- a/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala +++ b/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala @@ -46,40 +46,4 @@ object RandomGraphGenerator { UndirectedGraph(V, E, Set(src)) } - def generateRandomGraphFromSourceGraph(sourceGraph: UndirectedGraph, - maxNodeLimit: Int): UndirectedGraph = { - assert(sourceGraph.sources.size <= maxNodeLimit) - - var generatedGraph = UndirectedGraph(sourceGraph.sources, Set.empty, - sourceGraph.sources) - - try { - while (generatedGraph.V.size < maxNodeLimit) { - // find a random incident edge to add while respecting max degree limit. - val candidates = extensionCandidates(generatedGraph, sourceGraph) - if (candidates.isEmpty) throw CannotExtendException - - val edgeToAdd = candidates.toIndexedSeq(random.nextInt(candidates.size)) - generatedGraph = UndirectedGraph( - generatedGraph.V ++ Set(edgeToAdd.v1, edgeToAdd.v2), - generatedGraph.E + edgeToAdd, - generatedGraph.sources) - } - generatedGraph - } catch { - case CannotExtendException => generatedGraph - } - } - - private def extensionCandidates(graphToExtend: UndirectedGraph, - sourceGraph: UndirectedGraph): Set[Edge] = { - graphToExtend.V.flatMap { v => - sourceGraph.incidentEdges(v).filter { e => - // only take edges that do not exist and that won't exceed max indegree - !graphToExtend.E.contains(e) && - graphToExtend.incidentEdges(e.v1).size < MAX_NODE_DEGREE && - graphToExtend.incidentEdges(e.v2).size < MAX_NODE_DEGREE - } - } - } } diff --git a/tps-core/src/test/scala/tps/simulation/RandomGraphGeneratorTest.scala b/tps-core/src/test/scala/tps/simulation/RandomGraphGeneratorTest.scala index fc7ef293..0b54ed3a 100644 --- a/tps-core/src/test/scala/tps/simulation/RandomGraphGeneratorTest.scala +++ b/tps-core/src/test/scala/tps/simulation/RandomGraphGeneratorTest.scala @@ -18,16 +18,4 @@ class RandomGraphGeneratorTest extends FunSuite with Matchers { generated.E.size should equal (5) } - test("random graph from existing graph contains source and has right size") { - val sourceGraph = UndirectedGraphParser.run(testFile("network.tsv")).copy( - sources = Set(Vertex("A"))) - val maxNodeLimit = 3 - val generated = RandomGraphGenerator.generateRandomGraphFromSourceGraph( - sourceGraph, - maxNodeLimit) - - generated.V.size should equal (3) - generated.V should contain (Vertex("A")) - } - } From fb1bdcca67a14d0641f91d7bd7e68afbadd8a697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Sun, 25 Jun 2017 13:03:28 -0700 Subject: [PATCH 24/25] correct stale comment --- .../main/scala/tps/simulation/RandomGraphGenerator.scala | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala b/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala index cb274845..23279d4a 100644 --- a/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala +++ b/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala @@ -4,18 +4,15 @@ import tps.Graphs import tps.Graphs.{Edge, UndirectedGraph, Vertex} /** - * Generates a random graph of given size through a random walk on a given - * [[UndirectedGraph]], starting from its sources. + * Generates a random graph of given size, according to a predetermined + * likelihood of choosing between adding a new node and adding a new edge to + * it. */ object RandomGraphGenerator { private val RANDOM_SEED = 131161511 private val random = new scala.util.Random(RANDOM_SEED) - // for creating graphs from a source graph - private val MAX_NODE_DEGREE = 3 - - // for creating purely random graphs private val NODE_CREATION_PROBABILITY = 0.5 object CannotExtendException extends Exception From fadd650037df0584bc1fb5fecdc95781363c1487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= Date: Sun, 25 Jun 2017 13:23:09 -0700 Subject: [PATCH 25/25] clean up unused exception --- .../src/main/scala/tps/simulation/RandomGraphGenerator.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala b/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala index 23279d4a..965a4092 100644 --- a/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala +++ b/tps-core/src/main/scala/tps/simulation/RandomGraphGenerator.scala @@ -15,8 +15,6 @@ object RandomGraphGenerator { private val NODE_CREATION_PROBABILITY = 0.5 - object CannotExtendException extends Exception - def generateRandomGraph(nbEdges: Int): UndirectedGraph = { val src = Vertex("src") var V = Set[Vertex](src)