-
Notifications
You must be signed in to change notification settings - Fork 105
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
28 changed files
with
477 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
38 changes: 38 additions & 0 deletions
38
jupyter-lib/api/src/main/kotlin/org/jetbrains/kotlinx/jupyter/api/graphs/GraphNode.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package org.jetbrains.kotlinx.jupyter.api.graphs | ||
|
||
/** | ||
* Graph node which represents the object as a part of some hierarchy | ||
* | ||
* Classes implementing this interface should take care of [equals] and [hashCode] | ||
* because they are used for testing the nodes for equality, and wrong implementation | ||
* of these methods may lead to the wrong graph rendering, StackOverflow / OutOfMemory | ||
* errors and so on. See example in [NodeWrapper] | ||
* | ||
* @param T Underlying object type | ||
*/ | ||
interface GraphNode<T> { | ||
/** | ||
* Node label with all required information | ||
*/ | ||
val label: Label | ||
|
||
/** | ||
* Nodes which are connected with the ingoing edges to this one: | ||
* {this} <- {inNode} | ||
*/ | ||
val inNodes: List<GraphNode<T>> | ||
|
||
/** | ||
* Nodes which are connected with the outgoing edges to this one: | ||
* {this} -> {outNode} | ||
*/ | ||
val outNodes: List<GraphNode<T>> | ||
|
||
/** | ||
* Nodes which are connected with the undirected edges to this one: | ||
* {this} -- {biNode} | ||
*/ | ||
val biNodes: List<GraphNode<T>> | ||
|
||
companion object | ||
} |
17 changes: 17 additions & 0 deletions
17
jupyter-lib/api/src/main/kotlin/org/jetbrains/kotlinx/jupyter/api/graphs/Label.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package org.jetbrains.kotlinx.jupyter.api.graphs | ||
|
||
/** | ||
* [Label] contains all information related to the node itself | ||
*/ | ||
interface Label { | ||
/** | ||
* Node text. May be simple simple text or HTML | ||
*/ | ||
val text: String | ||
|
||
/** | ||
* Shape of this node. The full list of shapes is given | ||
* [here](https://graphviz.org/doc/info/shapes.html) | ||
*/ | ||
val shape: String? get() = null | ||
} |
22 changes: 22 additions & 0 deletions
22
jupyter-lib/api/src/main/kotlin/org/jetbrains/kotlinx/jupyter/api/graphs/NodeWrapper.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package org.jetbrains.kotlinx.jupyter.api.graphs | ||
|
||
import org.jetbrains.kotlinx.jupyter.api.graphs.labels.TextLabel | ||
|
||
/** | ||
* Use [NodeWrapper] if [T] cannot implement [GraphNode] itself for some reason | ||
*/ | ||
abstract class NodeWrapper<T>(val value: T) : GraphNode<T> { | ||
override val label: Label get() = TextLabel(value.toString()) | ||
|
||
override val inNodes get() = listOf<GraphNode<T>>() | ||
override val outNodes get() = listOf<GraphNode<T>>() | ||
override val biNodes get() = listOf<GraphNode<T>>() | ||
|
||
override fun equals(other: Any?): Boolean { | ||
return other is NodeWrapper<*> && other.value == this.value | ||
} | ||
|
||
override fun hashCode(): Int { | ||
return value.hashCode() | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
...c/main/kotlin/org/jetbrains/kotlinx/jupyter/api/graphs/labels/FilteringPropObjectLabel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package org.jetbrains.kotlinx.jupyter.api.graphs.labels | ||
|
||
import kotlin.reflect.KProperty1 | ||
|
||
/** | ||
* Convenience class for creating [PropObjectLabel] if only fixed subset | ||
* of properties [propertiesToRender] should be rendered | ||
*/ | ||
class FilteringPropObjectLabel<T : Any>( | ||
value: T, | ||
override val mainText: String = value.toString(), | ||
private val propertiesToRender: Collection<String> = emptyList(), | ||
) : PropObjectLabel<T>(value) { | ||
override fun shouldRenderProperty(prop: KProperty1<out T, *>): Boolean { | ||
return prop.name in propertiesToRender | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
...er-lib/api/src/main/kotlin/org/jetbrains/kotlinx/jupyter/api/graphs/labels/KClassLabel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package org.jetbrains.kotlinx.jupyter.api.graphs.labels | ||
|
||
import kotlin.reflect.KClass | ||
|
||
/** | ||
* Label representing [kClass] with all members in HTML table | ||
*/ | ||
class KClassLabel(private val kClass: KClass<*>) : RecordTableLabel() { | ||
override val mainText get() = kClass.simpleName.toString() | ||
|
||
override val properties: Collection<Iterable<String>> | ||
get() = kClass.members.map { listOf(it.name, it.returnType.toString()) } | ||
} |
28 changes: 28 additions & 0 deletions
28
...ib/api/src/main/kotlin/org/jetbrains/kotlinx/jupyter/api/graphs/labels/PropObjectLabel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package org.jetbrains.kotlinx.jupyter.api.graphs.labels | ||
|
||
import kotlin.reflect.KProperty1 | ||
import kotlin.reflect.full.memberProperties | ||
import kotlin.reflect.jvm.isAccessible | ||
|
||
/** | ||
* Renders [value] object with its properties for | ||
* those [shouldRenderProperty] returns `true` | ||
*/ | ||
open class PropObjectLabel<T : Any>(val value: T) : RecordTableLabel() { | ||
override val mainText get() = value.toString() | ||
|
||
override val properties: Collection<Iterable<String>> get() { | ||
val kClass = value::class | ||
|
||
return kClass.memberProperties | ||
.filter(::shouldRenderProperty) | ||
.map { prop -> | ||
@Suppress("UNCHECKED_CAST") | ||
prop as KProperty1<T, *> | ||
prop.isAccessible = true | ||
listOf(prop.name, prop.invoke(value).toString()) | ||
} | ||
} | ||
|
||
open fun shouldRenderProperty(prop: KProperty1<out T, *>) = true | ||
} |
42 changes: 42 additions & 0 deletions
42
...b/api/src/main/kotlin/org/jetbrains/kotlinx/jupyter/api/graphs/labels/RecordTableLabel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package org.jetbrains.kotlinx.jupyter.api.graphs.labels | ||
|
||
import org.jetbrains.kotlinx.jupyter.api.graphs.Label | ||
|
||
/** | ||
* Renders as n-column table | ||
* First column consists of one cell containing [mainText]. | ||
* Next `(n-1)` columns contain values from [properties]. It is | ||
* supposed that all element in [properties] collection would | ||
* have `(n-1)` elements. | ||
*/ | ||
abstract class RecordTableLabel : Label { | ||
override val text: String get() { | ||
val nProperties = properties.size | ||
|
||
fun inTable(builderAction: StringBuilder.() -> Unit) = buildString { | ||
append("<<table>") | ||
builderAction() | ||
append("</table>>") | ||
} | ||
|
||
if (nProperties == 0) return inTable { append("<tr><td>$mainText</td></tr>") } | ||
return inTable { | ||
properties.forEachIndexed { i, prop -> | ||
append("<tr>") | ||
if (i == 0) { | ||
append("""<td rowspan="$nProperties">$mainText</td>""") | ||
} | ||
prop.forEach { value -> | ||
append("""<td>$value</td>""") | ||
} | ||
appendLine("</tr>") | ||
} | ||
} | ||
} | ||
|
||
override val shape: String? get() = "plaintext" | ||
|
||
abstract val mainText: String | ||
|
||
abstract val properties: Collection<Iterable<String>> | ||
} |
10 changes: 10 additions & 0 deletions
10
jupyter-lib/api/src/main/kotlin/org/jetbrains/kotlinx/jupyter/api/graphs/labels/TextLabel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package org.jetbrains.kotlinx.jupyter.api.graphs.labels | ||
|
||
import org.jetbrains.kotlinx.jupyter.api.graphs.Label | ||
|
||
/** | ||
* Label representing a plain text inside a given [shape] | ||
*/ | ||
class TextLabel(value: String, override val shape: String? = "ellipse") : Label { | ||
override val text: String = "\"${value.replace("\"", "\\\"")}\"" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
...lib-ext/src/main/kotlin/org/jetbrains/kotlinx/jupyter/ext/graph/structure/DirectedEdge.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package org.jetbrains.kotlinx.jupyter.ext.graph.structure | ||
|
||
import org.jetbrains.kotlinx.jupyter.api.graphs.GraphNode | ||
|
||
data class DirectedEdge<T>( | ||
val fromNode: GraphNode<T>, | ||
val toNode: GraphNode<T>, | ||
) |
22 changes: 22 additions & 0 deletions
22
...er-lib/lib-ext/src/main/kotlin/org/jetbrains/kotlinx/jupyter/ext/graph/structure/Graph.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package org.jetbrains.kotlinx.jupyter.ext.graph.structure | ||
|
||
import org.jetbrains.kotlinx.jupyter.api.graphs.GraphNode | ||
|
||
interface Graph<T> : MultiGraph<T> { | ||
override val directedEdges: Set<DirectedEdge<T>> | ||
override val undirectedEdges: Set<UndirectedEdge<T>> | ||
|
||
companion object { | ||
fun <T> of(elements: Iterable<GraphNode<T>>): Graph<T> { | ||
val nodes = mutableSetOf<GraphNode<T>>() | ||
val directedEdges = mutableSetOf<DirectedEdge<T>>() | ||
val undirectedEdges = mutableSetOf<UndirectedEdge<T>>() | ||
|
||
for (element in elements) element.populate(nodes, directedEdges, undirectedEdges) | ||
|
||
return GraphImpl(nodes, directedEdges, undirectedEdges) | ||
} | ||
|
||
fun <T> of(vararg elements: GraphNode<T>): Graph<T> = of(elements.toList()) | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
...ib/lib-ext/src/main/kotlin/org/jetbrains/kotlinx/jupyter/ext/graph/structure/GraphImpl.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package org.jetbrains.kotlinx.jupyter.ext.graph.structure | ||
|
||
import org.jetbrains.kotlinx.jupyter.api.graphs.GraphNode | ||
|
||
class GraphImpl<T>( | ||
override val nodes: Set<GraphNode<T>>, | ||
override val directedEdges: Set<DirectedEdge<T>>, | ||
override val undirectedEdges: Set<UndirectedEdge<T>>, | ||
) : Graph<T> |
23 changes: 23 additions & 0 deletions
23
...b/lib-ext/src/main/kotlin/org/jetbrains/kotlinx/jupyter/ext/graph/structure/MultiGraph.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package org.jetbrains.kotlinx.jupyter.ext.graph.structure | ||
|
||
import org.jetbrains.kotlinx.jupyter.api.graphs.GraphNode | ||
|
||
interface MultiGraph<T> { | ||
val nodes: Set<GraphNode<T>> | ||
val directedEdges: Collection<DirectedEdge<T>> | ||
val undirectedEdges: Collection<UndirectedEdge<T>> | ||
|
||
companion object { | ||
fun <T> of(elements: Iterable<GraphNode<T>>): MultiGraph<T> { | ||
val nodes = mutableSetOf<GraphNode<T>>() | ||
val directedEdges = mutableListOf<DirectedEdge<T>>() | ||
val undirectedEdges = mutableListOf<UndirectedEdge<T>>() | ||
|
||
for (element in elements) element.populate(nodes, directedEdges, undirectedEdges) | ||
|
||
return MultiGraphImpl(nodes, directedEdges, undirectedEdges) | ||
} | ||
|
||
fun <T> of(vararg elements: GraphNode<T>): MultiGraph<T> = of(elements.toList()) | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
...b-ext/src/main/kotlin/org/jetbrains/kotlinx/jupyter/ext/graph/structure/MultiGraphImpl.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package org.jetbrains.kotlinx.jupyter.ext.graph.structure | ||
|
||
import org.jetbrains.kotlinx.jupyter.api.graphs.GraphNode | ||
|
||
class MultiGraphImpl<T>( | ||
override val nodes: Set<GraphNode<T>>, | ||
override val directedEdges: List<DirectedEdge<T>>, | ||
override val undirectedEdges: List<UndirectedEdge<T>>, | ||
) : MultiGraph<T> |
22 changes: 22 additions & 0 deletions
22
...b-ext/src/main/kotlin/org/jetbrains/kotlinx/jupyter/ext/graph/structure/UndirectedEdge.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package org.jetbrains.kotlinx.jupyter.ext.graph.structure | ||
|
||
import org.jetbrains.kotlinx.jupyter.api.graphs.GraphNode | ||
|
||
data class UndirectedEdge<T>( | ||
val fromNode: GraphNode<T>, | ||
val toNode: GraphNode<T>, | ||
) { | ||
override fun equals(other: Any?): Boolean { | ||
return other is UndirectedEdge<*> && ( | ||
(fromNode == other.fromNode) && (toNode == other.toNode) || | ||
(fromNode == other.toNode) && (toNode == other.fromNode) | ||
) | ||
} | ||
|
||
override fun hashCode(): Int { | ||
var h1 = fromNode.hashCode() | ||
var h2 = toNode.hashCode() | ||
if (h1 > h2) { val t = h2; h2 = h1; h1 = t } | ||
return 31 * h1 + h2 | ||
} | ||
} |
51 changes: 51 additions & 0 deletions
51
...ter-lib/lib-ext/src/main/kotlin/org/jetbrains/kotlinx/jupyter/ext/graph/structure/util.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package org.jetbrains.kotlinx.jupyter.ext.graph.structure | ||
|
||
import org.jetbrains.kotlinx.jupyter.api.graphs.GraphNode | ||
|
||
val <T> GraphNode<T>.allParents: Iterable<GraphNode<T>> get() { | ||
return IterablesView(listOf(inNodes, outNodes, biNodes)) | ||
} | ||
|
||
private class IterablesView<T>(private val iterables: Iterable<Iterable<T>>) : Iterable<T> { | ||
override fun iterator(): Iterator<T> { | ||
return MyIterator(iterables) | ||
} | ||
|
||
class MyIterator<T>(iterables: Iterable<Iterable<T>>) : Iterator<T> { | ||
private val outerIterator = iterables.iterator() | ||
private var innerIterator: Iterator<T>? = null | ||
|
||
override fun hasNext(): Boolean { | ||
while (innerIterator?.hasNext() != true) { | ||
if (!outerIterator.hasNext()) return false | ||
innerIterator = outerIterator.next().iterator() | ||
} | ||
return true | ||
} | ||
|
||
override fun next(): T { | ||
if (!hasNext()) throw IndexOutOfBoundsException() | ||
return innerIterator!!.next() | ||
} | ||
} | ||
} | ||
|
||
fun <T> GraphNode<T>.populate( | ||
nodes: MutableSet<GraphNode<T>>, | ||
directedEdges: MutableCollection<DirectedEdge<T>>, | ||
undirectedEdges: MutableCollection<UndirectedEdge<T>>, | ||
) { | ||
nodes.add(this) | ||
for (parent in inNodes) { | ||
directedEdges.add(DirectedEdge(parent, this)) | ||
} | ||
for (parent in outNodes) { | ||
directedEdges.add(DirectedEdge(this, parent)) | ||
} | ||
for (parent in this.biNodes) { | ||
undirectedEdges.add(UndirectedEdge(this, parent)) | ||
} | ||
for (parent in allParents) { | ||
if (parent !in nodes) parent.populate(nodes, directedEdges, undirectedEdges) | ||
} | ||
} |
Oops, something went wrong.