diff --git a/HISTORY.md b/HISTORY.md
index e0abb6ea..7410aa15 100755
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -9,7 +9,10 @@
* **Documentation Updates:**
* updated manual (e.g. p.20) with hyper-semantics of ITEM OF, thanks Brian
-### 2021-02-06
+### 2021-02-09
+* lists: refactored matrix ops to avoid JS stack overflows
+
+### 2021-02-08
* lists, objects, threads: new RESHAPE primitive
* lists: added internal naive (recursive) version of CROSSPRODUCT
* lists: added TRANSPOSE for higher dimensions, thanks, Brian!
diff --git a/snap.html b/snap.html
index 09e1bab6..a1e06016 100755
--- a/snap.html
+++ b/snap.html
@@ -9,7 +9,7 @@
-
+
diff --git a/src/lists.js b/src/lists.js
index 61f1f0e5..88ffb7dd 100644
--- a/src/lists.js
+++ b/src/lists.js
@@ -63,7 +63,7 @@ MorphicPreferences, TableDialogMorph, SpriteBubbleMorph, SpeechBubbleMorph,
TableFrameMorph, TableMorph, Variable, isSnapObject, Costume, contains, detect,
ZERO, WHITE*/
-modules.lists = '2021-February-08';
+modules.lists = '2021-February-09';
var List;
var ListWatcherMorph;
@@ -544,7 +544,8 @@ List.prototype.getDimension = function (rank = 0) {
};
List.prototype.width = function () {
- // private - answer the maximum length of my direct sub-lists (columns), if any
+ // private - answer the maximum length of my direct sub-lists (columns),
+ // if any
var i, item,
width = 0,
len = this.length();
@@ -660,14 +661,27 @@ List.prototype.crossproduct = function () {
// expects myself to be a list of lists.
// answers a new list of all possible tuples
// with one item from each of my sublists
- if (this.isEmpty()) {
- return new List([new List()]);
+ var result = new List(),
+ len = this.length(),
+ lengths = this.map(each => each.length()),
+ size = lengths.itemsArray().reduce((a, b) => a * b),
+ i, k, row, factor;
+
+ for (i = 1; i <= size; i += 1) {
+ row = new List();
+ factor = 1;
+ for (k = 1; k <= len; k += 1) {
+ row.add(
+ this.at(k).at(
+ ((Math.ceil(i / ((size / lengths.at(k)) * factor)) - 1) %
+ lengths.at(k)) + 1
+ )
+ );
+ factor /= lengths.at(k);
+ }
+ result.add(row);
}
- return this.at(1).map(
- first => this.cdr().crossproduct().map(
- each => this.cons(first, each)
- )
- ).flatten();
+ return result;
};
List.prototype.strideTranspose = function () {