pub struct Graph { /* private fields */ }
Expand description

A structure that stores a pointer to a computation graph, where every node corresponds to an operation.

Clone trait duplicates the pointer, not the underlying graph.

PartialEq trait compares pointers, not the related graphs.

Example

let c = create_context().unwrap();
let g1 = c.create_graph().unwrap();
let g2 = c.create_graph().unwrap();
assert_ne!(g1, g2);
let g3 = g1.clone();
assert_eq!(g1, g3);

Implementations

Adds an input node to the graph and returns it.

During evaluation, input nodes require values to be supplied.

Arguments

input_type - type of a new input node

Returns

New input node

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = scalar_type(BIT);
let n = g.input(t).unwrap();

Adds a node that sums two arrays or scalars of the same scalar type elementwise.

If input shapes are different, the broadcasting rules are applied (see the NumPy broadcasting rules). For example, adding two arrays of shapes [10,1,7] and [8,1] results in an array of shape [10,8,7].

Arguments
  • a - node containing the first term (array or scalar)
  • b - node containing the second term (array or scalar)
Returns

New addition node

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = scalar_type(BIT);
let n1 = g.input(t.clone()).unwrap();
let n2 = g.input(t).unwrap();
let n3 = g.add(n1, n2).unwrap();

Adds a node that subtracts two arrays or scalars of the same scalar type elementwise.

If input shapes are different, the broadcasting rules are applied (see the NumPy broadcasting rules). For example, subtracting two arrays of shapes [10,1,7] and [8,1] results in an array of shape [10,8,7].

Arguments
  • a - node containing the minuend (array of scalar)
  • b - node containing the subtrahend (array of scalar)
Returns

New subtraction node

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = scalar_type(BIT);
let n1 = g.input(t.clone()).unwrap();
let n2 = g.input(t).unwrap();
let n3 = g.subtract(n1, n2).unwrap();

Adds a node that multiplies two arrays or scalars of the same scalar type elementwise.

If input shapes are different, the broadcasting rules are applied (see the NumPy broadcasting rules). For example, multiplication of two arrays of shapes [10,1,7] and [8,1] results in an array of shape [10,8,7].

Arguments
  • a - node containing the first factor (array of scalar)
  • b - node containing the second factor (array of scalar)
Returns

New multiplication node

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = scalar_type(BIT);
let n1 = g.input(t.clone()).unwrap();
let n2 = g.input(t).unwrap();
let n3 = g.multiply(n1, n2).unwrap();

Adds a node that computes the dot product according to the NumPy rules:

  • if both factors are 1-dimensional arrays, return their inner product;
  • if both factors are 2-dimensional arrays, return their matrix product;
  • if one of the factors is scalar, return the result of multiply;
  • if the first factor is n-dimensional and the second one is 1-dimensional, compute the elementwise multiplication and return the sum over the last axis.
  • if both factors are n-dimensional (n>2), return the sum product over the last axis of the first factor and the second-to-last axis of the second factor, i.e.

dot(A, B)[i,j,k,m] = sum(A[i,j,:] * B[k,:,m]) (in the NumPy notation).

Arguments
  • a - node containing the first factor (array or scalar)
  • b - node containing the second factor (array or scalar)
Returns

New dot product node

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = array_type(vec![10], INT32);
let n1 = g.input(t.clone()).unwrap();
let n2 = g.input(t).unwrap();
let n3 = g.dot(n1, n2).unwrap();

Adds a node that computes the matrix product of two arrays according to the NumPy rules.

Each array is represented as an array of 2-dimensional matrix elements and this node returns the elementwise product of such matrix arrays.

Arguments
  • a - node containing the first array
  • b - node containing the second array
Returns

New matrix product node

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t1 = array_type(vec![2, 3], INT32);
let t2 = array_type(vec![3, 2], INT32);
let n1 = g.input(t1).unwrap();
let n2 = g.input(t2).unwrap();
let n3 = g.matmul(n1, n2).unwrap();

Adds a node that divides a scalar or each entry of an array by a positive constant integer scale.

Arguments
  • a - node containing a scalar or an array
  • scale - positive integer
Returns

New truncate node

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = array_type(vec![2, 3], INT32);
let n1 = g.input(t).unwrap();
let n2 = g.truncate(n1, 4).unwrap();

Adds a node that computes the sum of entries of an array along given axes (see numpy.sum).

