How do I invert a matrix in tensorflow-js? - tensorflow.js

Simple question. Is there an operation for it, also, how do you create an identity matrix? I've checked the documentation but can't find a single operation.

For now tensorflowJs does not have any direct operator that can return the inverse of a matrix M.
You can consider using the module Math.js
Having said that, it is possible to invert a matrix using tensorflowJs operators.
The following calculates the inverse of a matrix using the adjoint method with tensorflowJs operators.
// calculate the determinant of a matrix m
function det(m) {
return tf.tidy(() => {
const [r, _] = m.shape
if (r === 2) {
const t = m.as1D()
const a = t.slice([0], [1]).dataSync()[0]
const b = t.slice([1], [1]).dataSync()[0]
const c = t.slice([2], [1]).dataSync()[0]
const d = t.slice([3], [1]).dataSync()[0]
result = a * d - b * c
return result
} else {
let s = 0;
rows = [...Array(r).keys()]
for (let i = 0; i < r; i++) {
sub_m = m.gather(tf.tensor1d(rows.filter(e => e !== i), 'int32'))
sli = sub_m.slice([0, 1], [r - 1, r - 1])
s += Math.pow(-1, i) * det(sli)
}
return s
}
})
}
// the inverse of the matrix : matrix adjoint method
function invertMatrix(m) {
return tf.tidy(() => {
const d = det(m)
if (d === 0) {
return
}
[r, _] = m.shape
rows = [...Array(r).keys()]
dets = [];
for (let i = 0; i < r; i++) {
for (let j = 0; j < r; j++) {
const sub_m = m.gather(tf.tensor1d(rows.filter(e => e !== i), 'int32'))
let sli
if (j === 0) {
sli = sub_m.slice([0, 1], [r - 1, r - 1])
} else if (j === r - 1) {
sli = sub_m.slice([0, 0], [r - 1, r - 1])
} else {
const [a, b, c] = tf.split(sub_m, [j, 1, r - (j + 1)], 1)
sli = tf.concat([a, c], 1)
}
dets.push(Math.pow(-1, (i + j)) * det(sli))
}
}
com = tf.tensor2d(dets, [r, r])
tr_com = com.transpose()
inv_m = tr_com.div(tf.scalar(d))
return inv_m
})
}
const a = tf.tensor2d([1, 3, 3, 1, 4, 3, 1, 3, 4], [3, 3])
console.log("matrix a")
a.print()
const i = invertMatrix(a)
console.log("inverse i")
i.print()
const prod = i.dot(a)
console.log("a * i")
prod.print()
<html>
<head>
<!-- Load TensorFlow.js -->
<script src="https://cdn.jsdelivr.net/npm/#tensorflow/tfjs#0.12.0"> </script>
</head>
<body>
</body>
</html>
Using the Jordan-Gauss method, one can calculate the inverse of the matrix this way:
// calculate the determinant of a matrix m
function det(m) {
return tf.tidy(() => {
const [r, _] = m.shape
if (r === 2) {
const t = m.as1D()
const a = t.slice([0], [1]).dataSync()[0]
const b = t.slice([1], [1]).dataSync()[0]
const c = t.slice([2], [1]).dataSync()[0]
const d = t.slice([3], [1]).dataSync()[0]
result = a * d - b * c
return result
} else {
let s = 0;
rows = [...Array(r).keys()]
for (let i = 0; i < r; i++) {
sub_m = m.gather(tf.tensor1d(rows.filter(e => e !== i), 'int32'))
sli = sub_m.slice([0, 1], [r - 1, r - 1])
s += Math.pow(-1, i) * det(sli)
}
return s
}
})
}
// the inverse of the matrix : jordan-gauss method
function invertM(m) {
return tf.tidy(() => {
if (det(m) === 0) {
return
}
const [r, _] = m.shape
let inv = m.concat(tf.eye(r), 1)
rows = [...Array(r).keys()]
for (let i = 0; i < r; i++) {
inv = tf.tidy(() => {
for (let j = i + 1; j < r; j++) {
const elt = inv.slice([j, i], [1, 1]).as1D().asScalar()
const pivot = inv.slice([i, i], [1, 1]).as1D().asScalar()
let newrow
if (elt.dataSync()[0] !== 0) {
newrow = inv.gather(tf.tensor1d([i], 'int32')).sub(inv.gather(tf.tensor1d([j], 'int32')).div(elt).mul(pivot)).as1D()
const sli = inv.gather(rows.filter(e => e !== j))
const arr = []
if (j === 0) {
arr.push(newrow)
}
sli.unstack().forEach((t, ind) => {
if (ind !== j) {
arr.push(t)
} else {
arr.push(newrow)
arr.push(t)
}
})
if (j === r - 1) {
arr.push(newrow)
}
inv = tf.stack(arr)
}
}
return inv
})
}
const trian = tf.unstack(inv)
len = trian.length
trian[len - 1] = trian[len - 1].div(trian[len - 1].slice(trian[len - 1].shape[0] - 1, 1).asScalar())
for (let i = r - 2; i > -1; i--) {
for (j = r - 1; j > i; j--) {
trian[i] = trian[i].sub(trian[j].mul(trian[i].slice(j, 1).asScalar()))
}
trian[i] = trian[i].div(trian[i].slice(i, 1).asScalar())
}
return tf.split(tf.stack(trian), 2, 1)[1]
})
}
const a = tf.tensor2d([1, 3, 3, 1, 4, 3, 1, 3, 4], [3, 3])
console.log("matrix a")
a.print()
const i = invertM(a)
console.log("inverse i")
i.print()
const prod = i.dot(a)
console.log("a * i")
prod.print()
<html>
<head>
<!-- Load TensorFlow.js -->
<script src="https://cdn.jsdelivr.net/npm/#tensorflow/tfjs#0.12.0"> </script>
</head>
<body>
</body>
</html>

