blob: 8fc45c7ec361f8be8a4eba521135a4fe96b16f0f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
package org.apache.tinkerpop.gremlin.process.computer;
import org.apache.tinkerpop.gremlin.process.computer.util.VertexProgramHelper;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import java.util.Arrays;
import java.util.function.BiFunction;
import java.util.function.Supplier;
/**
* A {@link MessageScope} represents the range of a message. A message can have multiple receivers and message scope
* allows the underlying {@link GraphComputer} to apply the message passing algorithm in whichever manner is most
* efficient. It is best to use {@link MessageScope.Local} if possible as that provides more room for optimization by
* providers than {@link MessageScope.Global}.
*
* @author Marko A. Rodriguez (http://markorodriguez.com)
* @author Matthias Broecheler (me@matthiasb.com)
*/
public abstract class MessageScope {
/**
* A Global message is directed at an arbitrary vertex in the graph.
* The recipient vertex need not be adjacent to the sending vertex.
* This message scope should be avoided if a {@link Local} can be used.
*/
public final static class Global extends MessageScope {
private static final Global INSTANCE = Global.of();
private final Iterable<Vertex> vertices;
private Global(final Iterable<Vertex> vertices) {
this.vertices = vertices;
}
public static Global of(final Iterable<Vertex> vertices) {
return new Global(vertices);
}
public static Global of(final Vertex... vertices) {
return new Global(Arrays.asList(vertices));
}
public Iterable<Vertex> vertices() {
return this.vertices;
}
public static Global instance() {
return INSTANCE;
}
@Override
public int hashCode() {
return 4676576;
}
@Override
public boolean equals(final Object other) {
return other instanceof Global;
}
}
/**
* A Local message is directed to an adjacent (or "memory adjacent") vertex.
* The adjacent vertex set is defined by the provided {@link Traversal} that dictates how to go from the sending vertex to the receiving vertex.
* This is the preferred message scope as it can potentially be optimized by the underlying {@link Messenger} implementation.
* The preferred optimization is to not distribute a message object to all adjacent vertices.
* Instead, allow the recipients to read a single message object stored at the "sending" vertex.
* This is possible via `Traversal.reverse()`. This optimizations greatly reduces the amount of data created in the computation.
*
* @param <M> The {@link VertexProgram} message class
*/
public final static class Local<M> extends MessageScope {
public final Supplier<? extends Traversal<Vertex, Edge>> incidentTraversal;
public final BiFunction<M, Edge, M> edgeFunction;
private final String toStringOfTraversal;
private Local(final Supplier<? extends Traversal<Vertex, Edge>> incidentTraversal) {
this(incidentTraversal, (final M m, final Edge e) -> m); // the default is an identity function
}
private Local(final Supplier<? extends Traversal<Vertex, Edge>> incidentTraversal, final BiFunction<M, Edge, M> edgeFunction) {
this.incidentTraversal = incidentTraversal;
this.toStringOfTraversal = this.incidentTraversal.get().toString();
this.edgeFunction = edgeFunction;
}
public static <M> Local<M> of(final Supplier<? extends Traversal<Vertex, Edge>> incidentTraversal) {
return new Local<>(incidentTraversal);
}
public static <M> Local<M> of(final Supplier<? extends Traversal<Vertex, Edge>> incidentTraversal, final BiFunction<M, Edge, M> edgeFunction) {
return new Local<>(incidentTraversal, edgeFunction);
}
public BiFunction<M, Edge, M> getEdgeFunction() {
return this.edgeFunction;
}
public Supplier<? extends Traversal<Vertex, Edge>> getIncidentTraversal() {
return this.incidentTraversal;
}
@Override
public int hashCode() {
return this.edgeFunction.hashCode() + this.incidentTraversal.get().toString().hashCode();
}
@Override
public boolean equals(final Object other) {
return other instanceof Local &&
((Local<?>) other).toStringOfTraversal.equals(this.toStringOfTraversal) &&
((Local<?>) other).edgeFunction == this.edgeFunction;
}
/**
* A helper class that can be used to generate the reverse traversal of the traversal within a {@link MessageScope.Local}.
*/
public static class ReverseTraversalSupplier implements Supplier<Traversal<Vertex, Edge>> {
private final MessageScope.Local<?> localMessageScope;
public ReverseTraversalSupplier(final MessageScope.Local<?> localMessageScope) {
this.localMessageScope = localMessageScope;
}
public Traversal<Vertex, Edge> get() {
return VertexProgramHelper.reverse(this.localMessageScope.getIncidentTraversal().get().asAdmin());
}
}
}
}