For example, summing the array [[1000, 200], [30, 4]] along the first or the second axes results in the arrays [1030,204] or [1200,34], respectively. Summing along both axes yields 1234.

Arguments
  • a - node containing an array
  • axes - indices of the axes of a
Returns

New sum node

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = array_type(vec![3, 2, 3], INT32);
let axes = vec![1, 0];
let n1 = g.input(t).unwrap();
let n2 = g.sum(n1, axes).unwrap();

Adds a node that permutes an array along given axes (see numpy.transpose). This function generalizes matrix transposition.

For example, permutation of an array of shape [a,b,c] with permutation [2,0,1] results in an array of shape [c,a,b].

Arguments
  • a - node containing an array
  • axes - indices of the axes of a
Returns

New node with permuted axes

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = array_type(vec![3, 2, 3], INT32);
let axes = vec![1, 0, 2];
let n1 = g.input(t).unwrap();
let n2 = g.permute_axes(n1, axes).unwrap();

Adds a node that extracts a sub-array with a given index. This is a special case of get_slice and corresponds to single element indexing as in NumPy.

For example, given an array A of shape [a,b,c,d], its subarray B of shape [c,d] with index [i,j] can be extracted as follows

B = A[i,j,:,:] (in the NumPy notation)

Arguments
  • a - node containing an array
  • index - index of a sub-array
Returns

New node containing an extracted sub-array

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = array_type(vec![3, 2, 3], INT32);
let index = vec![2];
let n1 = g.input(t).unwrap();
let n2 = g.get(n1, index).unwrap();

Adds a node that extracts a sub-array corresponding to a given slice.

Our slicing conventions follow the NumPy rules.

For example, given an array A of shape [a,b], its subarray B containing only the last 3 rows of A can be extracted as follows

get_slice(A, [-3::])[i,j] = A[a-3+i,j].

Slices are defined as vectors of SliceElements that have 3 possible types:

  • SingleIndex(i64) is used to extract all the elements with a given index in a respective dimension,
  • SubArray(Option<i64>, Option<i64>, Option<i64>) describes the range of indices that should be extracted over a certain dimension (similar to the a:b:c notation in NumPy)
  • Ellipsis describes several consecutive dimensions that must be extracted in full, e.g. the slice [i,...,j] can be used to extract all the elements with the index i in the first dimension and the index j in the last one, while the indices of all the other dimensions have no constraints. See the NumPy slicing for more details.
Arguments
  • a - node containing an array
  • slice - array slice
Returns

New node containing an extracted sub-array

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = array_type(vec![3, 2, 3], INT32);
let slice = vec![SliceElement::Ellipsis, SliceElement::SubArray(None, None, Some(-2))];
let n1 = g.input(t).unwrap();
let n2 = g.get_slice(n1, slice).unwrap();

Adds a node that reshapes a value to a given compatible type (similar to numpy.reshape, but more general). Specifically,

  • if the input value is an array, it can be reshaped to any array with the same number of elements;
  • if the input value in the flattened form contains n arrays or scalars, it can be reshaped to any type with the same number of arrays and scalars. Each array can be reshaped as in the above rule.

For example, an array of shape [3,10,5] can be reshaped to [2,75]. A tuple with arrays of shapes [3,4], [12], [2,6] can be reshaped to a vector with 3 array elements of shape [2,2,3].

Arguments
  • a - node containing a value
  • new_type - type
Returns

New node with a reshaped value

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let old_t = array_type(vec![3, 2, 3], INT32);
let new_t = array_type(vec![3,6], INT32);
let n1 = g.input(old_t).unwrap();
let n2 = g.reshape(n1, new_t).unwrap();

Adds a node that joins a sequence of arrays governed by a given shape.

The input arrays should have the same shape or be able to be broadcast to the same shape.

For example, stacking 2 arrays of shapes [2,2] and [2,1] with the outer shape [2] works as follows

stack(arrays=[[[1,2],[3,4]], [5,6]], shape=[2]) = [[[1,2],[3,4]], [[5,5], [6,6]]]

Arguments
  • nodes - vector of nodes containing arrays
  • outer_shape - shape defining how the input arrays are arranged in the resulting array
Returns

New stack node

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t1 = array_type(vec![3, 2, 3], INT32);
let t2 = array_type(vec![2, 3], INT32);
let shape = vec![2];
let n1 = g.input(t1).unwrap();
let n2 = g.input(t2).unwrap();
let n3 = g.stack(vec![n1,n2], shape).unwrap();

Adds a node creating a constant of a given type and value.