For the identity matrix you can use tf.eye() and I am not sure what you mean by inverting a matrix but it could either be tf.reciprocal() which performs 1/x element-wise or you want to transpose it, which would be done using tf.transpose().

Related

SetTimeout() function not scaling in React (in recursive function)

I'm calling a function using the setTimeout() function from a recursive function, however increasing the timeout time doesn't bring any change to the speed of the execution.
I was trying to implement Mergesort, the merger() function recursively calls itself and also calls another function Merge() using SetTimeout() but no matter how large I set the timeout interval to be, the execution takes place at the same speed.
I found several previous questions on setTimeout not working, (I came across a way to multiply for loop's variable with the time interval, How can I do something like that here?) but I'm a beginner in development and react and couldn't connect them to this, I'd like to know why exactly it is happening.
This is the problem area.
function merger(l,r){
if(l>=r){
return;//returns recursively
}
var m =l+ parseInt((r-l)/2);
merger(l,m);
merger(m+1,r);
setTimeout(merge,10,l,m,r)
}
More detailed code
import { useState } from "react";
function Visualiser () {
const [array,setarray] = useState([]);
const gendivs = () => {
var nums = [];
for (let i=0; i<250; i++ ){
let x = Math.floor(Math.random()*600 + 10);
nums[i] = x;
}
setarray(nums)
}
const merge = (l,m,r) => {
setTimeout(()=>{
setarray((prev) => {
const arr = [...prev]
var n1 = m - l + 1;
var n2 = r - m;
// Create temp arrays
var L = [];
var R = [];
for (let i = 0; i < n1; i++){
L[i] = arr[l + i];
}
for (let j = 0; j < n2; j++) {
R[j] = arr[m + 1 + j];
}
// Copy data to temp arrays L[] and R[]
// Merge the temp arrays back into arr[l..r]
// Initial index of first subarray
var i = 0;
// Initial index of second subarray
var j = 0;
// Initial index of merged subarray
var k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
}
else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
return arr;
})
}, 10)
}
function merger(l,r){
if(l>=r){
return;//returns recursively
}
var m =l+ parseInt((r-l)/2);
merger(l,m);
merger(m+1,r);
setTimeout(merge,10,l,m,r)
}
function mergeSort () {
let l = 0;
let r = 249;
merger(l,r);
}
const selectsort = () => {
let t = [...array]
// One by one move boundary of unsorted subarray
for (let i = 0; i < 250; i++)
{
// Find the minimum element in unsorted array
let idx = i;
for (let j = i + 1; j < 250; j++) {
if (t[j] < t[idx])
idx = j;
}
var temp1 = t[i];
t[i] = t[idx];
t[idx] = temp1
// Swap the found minimum element with the first element
setTimeout(()=> {
setarray( (prev) => {
let arr = [...prev]
const temp = arr[i]
arr[i] = arr[idx]
arr[idx] = temp
return arr
})
},i*50)
}
}
const divs = array.map((ar, index) =>{
const h = ar.toString()+ "px"
return <div key={index} style = {{backgroundColor:"turquoise", margin: "1px", height: h, width: "3px"}}></div>
})
return (
<div>
<div className="btns">
<button onClick={gendivs}> Generate Array </button>
<button onClick={selectsort}> Selection Sort</button>
<button onClick={mergeSort}> Merge Sort</button>
</div>
<div className="d"> {divs} </div>
</div>
);
}
export default Visualiser;

