Marko A. Rodriguez created TINKERPOP3-960:
---------------------------------------------
Summary: Add a Bulk class which is used by Traverser
Key: TINKERPOP3-960
URL: https://issues.apache.org/jira/browse/TINKERPOP3-960
Project: TinkerPop 3
Issue Type: Bug
Components: process
Affects Versions: 3.1.0-incubating
Reporter: Marko A. Rodriguez
Assignee: Marko A. Rodriguez
Currently, {{Traverser.bulk()}} is a {{long}}. This should be generalized to
support any type of "bulk" that can be split, merged, and has a magnitude,
where our current representation would be a {{LongBulk}}.
There are three reasons to support this.
1. Right now we use {{Traverser.sack()}} to handle "energy flows" (0/0 to 1.0
energy in a traverser). We have introduced this ugly
{{TraversalSource.withBulk(false)}} to allow these to semantically make sense
(i.e. remain unitary). The "energy" should be the "bulk" as it can be split,
merged, and has a magnitude.
2. We can support complex numbers for bulks (and complex number arrays). There
is currently no strong use case for this beyond quantum simulation and wave
dynamics, but you never know what might unfold. A solid algorithm here would be
epic.
3. We need to be able to support {{BigInteger}} as the bulking model on complex
graphs easily blows {{long}}. There have been numerous times where I wanted to
{{repeat()}} more times, but can't without incurring long overflow and thus,
negative bulk. If the computation calls for it, a user should be able to use
{{BigInteger}}.
--------------------------
{code}
public interface Bulk<T> {
public boolean canMerge(Bulk<T> otherBulk);
public void merge(Bulk<T> otherBulk);
public Bulk<T> split();
public Number magnitude();
public T get();
public static Bulk<T> identity();
}
{code}
Our current model would be:
{code}
public class LongBulk extends Bulk<Long> {
public boolean canMerge(LongBulk otherBulk) { return true; }
public void merge(LongBulk otherBulk) { this.count += otherBulk.count; }
public LongBulk split() { return new LongBulk(this.count); }
public Number magnitude() { return this.count; }
public Long get() { return this.count; }
public static LongBulk identity() { return new LongBulk(1); }
}
{code}
Another benefit of this is that bulking is now decoupled from the {{Traverser}}
class and thus, you would be able to use different bulk classes with the same
{{Traverser}}-species:
{code}
g.withBulk(BigIntegerBulk.class).V().out().out()
{code}
...where the default is assumed {{LongBulk}} and thus, you don't have to
specify a {{withBulk}}. For backwards compatible sake, {{withBulk(false)}}
would simply be {{IdentityLongBulk}} would would just return a {{1}} for
everything.
We will want to then expose {{it.bulk()}} methods so algorithms can alter the
bulk as they see fit. However, this is where a backwards compatibility issue
would happen. {{Traverser.bulk() -> Bulk}} and {{Traverser.magnitude() ->
Number}} (sidenote ---- perhaps "magnitude" is just called "count").
{code}
g.withBulk(UnitaryBulk).V(0).bulk(1.0).outE().bulk(mult).by('weight').inV()
{code}
What is stellar about this is that it frees up ``sack" for more "objects" and
not for "bulking" when long is sufficient. Thus, we promote that "sack" is for
objects and "bulk" is for, well, bulk! Now we no longer have this weird tension
between bulk and sack as they have two different uses. Bulking is for altering
the "magnitude" of a traverser and sacking if for gathering statistics/data
about the graph along the way.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)