Arguments
  • output_type - type of a constant
  • value - value of a constant
Returns

New constant node

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = scalar_type(BIT);
let v = Value::from_scalar(0, BIT).unwrap();
let n = g.constant(t, v).unwrap();

Adds a node converting an integer array or scalar to the binary form.

Given an array of shape [a,b,c] and scalar type st, this node returns an array of shape [a,b,c,s] where s is the bit size of st. For example, an array of shape [1,2,3] with INT32 entries will be converted to a binary array of shape [1,2,3,32].

Arguments

a - node containing an array or scalar

Returns

New node converting an array/scalar to the binary form

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = array_type(vec![3, 2], INT32);
let n1 = g.input(t).unwrap();
let n2 = g.a2b(n1).unwrap();

Adds a node converting a binary array to an array of a given scalar type.

Given a binary array of shape [a,b,c] and a scalar type st of bit size c, this node returns an array of shape [a,b] with st entries. For example, a binary array of shape [2,3,32] can be converted to an array of shape [2,3] with INT32 entries.

Arguments
  • a - node containing an array or scalar
  • scalar_type - scalar type
Returns

New node converting an array from the binary form

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = array_type(vec![3, 32], BIT);
let n1 = g.input(t).unwrap();
let n2 = g.b2a(n1, INT32).unwrap();

Adds a node that creates a tuple from several (possibly, zero) elements.

Arguments

elements - vector of nodes

Returns

New node with a tuple

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t1 = array_type(vec![3, 2, 3], INT32);
let t2 = array_type(vec![2, 3], INT32);
let n1 = g.input(t1).unwrap();
let n2 = g.input(t2).unwrap();
let n3 = g.create_tuple(vec![n1,n2]).unwrap();

Adds a node that creates a vector from several (possibly, zero) elements of the same type.

Arguments

elements - vector of nodes

Returns

New node with a created vector

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = array_type(vec![3, 2, 3], INT32);
let n1 = g.input(t.clone()).unwrap();
let n2 = g.input(t.clone()).unwrap();
let n3 = g.create_vector(t, vec![n1,n2]).unwrap();

Adds a node that creates a named tuple from several (possibly, zero) elements.

Arguments

elements - vector of pairs (node name, node)

Returns

New node creating a named tuple

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t1 = array_type(vec![3, 2, 3], INT32);
let t2 = array_type(vec![2, 3], INT32);
let n1 = g.input(t1).unwrap();
let n2 = g.input(t2).unwrap();
let n3 = g.create_named_tuple(vec![("node1".to_owned(), n1), ("node2".to_owned(), n2)]).unwrap();

Adds a node that extracts an element of a tuple.

Arguments
  • tuple - node containing a tuple
  • index - index of a tuple element between 0 and tuple length minus 1
Returns

New node with an extracted element

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t1 = array_type(vec![3, 2, 3], INT32);
let t2 = array_type(vec![2, 3], INT32);
let n1 = g.input(t1).unwrap();
let n2 = g.input(t2).unwrap();
let n3 = g.create_tuple(vec![n1, n2]).unwrap();
let n4 = g.tuple_get(n3, 1).unwrap();

Adds a node that extracts an element of a named tuple.

Arguments
  • tuple - node containing a named tuple
  • key - key of a tuple element
Returns

New node extracting a tuple element

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t1 = array_type(vec![3, 2, 3], INT32);
let t2 = array_type(vec![2, 3], INT32);
let n1 = g.input(t1).unwrap();
let n2 = g.input(t2).unwrap();
let n3 = g.create_named_tuple(vec![("node1".to_owned(), n1), ("node2".to_owned(), n2)]).unwrap();
let n4 = g.named_tuple_get(n3, "node2".to_owned()).unwrap();

Adds a node that extracts an element of a vector.

Arguments
  • vec - node containing a vector
  • index - node containing the index of a tuple element
Returns

New node extracting a vector element

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = array_type(vec![3, 2, 3], INT32);
let n1 = g.input(t.clone()).unwrap();
let n2 = g.input(t.clone()).unwrap();
let n3 = g.create_vector(t, vec![n1,n2]).unwrap();
let index = g.constant(scalar_type(UINT32), Value::from_scalar(0, UINT32).unwrap()).unwrap();
let n4 = g.vector_get(n3, index).unwrap();

Adds a node that takes vectors V1(n, t1), V2(n, t2), …, Vk(n, tk) of the same length and returns a vector V(n, tuple(t1, …, tk)) (similar to zip).

