Repository: pbiswas101/Mathball (js)

Issue:
Kaprekar Number
### Do the checklist before filing the issue:

- [ ] Is this something you can **debug and fix**?
- [x] Do you have Node.js and all the relevant dev-dependencies installed?
- [ ] Is this a **feature request** that you can add?

###### NOTE: Provide a clear and concise description of the feature that needs to be added! Or if its a bug, then provide the necessary steps to reproduce it.

- *Give your answer below:*

------------

[Function: **M.isKaprekar()**] needs to be added!
For more info:

https://www.geeksforgeeks.org/kaprekar-number/

*M.isKaprekar()* needs to accept a positive integer and all other arguments passed should throw a type error which needs to be handled gracefully! For error handling, you should refer to how other features like M.isArmstrong() is implemented.

Pull request description:
Adding matrix exponentiation function. Issue #95
### Do the checklist before submitting the PR:

- [x] Have you read the guidelines mentioned in **CONTRIBUTING.md**?
- [x] Have you squashed your commits?

**Q**: What version of *Node.js* you've used in the project? (`e.g. Node v10.11.0`)
**A**:v11.6.0

**Q**: Mention the *Issue Number*! (`e.g. Fixed #8`)
**A**:#95

- *Give additional information regarding the PR below:*

------------


Patch:
diff --git a/README.md b/README.md
index c2c1d98..30db972 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,7 @@ $ npm install mathball --save
 
 - **Range of Numbers** - [rangePrime][7] - [rangeFibonacci][8] - [rangePalindrome][6]
 
-- **Mathematical Utilities** - [Complex][49] - [frequency][40] - [gcd][10] - [getAllPerm][55] - [isEven][11] - [isOdd][12] - [lcm][13] - [length][14] - [max][15] - [min][16] - [modInv][39] - [nCr][48] - [pow][46] - [sort][17] - [sum][18] - [toDegrees][50] - [toRadians][51] - [matrixMultiply][58]
+- **Mathematical Utilities** - [Complex][49] - [frequency][40] - [gcd][10] - [getAllPerm][55] - [isEven][11] - [isOdd][12] - [lcm][13] - [length][14] - [max][15] - [min][16] - [modInv][39] - [nCr][48] - [pow][46] - [sort][17] - [sum][18] - [toDegrees][50] - [toRadians][51] - [matrixMultiply][58] - [matrixExpo][59]
 
 - **Data Structures** - [priorityQueue][44] - [stack][53] - [graph][57]
 
@@ -127,3 +127,4 @@ The MIT License 2019 - [Priyabrata Biswas][20].
 [56]: https://github.com/pbiswas101/Mathball/blob/master/src/ugly/index.js
 [57]: https://github.com/pbiswas101/Mathball/blob/master/src/graph/index.js
 [58]: https://github.com/pbiswas101/Mathball/blob/master/src/matrixMultiply/index.js
+[59]: https://github.com/pbiswas101/Mathball/blob/master/src/matrixExponentiation/index.js
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index 67034a7..04ce4fc 100644
--- a/src/index.js
+++ b/src/index.js
@@ -38,6 +38,7 @@ const frequency = require('./frequency'),
 	min = require('./min'),
 	modInv = require('./modInv'),
 	matrixMultiply = require('./matrixMultiply'),
+	matrixExpo = require('./matrixExponentiation'),
 	pow = require('./pow'),
 	sort = require('./sort'),
 	sum = require('./sum'),
@@ -75,6 +76,7 @@ module.exports = {
 	isLucky: lucky.isLucky,
 	magic: magic.magic,
 	matrixMultiply,
+	matrixExpo: matrixExpo.matrixExpo,
 	max,
 	min,
 	nCr,
diff --git a/src/matrixExponentiation/index.js b/src/matrixExponentiation/index.js
new file mode 100644
index 0000000..bdba046
--- /dev/null
+++ b/src/matrixExponentiation/index.js
@@ -0,0 +1,52 @@
+/*Fast way to implement matrix exponentiation
+    Function: matrixExpo(matrix, power)
+*/
+
+const validate = require('../validation/number-array'),
+      validateNumber = require('../validation/positive-integer'),
+      multiply = require('../matrixMultiply');
+
+function matrixExpo(matrix, power, dimension){
+    let i, j, answer = [], temp = [];
+    
+
+    //Generating identity matrix of order 'dimension'
+    for(i = 0; i< dimension; i++){
+        for(j = 0; j< dimension; j++){
+            if(i == j){
+                temp.push(0);
+            }
+            else{
+                temp.push(1);
+            }
+        }
+        answer.push(temp.reverse());
+        temp = [];
+    }
+
+    while(power > 0){
+        if(power%2 === 1){
+            answer = multiply(matrix, answer);
+        }
+        matrix = multiply(matrix, matrix);
+        power = Math.floor(power/2);
+    }
+
+    return answer;
+}
+
+exports.matrixExpo = (mat1, power) => {
+    
+    validateNumber(power, "matrixExpo");
+    let dimension = mat1.length;
+    
+    for(let i = 0; i< dimension; i++){
+
+        validate(mat1[i], "matrixExpo");
+
+        if(mat1[i].length !== dimension){
+            return "Not a square matrix";
+        }
+    }
+    return matrixExpo(mat1, power, dimension);
+};
\ No newline at end of file


Test patch:
diff --git a/test/matrixExponentiation-spec.js b/test/matrixExponentiation-spec.js
new file mode 100644
index 0000000..1494a29
--- /dev/null
+++ b/test/matrixExponentiation-spec.js
@@ -0,0 +1,25 @@
+const assert = require('assert'),
+        matrixExpo = require('../src/matrixExponentiation').matrixExpo;
+
+describe('[Funtion: matrixExpo]',() => {
+
+    it('should be a function', () => {
+        assert.strictEqual(typeof matrixExpo, 'function');
+    });
+
+    it('should return an error if the matrix is not a square matrix', () => {
+        assert.strictEqual(matrixExpo([[1,2], [3]], 2), "Not a square matrix");
+    });
+
+    it('should return an error if the power is not a positive integer', () => {
+        assert.throws(() => matrixExpo([[1,2], [3,4]], -2), TypeError);
+    });
+
+    it('should return [[ 37, 54 ], [ 81, 118 ]] when ([[1,2], [3,4]], 3) is passed as arguments', () => {
+        assert.deepEqual(matrixExpo([[1,2], [3,4]], 3), [[ 37, 54 ], [ 81, 118 ]] );
+    });
+
+    it('should return [[ 7, 10 ], [ 15, 22 ]] when ([[1,2], [3,4]], 2) is passed as arguments', () => {
+        assert.deepEqual(matrixExpo([[1,2], [3,4]], 2), [[ 7, 10 ], [ 15, 22 ]] );
+    });
+});
\ No newline at end of file