Memoize not working as expected? - javascript

I'm currently learning about memoization. As a simple exercise I implemented memoization with a fibonacci. However I'm having problems as to why when I do not rename the memoized function it takes slower to complete than when I rename it. Take a look at the code.
This doesn't work correctly and doesn't cache correctly.
function memoize(func) {
const cache = {};
return function(args) {
const cacheKeys = Object.keys(cache).map(el => +el);
if (cacheKeys.includes(args)) {
return cache[args];
}
cache[args] = func(args);
return cache[args];
};
}
function wrapped_fibonacci(n) {
if (n <= 2) {
return 1;
}
return wrapped_fibonacci(n - 1) + wrapped_fibonacci(n - 2);
}
const fibonacci = memoize(wrapped_fibonacci); // <== I do not rename the function.
for (let i = 1; i <= 40; i++) {
console.log(fibonacci(i));
}
However, when I write my code like this. It works correctly and is performant
function memoize(func) {
const cache = {};
return function(args) {
const cacheKeys = Object.keys(cache).map(el => +el);
if (cacheKeys.includes(args)) {
return cache[args];
}
cache[args] = func(args);
return cache[args];
};
}
function fibonacci(n) {
if (n <= 2) {
return 1;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
fibonacci = memoize(fibonacci); //<== I rename the function
for (let i = 1; i <= 40; i++) {
console.log(fibonacci(i));
}
As you can see. I just reassigned the function name.
I'm doing these tests on node.js v8.3.0
The results of the first is as such.
time node fib.js
real 0m2.413s │~
user 0m2.400s │~
sys 0m0.008s
The results of the second goes as such
time node fib.js
real 0m0.263s │~
user 0m0.252s │~
sys 0m0.008s
THATS 1.8S DIFFERENCE
Anyone able to shed some light on this?

In the working example, you're replacing fibonacci with a memoized function also called fibonacci. The recursive calls are using this memoized function, because fibonacci-the-original was replaced by fibonacci-the-memoized.
In the non-working example, you're creating a memoized function fibonacci from wrapped_fibonacci, but that function still calls wrapped_fibonacci, the unmemoized original, recursively.
If you'd also replace wrapped_fibonacci, it would speed up again:
const fibonacci = wrapped_fibonacci = memoize(wrapped_fibonacci)

Related

How to write a function to evaluate this expression? [duplicate]

A friend of mine challenged me to write a function that works with both of these scenarios
add(2,4) // 6
add(2)(4) // 6
My instinct was the write an add() function that returns itself but I'm not sure I'm heading in the right direction. This failed.
function add(num1, num2){
if (num1 && num2){
return num1 + num2;
} else {
return this;
}
}
alert(add(1)(2));
So I started reading up on functions that return other functions or return themselves.
http://davidwalsh.name/javascript-functions
JavaScript: self-calling function returns a closure. What is it for?
JavaScript: self-calling function returns a closure. What is it for?
I am going to keep trying, but if someone out there has a slick solution, I'd love to see it!
I wrote a curried function whose valueOf() method and function context (this) are bound with the sum no matter how many arguments are passed each time.
/* add function */
let add = function add(...args) {
const sum = args.reduce((acc, val) => acc + val, this);
const chain = add.bind(sum);
chain.valueOf = () => sum;
return chain;
}.bind(0);
/* tests */
console.log('add(1, 2) = ' + add(1, 2));
console.log('add(1)(2) = ' + add(1)(2));
/* even cooler stuff */
console.log('add(1, 2)(3) = ' + add(1, 2)(3));
console.log('add(1, 2, 3)(4, 5)(6) = ' + add(1, 2, 3)(4, 5)(6));
/* retains expected state */
let add7 = add(7);
console.log('let add7 = add(7)');
console.log('add7(3) = ' + add7(3));
console.log('add7(8) = ' + add7(8));
The reason why both mechanisms are required is because the body of add() must use the called function's bound context in order to access the sum of the intermediate partial application, and the call site must use the valueOf() member (either implicitly or explicitly) in order to access the final sum.
There is an article on Dr.Dobs Journal about "Currying and Partial Functions in JavaScript" which describes exactly this problem.
One solution found in this article is:
// a curried add
// accepts partial list of arguments
function add(x, y) {
if (typeof y === "undefined") { // partial
return function (y) {
return x + y;
};
}
// full application
return x + y;
}
function add(num1, num2){
if (num1 && num2) {
return num1 + num2;
} else if (num1) {
return function(num2){return num1 + num2;};
}
return 0;
}
The concept that you're looking for is called currying and it has to do with function transformation and partial function application. This is useful for when you find yourself calling the same function over and over with mostly the same arguments.
An example of implementing add(2)(6) via currying would look something like this...
function add(x,y) {
if (typeof y === 'undefined') {
return function(y) {
return x + y;
}
}
}
add(2)(4); // => 6
Additionally, you could do something like this...
var add6 = add(6);
typeof add6; // => 'function'
add6(4); // => 10
var add = function(){
// the function was called with 2 arguments
if(arguments.length > 1)
arguments.callee.first_argument = arguments[0];
// if the first argument was initialized
if(arguments.callee.first_argument){
var result = arguments.callee.first_argument + arguments[arguments.length - 1];
arguments.callee.first_argument = 0;
return result;
}else{// if the function was called with one argument only then we need to memorize it and return the same function handler
arguments.callee.first_argument = arguments.callee.first_argument || arguments[0];
return arguments.callee;
}
}
console.log(add(2)(4));
console.log(add(2, 4));
An extended solution which depends on the environment:
function add(){
add.toString = function(){
var answer = 0;
for(i = 0; i < add.params.length; i++)
answer += add.params[i];
return answer;
};
add.params = add.params || [];
for(var i = 0; i < arguments.length; i++)
add.params.push(arguments[i])
return add;
}
console.log(add(2)(4)(6)(8))
console.log(add(2, 4, 6, 8));
We can use the concept of closures which is provided by Javascript.
Code snippet:
function add(a,b){
if(b !== undefined){
console.log(a + b);
return;
}
return function(b){
console.log(a + b);
}
}
add(2,3);
add(2)(3);
In general you need to have an agreement whether the function should return a function (for calling with more arguments) or the end result. Imagine the add function would have to work like this as well:
add(1, 2, 3)(4, 5) // -> 15
...then it becomes ambiguous, because you might want to call again:
add(1, 2, 3)(4, 5)(6) // -> 21
...and so add(1, 2, 3)(4, 5) should have returned a function, and not 15.
You could for instance agree that you have to call the function again, but without arguments, in order to get the numeric result:
function add(...args) {
if (args.length === 0) return 0;
let sum = args.reduce((a, b) => a+b, 0);
return (...args) => args.length ? add(sum, ...args) : sum;
}
console.log(add()); // 0
console.log(add(1,2,3)()); // 6
console.log(add(1,2,3)(4,5)()); // 15
console.log(add(1,2,3)(4,5)(6)()); // 21
One may think that he/she has to invoke the same function two times, but if you think deeply you will realize that the problem is pretty straight forward, you have to invoke the add function one time then you need to invoke what ever the add function returns.
function add(a){
return function(b){
return a+b;
}
}
console.log(add(20)(20));
//output: 40
you can return function as many as time you want. suppose for y = mx+c
const y= function (m){
return function(x){
return function (c){
return m*x+c
}
}
}
console.log(y(10)(5)(10));
//out put: 60

Random Fibonacci Generator

I'm trying to create a simple program in javascript where the Fibonacci square can be created by a random number sequence but I can't seem to connect both parts of my code. The first side being: the call for a random number and the second part: calculating the Fibonacci square.
var n = function getRandomNum() {
return Math.floor(Math.random()*100) +1;
}
function fib(x) {
if (x < 2) {
return x;
} else {
return fib(x - 1) + fib(x - 2);
}
}
console.log(fib(n));
Tell me where I'm going wrong. These are the errors I get when I run it.
RangeError: Maximum call stack size exceeded
at fib:7:13
at fib:11:12
at fib:11:12
at fib:11:12
at fib:11:12
at fib:11:12
Aside from not invoking the random number generator, you're using a very poorly optimized algorithm. If you think through all the redundant calls that need to take place, you'll see why the stack limit is reached.
var n = function getRandomNum() {
return Math.floor(Math.random() * 100) + 1;
}(); // <-- quick inline invocation... not normally how you'd use this.
console.log(n);
function fib(x) {
function _fib(x, a, b) {
if (x < 2) {
return a;
}
return _fib(x - 1, b, a + b);
}
return _fib(x, 0, 1);
}
console.log(fib(n));
Since you don't call n function, you should call it like the following.
var n = function getRandomNum() {
return Math.floor(Math.random()*100) +1;
}
function fib(x) {
if (x < 2) {
return x;
} else {
return fib(x - 1) + fib(x - 2);
}
}
console.log(fib(n));
But, there's a huge problem in your code, as #rock star mentioned, there's no any optimizing process in your code. That is why your code has caused the problem on memory leak
To avoid this, you can simply use memoization, click this link you don't have any clue on it.
Javascript Memoization Explanation?
So, your code can be improved like the folloiwng, by adapting memoization algorithm.
var n = function getRandomNum() {
return Math.floor(Math.random()*100) +1;
}
var result = [];
result[0] = 1;
result[1] = 1;
function fib(x) {
var ix, ixLen;
for(ix = 0, ixLen = x; ix < ixLen; ix++){
if(!result[ix]){
result[ix] = result[ix-2] + result[ix-1];
}
}
console.log('n:', x, ' result: ', result[ix-1]);
return result[ix-1];
}
console.log(fib(n()));
Compare the result with this site.
http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/fibtable.html

Do I really need to use protoypes for this in javascript? (Practical example)

Can this be written without complexing things with prototypes?
Why? The current code does what I want, but it bothers me how trixy it is to follow and how error prone it is, also seems to be performance wasting since things are duplicated.
Aim? The more I spend using prototype and this I get the sense the code would be simpler and more to the point if this was not the case.
Especially if the this-functions in SystemBlueprint can be rewritten to take an instance as argument instead. And if object Function Log() and Out could just be plain objects somehow? How can Log or Out be extracted outside of SystemBuilder?
Full code in Jsbin
https://jsbin.com/pigosijaxo/edit?js,console (Updated)
// Local for each System object
var SystemData = {
name: '?',
id: 1,
actions: [],
destinations: []
}
// Variables shared among all Systems
const SystemShare = {
global: 1
}
// this-Functions shared among all Systems
function SystemBlueprint() {}
SystemBlueprint.prototype = {
run() {
var length = this.actions.length
for (var i = 0; i < length; i++) {
var result = this.actions[i](arguments, this)
if (result && this.destinations.length > 0) {
for (var n = 0; n < this.destinations.length; n++) {
this.destinations[n].call(null, result)
}
}
}
},
does(algorithm) {
this.actions.push(algorithm)
return this
},
random(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
}
function SystemBuilder(name) {
// copy shared methods
var system = Object.create(SystemBlueprint.prototype)
Object.assign(system, JSON.parse(JSON.stringify(SystemData))) //deep copy
system.name = name
system.id = SystemShare.global++
function Log() {}
Log.prototype.local = () => console.log('fields: ' + JSON.stringify(Object.keys(system))),
system.log = new Log()
function Out(){}
Out.prototype.into = (destination) => {
system.destinations.push(destination)
return system
}
system.out = new Out()
system.trigger = {}
function OnEvent(trigger){
if(trigger === undefined) return
trigger.call(null, system.run.bind(system))
return system
}
system.trigger.on = new OnEvent()
return system
}
var system = new SystemBuilder()
system.my = 'Testing'
system.log.local()
system.does( () => 'printing output...')
system.out.into(console.log)
system.run()
Partial Answer, implementation from comment suggestion by #Bellian, a bit on the way for sure, thanks!
Where? Inside function SystemBuilder(...):
Instead of
function Log() {}
Log.prototype.local = () => console.log('fields: ' + JSON.stringify(Object.keys(system))),
system.log = new Log()
Do this
function _local(system){
console.log('fields: ' + JSON.stringify(Object.keys(system)))
}
system.log = {local: _local.bind(this, system)}

Bluebird promise: why it doesn't timeout?

So, I'm trying to model some long computation. for this purpose I'm computing the fibonacci number. In case when computation takes to much time I need to reject it.
The question: why TimeoutErrror handler doesn't work? How to fix the code?
const expect = require('chai').expect
const Promise = require('bluebird')
function profib(n, prev = '0', cur = '1') {
return new Promise.resolve(n < 2)
.then(function(isTerm) {
if(isTerm) {
return cur
} else {
n = n - 2
return profib(n, cur, strAdd(cur, prev));
}
})
}
const TIMEOUT = 10000
const N = 20000
describe('recursion', function() {
it.only('cancelation', function() {
this.timeout(2 * TIMEOUT)
let prom = profib(N).timeout(1000)
.catch(Promise.TimeoutError, function(e) {
console.log('timeout', e)
return '-1'
})
return prom.then((num) => {
expect(num).equal('-1')
})
})
})
const strAdd = function(lnum, rnum) {
lnum = lnum.split('').reverse();
rnum = rnum.split('').reverse();
var len = Math.max(lnum.length, rnum.length),
acc = 0;
res = [];
for(var i = 0; i < len; i++) {
var subres = Number(lnum[i] || 0) + Number(rnum[i] || 0) + acc;
acc = ~~(subres / 10); // integer division
res.push(subres % 10);
}
if (acc !== 0) {
res.push(acc);
}
return res.reverse().join('');
};
Some info about environment:
➜ node -v
v6.3.1
➜ npm list --depth=0
├── bluebird#3.4.6
├── chai#3.5.0
└── mocha#3.2.0
If I'm reading your code correctly profib does not exit until it's finished.
Timeouts are not interrupts. They are just events added to the list of events for the browser/node to run. The browser/node runs the next event when the code for the current event finishes.
Example:
setTimeout(function() {
console.log("timeout");
}, 1);
for(var i = 0; i < 100000; ++i) {
console.log(i);
}
Even though the timeout is set for 1 millisecond it doesn't appear until after the loop finishes (Which takes about 5 seconds on my machine)
You can see the same problem with a simple forever loop
const TIMEOUT = 10000
describe('forever', function() {
it.only('cancelation', function() {
this.timeout(2 * TIMEOUT)
while(true) { } // loop forever
})
})
Run in with your environment and you'll see it never times out. JavaScript does not support interrupts, it only supports events.
As for fixing the code you need to insert a call to setTimeout. For example, let's change forever loop so it exits (and therefore allows other events)
const TIMEOUT = 100
function alongtime(n) {
return new Promise(function(resolve, reject) {
function loopTillDone() {
if (n) {
--n;
setTimeout(loopTillDone);
} else {
resolve();
}
}
loopTillDone();
});
}
describe('forever', function() {
it.only('cancelation', function(done) {
this.timeout(2 * TIMEOUT)
alongtime(100000000).then(done);
})
})
Unfortunately using setTimeout is really a slow operation and arguably shouldn't be used in a function like profib. I don't really know what to suggest.
The problem appears because promises work in a "greedy" manner(it's my own explanation). For this reason function profib doesn't release event loop. To fix this issue I need to release event loop. The easiest way to do that with Promise.delay():
function profib(n, prev = '0', cur = '1') {
return new Promise.resolve(n < 2)
.then(function(isTerm) {
if(isTerm) {
return cur
} else {
n = n - 2
return Promise.delay(0).then(() => profib(n, cur, strAdd(cur, prev));
}
})
}
gman has already explained why your idea doesn't work. The simple and efficient solution would be to add a condition in your loop that checks the time and breaks, like thus :
var deadline = Date.now() + TIMEOUT
function profib(n, prev = '0', cur = '1') {
if (Date.now() >= deadline) throw new Error("timed out")
// your regular fib recursion here
}
Calling profib will either eventually return the result, or throw an error. However, it will block any other JavaScript from running while doing the calculation. Asynchronous execution isn't the solution here. Or at least, not all of it. What you need for such CPU-intensive tasks is a WebWorker to run it in another JavaScript context. Then you can wrap your WebWorker's communication channel in a Promise to get the API you envisioned originally.

log recursion from jquery function

I'm trying to calculate a series with a recursive function and jQuery but I don't know how to log each recursion that the function is making so I could get the series members.
the code is the following:
$(document).ready(function () {
$("#button").click(function () {
var n = $("#number").val();
function series(n) {
if (n == 1) {
return 6;
} else {
return 0.5 * series(n - 1) + 4;
}
}
console.log(series(n));
});
});
The problem is that the function only logs the last series member. For example if n = 4 the series should be 6, 7, 7.5, 7.75.
The function only returns 7.75.
This is the series formula: series(n) = 0.5 * series(n - 1) + 4, if n = 1 then series(n) = 6;
Thank you!
It's not the most beautiful looking example, but if you take your code and then wrap it in another function with a results array. Then call your inner recursive function and store them to that array it can return the results as an array. You can then use a join to make it into a string to display using jQuery or console log it.
Fiddle: http://jsfiddle.net/mcfarljw/hPWuW/
function getSeriesArray(n) {
var results = [];
function series(n) {
if (n === 1) {
results.push(6);
return 6;
} else {
var result = 0.5 * series(n - 1) + 4;
results.push(result);
return result;
}
}
series(n);
return results;
}
Your use of console.log() is only accepting the output of the outermost series call. If you want to log every iteration you either need to log inside your series method or keep track of every result during the iterations in the series method and then log whatever you used to keep track.
This seems like homework so I wont give too much away, but it might help is used the inspector in browser to walked the execution and get a feel for how the code is flowing.
Try this
$(document).ready(function () {
$("#button").click(function () {
var n = $("#number").val();
function series(n) {
var val=6;
if (n != 1) {
val= 0.5 * series(n - 1) + 4;
}
console.log(val);
return val;
}
});
});

Categories

Resources