chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ /* ******************************************************************************
|
||||
~ *
|
||||
~ *
|
||||
~ * This program and the accompanying materials are made available under the
|
||||
~ * terms of the Apache License, Version 2.0 which is available at
|
||||
~ * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
~ *
|
||||
~ * See the NOTICE file distributed with this work for additional
|
||||
~ * information regarding copyright ownership.
|
||||
~ * Unless required by applicable law or agreed to in writing, software
|
||||
~ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
~ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
~ * License for the specific language governing permissions and limitations
|
||||
~ * under the License.
|
||||
~ *
|
||||
~ * SPDX-License-Identifier: Apache-2.0
|
||||
~ ******************************************************************************/
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.eclipse.deeplearning4j</groupId>
|
||||
<artifactId>deeplearning4j-parent</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>deeplearning4j-graph</artifactId>
|
||||
|
||||
<properties>
|
||||
<module.name>deeplearning4j.graph</module.name>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.moditect</groupId>
|
||||
<artifactId>moditect-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.deeplearning4j</groupId>
|
||||
<artifactId>deeplearning4j-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.threadly</groupId>
|
||||
<artifactId>threadly</artifactId>
|
||||
<version>${threadly.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
<artifactId>junit-platform-launcher</artifactId>
|
||||
<version>${junit.platform.launcher.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.deeplearning4j</groupId>
|
||||
<artifactId>deeplearning4j-common-tests</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
||||
+257
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph;
|
||||
|
||||
import org.deeplearning4j.graph.api.BaseGraph;
|
||||
import org.deeplearning4j.graph.api.Edge;
|
||||
import org.deeplearning4j.graph.api.Vertex;
|
||||
import org.deeplearning4j.graph.exception.NoEdgesException;
|
||||
import org.deeplearning4j.graph.vertexfactory.VertexFactory;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.*;
|
||||
|
||||
public class Graph<V, E> extends BaseGraph<V, E> {
|
||||
private boolean allowMultipleEdges;
|
||||
private List<Edge<E>>[] edges; //edge[i].get(j).to = k, then edge from i -> k
|
||||
private List<Vertex<V>> vertices;
|
||||
|
||||
public Graph(int numVertices, VertexFactory<V> vertexFactory) {
|
||||
this(numVertices, false, vertexFactory);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Graph(int numVertices, boolean allowMultipleEdges, VertexFactory<V> vertexFactory) {
|
||||
if (numVertices <= 0)
|
||||
throw new IllegalArgumentException();
|
||||
this.allowMultipleEdges = allowMultipleEdges;
|
||||
|
||||
vertices = new ArrayList<>(numVertices);
|
||||
for (int i = 0; i < numVertices; i++)
|
||||
vertices.add(vertexFactory.create(i));
|
||||
|
||||
edges = (List<Edge<E>>[]) Array.newInstance(List.class, numVertices);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Graph(List<Vertex<V>> vertices, boolean allowMultipleEdges) {
|
||||
this.vertices = new ArrayList<>(vertices);
|
||||
this.allowMultipleEdges = allowMultipleEdges;
|
||||
edges = (List<Edge<E>>[]) Array.newInstance(List.class, vertices.size());
|
||||
}
|
||||
|
||||
public Graph(List<Vertex<V>> vertices) {
|
||||
this(vertices, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int numVertices() {
|
||||
return vertices.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vertex<V> getVertex(int idx) {
|
||||
if (idx < 0 || idx >= vertices.size())
|
||||
throw new IllegalArgumentException("Invalid index: " + idx);
|
||||
return vertices.get(idx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Vertex<V>> getVertices(int[] indexes) {
|
||||
List<Vertex<V>> out = new ArrayList<>(indexes.length);
|
||||
for (int i : indexes)
|
||||
out.add(getVertex(i));
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Vertex<V>> getVertices(int from, int to) {
|
||||
if (to < from || from < 0 || to >= vertices.size())
|
||||
throw new IllegalArgumentException("Invalid range: from=" + from + ", to=" + to);
|
||||
List<Vertex<V>> out = new ArrayList<>(to - from + 1);
|
||||
for (int i = from; i <= to; i++)
|
||||
out.add(getVertex(i));
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEdge(Edge<E> edge) {
|
||||
if (edge.getFrom() < 0 || edge.getTo() >= vertices.size())
|
||||
throw new IllegalArgumentException("Invalid edge: " + edge + ", from/to indexes out of range");
|
||||
|
||||
List<Edge<E>> fromList = edges[edge.getFrom()];
|
||||
if (fromList == null) {
|
||||
fromList = new ArrayList<>();
|
||||
edges[edge.getFrom()] = fromList;
|
||||
}
|
||||
addEdgeHelper(edge, fromList);
|
||||
|
||||
if (edge.isDirected())
|
||||
return;
|
||||
|
||||
//Add other way too (to allow easy lookup for undirected edges)
|
||||
List<Edge<E>> toList = edges[edge.getTo()];
|
||||
if (toList == null) {
|
||||
toList = new ArrayList<>();
|
||||
edges[edge.getTo()] = toList;
|
||||
}
|
||||
addEdgeHelper(edge, toList);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Edge<E>> getEdgesOut(int vertex) {
|
||||
if (edges[vertex] == null)
|
||||
return Collections.emptyList();
|
||||
return new ArrayList<>(edges[vertex]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVertexDegree(int vertex) {
|
||||
if (edges[vertex] == null)
|
||||
return 0;
|
||||
return edges[vertex].size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vertex<V> getRandomConnectedVertex(int vertex, Random rng) throws NoEdgesException {
|
||||
if (vertex < 0 || vertex >= vertices.size())
|
||||
throw new IllegalArgumentException("Invalid vertex index: " + vertex);
|
||||
if (edges[vertex] == null || edges[vertex].isEmpty())
|
||||
throw new NoEdgesException("Cannot generate random connected vertex: vertex " + vertex
|
||||
+ " has no outgoing/undirected edges");
|
||||
int connectedVertexNum = rng.nextInt(edges[vertex].size());
|
||||
Edge<E> edge = edges[vertex].get(connectedVertexNum);
|
||||
if (edge.getFrom() == vertex)
|
||||
return vertices.get(edge.getTo()); //directed or undirected, vertex -> x
|
||||
else
|
||||
return vertices.get(edge.getFrom()); //Undirected edge, x -> vertex
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Vertex<V>> getConnectedVertices(int vertex) {
|
||||
if (vertex < 0 || vertex >= vertices.size())
|
||||
throw new IllegalArgumentException("Invalid vertex index: " + vertex);
|
||||
|
||||
if (edges[vertex] == null)
|
||||
return Collections.emptyList();
|
||||
List<Vertex<V>> list = new ArrayList<>(edges[vertex].size());
|
||||
for (Edge<E> edge : edges[vertex]) {
|
||||
list.add(vertices.get(edge.getTo()));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getConnectedVertexIndices(int vertex) {
|
||||
int[] out = new int[(edges[vertex] == null ? 0 : edges[vertex].size())];
|
||||
if (out.length == 0)
|
||||
return out;
|
||||
for (int i = 0; i < out.length; i++) {
|
||||
Edge<E> e = edges[vertex].get(i);
|
||||
out[i] = (e.getFrom() == vertex ? e.getTo() : e.getFrom());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private void addEdgeHelper(Edge<E> edge, List<Edge<E>> list) {
|
||||
if (!allowMultipleEdges) {
|
||||
//Check to avoid multiple edges
|
||||
boolean duplicate = false;
|
||||
|
||||
if (edge.isDirected()) {
|
||||
for (Edge<E> e : list) {
|
||||
if (e.getTo() == edge.getTo()) {
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (Edge<E> e : list) {
|
||||
if ((e.getFrom() == edge.getFrom() && e.getTo() == edge.getTo())
|
||||
|| (e.getTo() == edge.getFrom() && e.getFrom() == edge.getTo())) {
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!duplicate) {
|
||||
list.add(edge);
|
||||
}
|
||||
} else {
|
||||
//allow multiple/duplicate edges
|
||||
list.add(edge);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Graph {");
|
||||
sb.append("\nVertices {");
|
||||
for (Vertex<V> v : vertices) {
|
||||
sb.append("\n\t").append(v);
|
||||
}
|
||||
sb.append("\n}");
|
||||
sb.append("\nEdges {");
|
||||
for (int i = 0; i < edges.length; i++) {
|
||||
sb.append("\n\t");
|
||||
if (edges[i] == null)
|
||||
continue;
|
||||
sb.append(i).append(":");
|
||||
for (Edge<E> e : edges[i]) {
|
||||
sb.append(" ").append(e);
|
||||
}
|
||||
}
|
||||
sb.append("\n}");
|
||||
sb.append("\n}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Graph))
|
||||
return false;
|
||||
Graph g = (Graph) o;
|
||||
if (allowMultipleEdges != g.allowMultipleEdges)
|
||||
return false;
|
||||
if (edges.length != g.edges.length)
|
||||
return false;
|
||||
if (vertices.size() != g.vertices.size())
|
||||
return false;
|
||||
for (int i = 0; i < edges.length; i++) {
|
||||
if (!edges[i].equals(g.edges[i]))
|
||||
return false;
|
||||
}
|
||||
return vertices.equals(g.vertices);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 23;
|
||||
result = 31 * result + (allowMultipleEdges ? 1 : 0);
|
||||
result = 31 * result + Arrays.hashCode(edges);
|
||||
result = 31 * result + vertices.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph;
|
||||
|
||||
import org.deeplearning4j.graph.api.IGraph;
|
||||
import org.deeplearning4j.graph.api.IVertexSequence;
|
||||
import org.deeplearning4j.graph.api.Vertex;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class VertexSequence<V> implements IVertexSequence<V> {
|
||||
private final IGraph<V, ?> graph;
|
||||
private int[] indices;
|
||||
private int currIdx = 0;
|
||||
|
||||
public VertexSequence(IGraph<V, ?> graph, int[] indices) {
|
||||
this.graph = graph;
|
||||
this.indices = indices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int sequenceLength() {
|
||||
return indices.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return currIdx < indices.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vertex<V> next() {
|
||||
if (!hasNext())
|
||||
throw new NoSuchElementException();
|
||||
return graph.getVertex(indices[currIdx++]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.api;
|
||||
|
||||
public abstract class BaseGraph<V, E> implements IGraph<V, E> {
|
||||
|
||||
|
||||
public void addEdge(int from, int to, E value, boolean directed) {
|
||||
addEdge(new Edge<>(from, to, value, directed));
|
||||
}
|
||||
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.api;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class Edge<T> {
|
||||
|
||||
private final int from;
|
||||
private final int to;
|
||||
private final T value;
|
||||
private final boolean directed;
|
||||
|
||||
public Edge(int from, int to, T value, boolean directed) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.value = value;
|
||||
this.directed = directed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "edge(" + (directed ? "directed" : "undirected") + "," + from + (directed ? "->" : "--") + to + ","
|
||||
+ (value != null ? value : "") + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Edge))
|
||||
return false;
|
||||
Edge<?> e = (Edge<?>) o;
|
||||
if (directed != e.directed)
|
||||
return false;
|
||||
if (directed) {
|
||||
if (from != e.from)
|
||||
return false;
|
||||
if (to != e.to)
|
||||
return false;
|
||||
} else {
|
||||
if (from == e.from) {
|
||||
if (to != e.to)
|
||||
return false;
|
||||
} else {
|
||||
if (from != e.to)
|
||||
return false;
|
||||
if (to != e.from)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((value != null && e.value == null) || (value == null && e.value != null))
|
||||
return false;
|
||||
return value == null || value.equals(e.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 17;
|
||||
result = 31 * result + (directed ? 1 : 0);
|
||||
result = 31 * result + from;
|
||||
result = 31 * result + to;
|
||||
result = 31 * result + (value == null ? 0 : value.hashCode());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.api;
|
||||
|
||||
import org.deeplearning4j.graph.exception.NoEdgesException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public interface IGraph<V, E> {
|
||||
|
||||
/** Number of vertices in the graph */
|
||||
public int numVertices();
|
||||
|
||||
/**Get a vertex in the graph for a given index
|
||||
* @param idx integer index of the vertex to get. must be in range 0 to numVertices()
|
||||
* @return vertex
|
||||
*/
|
||||
public Vertex<V> getVertex(int idx);
|
||||
|
||||
/** Get multiple vertices in the graph
|
||||
* @param indexes the indexes of the vertices to retrieve
|
||||
* @return list of vertices
|
||||
*/
|
||||
public List<Vertex<V>> getVertices(int[] indexes);
|
||||
|
||||
/** Get multiple vertices in the graph, with secified indices
|
||||
* @param from first vertex to get, inclusive
|
||||
* @param to last vertex to get, inclusive
|
||||
* @return list of vertices
|
||||
*/
|
||||
public List<Vertex<V>> getVertices(int from, int to);
|
||||
|
||||
/** Add an edge to the graph.
|
||||
*/
|
||||
public void addEdge(Edge<E> edge);
|
||||
|
||||
/** Convenience method for adding an edge (directed or undirected) to graph */
|
||||
public void addEdge(int from, int to, E value, boolean directed);
|
||||
|
||||
/** Returns a list of edges for a vertex with a given index
|
||||
* For undirected graphs, returns all edges incident on the vertex
|
||||
* For directed graphs, only returns outward directed edges
|
||||
* @param vertex index of the vertex to
|
||||
* @return list of edges for this vertex
|
||||
*/
|
||||
public List<Edge<E>> getEdgesOut(int vertex);
|
||||
|
||||
/** Returns the degree of the vertex.<br>
|
||||
* For undirected graphs, this is just the degree.<br>
|
||||
* For directed graphs, this returns the outdegree
|
||||
* @param vertex vertex to get degree for
|
||||
* @return vertex degree
|
||||
*/
|
||||
public int getVertexDegree(int vertex);
|
||||
|
||||
/** Randomly sample a vertex connected to a given vertex. Sampling is done uniformly at random.
|
||||
* Specifically, returns a random X such that either a directed edge (vertex -> X) exists,
|
||||
* or an undirected edge (vertex -- X) exists<br>
|
||||
* Can be used for example to implement a random walk on the graph (specifically: a unweighted random walk)
|
||||
* @param vertex vertex to randomly sample from
|
||||
* @param rng Random number generator to use
|
||||
* @return A vertex connected to the specified vertex,
|
||||
* @throws NoEdgesException thrown if the specified vertex has no edges, or no outgoing edges (in the case
|
||||
* of a directed graph).
|
||||
*/
|
||||
public Vertex<V> getRandomConnectedVertex(int vertex, Random rng) throws NoEdgesException;
|
||||
|
||||
/**Get a list of all of the vertices that the specified vertex is connected to<br>
|
||||
* Specifically, for undirected graphs return list of all X such that (vertex -- X) exists<br>
|
||||
* For directed graphs, return list of all X such that (vertex -> X) exists
|
||||
* @param vertex Index of the vertex
|
||||
* @return list of vertices that the specified vertex is connected to
|
||||
*/
|
||||
public List<Vertex<V>> getConnectedVertices(int vertex);
|
||||
|
||||
/**Return an array of indexes of vertices that the specified vertex is connected to.<br>
|
||||
* Specifically, for undirected graphs return int[] of all X.vertexID() such that (vertex -- X) exists<br>
|
||||
* For directed graphs, return int[] of all X.vertexID() such that (vertex -> X) exists
|
||||
* @param vertex index of the vertex
|
||||
* @return list of vertices that the specified vertex is connected to
|
||||
* @see #getConnectedVertices(int)
|
||||
*/
|
||||
public int[] getConnectedVertexIndices(int vertex);
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.api;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
public interface IVertexSequence<T> extends Iterator<Vertex<T>> {
|
||||
|
||||
/** Length of the vertex sequence */
|
||||
int sequenceLength();
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.api;
|
||||
|
||||
public enum NoEdgeHandling {
|
||||
SELF_LOOP_ON_DISCONNECTED, EXCEPTION_ON_DISCONNECTED
|
||||
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.api;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class Vertex<T> {
|
||||
|
||||
private final int idx;
|
||||
private final T value;
|
||||
|
||||
public int vertexID() {
|
||||
return idx;
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "vertex(" + idx + "," + (value != null ? value : "") + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Vertex))
|
||||
return false;
|
||||
Vertex<?> v = (Vertex<?>) o;
|
||||
if (idx != v.idx)
|
||||
return false;
|
||||
if ((value == null && v.value != null) || (value != null && v.value == null))
|
||||
return false;
|
||||
return value == null || value.equals(v.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 17;
|
||||
result = 31 * result + idx;
|
||||
result = 31 * result + (value == null ? 0 : value.hashCode());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.data;
|
||||
|
||||
import org.deeplearning4j.graph.api.Edge;
|
||||
|
||||
public interface EdgeLineProcessor<E> {
|
||||
|
||||
/** Process a line of text into an edge.
|
||||
* May return null if line is not a valid edge (i.e., comment line etc)
|
||||
*/
|
||||
Edge<E> processLine(String line);
|
||||
|
||||
}
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.data;
|
||||
|
||||
import org.deeplearning4j.graph.api.Edge;
|
||||
import org.deeplearning4j.graph.api.Vertex;
|
||||
import org.deeplearning4j.graph.data.impl.DelimitedEdgeLineProcessor;
|
||||
import org.deeplearning4j.graph.data.impl.WeightedEdgeLineProcessor;
|
||||
import org.deeplearning4j.graph.Graph;
|
||||
import org.deeplearning4j.graph.vertexfactory.StringVertexFactory;
|
||||
import org.deeplearning4j.graph.vertexfactory.VertexFactory;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/** Utility methods for loading graphs
|
||||
*
|
||||
*/
|
||||
public class GraphLoader {
|
||||
|
||||
private GraphLoader() {}
|
||||
|
||||
/** Simple method for loading an undirected graph, where the graph is represented by a edge list with one edge
|
||||
* per line with a delimiter in between<br>
|
||||
* This method assumes that all lines in the file are of the form {@code i<delim>j} where i and j are integers
|
||||
* in range 0 to numVertices inclusive, and "<delim>" is the user-provided delimiter
|
||||
* <b>Note</b>: this method calls {@link #loadUndirectedGraphEdgeListFile(String, int, String, boolean)} with allowMultipleEdges = true.
|
||||
* @param path Path to the edge list file
|
||||
* @param numVertices number of vertices in the graph
|
||||
* @return graph
|
||||
* @throws IOException if file cannot be read
|
||||
*/
|
||||
public static Graph<String, String> loadUndirectedGraphEdgeListFile(String path, int numVertices, String delim)
|
||||
throws IOException {
|
||||
return loadUndirectedGraphEdgeListFile(path, numVertices, delim, true);
|
||||
}
|
||||
|
||||
/** Simple method for loading an undirected graph, where the graph is represented by a edge list with one edge
|
||||
* per line with a delimiter in between<br>
|
||||
* This method assumes that all lines in the file are of the form {@code i<delim>j} where i and j are integers
|
||||
* in range 0 to numVertices inclusive, and "<delim>" is the user-provided delimiter
|
||||
* @param path Path to the edge list file
|
||||
* @param numVertices number of vertices in the graph
|
||||
* @param allowMultipleEdges If set to false, the graph will not allow multiple edges between any two vertices to exist. However,
|
||||
* checking for duplicates during graph loading can be costly, so use allowMultipleEdges=true when
|
||||
* possible.
|
||||
* @return graph
|
||||
* @throws IOException if file cannot be read
|
||||
*/
|
||||
public static Graph<String, String> loadUndirectedGraphEdgeListFile(String path, int numVertices, String delim,
|
||||
boolean allowMultipleEdges) throws IOException {
|
||||
Graph<String, String> graph = new Graph<>(numVertices, allowMultipleEdges, new StringVertexFactory());
|
||||
EdgeLineProcessor<String> lineProcessor = new DelimitedEdgeLineProcessor(delim, false);
|
||||
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(new File(path)))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
Edge<String> edge = lineProcessor.processLine(line);
|
||||
if (edge != null) {
|
||||
graph.addEdge(edge);
|
||||
}
|
||||
}
|
||||
}
|
||||
return graph;
|
||||
}
|
||||
|
||||
/**Method for loading a weighted graph from an edge list file, where each edge (inc. weight) is represented by a
|
||||
* single line. Graph may be directed or undirected<br>
|
||||
* This method assumes that edges are of the format: {@code fromIndex<delim>toIndex<delim>edgeWeight} where {@code <delim>}
|
||||
* is the delimiter.
|
||||
* <b>Note</b>: this method calls {@link #loadWeightedEdgeListFile(String, int, String, boolean, boolean, String...)} with allowMultipleEdges = true.
|
||||
* @param path Path to the edge list file
|
||||
* @param numVertices The number of vertices in the graph
|
||||
* @param delim The delimiter used in the file (typically: "," or " " etc)
|
||||
* @param directed whether the edges should be treated as directed (true) or undirected (false)
|
||||
* @param ignoreLinesStartingWith Starting characters for comment lines. May be null. For example: "//" or "#"
|
||||
* @return The graph
|
||||
* @throws IOException
|
||||
*/
|
||||
public static Graph<String, Double> loadWeightedEdgeListFile(String path, int numVertices, String delim,
|
||||
boolean directed, String... ignoreLinesStartingWith) throws IOException {
|
||||
return loadWeightedEdgeListFile(path, numVertices, delim, directed, true, ignoreLinesStartingWith);
|
||||
}
|
||||
|
||||
/**Method for loading a weighted graph from an edge list file, where each edge (inc. weight) is represented by a
|
||||
* single line. Graph may be directed or undirected<br>
|
||||
* This method assumes that edges are of the format: {@code fromIndex<delim>toIndex<delim>edgeWeight} where {@code <delim>}
|
||||
* is the delimiter.
|
||||
* @param path Path to the edge list file
|
||||
* @param numVertices The number of vertices in the graph
|
||||
* @param delim The delimiter used in the file (typically: "," or " " etc)
|
||||
* @param directed whether the edges should be treated as directed (true) or undirected (false)
|
||||
* @param allowMultipleEdges If set to false, the graph will not allow multiple edges between any two vertices to exist. However,
|
||||
* checking for duplicates during graph loading can be costly, so use allowMultipleEdges=true when
|
||||
* possible.
|
||||
* @param ignoreLinesStartingWith Starting characters for comment lines. May be null. For example: "//" or "#"
|
||||
* @return The graph
|
||||
* @throws IOException
|
||||
*/
|
||||
public static Graph<String, Double> loadWeightedEdgeListFile(String path, int numVertices, String delim,
|
||||
boolean directed, boolean allowMultipleEdges, String... ignoreLinesStartingWith)
|
||||
throws IOException {
|
||||
Graph<String, Double> graph = new Graph<>(numVertices, allowMultipleEdges, new StringVertexFactory());
|
||||
EdgeLineProcessor<Double> lineProcessor =
|
||||
new WeightedEdgeLineProcessor(delim, directed, ignoreLinesStartingWith);
|
||||
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(new File(path)))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
Edge<Double> edge = lineProcessor.processLine(line);
|
||||
if (edge != null) {
|
||||
graph.addEdge(edge);
|
||||
}
|
||||
}
|
||||
}
|
||||
return graph;
|
||||
}
|
||||
|
||||
/** Load a graph into memory, using a given EdgeLineProcessor.
|
||||
* Assume one edge per line
|
||||
* @param path Path to the file containing the edges, one per line
|
||||
* @param lineProcessor EdgeLineProcessor used to convert lines of text into a graph (or null for comment lines etc)
|
||||
* @param vertexFactory Used to create vertices
|
||||
* @param numVertices number of vertices in the graph
|
||||
* @param allowMultipleEdges whether the graph should allow multiple edges between a given pair of vertices or not
|
||||
* @return IGraph
|
||||
*/
|
||||
public static <V, E> Graph<V, E> loadGraph(String path, EdgeLineProcessor<E> lineProcessor,
|
||||
VertexFactory<V> vertexFactory, int numVertices, boolean allowMultipleEdges) throws IOException {
|
||||
Graph<V, E> graph = new Graph<>(numVertices, allowMultipleEdges, vertexFactory);
|
||||
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(new File(path)))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
Edge<E> edge = lineProcessor.processLine(line);
|
||||
if (edge != null) {
|
||||
graph.addEdge(edge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
/** Load graph, assuming vertices are in one file and edges are in another file.
|
||||
*
|
||||
* @param vertexFilePath Path to file containing vertices, one per line
|
||||
* @param edgeFilePath Path to the file containing edges, one per line
|
||||
* @param vertexLoader VertexLoader, for loading vertices from the file
|
||||
* @param edgeLineProcessor EdgeLineProcessor, converts text lines into edges
|
||||
* @param allowMultipleEdges whether the graph should allow (or filter out) multiple edges
|
||||
* @return IGraph loaded from files
|
||||
*/
|
||||
public static <V, E> Graph<V, E> loadGraph(String vertexFilePath, String edgeFilePath, VertexLoader<V> vertexLoader,
|
||||
EdgeLineProcessor<E> edgeLineProcessor, boolean allowMultipleEdges) throws IOException {
|
||||
//Assume vertices are in one file
|
||||
//And edges are in another file
|
||||
|
||||
List<Vertex<V>> vertices = vertexLoader.loadVertices(vertexFilePath);
|
||||
Graph<V, E> graph = new Graph<>(vertices, allowMultipleEdges);
|
||||
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(new File(edgeFilePath)))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
Edge<E> edge = edgeLineProcessor.processLine(line);
|
||||
if (edge != null) {
|
||||
graph.addEdge(edge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return graph;
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.data;
|
||||
|
||||
import org.deeplearning4j.graph.api.Vertex;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public interface VertexLoader<V> {
|
||||
|
||||
List<Vertex<V>> loadVertices(String path) throws IOException;
|
||||
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.data.impl;
|
||||
|
||||
import org.deeplearning4j.graph.api.Edge;
|
||||
import org.deeplearning4j.graph.data.EdgeLineProcessor;
|
||||
|
||||
public class DelimitedEdgeLineProcessor implements EdgeLineProcessor<String> {
|
||||
private final String delimiter;
|
||||
private final String[] skipLinesStartingWith;
|
||||
private final boolean directed;
|
||||
|
||||
public DelimitedEdgeLineProcessor(String delimiter, boolean directed) {
|
||||
this(delimiter, directed, null);
|
||||
}
|
||||
|
||||
public DelimitedEdgeLineProcessor(String delimiter, boolean directed, String... skipLinesStartingWith) {
|
||||
this.delimiter = delimiter;
|
||||
this.skipLinesStartingWith = skipLinesStartingWith;
|
||||
this.directed = directed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Edge<String> processLine(String line) {
|
||||
if (skipLinesStartingWith != null) {
|
||||
for (String s : skipLinesStartingWith) {
|
||||
if (line.startsWith(s))
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String[] split = line.split(delimiter);
|
||||
if (split.length != 2)
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid line: expected format \"" + 0 + delimiter + 1 + "\"; received \"" + line + "\"");
|
||||
|
||||
int from = Integer.parseInt(split[0]);
|
||||
int to = Integer.parseInt(split[1]);
|
||||
String edgeName = from + (directed ? "->" : "--") + to;
|
||||
return new Edge<>(from, to, edgeName, directed);
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.data.impl;
|
||||
|
||||
import org.deeplearning4j.graph.api.Vertex;
|
||||
import org.deeplearning4j.graph.data.VertexLoader;
|
||||
import org.deeplearning4j.graph.exception.ParseException;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**Load vertex information, one per line of form "0<delim>Some text attribute/label"
|
||||
*/
|
||||
public class DelimitedVertexLoader implements VertexLoader<String> {
|
||||
|
||||
private final String delimiter;
|
||||
private final String[] ignoreLinesPrefix;
|
||||
|
||||
public DelimitedVertexLoader(String delimiter) {
|
||||
this(delimiter, null);
|
||||
}
|
||||
|
||||
public DelimitedVertexLoader(String delimiter, String... ignoreLinesPrefix) {
|
||||
this.delimiter = delimiter;
|
||||
this.ignoreLinesPrefix = ignoreLinesPrefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Vertex<String>> loadVertices(String path) throws IOException {
|
||||
List<Vertex<String>> vertices = new ArrayList<>();
|
||||
|
||||
int lineCount = 0;
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(new File(path)))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
lineCount++;
|
||||
if (ignoreLinesPrefix != null) {
|
||||
boolean skipLine = false;
|
||||
for (String s : ignoreLinesPrefix) {
|
||||
if (line.startsWith(s)) {
|
||||
skipLine = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skipLine)
|
||||
continue;
|
||||
}
|
||||
|
||||
int idx = line.indexOf(delimiter);
|
||||
if (idx == -1)
|
||||
throw new ParseException("Error parsing line (could not find delimiter): " + line);
|
||||
|
||||
String first = line.substring(0, idx);
|
||||
String second = line.substring(idx + 1);
|
||||
|
||||
vertices.add(new Vertex<>(Integer.parseInt(first), second));
|
||||
}
|
||||
}
|
||||
|
||||
return vertices;
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.data.impl;
|
||||
|
||||
import org.deeplearning4j.graph.api.Edge;
|
||||
import org.deeplearning4j.graph.data.EdgeLineProcessor;
|
||||
|
||||
public class WeightedEdgeLineProcessor implements EdgeLineProcessor<Double> {
|
||||
private final String delimiter;
|
||||
private final String[] skipLinesStartingWith;
|
||||
private final boolean directed;
|
||||
|
||||
public WeightedEdgeLineProcessor(String delimiter, boolean directed) {
|
||||
this(delimiter, directed, null);
|
||||
}
|
||||
|
||||
public WeightedEdgeLineProcessor(String delimiter, boolean directed, String... skipLinesStartingWith) {
|
||||
this.delimiter = delimiter;
|
||||
this.skipLinesStartingWith = skipLinesStartingWith;
|
||||
this.directed = directed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Edge<Double> processLine(String line) {
|
||||
if (skipLinesStartingWith != null) {
|
||||
for (String s : skipLinesStartingWith) {
|
||||
if (line.startsWith(s))
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String[] split = line.split(delimiter);
|
||||
if (split.length != 3)
|
||||
throw new IllegalArgumentException("Invalid line: expected format \"" + 0 + delimiter + 1 + delimiter
|
||||
+ "weight\"; received \"" + line + "\"");
|
||||
|
||||
int from = Integer.parseInt(split[0]);
|
||||
int to = Integer.parseInt(split[1]);
|
||||
double weight = Double.parseDouble(split[2]);
|
||||
return new Edge<>(from, to, weight, directed);
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.exception;
|
||||
|
||||
public class NoEdgesException extends RuntimeException {
|
||||
|
||||
public NoEdgesException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public NoEdgesException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public NoEdgesException(String s, Exception e) {
|
||||
super(s, e);
|
||||
}
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.exception;
|
||||
|
||||
public class ParseException extends RuntimeException {
|
||||
public ParseException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ParseException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public ParseException(String s, Exception e) {
|
||||
super(s, e);
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.iterator;
|
||||
|
||||
import org.deeplearning4j.graph.api.IVertexSequence;
|
||||
|
||||
public interface GraphWalkIterator<T> {
|
||||
|
||||
/** Length of the walks returned by next()
|
||||
* Note that a walk of length {@code i} contains {@code i+1} vertices
|
||||
*/
|
||||
int walkLength();
|
||||
|
||||
/**Get the next vertex sequence.
|
||||
*/
|
||||
IVertexSequence<T> next();
|
||||
|
||||
/** Whether the iterator has any more vertex sequences. */
|
||||
boolean hasNext();
|
||||
|
||||
/** Reset the graph walk iterator. */
|
||||
void reset();
|
||||
}
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.iterator;
|
||||
|
||||
import org.deeplearning4j.graph.api.IGraph;
|
||||
import org.deeplearning4j.graph.api.IVertexSequence;
|
||||
import org.deeplearning4j.graph.api.NoEdgeHandling;
|
||||
import org.deeplearning4j.graph.api.Vertex;
|
||||
import org.deeplearning4j.graph.exception.NoEdgesException;
|
||||
import org.deeplearning4j.graph.VertexSequence;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Random;
|
||||
|
||||
public class RandomWalkIterator<V> implements GraphWalkIterator<V> {
|
||||
|
||||
private final IGraph<V, ?> graph;
|
||||
private final int walkLength;
|
||||
private final NoEdgeHandling mode;
|
||||
private final int firstVertex;
|
||||
private final int lastVertex;
|
||||
|
||||
|
||||
private int position;
|
||||
private Random rng;
|
||||
private int[] order;
|
||||
|
||||
public RandomWalkIterator(IGraph<V, ?> graph, int walkLength) {
|
||||
this(graph, walkLength, System.currentTimeMillis(), NoEdgeHandling.EXCEPTION_ON_DISCONNECTED);
|
||||
}
|
||||
|
||||
/**Construct a RandomWalkIterator for a given graph, with a specified walk length and random number generator seed.<br>
|
||||
* Uses {@code NoEdgeHandling.EXCEPTION_ON_DISCONNECTED} - hence exception will be thrown when generating random
|
||||
* walks on graphs with vertices containing having no edges, or no outgoing edges (for directed graphs)
|
||||
* @see #RandomWalkIterator(IGraph, int, long, NoEdgeHandling)
|
||||
*/
|
||||
public RandomWalkIterator(IGraph<V, ?> graph, int walkLength, long rngSeed) {
|
||||
this(graph, walkLength, rngSeed, NoEdgeHandling.EXCEPTION_ON_DISCONNECTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param graph IGraph to conduct walks on
|
||||
* @param walkLength length of each walk. Walk of length 0 includes 1 vertex, walk of 1 includes 2 vertices etc
|
||||
* @param rngSeed seed for randomization
|
||||
* @param mode mode for handling random walks from vertices with either no edges, or no outgoing edges (for directed graphs)
|
||||
*/
|
||||
public RandomWalkIterator(IGraph<V, ?> graph, int walkLength, long rngSeed, NoEdgeHandling mode) {
|
||||
this(graph, walkLength, rngSeed, mode, 0, graph.numVertices());
|
||||
}
|
||||
|
||||
/**Constructor used to generate random walks starting at a subset of the vertices in the graph. Order of starting
|
||||
* vertices is randomized within this subset
|
||||
* @param graph IGraph to conduct walks on
|
||||
* @param walkLength length of each walk. Walk of length 0 includes 1 vertex, walk of 1 includes 2 vertices etc
|
||||
* @param rngSeed seed for randomization
|
||||
* @param mode mode for handling random walks from vertices with either no edges, or no outgoing edges (for directed graphs)
|
||||
* @param firstVertex first vertex index (inclusive) to start random walks from
|
||||
* @param lastVertex last vertex index (exclusive) to start random walks from
|
||||
*/
|
||||
public RandomWalkIterator(IGraph<V, ?> graph, int walkLength, long rngSeed, NoEdgeHandling mode, int firstVertex,
|
||||
int lastVertex) {
|
||||
this.graph = graph;
|
||||
this.walkLength = walkLength;
|
||||
this.rng = new Random(rngSeed);
|
||||
this.mode = mode;
|
||||
this.firstVertex = firstVertex;
|
||||
this.lastVertex = lastVertex;
|
||||
|
||||
order = new int[lastVertex - firstVertex];
|
||||
for (int i = 0; i < order.length; i++)
|
||||
order[i] = firstVertex + i;
|
||||
reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IVertexSequence<V> next() {
|
||||
if (!hasNext())
|
||||
throw new NoSuchElementException();
|
||||
//Generate a random walk starting at vertex order[current]
|
||||
int currVertexIdx = order[position++];
|
||||
int[] indices = new int[walkLength + 1];
|
||||
indices[0] = currVertexIdx;
|
||||
if (walkLength == 0)
|
||||
return new VertexSequence<>(graph, indices);
|
||||
|
||||
Vertex<V> next;
|
||||
try {
|
||||
next = graph.getRandomConnectedVertex(currVertexIdx, rng);
|
||||
} catch (NoEdgesException e) {
|
||||
switch (mode) {
|
||||
case SELF_LOOP_ON_DISCONNECTED:
|
||||
for (int i = 1; i < walkLength; i++)
|
||||
indices[i] = currVertexIdx;
|
||||
return new VertexSequence<>(graph, indices);
|
||||
case EXCEPTION_ON_DISCONNECTED:
|
||||
throw e;
|
||||
default:
|
||||
throw new RuntimeException("Unknown/not implemented NoEdgeHandling mode: " + mode);
|
||||
}
|
||||
}
|
||||
indices[1] = next.vertexID();
|
||||
currVertexIdx = indices[1];
|
||||
|
||||
for (int i = 2; i <= walkLength; i++) { //<= walk length: i.e., if walk length = 2, it contains 3 vertices etc
|
||||
next = graph.getRandomConnectedVertex(currVertexIdx, rng);
|
||||
currVertexIdx = next.vertexID();
|
||||
indices[i] = currVertexIdx;
|
||||
}
|
||||
return new VertexSequence<>(graph, indices);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return position < order.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
position = 0;
|
||||
//https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
|
||||
for (int i = order.length - 1; i > 0; i--) {
|
||||
int j = rng.nextInt(i + 1);
|
||||
int temp = order[j];
|
||||
order[j] = order[i];
|
||||
order[i] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int walkLength() {
|
||||
return walkLength;
|
||||
}
|
||||
}
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.iterator;
|
||||
|
||||
import org.deeplearning4j.graph.api.Edge;
|
||||
import org.deeplearning4j.graph.api.IGraph;
|
||||
import org.deeplearning4j.graph.api.IVertexSequence;
|
||||
import org.deeplearning4j.graph.api.NoEdgeHandling;
|
||||
import org.deeplearning4j.graph.exception.NoEdgesException;
|
||||
import org.deeplearning4j.graph.VertexSequence;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Random;
|
||||
|
||||
public class WeightedRandomWalkIterator<V> implements GraphWalkIterator<V> {
|
||||
|
||||
private final IGraph<V, ? extends Number> graph;
|
||||
private final int walkLength;
|
||||
private final NoEdgeHandling mode;
|
||||
private final int firstVertex;
|
||||
private final int lastVertex;
|
||||
|
||||
|
||||
private int position;
|
||||
private Random rng;
|
||||
private int[] order;
|
||||
|
||||
public WeightedRandomWalkIterator(IGraph<V, ? extends Number> graph, int walkLength) {
|
||||
this(graph, walkLength, System.currentTimeMillis(), NoEdgeHandling.EXCEPTION_ON_DISCONNECTED);
|
||||
}
|
||||
|
||||
/**Construct a RandomWalkIterator for a given graph, with a specified walk length and random number generator seed.<br>
|
||||
* Uses {@code NoEdgeHandling.EXCEPTION_ON_DISCONNECTED} - hence exception will be thrown when generating random
|
||||
* walks on graphs with vertices containing having no edges, or no outgoing edges (for directed graphs)
|
||||
* @see #WeightedRandomWalkIterator(IGraph, int, long, NoEdgeHandling)
|
||||
*/
|
||||
public WeightedRandomWalkIterator(IGraph<V, ? extends Number> graph, int walkLength, long rngSeed) {
|
||||
this(graph, walkLength, rngSeed, NoEdgeHandling.EXCEPTION_ON_DISCONNECTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param graph IGraph to conduct walks on
|
||||
* @param walkLength length of each walk. Walk of length 0 includes 1 vertex, walk of 1 includes 2 vertices etc
|
||||
* @param rngSeed seed for randomization
|
||||
* @param mode mode for handling random walks from vertices with either no edges, or no outgoing edges (for directed graphs)
|
||||
*/
|
||||
public WeightedRandomWalkIterator(IGraph<V, ? extends Number> graph, int walkLength, long rngSeed,
|
||||
NoEdgeHandling mode) {
|
||||
this(graph, walkLength, rngSeed, mode, 0, graph.numVertices());
|
||||
}
|
||||
|
||||
/**Constructor used to generate random walks starting at a subset of the vertices in the graph. Order of starting
|
||||
* vertices is randomized within this subset
|
||||
* @param graph IGraph to conduct walks on
|
||||
* @param walkLength length of each walk. Walk of length 0 includes 1 vertex, walk of 1 includes 2 vertices etc
|
||||
* @param rngSeed seed for randomization
|
||||
* @param mode mode for handling random walks from vertices with either no edges, or no outgoing edges (for directed graphs)
|
||||
* @param firstVertex first vertex index (inclusive) to start random walks from
|
||||
* @param lastVertex last vertex index (exclusive) to start random walks from
|
||||
*/
|
||||
public WeightedRandomWalkIterator(IGraph<V, ? extends Number> graph, int walkLength, long rngSeed,
|
||||
NoEdgeHandling mode, int firstVertex, int lastVertex) {
|
||||
this.graph = graph;
|
||||
this.walkLength = walkLength;
|
||||
this.rng = new Random(rngSeed);
|
||||
this.mode = mode;
|
||||
this.firstVertex = firstVertex;
|
||||
this.lastVertex = lastVertex;
|
||||
|
||||
order = new int[lastVertex - firstVertex];
|
||||
for (int i = 0; i < order.length; i++)
|
||||
order[i] = firstVertex + i;
|
||||
reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IVertexSequence<V> next() {
|
||||
if (!hasNext())
|
||||
throw new NoSuchElementException();
|
||||
//Generate a weighted random walk starting at vertex order[current]
|
||||
int currVertexIdx = order[position++];
|
||||
int[] indices = new int[walkLength + 1];
|
||||
indices[0] = currVertexIdx;
|
||||
if (walkLength == 0)
|
||||
return new VertexSequence<>(graph, indices);
|
||||
|
||||
for (int i = 1; i <= walkLength; i++) {
|
||||
List<? extends Edge<? extends Number>> edgeList = graph.getEdgesOut(currVertexIdx);
|
||||
|
||||
//First: check if there are any outgoing edges from this vertex. If not: handle the situation
|
||||
if (edgeList == null || edgeList.isEmpty()) {
|
||||
switch (mode) {
|
||||
case SELF_LOOP_ON_DISCONNECTED:
|
||||
for (int j = i; j < walkLength; j++)
|
||||
indices[j] = currVertexIdx;
|
||||
return new VertexSequence<>(graph, indices);
|
||||
case EXCEPTION_ON_DISCONNECTED:
|
||||
throw new NoEdgesException("Cannot conduct random walk: vertex " + currVertexIdx
|
||||
+ " has no outgoing edges. "
|
||||
+ " Set NoEdgeHandling mode to NoEdgeHandlingMode.SELF_LOOP_ON_DISCONNECTED to self loop instead of "
|
||||
+ "throwing an exception in this situation.");
|
||||
default:
|
||||
throw new RuntimeException("Unknown/not implemented NoEdgeHandling mode: " + mode);
|
||||
}
|
||||
}
|
||||
|
||||
//To do a weighted random walk: we need to know total weight of all outgoing edges
|
||||
double totalWeight = 0.0;
|
||||
for (Edge<? extends Number> edge : edgeList) {
|
||||
totalWeight += edge.getValue().doubleValue();
|
||||
}
|
||||
|
||||
double d = rng.nextDouble();
|
||||
double threshold = d * totalWeight;
|
||||
double sumWeight = 0.0;
|
||||
for (Edge<? extends Number> edge : edgeList) {
|
||||
sumWeight += edge.getValue().doubleValue();
|
||||
if (sumWeight >= threshold) {
|
||||
if (edge.isDirected()) {
|
||||
currVertexIdx = edge.getTo();
|
||||
} else {
|
||||
if (edge.getFrom() == currVertexIdx) {
|
||||
currVertexIdx = edge.getTo();
|
||||
} else {
|
||||
currVertexIdx = edge.getFrom(); //Undirected edge: might be next--currVertexIdx instead of currVertexIdx--next
|
||||
}
|
||||
}
|
||||
indices[i] = currVertexIdx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new VertexSequence<>(graph, indices);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return position < order.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
position = 0;
|
||||
//https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
|
||||
for (int i = order.length - 1; i > 0; i--) {
|
||||
int j = rng.nextInt(i + 1);
|
||||
int temp = order[j];
|
||||
order[j] = order[i];
|
||||
order[i] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int walkLength() {
|
||||
return walkLength;
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.iterator.parallel;
|
||||
|
||||
import org.deeplearning4j.graph.iterator.GraphWalkIterator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface GraphWalkIteratorProvider<V> {
|
||||
|
||||
/**Get a list of GraphWalkIterators. In general: may return less than the specified number of iterators,
|
||||
* (for example, for small networks) but never more than it
|
||||
* @param numIterators Number of iterators to return
|
||||
*/
|
||||
List<GraphWalkIterator<V>> getGraphWalkIterators(int numIterators);
|
||||
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.iterator.parallel;
|
||||
|
||||
import org.deeplearning4j.graph.api.IGraph;
|
||||
import org.deeplearning4j.graph.api.NoEdgeHandling;
|
||||
import org.deeplearning4j.graph.iterator.GraphWalkIterator;
|
||||
import org.deeplearning4j.graph.iterator.RandomWalkIterator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class RandomWalkGraphIteratorProvider<V> implements GraphWalkIteratorProvider<V> {
|
||||
|
||||
private IGraph<V, ?> graph;
|
||||
private int walkLength;
|
||||
private Random rng;
|
||||
private NoEdgeHandling mode;
|
||||
|
||||
public RandomWalkGraphIteratorProvider(IGraph<V, ?> graph, int walkLength) {
|
||||
this(graph, walkLength, System.currentTimeMillis(), NoEdgeHandling.EXCEPTION_ON_DISCONNECTED);
|
||||
}
|
||||
|
||||
public RandomWalkGraphIteratorProvider(IGraph<V, ?> graph, int walkLength, long seed, NoEdgeHandling mode) {
|
||||
this.graph = graph;
|
||||
this.walkLength = walkLength;
|
||||
this.rng = new Random(seed);
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<GraphWalkIterator<V>> getGraphWalkIterators(int numIterators) {
|
||||
int nVertices = graph.numVertices();
|
||||
if (numIterators > nVertices)
|
||||
numIterators = nVertices;
|
||||
|
||||
int verticesPerIter = nVertices / numIterators;
|
||||
|
||||
List<GraphWalkIterator<V>> list = new ArrayList<>(numIterators);
|
||||
int last = 0;
|
||||
for (int i = 0; i < numIterators; i++) {
|
||||
int from = last;
|
||||
int to = Math.min(nVertices, from + verticesPerIter);
|
||||
if (i == numIterators - 1)
|
||||
to = nVertices;
|
||||
|
||||
GraphWalkIterator<V> iter = new RandomWalkIterator<>(graph, walkLength, rng.nextLong(), mode, from, to);
|
||||
list.add(iter);
|
||||
last = to;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.iterator.parallel;
|
||||
|
||||
import org.deeplearning4j.graph.api.IGraph;
|
||||
import org.deeplearning4j.graph.api.NoEdgeHandling;
|
||||
import org.deeplearning4j.graph.iterator.GraphWalkIterator;
|
||||
import org.deeplearning4j.graph.iterator.WeightedRandomWalkIterator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class WeightedRandomWalkGraphIteratorProvider<V> implements GraphWalkIteratorProvider<V> {
|
||||
|
||||
private IGraph<V, ? extends Number> graph;
|
||||
private int walkLength;
|
||||
private Random rng;
|
||||
private NoEdgeHandling mode;
|
||||
|
||||
public WeightedRandomWalkGraphIteratorProvider(IGraph<V, ? extends Number> graph, int walkLength) {
|
||||
this(graph, walkLength, System.currentTimeMillis(), NoEdgeHandling.EXCEPTION_ON_DISCONNECTED);
|
||||
}
|
||||
|
||||
public WeightedRandomWalkGraphIteratorProvider(IGraph<V, ? extends Number> graph, int walkLength, long seed,
|
||||
NoEdgeHandling mode) {
|
||||
this.graph = graph;
|
||||
this.walkLength = walkLength;
|
||||
this.rng = new Random(seed);
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<GraphWalkIterator<V>> getGraphWalkIterators(int numIterators) {
|
||||
int nVertices = graph.numVertices();
|
||||
if (numIterators > nVertices)
|
||||
numIterators = nVertices;
|
||||
|
||||
int verticesPerIter = nVertices / numIterators;
|
||||
|
||||
List<GraphWalkIterator<V>> list = new ArrayList<>(numIterators);
|
||||
int last = 0;
|
||||
for (int i = 0; i < numIterators; i++) {
|
||||
int from = last;
|
||||
int to = Math.min(nVertices, from + verticesPerIter);
|
||||
if (i == numIterators - 1)
|
||||
to = nVertices;
|
||||
|
||||
GraphWalkIterator<V> iter =
|
||||
new WeightedRandomWalkIterator<>(graph, walkLength, rng.nextLong(), mode, from, to);
|
||||
list.add(iter);
|
||||
last = to;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.models;
|
||||
|
||||
public interface BinaryTree {
|
||||
|
||||
long getCode(int element);
|
||||
|
||||
int getCodeLength(int element);
|
||||
|
||||
String getCodeString(int element);
|
||||
|
||||
int[] getPathInnerNodes(int element);
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.models;
|
||||
|
||||
import org.deeplearning4j.graph.api.IGraph;
|
||||
import org.deeplearning4j.graph.api.Vertex;
|
||||
import org.nd4j.linalg.api.ndarray.INDArray;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public interface GraphVectors<V, E> extends Serializable {
|
||||
|
||||
public IGraph<V, E> getGraph();
|
||||
|
||||
public int numVertices();
|
||||
|
||||
public int getVectorSize();
|
||||
|
||||
public INDArray getVertexVector(Vertex<V> vertex);
|
||||
|
||||
public INDArray getVertexVector(int vertexIdx);
|
||||
|
||||
public int[] verticesNearest(int vertexIdx, int top);
|
||||
|
||||
double similarity(Vertex<V> vertex1, Vertex<V> vertex2);
|
||||
|
||||
double similarity(int vertexIdx1, int vertexIdx2);
|
||||
|
||||
}
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.models.deepwalk;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.deeplearning4j.graph.api.IGraph;
|
||||
import org.deeplearning4j.graph.api.IVertexSequence;
|
||||
import org.deeplearning4j.graph.api.NoEdgeHandling;
|
||||
import org.deeplearning4j.graph.iterator.GraphWalkIterator;
|
||||
import org.deeplearning4j.graph.iterator.parallel.GraphWalkIteratorProvider;
|
||||
import org.deeplearning4j.graph.iterator.parallel.RandomWalkGraphIteratorProvider;
|
||||
import org.deeplearning4j.graph.models.embeddings.GraphVectorLookupTable;
|
||||
import org.deeplearning4j.graph.models.embeddings.GraphVectorsImpl;
|
||||
import org.deeplearning4j.graph.models.embeddings.InMemoryGraphLookupTable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.threadly.concurrent.PriorityScheduler;
|
||||
import org.threadly.concurrent.future.FutureUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
public class DeepWalk<V, E> extends GraphVectorsImpl<V, E> {
|
||||
public static final int STATUS_UPDATE_FREQUENCY = 1000;
|
||||
private Logger log = LoggerFactory.getLogger(DeepWalk.class);
|
||||
|
||||
private int vectorSize;
|
||||
private int windowSize;
|
||||
private double learningRate;
|
||||
private boolean initCalled = false;
|
||||
private long seed;
|
||||
private int nThreads = Runtime.getRuntime().availableProcessors();
|
||||
private transient AtomicLong walkCounter = new AtomicLong(0);
|
||||
|
||||
public DeepWalk() {
|
||||
|
||||
}
|
||||
|
||||
public int getVectorSize() {
|
||||
return vectorSize;
|
||||
}
|
||||
|
||||
public int getWindowSize() {
|
||||
return windowSize;
|
||||
}
|
||||
|
||||
public double getLearningRate() {
|
||||
return learningRate;
|
||||
}
|
||||
|
||||
public void setLearningRate(double learningRate) {
|
||||
this.learningRate = learningRate;
|
||||
if (lookupTable != null)
|
||||
lookupTable.setLearningRate(learningRate);
|
||||
}
|
||||
|
||||
/** Initialize the DeepWalk model with a given graph. */
|
||||
public void initialize(IGraph<V, E> graph) {
|
||||
int nVertices = graph.numVertices();
|
||||
int[] degrees = new int[nVertices];
|
||||
for (int i = 0; i < nVertices; i++)
|
||||
degrees[i] = graph.getVertexDegree(i);
|
||||
initialize(degrees);
|
||||
}
|
||||
|
||||
/** Initialize the DeepWalk model with a list of vertex degrees for a graph.<br>
|
||||
* Specifically, graphVertexDegrees[i] represents the vertex degree of the ith vertex<br>
|
||||
* vertex degrees are used to construct a binary (Huffman) tree, which is in turn used in
|
||||
* the hierarchical softmax implementation
|
||||
* @param graphVertexDegrees degrees of each vertex
|
||||
*/
|
||||
public void initialize(int[] graphVertexDegrees) {
|
||||
log.info("Initializing: Creating Huffman tree and lookup table...");
|
||||
GraphHuffman gh = new GraphHuffman(graphVertexDegrees.length);
|
||||
gh.buildTree(graphVertexDegrees);
|
||||
lookupTable = new InMemoryGraphLookupTable(graphVertexDegrees.length, vectorSize, gh, learningRate);
|
||||
initCalled = true;
|
||||
log.info("Initialization complete");
|
||||
}
|
||||
|
||||
/** Fit the model, in parallel.
|
||||
* This creates a set of GraphWalkIterators, which are then distributed one to each thread
|
||||
* @param graph Graph to fit
|
||||
* @param walkLength Length of rangom walks to generate
|
||||
*/
|
||||
public void fit(IGraph<V, E> graph, int walkLength) {
|
||||
if (!initCalled)
|
||||
initialize(graph);
|
||||
//First: create iterators, one for each thread
|
||||
|
||||
GraphWalkIteratorProvider<V> iteratorProvider = new RandomWalkGraphIteratorProvider<>(graph, walkLength, seed,
|
||||
NoEdgeHandling.SELF_LOOP_ON_DISCONNECTED);
|
||||
|
||||
fit(iteratorProvider);
|
||||
}
|
||||
|
||||
/** Fit the model, in parallel, using a given GraphWalkIteratorProvider.<br>
|
||||
* This object is used to generate multiple GraphWalkIterators, which can then be distributed to each thread
|
||||
* to do in parallel<br>
|
||||
* Note that {@link #fit(IGraph, int)} will be more convenient in many cases<br>
|
||||
* Note that {@link #initialize(IGraph)} or {@link #initialize(int[])} <em>must</em> be called first.
|
||||
* @param iteratorProvider GraphWalkIteratorProvider
|
||||
* @see #fit(IGraph, int)
|
||||
*/
|
||||
public void fit(GraphWalkIteratorProvider<V> iteratorProvider) {
|
||||
if (!initCalled)
|
||||
throw new UnsupportedOperationException("DeepWalk not initialized (call initialize before fit)");
|
||||
List<GraphWalkIterator<V>> iteratorList = iteratorProvider.getGraphWalkIterators(nThreads);
|
||||
|
||||
PriorityScheduler scheduler = new PriorityScheduler(nThreads);
|
||||
|
||||
List<Future<Void>> list = new ArrayList<>(iteratorList.size());
|
||||
//log.info("Fitting Graph with {} threads", Math.max(nThreads,iteratorList.size()));
|
||||
for (GraphWalkIterator<V> iter : iteratorList) {
|
||||
LearningCallable c = new LearningCallable(iter);
|
||||
list.add(scheduler.submit(c));
|
||||
}
|
||||
|
||||
scheduler.shutdown(); // wont shutdown till complete
|
||||
|
||||
try {
|
||||
FutureUtils.blockTillAllCompleteOrFirstError(list);
|
||||
} catch (InterruptedException e) {
|
||||
// should not be possible with blocking till scheduler terminates
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException(e);
|
||||
} catch (ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**Fit the DeepWalk model <b>using a single thread</b> using a given GraphWalkIterator. If parallel fitting is required,
|
||||
* {@link #fit(IGraph, int)} or {@link #fit(GraphWalkIteratorProvider)} should be used.<br>
|
||||
* Note that {@link #initialize(IGraph)} or {@link #initialize(int[])} <em>must</em> be called first.
|
||||
*
|
||||
* @param iterator iterator for graph walks
|
||||
*/
|
||||
public void fit(GraphWalkIterator<V> iterator) {
|
||||
if (!initCalled)
|
||||
throw new UnsupportedOperationException("DeepWalk not initialized (call initialize before fit)");
|
||||
int walkLength = iterator.walkLength();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
IVertexSequence<V> sequence = iterator.next();
|
||||
|
||||
//Skipgram model:
|
||||
int[] walk = new int[walkLength + 1];
|
||||
int i = 0;
|
||||
while (sequence.hasNext())
|
||||
walk[i++] = sequence.next().vertexID();
|
||||
|
||||
skipGram(walk);
|
||||
|
||||
long iter = walkCounter.incrementAndGet();
|
||||
if (iter % STATUS_UPDATE_FREQUENCY == 0) {
|
||||
log.info("Processed {} random walks on graph", iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void skipGram(int[] walk) {
|
||||
for (int mid = windowSize; mid < walk.length - windowSize; mid++) {
|
||||
for (int pos = mid - windowSize; pos <= mid + windowSize; pos++) {
|
||||
if (pos == mid)
|
||||
continue;
|
||||
|
||||
//pair of vertices: walk[mid] -> walk[pos]
|
||||
lookupTable.iterate(walk[mid], walk[pos]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GraphVectorLookupTable lookupTable() {
|
||||
return lookupTable;
|
||||
}
|
||||
|
||||
|
||||
public static class Builder<V, E> {
|
||||
private int vectorSize = 100;
|
||||
private long seed = System.currentTimeMillis();
|
||||
private double learningRate = 0.01;
|
||||
private int windowSize = 2;
|
||||
|
||||
/** Sets the size of the vectors to be learned for each vertex in the graph */
|
||||
public Builder<V, E> vectorSize(int vectorSize) {
|
||||
this.vectorSize = vectorSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Set the learning rate */
|
||||
public Builder<V, E> learningRate(double learningRate) {
|
||||
this.learningRate = learningRate;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the window size used in skipgram model */
|
||||
public Builder<V, E> windowSize(int windowSize) {
|
||||
this.windowSize = windowSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Seed for random number generation (used for repeatability).
|
||||
* Note however that parallel/async gradient descent might result in behaviour that
|
||||
* is not repeatable, in spite of setting seed
|
||||
*/
|
||||
public Builder<V, E> seed(long seed) {
|
||||
this.seed = seed;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DeepWalk<V, E> build() {
|
||||
DeepWalk<V, E> dw = new DeepWalk<>();
|
||||
dw.vectorSize = vectorSize;
|
||||
dw.windowSize = windowSize;
|
||||
dw.learningRate = learningRate;
|
||||
dw.seed = seed;
|
||||
|
||||
return dw;
|
||||
}
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
private class LearningCallable implements Callable<Void> {
|
||||
|
||||
private final GraphWalkIterator<V> iterator;
|
||||
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
fit(iterator);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.models.deepwalk;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.deeplearning4j.graph.models.BinaryTree;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
public class GraphHuffman implements BinaryTree {
|
||||
private final int MAX_CODE_LENGTH;
|
||||
private final long[] codes;
|
||||
private final byte[] codeLength;
|
||||
private final int[][] innerNodePathToLeaf;
|
||||
|
||||
/**
|
||||
* @param nVertices number of vertices in the graph that this Huffman tree is being built for
|
||||
*/
|
||||
public GraphHuffman(int nVertices) {
|
||||
this(nVertices, 64);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nVertices nVertices number of vertices in the graph that this Huffman tree is being built for
|
||||
* @param maxCodeLength MAX_CODE_LENGTH for Huffman tree
|
||||
*/
|
||||
public GraphHuffman(int nVertices, int maxCodeLength) {
|
||||
this.codes = new long[nVertices];
|
||||
this.codeLength = new byte[nVertices];
|
||||
this.innerNodePathToLeaf = new int[nVertices][0];
|
||||
this.MAX_CODE_LENGTH = maxCodeLength;
|
||||
}
|
||||
|
||||
/** Build the Huffman tree given an array of vertex degrees
|
||||
* @param vertexDegree vertexDegree[i] = degree of ith vertex
|
||||
*/
|
||||
public void buildTree(int[] vertexDegree) {
|
||||
PriorityQueue<Node> pq = new PriorityQueue<>();
|
||||
for (int i = 0; i < vertexDegree.length; i++)
|
||||
pq.add(new Node(i, vertexDegree[i], null, null));
|
||||
|
||||
while (pq.size() > 1) {
|
||||
Node left = pq.remove();
|
||||
Node right = pq.remove();
|
||||
Node newNode = new Node(-1, left.count + right.count, left, right);
|
||||
pq.add(newNode);
|
||||
}
|
||||
|
||||
//Eventually: only one node left -> full tree
|
||||
Node tree = pq.remove();
|
||||
|
||||
//Now: convert tree into binary codes. Traverse tree (preorder traversal) -> record path (left/right) -> code
|
||||
int[] innerNodePath = new int[MAX_CODE_LENGTH];
|
||||
traverse(tree, 0L, (byte) 0, -1, innerNodePath, 0);
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
private static class Node implements Comparable<Node> {
|
||||
private final int vertexIdx;
|
||||
private final long count;
|
||||
private Node left;
|
||||
private Node right;
|
||||
|
||||
@Override
|
||||
public int compareTo(Node o) {
|
||||
return Long.compare(count, o.count);
|
||||
}
|
||||
}
|
||||
|
||||
private int traverse(Node node, long codeSoFar, byte codeLengthSoFar, int innerNodeCount, int[] innerNodePath,
|
||||
int currDepth) {
|
||||
if (codeLengthSoFar >= MAX_CODE_LENGTH)
|
||||
throw new RuntimeException("Cannot generate code: code length exceeds " + MAX_CODE_LENGTH + " bits");
|
||||
if (node.left == null && node.right == null) {
|
||||
//Leaf node
|
||||
codes[node.vertexIdx] = codeSoFar;
|
||||
codeLength[node.vertexIdx] = codeLengthSoFar;
|
||||
innerNodePathToLeaf[node.vertexIdx] = Arrays.copyOf(innerNodePath, currDepth);
|
||||
return innerNodeCount;
|
||||
}
|
||||
|
||||
//This is an inner node. It's index is 'innerNodeCount'
|
||||
innerNodeCount++;
|
||||
innerNodePath[currDepth] = innerNodeCount;
|
||||
|
||||
long codeLeft = setBit(codeSoFar, codeLengthSoFar, false);
|
||||
innerNodeCount = traverse(node.left, codeLeft, (byte) (codeLengthSoFar + 1), innerNodeCount, innerNodePath,
|
||||
currDepth + 1);
|
||||
|
||||
long codeRight = setBit(codeSoFar, codeLengthSoFar, true);
|
||||
innerNodeCount = traverse(node.right, codeRight, (byte) (codeLengthSoFar + 1), innerNodeCount, innerNodePath,
|
||||
currDepth + 1);
|
||||
return innerNodeCount;
|
||||
}
|
||||
|
||||
private static long setBit(long in, int bitNum, boolean value) {
|
||||
if (value)
|
||||
return (in | 1L << bitNum); //Bit mask |: 00010000
|
||||
else
|
||||
return (in & ~(1 << bitNum)); //Bit mask &: 11101111
|
||||
}
|
||||
|
||||
private static boolean getBit(long in, int bitNum) {
|
||||
long mask = 1L << bitNum;
|
||||
return (in & mask) != 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCode(int vertexNum) {
|
||||
return codes[vertexNum];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCodeLength(int vertexNum) {
|
||||
return codeLength[vertexNum];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCodeString(int vertexNum) {
|
||||
long code = codes[vertexNum];
|
||||
int len = codeLength[vertexNum];
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < len; i++)
|
||||
sb.append(getBit(code, i) ? "1" : "0");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getPathInnerNodes(int vertexNum) {
|
||||
return innerNodePathToLeaf[vertexNum];
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.models.embeddings;
|
||||
|
||||
import org.nd4j.linalg.api.ndarray.INDArray;
|
||||
|
||||
public interface GraphVectorLookupTable {
|
||||
|
||||
/**The size of the vector representations
|
||||
*/
|
||||
int vectorSize();
|
||||
|
||||
/** Reset (randomize) the weights. */
|
||||
void resetWeights();
|
||||
|
||||
/** Conduct learning given a pair of vertices (in and out) */
|
||||
void iterate(int first, int second);
|
||||
|
||||
/** Get the vector for the vertex with index idx */
|
||||
public INDArray getVector(int idx);
|
||||
|
||||
/** Set the learning rate */
|
||||
void setLearningRate(double learningRate);
|
||||
|
||||
/** Returns the number of vertices in the graph */
|
||||
int getNumVertices();
|
||||
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.models.embeddings;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.deeplearning4j.graph.api.IGraph;
|
||||
import org.deeplearning4j.graph.api.Vertex;
|
||||
import org.deeplearning4j.graph.models.GraphVectors;
|
||||
import org.nd4j.linalg.api.blas.Level1;
|
||||
import org.nd4j.linalg.api.ndarray.INDArray;
|
||||
import org.nd4j.linalg.factory.Nd4j;
|
||||
import org.nd4j.linalg.ops.transforms.Transforms;
|
||||
import org.nd4j.common.primitives.Pair;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class GraphVectorsImpl<V, E> implements GraphVectors<V, E> {
|
||||
|
||||
protected IGraph<V, E> graph;
|
||||
protected GraphVectorLookupTable lookupTable;
|
||||
|
||||
|
||||
@Override
|
||||
public IGraph<V, E> getGraph() {
|
||||
return graph;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int numVertices() {
|
||||
return lookupTable.getNumVertices();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVectorSize() {
|
||||
return lookupTable.vectorSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public INDArray getVertexVector(Vertex<V> vertex) {
|
||||
return lookupTable.getVector(vertex.vertexID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public INDArray getVertexVector(int vertexIdx) {
|
||||
return lookupTable.getVector(vertexIdx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] verticesNearest(int vertexIdx, int top) {
|
||||
|
||||
INDArray vec = lookupTable.getVector(vertexIdx).dup();
|
||||
double norm2 = vec.norm2Number().doubleValue();
|
||||
|
||||
|
||||
PriorityQueue<Pair<Double, Integer>> pq =
|
||||
new PriorityQueue<>(lookupTable.getNumVertices(), new PairComparator());
|
||||
|
||||
Level1 l1 = Nd4j.getBlasWrapper().level1();
|
||||
for (int i = 0; i < numVertices(); i++) {
|
||||
if (i == vertexIdx)
|
||||
continue;
|
||||
|
||||
INDArray other = lookupTable.getVector(i);
|
||||
double cosineSim = l1.dot(vec.length(), 1.0, vec, other) / (norm2 * other.norm2Number().doubleValue());
|
||||
|
||||
pq.add(new Pair<>(cosineSim, i));
|
||||
}
|
||||
|
||||
int[] out = new int[top];
|
||||
for (int i = 0; i < top; i++) {
|
||||
out[i] = pq.remove().getSecond();
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
private static class PairComparator implements Comparator<Pair<Double, Integer>> {
|
||||
@Override
|
||||
public int compare(Pair<Double, Integer> o1, Pair<Double, Integer> o2) {
|
||||
return -Double.compare(o1.getFirst(), o2.getFirst());
|
||||
}
|
||||
}
|
||||
|
||||
/**Returns the cosine similarity of the vector representations of two vertices in the graph
|
||||
* @return Cosine similarity of two vertices
|
||||
*/
|
||||
@Override
|
||||
public double similarity(Vertex<V> vertex1, Vertex<V> vertex2) {
|
||||
return similarity(vertex1.vertexID(), vertex2.vertexID());
|
||||
}
|
||||
|
||||
/**Returns the cosine similarity of the vector representations of two vertices in the graph,
|
||||
* given the indices of these verticies
|
||||
* @return Cosine similarity of two vertices
|
||||
*/
|
||||
@Override
|
||||
public double similarity(int vertexIdx1, int vertexIdx2) {
|
||||
if (vertexIdx1 == vertexIdx2)
|
||||
return 1.0;
|
||||
|
||||
INDArray vector = Transforms.unitVec(getVertexVector(vertexIdx1));
|
||||
INDArray vector2 = Transforms.unitVec(getVertexVector(vertexIdx2));
|
||||
return Nd4j.getBlasWrapper().dot(vector, vector2);
|
||||
}
|
||||
}
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.models.embeddings;
|
||||
|
||||
import org.apache.commons.math3.util.FastMath;
|
||||
import org.deeplearning4j.graph.models.BinaryTree;
|
||||
import org.nd4j.linalg.api.blas.Level1;
|
||||
import org.nd4j.linalg.api.ndarray.INDArray;
|
||||
import org.nd4j.linalg.factory.Nd4j;
|
||||
|
||||
public class InMemoryGraphLookupTable implements GraphVectorLookupTable {
|
||||
|
||||
protected int nVertices;
|
||||
protected int vectorSize;
|
||||
protected BinaryTree tree;
|
||||
protected INDArray vertexVectors; //'input' vectors
|
||||
protected INDArray outWeights; //'output' vectors. Specifically vectors for inner nodes in binary tree
|
||||
protected double learningRate;
|
||||
|
||||
protected double[] expTable;
|
||||
protected static double MAX_EXP = 6;
|
||||
|
||||
public InMemoryGraphLookupTable(int nVertices, int vectorSize, BinaryTree tree, double learningRate) {
|
||||
this.nVertices = nVertices;
|
||||
this.vectorSize = vectorSize;
|
||||
this.tree = tree;
|
||||
this.learningRate = learningRate;
|
||||
resetWeights();
|
||||
|
||||
expTable = new double[1000];
|
||||
for (int i = 0; i < expTable.length; i++) {
|
||||
double tmp = FastMath.exp((i / (double) expTable.length * 2 - 1) * MAX_EXP);
|
||||
expTable[i] = tmp / (tmp + 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
public INDArray getVertexVectors() {
|
||||
return vertexVectors;
|
||||
}
|
||||
|
||||
public INDArray getOutWeights() {
|
||||
return outWeights;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int vectorSize() {
|
||||
return vectorSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetWeights() {
|
||||
this.vertexVectors = Nd4j.rand(nVertices, vectorSize).subi(0.5).divi(vectorSize);
|
||||
this.outWeights = Nd4j.rand(nVertices - 1, vectorSize).subi(0.5).divi(vectorSize); //Full binary tree with L leaves has L-1 inner nodes
|
||||
}
|
||||
|
||||
@Override
|
||||
public void iterate(int first, int second) {
|
||||
//Get vectors and gradients
|
||||
//vecAndGrads[0][0] is vector of vertex(first); vecAndGrads[1][0] is corresponding gradient
|
||||
INDArray[][] vecAndGrads = vectorsAndGradients(first, second);
|
||||
|
||||
Level1 l1 = Nd4j.getBlasWrapper().level1();
|
||||
for (int i = 0; i < vecAndGrads[0].length; i++) {
|
||||
//Update: v = v - lr * gradient
|
||||
l1.axpy(vecAndGrads[0][i].length(), -learningRate, vecAndGrads[1][i], vecAndGrads[0][i]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns vertex vector and vector gradients, plus inner node vectors and inner node gradients<br>
|
||||
* Specifically, out[0] are vectors, out[1] are gradients for the corresponding vectors<br>
|
||||
* out[0][0] is vector for first vertex; out[0][1] is gradient for this vertex vector<br>
|
||||
* out[0][i] (i>0) is the inner node vector along path to second vertex; out[1][i] is gradient for inner node vertex<br>
|
||||
* This design is used primarily to aid in testing (numerical gradient checks)
|
||||
* @param first first (input) vertex index
|
||||
* @param second second (output) vertex index
|
||||
*/
|
||||
public INDArray[][] vectorsAndGradients(int first, int second) {
|
||||
//Input vertex vector gradients are composed of the inner node gradients
|
||||
//Get vector for first vertex, as well as code for second:
|
||||
INDArray vec = vertexVectors.getRow(first);
|
||||
int codeLength = tree.getCodeLength(second);
|
||||
long code = tree.getCode(second);
|
||||
int[] innerNodesForVertex = tree.getPathInnerNodes(second);
|
||||
|
||||
INDArray[][] out = new INDArray[2][innerNodesForVertex.length + 1];
|
||||
|
||||
Level1 l1 = Nd4j.getBlasWrapper().level1();
|
||||
INDArray accumError = Nd4j.create(vec.shape());
|
||||
for (int i = 0; i < codeLength; i++) {
|
||||
|
||||
//Inner node:
|
||||
int innerNodeIdx = innerNodesForVertex[i];
|
||||
boolean path = getBit(code, i); //left or right?
|
||||
|
||||
INDArray innerNodeVector = outWeights.getRow(innerNodeIdx);
|
||||
double sigmoidDot = sigmoid(Nd4j.getBlasWrapper().dot(innerNodeVector, vec));
|
||||
|
||||
|
||||
|
||||
//Calculate gradient for inner node + accumulate error:
|
||||
INDArray innerNodeGrad;
|
||||
if (path) {
|
||||
innerNodeGrad = vec.mul(sigmoidDot - 1);
|
||||
l1.axpy(vec.length(), sigmoidDot - 1, innerNodeVector, accumError);
|
||||
} else {
|
||||
innerNodeGrad = vec.mul(sigmoidDot);
|
||||
l1.axpy(vec.length(), sigmoidDot, innerNodeVector, accumError);
|
||||
}
|
||||
|
||||
out[0][i + 1] = innerNodeVector;
|
||||
out[1][i + 1] = innerNodeGrad;
|
||||
}
|
||||
|
||||
out[0][0] = vec;
|
||||
out[1][0] = accumError;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Calculate the probability of the second vertex given the first vertex
|
||||
* i.e., P(v_second | v_first)
|
||||
* @param first index of the first vertex
|
||||
* @param second index of the second vertex
|
||||
* @return probability, P(v_second | v_first)
|
||||
*/
|
||||
public double calculateProb(int first, int second) {
|
||||
//Get vector for first vertex, as well as code for second:
|
||||
INDArray vec = vertexVectors.getRow(first);
|
||||
int codeLength = tree.getCodeLength(second);
|
||||
long code = tree.getCode(second);
|
||||
int[] innerNodesForVertex = tree.getPathInnerNodes(second);
|
||||
|
||||
double prob = 1.0;
|
||||
for (int i = 0; i < codeLength; i++) {
|
||||
boolean path = getBit(code, i); //left or right?
|
||||
//Inner node:
|
||||
int innerNodeIdx = innerNodesForVertex[i];
|
||||
INDArray nwi = outWeights.getRow(innerNodeIdx);
|
||||
|
||||
double dot = Nd4j.getBlasWrapper().dot(nwi, vec);
|
||||
|
||||
//double sigmoidDot = sigmoid(dot);
|
||||
double innerProb = (path ? sigmoid(dot) : sigmoid(-dot)); //prob of going left or right at inner node
|
||||
prob *= innerProb;
|
||||
}
|
||||
return prob;
|
||||
}
|
||||
|
||||
/** Calculate score. -log P(v_second | v_first) */
|
||||
public double calculateScore(int first, int second) {
|
||||
//Score is -log P(out|in)
|
||||
double prob = calculateProb(first, second);
|
||||
return -FastMath.log(prob);
|
||||
}
|
||||
|
||||
public BinaryTree getTree() {
|
||||
return tree;
|
||||
}
|
||||
|
||||
public INDArray getInnerNodeVector(int innerNode) {
|
||||
return outWeights.getRow(innerNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public INDArray getVector(int idx) {
|
||||
return vertexVectors.getRow(idx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLearningRate(double learningRate) {
|
||||
this.learningRate = learningRate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumVertices() {
|
||||
return nVertices;
|
||||
}
|
||||
|
||||
private static double sigmoid(double in) {
|
||||
return 1.0 / (1.0 + FastMath.exp(-in));
|
||||
}
|
||||
|
||||
private boolean getBit(long in, int bitNum) {
|
||||
long mask = 1L << bitNum;
|
||||
return (in & mask) != 0L;
|
||||
}
|
||||
|
||||
public void setVertexVectors(INDArray vertexVectors) {
|
||||
this.vertexVectors = vertexVectors;
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.models.loader;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.io.LineIterator;
|
||||
import org.deeplearning4j.graph.models.GraphVectors;
|
||||
import org.deeplearning4j.graph.models.deepwalk.DeepWalk;
|
||||
import org.deeplearning4j.graph.models.embeddings.GraphVectorsImpl;
|
||||
import org.deeplearning4j.graph.models.embeddings.InMemoryGraphLookupTable;
|
||||
import org.nd4j.linalg.api.ndarray.INDArray;
|
||||
import org.nd4j.linalg.factory.Nd4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GraphVectorSerializer {
|
||||
private static final Logger log = LoggerFactory.getLogger(GraphVectorSerializer.class);
|
||||
private static final String DELIM = "\t";
|
||||
|
||||
private GraphVectorSerializer() {}
|
||||
|
||||
public static void writeGraphVectors(DeepWalk deepWalk, String path) throws IOException {
|
||||
|
||||
int nVertices = deepWalk.numVertices();
|
||||
int vectorSize = deepWalk.getVectorSize();
|
||||
|
||||
try (BufferedWriter write = new BufferedWriter(new FileWriter(new File(path), false))) {
|
||||
for (int i = 0; i < nVertices; i++) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(i);
|
||||
INDArray vec = deepWalk.getVertexVector(i);
|
||||
for (int j = 0; j < vectorSize; j++) {
|
||||
double d = vec.getDouble(j);
|
||||
sb.append(DELIM).append(d);
|
||||
}
|
||||
sb.append("\n");
|
||||
write.write(sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
log.info("Wrote {} vectors of length {} to: {}", nVertices, vectorSize, path);
|
||||
}
|
||||
|
||||
public static GraphVectors loadTxtVectors(File file) throws IOException {
|
||||
|
||||
List<double[]> vectorList = new ArrayList<>();
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||
LineIterator iter = IOUtils.lineIterator(reader);
|
||||
|
||||
while (iter.hasNext()) {
|
||||
String line = iter.next();
|
||||
String[] split = line.split(DELIM);
|
||||
double[] vec = new double[split.length - 1];
|
||||
for (int i = 1; i < split.length; i++) {
|
||||
vec[i - 1] = Double.parseDouble(split[i]);
|
||||
}
|
||||
vectorList.add(vec);
|
||||
}
|
||||
}
|
||||
|
||||
int vecSize = vectorList.get(0).length;
|
||||
int nVertices = vectorList.size();
|
||||
|
||||
INDArray vectors = Nd4j.create(nVertices, vecSize);
|
||||
for (int i = 0; i < vectorList.size(); i++) {
|
||||
double[] vec = vectorList.get(i);
|
||||
for (int j = 0; j < vec.length; j++) {
|
||||
vectors.put(i, j, vec[j]);
|
||||
}
|
||||
}
|
||||
|
||||
InMemoryGraphLookupTable table = new InMemoryGraphLookupTable(nVertices, vecSize, null, 0.01);
|
||||
table.setVertexVectors(vectors);
|
||||
|
||||
return new GraphVectorsImpl<>(null, table);
|
||||
}
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.vertexfactory;
|
||||
|
||||
import org.deeplearning4j.graph.api.Vertex;
|
||||
|
||||
public class IntegerVertexFactory implements VertexFactory<Integer> {
|
||||
@Override
|
||||
public Vertex<Integer> create(int vertexIdx) {
|
||||
return new Vertex<>(vertexIdx, vertexIdx);
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.vertexfactory;
|
||||
|
||||
import org.deeplearning4j.graph.api.Vertex;
|
||||
|
||||
public class StringVertexFactory implements VertexFactory<String> {
|
||||
|
||||
private final String format;
|
||||
|
||||
public StringVertexFactory() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public StringVertexFactory(String format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vertex<String> create(int vertexIdx) {
|
||||
if (format != null)
|
||||
return new Vertex<>(vertexIdx, String.format(format, vertexIdx));
|
||||
else
|
||||
return new Vertex<>(vertexIdx, String.valueOf(vertexIdx));
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.vertexfactory;
|
||||
|
||||
import org.deeplearning4j.graph.api.Vertex;
|
||||
|
||||
public interface VertexFactory<T> {
|
||||
|
||||
Vertex<T> create(int vertexIdx);
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package org.deeplearning4j.graph.vertexfactory;
|
||||
|
||||
import org.deeplearning4j.graph.api.Vertex;
|
||||
|
||||
public class VoidVertexFactory implements VertexFactory<Void> {
|
||||
@Override
|
||||
public Vertex<Void> create(int vertexIdx) {
|
||||
return new Vertex<>(vertexIdx, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
open module deeplearning4j.graph {
|
||||
requires commons.io;
|
||||
requires commons.math3;
|
||||
requires nd4j.common;
|
||||
requires slf4j.api;
|
||||
requires threadly;
|
||||
requires nd4j.api;
|
||||
exports org.deeplearning4j.graph.api;
|
||||
exports org.deeplearning4j.graph.data;
|
||||
exports org.deeplearning4j.graph.data.impl;
|
||||
exports org.deeplearning4j.graph.exception;
|
||||
exports org.deeplearning4j.graph.graph;
|
||||
exports org.deeplearning4j.graph.iterator;
|
||||
exports org.deeplearning4j.graph.iterator.parallel;
|
||||
exports org.deeplearning4j.graph.models;
|
||||
exports org.deeplearning4j.graph.models.deepwalk;
|
||||
exports org.deeplearning4j.graph.models.embeddings;
|
||||
exports org.deeplearning4j.graph.models.loader;
|
||||
exports org.deeplearning4j.graph.vertexfactory;
|
||||
}
|
||||
Reference in New Issue
Block a user