Write a function which return any number of hexadecimal colors in an array

I stack, I don't know how to create arrays of hexadecimal colors. If You know, please share.
function concatArray(n){
let arr = []
let hashtag = '#'
let semicolon = ','
let r = Math.floor(Math.random() * 16)
let g = Math.floor(Math.random() * 16)
let b = Math.floor(Math.random() * 16)
for(i = 0; i < n; i++){
arr.push(hashtag,r,g,b,semicolon)
}
console.log(arr.join(''))
}
let arrayOfHexaColors = () => {
let allHexCodes = '123456789abcdef';
let loopCount = parseInt(Math.random() * 50);
let hexColorArr = [];
for(let x=1; x<=loopCount; x++) {
let hexChars = [];
for (let i = 0; i < 6; i++) {
hexChars.push(allHexCodes[parseInt(Math.random() * allHexCodes.length) - 1]);
}
hexColorArr.push('#' + hexChars.join(''));
}
return hexColorArr;
}
console.log(arrayOfHexaColors());

Merge Function for two arrays

Merge Function for two arrays, The function is not working properly and doesn't give the required answer. I want that the sorted arrays are merged up as it is the function saying, but it doesn't work.
var Merge = function(array,array1,array2)
{
var n_array = array.length;
var n_array1 = array1.length;
var i = j = k = 0;
while(i < n_array && j < n_array1)
{
if(array[i] <= array2[j])
{
array2[k] = array[i];
i = i + 1;
}
else
{
array2[k] = array1[j];
j = j + 1;
}
k = k + 1;
}
while(i < n_array)
{
array2[k] = array[i];
i = i + 1;
k = k + 1;
}
while(j < n_array1)
{
array2[k] = array1[j];
j = j + 1;
k = k + 1;
}
return array2;
};
array = [1,3,5,7];
array1 = [2,4,6,8];
array2 = [];
var result = Merge(array,array1,array2);
console.log("The array is sorted is " + result);
Why my code give an answer:
The array is sorted is 2,4,6,8,1,3,5,7
var Merge = function(array,array1,array2)
{
var n_array = array.length;
var n_array1 = array1.length;
var i = j = k = 0;
while(i < n_array && j < n_array1)
{
if(array[i] <= array1[j])
{
array2[k] = array[i];
i = i + 1;
}
else
{
array2[k] = array1[j];
j = j + 1;
}
k = k + 1;
}
while(i < n_array)
{
array2[k] = array[i];
i = i + 1;
k = k + 1;
}
while(j < n_array1)
{
array2[k] = array1[j];
j = j + 1;
k = k + 1;
}
return array2;
};
array = [1,3,5,7];
array1 = [2,4,6,8];
array2 = [];
var result = Merge(array,array1,array2);
console.log("The array is sorted is " + result);
It Works :)
This is the edited solution to the OP's problem.
While the fix for your code is mentioned above, that is a lot of lines for just doing a merge and sort. If you know you will be dealing with numbers you could use the following:
var arr = [1, 10, 22];
var arr1 = [20, 17, 3];
var arr2 = arr.concat(arr1);
sortAsc(arr2);
function sortAsc(arrayToSort){
return arrayToSort.sort(function(a, b){
return a - b;
});
}