Arguments

nodes - vector of nodes containing input vectors

Returns

New zip node

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = array_type(vec![3, 2, 3], INT32);
let vec_t = vector_type(3, t);
let n1 = g.input(vec_t.clone()).unwrap();
let n2 = g.input(vec_t.clone()).unwrap();
let n3 = g.zip(vec![n1,n2]).unwrap();

Adds a node that creates a vector with n copies of a value of a given node.

Arguments
  • a - node containing a value
  • n - number of copies
Returns

New repeat node

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = array_type(vec![3, 2, 3], INT32);
let n1 = g.input(t).unwrap();
let n2 = g.repeat(n1, 10).unwrap();

Adds a node that calls another graph with inputs contained in given nodes.

The input graph must be finalized and have as many inputs as the number of provided arguments.

For example, let G be a graph implementing the function max(x,0), then call(G, [17]) = max(17, 0).

Arguments
  • graph - graph with n input nodes
  • arguments - vector of n nodes
Returns

New call node

Example
let c = create_context().unwrap();

let g1 = c.create_graph().unwrap();
let t = array_type(vec![3, 2, 3], INT32);
let n1 = g1.input(t.clone()).unwrap();
let n2 = g1.repeat(n1, 10).unwrap();
let n3 = g1.vector_to_array(n2).unwrap();
n3.set_as_output().unwrap();
g1.finalize().unwrap();

let g2 = c.create_graph().unwrap();
let n4 = g2.input(t).unwrap();
let n5 = g2.add(n4.clone(), n4).unwrap();
let n6 = g2.call(g1, vec![n5]).unwrap();

Adds a node that iteratively computes a given finalized graph on the elements of a given vector and updates the state value accordingly.

This node calls another graph with 2 input nodes old_state and input and an output node that returns a tuple (new_state, output). This graph is used to map the elements of a given vector V to another vector W as follows:

graph(state_0, V[0]) -> (state1, W[0]),
graph(state_1, V[1]) -> (state2, W[1]),
...
graph(state_k, V[k]) -> (final_state, W[k]).

The output is a tuple (final_state, W). The initial state state_0 should be provided as an argument.

This node generalize map and reduce procedures (see MapReduce for more details).

For example, let G be a graph implementing the function max(x,0) and incrementing state if its output is negative, then iterate(G, 0, [-1,2,0,3,2]) = (1, [0,2,0,3,2]). The final state is equal to the number of negative values in the input vector.

Arguments
  • graph - graph with 2 input nodes of types Ts and Ti and returning a tuple of type (Ts, To)
  • state - node containing an initial state of type Ts
  • input - node containing a vector with elements of type Ti
Returns

New iterate node

Example
let c = create_context().unwrap();

let t_s = scalar_type(INT32);
let t = scalar_type(INT32);
let vec_t = vector_type(10, t.clone());

let g1 = c.create_graph().unwrap();
{
    let old_state = g1.input(t_s.clone()).unwrap();
    let input = g1.input(t.clone()).unwrap();
    let sum = g1.add(old_state.clone(), input).unwrap();
    let out_tuple = g1.create_tuple(vec![sum, old_state]).unwrap();
    out_tuple.set_as_output().unwrap();
    g1.finalize().unwrap();
}

let g2 = c.create_graph().unwrap();
let initial_state = g2.input(t).unwrap();
let input_vector = g2.input(vec_t).unwrap();
g2.iterate(g1, initial_state, input_vector).unwrap();

Adds a node converting an array to a vector.

Given an array of shape [a,b,c], this node returns a vector of a arrays of shape [b,c].

Arguments

a - node containing an array

Returns

New node converting an array to a vector

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = array_type(vec![4, 3, 2], INT32);
let n1 = g.input(t).unwrap();
let n2 = g.array_to_vector(n1).unwrap();
let index = g.constant(scalar_type(UINT32), Value::from_scalar(0, UINT32).unwrap()).unwrap();
let n3 = g.vector_get(n2.clone(), index).unwrap();

assert!(n2.get_type().unwrap().is_vector());
assert_eq!(n3.get_type().unwrap().get_shape(), vec![3,2]);

Adds a node converting a vector to an array.

Given a vector of a arrays of shape [b,c], this node returns an array of shape [a,b,c].

Arguments

a - node containing a vector

Returns

