Reduction in Action

Code
{
  const container = d3
    .create("div")
    .attr("class", "mat-container")
    .style("margin", "auto");

  container
    .selectAll(".row")
    .data(A)
    .join("div")
    .attr("class", "row")
    .selectAll("div")
    .data((d) => d)
    .join("div")
    .attr("class", "element")
    .style("background", "#eee")
    .style("width", "60px")
    .style("min-height", "60px")
    .style("padding", "5px")
    .style("margin", "2px")
    .style("text-align", "center")
    .style("border-radius", "5px")
    .style("display", "inline-block")
    .style("border", "2px solid white")
    .style("font-size", "15px")
    .style("line-height", "60px")
    .style("overflow", "hidden")
    .text((d) => d);
  yield container.node();

  let pivot,
    antiPivot = [];
  let offset = 0;
  for (let i = 0; i < steps.length; i++) {
    let step = steps[i];

    if (step.name === "offset") {
      container
        .selectAll(".row")
        .filter((d, k) => k === step.offset)
        .selectAll(".element")
        .style("background", "#BDF3C2");
      container
        .selectAll(".row")
        .selectAll(".element")
        .filter((d, k) => k === step.offset)
        .style("background", "#BDF3C2");

      offset = step.offset + 1;
    }

    clean(offset);

    if (step.pivot) {
      pivot = [...step.pivot];
      showPivot(pivot);
    }
    if (step.antiPivot) {
      antiPivot = [...step.antiPivot];
      showAntiPivot(antiPivot);
    }

    await Promises.delay(delay);

    if (step.name === "exchangeRows") {
      container
        .selectAll(".row")
        .filter((d, k) => k === step.args[0] || k === step.args[1])
        .selectAll(".element")
        .filter((d, k) => k >= offset)
        .style("background", "beige");
      await Promises.delay(delay);

      pivot[0] = step.offset;
      showPivot(pivot);
    } else if (step.name === "exchangeCols") {
      container
        .selectAll(".row")
        .filter((d, k) => k >= offset)
        .selectAll(".element")
        .filter((d, k) => k === step.args[0] || k === step.args[1])
        .style("background", "beige");
      await Promises.delay(delay);
      pivot[1] = step.offset;
      showPivot(pivot);
    } else if (step.name === "replaceRow") {
      container
        .selectAll(".row")
        .filter((d, k) => k === step.args[0] || k === step.args[1])
        .selectAll(".element")
        .filter((d, k) => k >= offset)
        .style("background", "beige");
      await Promises.delay(delay);
    } else if (step.name === "replaceCol") {
      container
        .selectAll(".row")
        .filter((d, k) => k >= offset)
        .selectAll(".element")
        .filter((d, k) => k === step.args[0] || k === step.args[1])
        .style("background", "beige");
      await Promises.delay(delay);
    }

    container
      .selectAll(".row")
      .data(step.mat)
      .selectAll("div")
      .data((d) => d)
      .html((d) => d);
  }
  container
    .selectAll(".row")
    .selectAll(".element")
    .style("border", "2px solid white");

  function clean(offset) {
    container
      .selectAll(".row")
      .filter((d, k) => k >= offset)
      .selectAll(".element")
      .filter((d, k) => k >= offset)
      .style("background", "#eee");
  }

  function showPivot([i, j]) {
    container
      .selectAll(".row")
      .selectAll(".element")
      .style("border", "2px solid white");
    container
      .selectAll(".row")
      .filter((d, k) => k === i)
      .selectAll(".element")
      .filter((d, k) => k === j)
      .style("border", "3px solid green");
  }
  function showAntiPivot([i, j]) {
    container
      .selectAll(".row")
      .filter((d, k) => k === i)
      .selectAll(".element")
      .filter((d, k) => k === j)
      .style("border", "3px solid red");
  }
}

For more details, see: Normal Form.

Code
delay = 300

A = {
  let rows = 7; //d3.randomInt(1, 10)();
  let cols = 7; //d3.randomInt(1, 10)();

  return d3.range(0, rows).map((row) => {
    return d3.range(0, cols).map((elm) => d3.randomInt(-3, 3)());
  });
}

nf = require("https://bundle.run/@tdajs/normal-form@2.0.0")

steps = new nf.NormalForm(A, {
  recordSteps: true
}).steps