All possible combinations across arrays in nodejs

Lets say I have three arrays:
var arr1 = ['red', 'orange', 'yellow',];
var arr2 = ['car', 'bus'];
var arr3 = ['china'];
How to get the following combinations:
1. Order matters,
2. Each result(can be a array) should contain 0..1 element of each arr
3. Element of arr1,arr2,arr3 can appear 0..1 times :
red,car,china
red,china,car
car,red,china
car,china,red
china,car,red,
china,red,car
red,bus,china
red,china,bus
bus,red,china
bus,china,red
china,bus,red,
china,red,bus
orange,car,china
orange,china,bus
bus,orange,china
bus,china,orange
china,bus,orange,
china,orange,bus
orange,bus,china
orange,china,bus
bus,orange,china
bus,china,orange
china,bus,orange,
yellow,car,china
yellow,china,car
car,yellow,china
car,china,yellow
china,car,yellow,
china,yellow,car
yellow,bus,china
yellow,china,bus
bus,yellow,china
bus,china,yellow
china,bus,yellow,
china,yellow,bus
red,car
car,red
red,bus
bus,red
orange,car
car,orange,
orange,bus
bus,orange,
yellow,car
car,yellow,
yellow,bus
bus,yellow,
red,china
china,red,
orange,china
china,orange,
yellow,china
china,yellow,
car,china
china,car,
bus,china
china,bus,
red,
orange,
yellow,
car,
bus,
china,
What I could not figure out is how to control the appear times in the element of each arr, my code is as follows:
function get_titles_appearances(titles_columns) {
titles_columns = titles_columns || [];
var n = titles_columns.length;
if (n === 0) { return [] }
if (n === 1) { return titles_columns[0] }
var save = function () {
var m = groups.length, c = [];
while (m--) { c[m] = groups[m] }
rtn.push(c);
}
var i = 0, len = 0, counter = [], groups = [], rtn = [];
for (; i < n; i++) {
counter[i] = 0;
groups[i] = titles_columns[i][0];
}
save();
while (true) {
i = n - 1, len = titles_columns[i].length;
if (++counter[i] >= len) {
while (counter[i] >= len) {
if (i === 0) { return rtn }
groups[i] = titles_columns[i][0];
counter[i--] = 0;
counter[i]++;
len = titles_columns[i].length;
}
}
groups[i] = titles_columns[i][counter[i]];
save();
}
}
_.forEach(get_titles_appearances(titles_columns_config_default), function (value) {
// titles_appearances.push( _.join(value, '')+"':'"+_.join(value, ','))
titles_appearances = titles_appearances+"{"+ _.join(value, '')+":"+_.join(value, ',')+"},"
})
titles_columns_config_default refer to [arr1,arr2,arr3]

gradient bars Chart JS