New node converting a vector to an array

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = array_type(vec![3, 2], INT32);
let vec_t = vector_type(4, t);
let n1 = g.input(vec_t).unwrap();
let n2 = g.vector_to_array(n1).unwrap();

assert!(n2.get_type().unwrap().is_array());
assert_eq!(n2.get_type().unwrap().get_shape(), vec![4, 3, 2]);

Adds a node computing a given custom operation.

Custom operations can be created by the user as public structs implementing the CustomOperationBody.

Arguments
  • op - custom operation
  • arguments - vector of nodes used as input for the custom operation
Returns

New custom operation node

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = array_type(vec![3, 2], BIT);
let n1 = g.input(t).unwrap();
let n2 = g.custom_op(CustomOperation::new(Not {}), vec![n1]).unwrap();

Checks that the graph has an output node and finalizes the graph.

After finalization the graph can’t be changed.

Returns

Finalized graph

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = array_type(vec![3, 2], INT32);
let vec_t = vector_type(4, t);
let n1 = g.input(vec_t).unwrap();
let n2 = g.vector_to_array(n1).unwrap();
n2.set_as_output().unwrap();
g.finalize().unwrap();

Returns the vector of nodes contained in the graph in order of construction.

Returns

Vector of nodes of the graph

Promotes a given node to the output node of the parent graph.

Arguments

output_node - node to be set as output

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = array_type(vec![3, 2], INT32);
let vec_t = vector_type(4, t);
let n1 = g.input(vec_t).unwrap();
let n2 = g.vector_to_array(n1).unwrap();
g.set_output_node(n2).unwrap();
g.finalize().unwrap();

Returns the output node of the graph.

Returns

Output node of the graph

Returns the ID of the graph.

A graph ID is a serial number of a graph between 0 and n-1 where n is the number of graphs in the parent context.

Returns

Graph ID

Returns the number of the graph nodes.

Returns

Number of the graph nodes

Returns the node corresponding to a given ID.

Arguments

id - node ID

Returns

Node with a given ID

Returns the context of the graph nodes.

Returns

Context of the graph

Applies Context::set_main_graph to the parent context and this graph. Returns the clone of this.

Returns

This graph

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = array_type(vec![3, 2], INT32);
let n = g.input(t).unwrap();
n.set_as_output().unwrap();
g.finalize().unwrap();
g.set_as_main().unwrap();

Applies Context::set_graph_name to the parent context and this graph. Returns the clone of this.

Arguments

name - name of the graph

Returns

This graph

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
g.set_name("relu").unwrap();

Applies Context::get_graph_name to the parent context and this graph.

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
g.set_name("relu").unwrap();
assert_eq!(g.get_name().unwrap(), "relu".to_owned());

Applies Context::retrieve_node to the parent context and this graph.

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let n = g.input(scalar_type(BIT)).unwrap();
n.set_name("input_node").unwrap();
assert!(n == g.retrieve_node("input_node").unwrap());

Rearrange given input values according to the names and the order of the related input nodes.

For example, given a graph with the first input node named ‘A’ and the second one named ‘B’ and input values {'B': v, 'A': w}, this function returns a vector [w, v].

Arguments

values - hashmap of values keyed by node names

Returns

Vector of values arranged by node names

Example
let c = create_context().unwrap();
let g = c.create_graph().unwrap();
let t = scalar_type(BIT);
let n1 = g.input(t.clone()).unwrap();
n1.set_name("input1").unwrap();
let n2 = g.input(t.clone()).unwrap();
n2.set_name("input2").unwrap();

let mut input_map = HashMap::new();
input_map.insert("input2", 2);
input_map.insert("input1", 1);
let ordered_input = g.prepare_input_values(input_map).unwrap();

assert_eq!(vec![1,2], ordered_input);

Trait Implementations

Returns a new Graph value with a copy of the pointer to a computation graph.

Performs copy-assignment from source. Read more

Formats the value using the given formatter. Read more

Hashes the graph pointer.

Arguments

state - state of a hash function that is changed after hashing the graph

Feeds a slice of this type into the given Hasher. Read more

Tests whether self and other graphs are equal via comparison of their respective pointers.

Arguments

other - another Graph value

Returns

true if self and other are equal, false otherwise

This method tests for !=.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Compare self to key and return true if they are equal.

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The resulting type after obtaining ownership.

Creates owned data from borrowed data, usually by cloning. Read more

🔬 This is a nightly-only experimental API. (toowned_clone_into)

Uses borrowed data to replace owned data, usually by cloning. Read more

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.