diff --git a/README.md b/README.md
index 18e0b50f5..d83fcaa59 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,11 @@ pip3 install tensornetwork
For details about the TensorNetwork API, see the [reference documentation.](https://tensornetwork.readthedocs.io)
-We also have a basic [tutorial colab](https://colab.research.google.com/drive/1Fp9DolkPT-P_Dkg_s9PLbTOKSq64EVSu) for a more "hands-on" example.
+## Tutorials
+
+[Basic API tutorial](https://colab.research.google.com/drive/1Fp9DolkPT-P_Dkg_s9PLbTOKSq64EVSu)
+
+[Tensor Networks inside Neural Networks using Keras](https://colab.research.google.com/drive/1JUh84N5sbfQYk6HWowWCGl0IZ1idQi6z)
## Basic Example
Here, we build a simple 2 node contraction.
diff --git a/gui/README.md b/gui/README.md
deleted file mode 100644
index 45c410a62..000000000
--- a/gui/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# TensorNetwork GUI
-
-⚠️ **UNDER CONSTRUCTION** 🏗️
-
-A graphical interface for defining tensor networks. Compiles to TensorNetwork Python code.
diff --git a/gui/css/index.css b/gui/css/index.css
deleted file mode 100644
index 1dcce637d..000000000
--- a/gui/css/index.css
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
-Copyright 2019 The TensorNetwork Authors
-Licensed 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.
-*/
-
-.app {
- display: flex;
- flex-direction: row;
- font: normal 15px sans-serif;
-}
-
-svg.workspace {
- float: left;
- background-color: #f9f9f9;
-}
-
-svg.workspace .drag-selector {
- stroke: #fff;
- stroke-width: 2;
- fill: rgba(200, 200, 200, 0.5);
-}
-
-a.export {
- position: absolute;
-}
-
-svg text {
- user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- -webkit-user-select: none;
-}
-
-.toolbar {
- width: 300px;
- background-color: #fff;
- box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.2);
-}
-
-section {
- padding: 10px 20px;
- border-bottom: 1px solid #ddd;
-}
-
-.tensor-creator .svg-container {
- height: 200px;
-}
-
-.delete {
- text-align: right;
- float: right;
- color: darkred;
-}
-
-.button-holder {
- padding: 20px 0;
-}
-
-.code-output {
- position: absolute;
- top: 600px;
- width: 900px;
- padding: 10px;
-}
-
-label {
- padding: 10px;
-}
\ No newline at end of file
diff --git a/gui/index.html b/gui/index.html
deleted file mode 100644
index f235bcc6a..000000000
--- a/gui/index.html
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- TensorNetwork GUI
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/gui/js/app.js b/gui/js/app.js
deleted file mode 100644
index 71c8dc85b..000000000
--- a/gui/js/app.js
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2019 The TensorNetwork Authors
-//
-// Licensed 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.
-
-let app = new Vue({
- el: '#app',
- data: {
- state: initialState // now state object is reactive, whereas initialState is not
- },
- methods: {
- exportSVG: function(event) {
- event.preventDefault();
- let serializer = new XMLSerializer();
- let workspace = document.getElementById('workspace');
- let blob = new Blob([serializer.serializeToString(workspace)], {type:"image/svg+xml;charset=utf-8"});
- let url = URL.createObjectURL(blob);
- let link = document.createElement('a');
- link.href = url;
- link.download = "export.svg";
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
- }
- },
- template: `
-
Node {{node.name}} has {{node.axes.length}} axes:
-
-
- Axis {{i}} ({{axisName}})
- is connected to axis {{neighborAt(i)[1]}}
- ({{getAxis(neighborAt(i))}})
- of node {{getNode(neighborAt(i)[0]).name}}
- by edge "{{edgeNameAt(i)}}"
-
- is free
-
-
-
- `
- }
-);
diff --git a/gui/js/output.js b/gui/js/output.js
deleted file mode 100644
index 6347db6d1..000000000
--- a/gui/js/output.js
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2019 The TensorNetwork Authors
-//
-// Licensed 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.
-
-Vue.component(
- 'code-output',
- {
- props: {
- state: Object
- },
- computed: {
- outputCode: function() {
- let code = `import numpy as np\nimport tensornetwork as tn\n`;
-
- code += `\n# Node definitions\n`;
- code += `# TODO: replace np.zeros with actual values\n\n`;
-
- for (let i = 0; i < this.state.nodes.length; i++) {
- let node = this.state.nodes[i];
- let values = this.placeholderValues(node);
- let axes = this.axisNames(node);
- code += `${node.name} = tn.Node(${values}, name="${node.name}"${axes})\n`;
- }
-
- code += `\n# Edge definitions\n\n`;
-
- for (let i = 0; i < this.state.edges.length; i++) {
- let edge = this.state.edges[i];
- let name = this.edgeName(edge);
- code += `tn.connect(${edge[0][0]}[${edge[0][1]}], ${edge[1][0]}[${edge[1][1]}]${name})\n`;
- }
-
- return code;
- }
- },
- methods: {
- placeholderValues: function(node) {
- let code = `np.zeros((`;
- for (let i = 0; i < node.axes.length; i++) {
- code += `0, `;
- }
- code += `))`;
- return code;
- },
- axisNames: function(node) {
- let code = `, axis_names=[`;
- let willOutput = false;
- for (let i = 0; i < node.axes.length; i++) {
- let axis = node.axes[i].name;
- if (axis) {
- willOutput = true;
- code += `"${axis}", `
- }
- else {
- code += `None, `
- }
- }
- code += `]`;
- return willOutput ? code : ``;
- },
- edgeName: function(edge) {
- let name = edge[2];
- return name ? `, name="${name}"` : ``;
- }
- },
- template: `
-
-
TensorNetwork Output
-
{{outputCode}}
-
- `
- }
-);
-
diff --git a/gui/js/toolbar.js b/gui/js/toolbar.js
deleted file mode 100644
index 823ffe150..000000000
--- a/gui/js/toolbar.js
+++ /dev/null
@@ -1,519 +0,0 @@
-// Copyright 2019 The TensorNetwork Authors
-//
-// Licensed 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.
-
-Vue.component(
- 'toolbar',
- {
- props: {
- state: Object
- },
- data: function() {
- return {
- copyNodeName: '',
- }
- },
- methods: {
- deselectNode: function() {
- this.state.selectedNodes = [];
- },
- deleteNode: function(event) {
- event.preventDefault();
- let selectedName = this.state.selectedNodes[0].name;
-
- this.state.edges = this.state.edges.filter(function(edge) {
- if (edge[0][0] === selectedName || edge[1][0] === selectedName) {
- return false;
- }
- else {
- return true;
- }
- });
- this.state.nodes = this.state.nodes.filter(function(node) {
- return node.name !== selectedName;
- });
- this.selectedNodes = [];
- },
- copyNode: function(event) {
- event.preventDefault();
- let workspace = document.getElementById('workspace').getBoundingClientRect();
-
- let node = JSON.parse(JSON.stringify(this.node));
- node.name = this.copyNodeName;
- node.position = {x: workspace.width / 2, y: workspace.height / 2};
-
- this.state.nodes.push(node);
- this.state.selectedNodes = [node];
- this.copyNodeName = '';
- },
- rotate: function(angle) {
- this.node.rotation += angle;
- }
- },
- computed: {
- node: function() {
- return this.state.selectedNodes[0];
- },
- copyNodeDisabled: function() {
- return this.nameTaken || this.copyNodeName == null || this.copyNodeName === '';
- },
- nameTaken: function() {
- for (let i = 0; i < this.state.nodes.length; i++) {
- if (this.copyNodeName === this.state.nodes[i].name) {
- return true;
- }
- }
- return false;
- }
- },
- template: `
-
-
-
-
-
Selecting nodes
-
Click a node to select it for editing.
-
Drag-select or shift-click multiple nodes to drag as a group and adjust alignment and
- spacing.
- Shift-click a node in the workspace to deselect it.
-
-
-
Align Vertically
-
-
-
-
Align Horizontally
-
-
-
-
Space Vertically
-
-
-
-
Space Horizontally
-
-
-
- `
- }
-);
diff --git a/gui/js/workspace.js b/gui/js/workspace.js
deleted file mode 100644
index dea17bbca..000000000
--- a/gui/js/workspace.js
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright 2019 The TensorNetwork Authors
-//
-// Licensed 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.
-
-Vue.component(
- 'workspace',
- {
- props: {
- state: Object
- },
- data: function() {
- return {
- width: 900,
- height: 600,
- dragSelector: {
- dragging: false,
- startX: null,
- startY: null,
- endX: null,
- endY: null
- },
- protoEdge: {
- x: null,
- y: null,
- node: null,
- axis: null,
- dragging: false
- }
- };
- },
- methods: {
- onMouseDown: function(event) {
- this.state.selectedNodes = [];
-
- document.addEventListener('mousemove', this.onMouseMove);
- document.addEventListener('mouseup', this.onMouseUp);
-
- let workspace = document.getElementById('workspace').getBoundingClientRect();
-
- this.dragSelector.dragging = true;
- this.dragSelector.startX = event.pageX - workspace.left;
- this.dragSelector.startY = event.pageY - workspace.top;
- this.dragSelector.endX = event.pageX - workspace.left;
- this.dragSelector.endY = event.pageY - workspace.top;
- },
- onMouseMove: function(event) {
- let workspace = document.getElementById('workspace').getBoundingClientRect();
-
- this.dragSelector.endX = event.pageX - workspace.left;
- this.dragSelector.endY = event.pageY - workspace.top;
- },
- onMouseUp: function() {
- document.removeEventListener('mousemove', this.onMouseMove);
- document.removeEventListener('mouseup', this.onMouseUp);
-
- this.dragSelector.dragging = false;
-
- let x1 = this.dragSelector.startX;
- let x2 = this.dragSelector.endX;
- let y1 = this.dragSelector.startY;
- let y2 = this.dragSelector.endY;
-
- this.state.selectedNodes = [];
- let selected = this.state.selectedNodes;
- this.state.nodes.forEach(function(node) {
- let x = node.position.x;
- let y = node.position.y;
- if ((x1 <= x && x <= x2) || (x2 <= x && x <= x1)) {
- if ((y1 <= y && y <= y2) || (y2 <= y && y <= y1)) {
- selected.push(node);
- }
- }
- });
- this.state.selectedNodes.sort(function(node1, node2) {
- let distance1 = (node1.position.x - x1) ** 2 + (node1.position.y - y1) ** 2;
- let distance2 = (node2.position.x - x1) ** 2 + (node2.position.y - y1) ** 2;
- return distance1 - distance2;
- })
- },
- onAxisMouseDown: function(node, axis) {
- if (this.axisOccupied(node, axis)) {
- return;
- }
- document.addEventListener('mousemove', this.dragAxis);
- document.addEventListener('mouseup', this.releaseAxisDrag);
- this.protoEdge.node = node;
- this.protoEdge.axis = axis;
- },
- dragAxis: function(event) {
- let workspace = document.getElementById('workspace').getBoundingClientRect();
- this.protoEdge.dragging = true;
- this.protoEdge.x = event.clientX - workspace.left;
- this.protoEdge.y = event.clientY - workspace.top;
- },
- releaseAxisDrag: function() {
- document.removeEventListener('mousemove', this.dragAxis);
- document.removeEventListener('mouseup', this.releaseAxisDrag);
- this.protoEdge.dragging = false;
- this.protoEdge.node = null;
- this.protoEdge.axis = null;
- },
- onAxisMouseUp: function(node, axis) {
- if (this.protoEdge.dragging) {
- if (this.axisOccupied(node, axis)) {
- return;
- }
- if (this.protoEdge.node.name === node.name
- && this.protoEdge.axis === axis) {
- return; // don't allow connection of an axis to itself
- }
- this.state.edges.push([
- [this.protoEdge.node.name, this.protoEdge.axis],
- [node.name, axis],
- null
- ])
- }
- },
- axisOccupied: function(node, axis) {
- for (let i = 0; i < this.state.edges.length; i++) {
- let edge = this.state.edges[i];
- if ((node.name === edge[0][0] && axis === edge[0][1])
- || (node.name === edge[1][0] && axis === edge[1][1])) {
- return true;
- }
- }
- return false;
- }
- },
- template: `
-
- `
- }
-);
-
-Vue.component(
- 'drag-selector',
- {
- props: {
- startX: Number,
- startY: Number,
- endX: Number,
- endY: Number,
- },
- computed: {
- x: function() {
- return Math.min(this.startX, this.endX);
- },
- y: function() {
- return Math.min(this.startY, this.endY);
- },
- width: function() {
- return Math.abs(this.startX - this.endX);
- },
- height: function() {
- return Math.abs(this.startY - this.endY);
- }
- },
- template: `
-
- `
- }
-);
diff --git a/tensornetwork/block_tensor/block_tensor.py b/tensornetwork/block_tensor/block_tensor.py
index a35a8941a..1ad942293 100644
--- a/tensornetwork/block_tensor/block_tensor.py
+++ b/tensornetwork/block_tensor/block_tensor.py
@@ -135,13 +135,14 @@ def compute_nonzero_block_shapes(charges: List[np.ndarray],
return charge_shape_dict
-def retrieve_non_zero_diagonal_blocks(data: np.ndarray,
- charges: List[np.ndarray],
- flows: List[Union[bool, int]]) -> Dict:
+def retrieve_non_zero_diagonal_blocks(
+ data: np.ndarray,
+ charges: List[np.ndarray],
+ flows: List[Union[bool, int]],
+ return_data: Optional[bool] = True) -> Dict:
"""
Given the meta data and underlying data of a symmetric matrix, compute
all diagonal blocks and return them in a dict.
- !!!!!!!!! This is currently very slow!!!!!!!!!!!!
Args:
data: An np.ndarray of the data. The number of elements in `data`
has to match the number of non-zero elements defined by `charges`
@@ -153,6 +154,17 @@ def retrieve_non_zero_diagonal_blocks(data: np.ndarray,
with values `1` or `-1`, denoting the flow direction
of the charges on each leg. `1` is inflowing, `-1` is outflowing
charge.
+ return_data: If `True`, the return dictionary maps quantum numbers `q` to
+ actual `np.ndarray` with the data. This involves a copy of data.
+ If `False`, the returned dict maps quantum numbers of a list
+ [locations, shape], where `locations` is an np.ndarray of type np.int64
+ containing the locations of the tensor elements within A.data, i.e.
+ `A.data[locations]` contains the elements belonging to the tensor with
+ quantum numbers `(q,q). `shape` is the shape of the corresponding array.
+
+ Returns:
+ dict: Dictionary mapping quantum numbers (integers) to either an np.ndarray
+ or a python list of locations and shapes, depending on the value of `return_data`.
"""
#TODO: this is currently way too slow!!!!
#Run the following benchmark for testing (typical MPS use case)
@@ -209,7 +221,6 @@ def retrieve_non_zero_diagonal_blocks(data: np.ndarray,
# get the degeneracies of each row and column charge
row_degeneracies = dict(zip(unique_row_charges, row_dims))
column_degeneracies = dict(zip(unique_column_charges, column_dims))
- blocks = {}
number_of_seen_elements = 0
idxs = {c: [] for c in common_charges}
@@ -220,10 +231,22 @@ def retrieve_non_zero_diagonal_blocks(data: np.ndarray,
row_degeneracies[-charge] + number_of_seen_elements))
number_of_seen_elements += row_degeneracies[-charge]
+ blocks = {}
+ if not return_data:
+ for c, idx in idxs.items():
+ num_elements = np.sum([len(t) for t in idx])
+ indexes = np.empty(num_elements, dtype=np.int64)
+ np.concatenate(idx, out=indexes)
+ blocks[c] = [indexes, (row_degeneracies[c], column_degeneracies[-c])]
+ return blocks
+
for c, idx in idxs.items():
- indexes = np.concatenate(idx)
+ num_elements = np.sum([len(t) for t in idx])
+ indexes = np.empty(num_elements, dtype=np.int64)
+ np.concatenate(idx, out=indexes)
blocks[c] = np.reshape(data[indexes],
(row_degeneracies[c], column_degeneracies[-c]))
+
return blocks
@@ -532,19 +555,31 @@ def raise_error():
if self.shape[n] < dense_shape[n]:
raise_error()
- def get_diagonal_blocks(self) -> Dict:
+ def get_diagonal_blocks(self, return_data: Optional[bool] = True) -> Dict:
"""
Obtain the diagonal blocks of symmetric matrix.
BlockSparseTensor has to be a matrix.
+ Args:
+ return_data: If `True`, the return dictionary maps quantum numbers `q` to
+ actual `np.ndarray` with the data. This involves a copy of data.
+ If `False`, the returned dict maps quantum numbers of a list
+ [locations, shape], where `locations` is an np.ndarray of type np.int64
+ containing the locations of the tensor elements within A.data, i.e.
+ `A.data[locations]` contains the elements belonging to the tensor with
+ quantum numbers `(q,q). `shape` is the shape of the corresponding array.
Returns:
dict: Dictionary mapping charge to np.ndarray of rank 2 (a matrix)
+
"""
if self.rank != 2:
raise ValueError(
"`get_diagonal_blocks` can only be called on a matrix, but found rank={}"
.format(self.rank))
return retrieve_non_zero_diagonal_blocks(
- data=self.data, charges=self.charges, flows=self.flows)
+ data=self.data,
+ charges=self.charges,
+ flows=self.flows,
+ return_data=return_data)
def reshape(tensor: BlockSparseTensor,