I want to be able to color each bar with a different color in a gradient way like the folloing image
Can any body tell me how to do that?
This is using ChartJS 2.4.0. http://www.chartjs.org/docs/latest/charts/bar.html
Given x number of datapoints in your Bar Graph, you'll need to generate an array of x number of colors: one color per each datapoint.
data: [10,20,30,40,50,60,70,80],
backgroundColor: ["#ded21e", "#cbd026", "#b8ce2d", "#a5cc35", "#93cb3c", "#80c944", "#6dc74b", "#5ac553"]
Here is a CodePen: https://codepen.io/pgardner/pen/GyeBLW
Credit goes to Neil McCallion, whose CodePen here does much of the legwork: https://codepen.io/njmcode/pen/axoyD
Here is the essential function:
function color() {
// Converts a #ffffff hex string into an [r,g,b] array
function hex2rgb(hex) {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? [
parseInt(result[1], 16),
parseInt(result[2], 16),
parseInt(result[3], 16)
] : null;
}
// Inverse of the above
function rgb2hex(rgb) {
return '#' + ((1 << 24) + (rgb[0] << 16) + (rgb[1] << 8) + rgb[2]).toString(16).slice(1);
}
// Interpolates two [r,g,b] colors and returns an [r,g,b] of the result
// Taken from the awesome ROT.js roguelike dev library at
// https://github.com/ondras/rot.js
function _interpolateRgb(color1, color2, factor) {
if (arguments.length < 3) { factor = 0.5; }
let result = color1.slice();
for (let i=0;i<3;i++) {
result[i] = Math.round(result[i] + factor*(color2[i]-color1[i]));
}
return result;
}
function rgb2hsl(color) {
const r = color[0]/255;
const g = color[1]/255;
const b = color[2]/255;
const max = Math.max(r, g, b), min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max == min) {
h = s = 0; // achromatic
} else {
let d = max - min;
s = (l > 0.5 ? d / (2 - max - min) : d / (max + min));
switch(max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return [h, s, l];
}
function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
}
function hsl2rgb(color) {
let l = color[2];
if (color[1] == 0) {
l = Math.round(l*255);
return [l, l, l];
} else {
let s = color[1];
let q = (l < 0.5 ? l * (1 + s) : l + s - l * s);
let p = 2 * l - q;
let r = hue2rgb(p, q, color[0] + 1/3);
let g = hue2rgb(p, q, color[0]);
let b = hue2rgb(p, q, color[0] - 1/3);
return [Math.round(r*255), Math.round(g*255), Math.round(b*255)];
}
}
function _interpolateHsl(color1, color2, factor) {
if (arguments.length < 3) { factor = 0.5; }
let hsl1 = rgb2hsl(color1);
let hsl2 = rgb2hsl(color2);
for (let i=0;i<3;i++) {
hsl1[i] += factor*(hsl2[i]-hsl1[i]);
}
return hsl2rgb(hsl1);
}
function generateGradient(color1, color2, total, interpolation) {
const colorStart = typeof color1 === 'string' ? hex2rgb(color1) : color1;
const colorEnd = typeof color2 === 'string' ? hex2rgb(color2) : color2;
// will the gradient be via RGB or HSL
switch(interpolation) {
case 'rgb':
return colorsToGradientRgb(colorStart, colorEnd, total);
case 'hsl':
return colorsToGradientHsl(colorStart, colorEnd, total);
default:
return false;
}
}
function colorsToGradientRgb(startColor, endColor, steps) {
// returns array of hex values for color, since rgb would be an array of arrays and not strings, easier to handle hex strings
let arrReturnColors = [];
let interimColorRGB;
let interimColorHex;
const totalColors = steps;
const factorStep = 1 / (totalColors - 1);
for (let idx = 0; idx < totalColors; idx++) {
interimColorRGB = _interpolateRgb(startColor, endColor, factorStep * idx);
interimColorHex = rgb2hex(interimColorRGB);
arrReturnColors.push(interimColorHex);
}
return arrReturnColors;
}
function colorsToGradientHsl(startColor, endColor, steps) {
// returns array of hex values for color, since rgb would be an array of arrays and not strings, easier to handle hex strings
let arrReturnColors = [];
let interimColorRGB;
let interimColorHex;
const totalColors = steps;
const factorStep = 1 / (totalColors - 1);
for (let idx = 0; idx < totalColors; idx++) {
interimColorRGB = _interpolateHsl(startColor, endColor, factorStep * idx);
interimColorHex = rgb2hex(interimColorRGB);
arrReturnColors.push(interimColorHex);
}
return arrReturnColors;
}
return {
generateGradient
};
}
Given 2 colors '#ded21e' and '#5ac553', you would call the function in this manner:
let arrBarGraphColors = color().generateGradient('#ded21e', '#5ac553', data.length, 'rgb');
Specify between 'rgb' and 'hsl'. The linked CodePens should give you an idea of the differences between the two.

Resources