importScripts('protein.js', 'utils.js', 'energy.js');
self.addEventListener('message', function(e) {
var msg = JSON.parse(e.data);
Ela(
msg.seq,
msg.ang,
msg.l,
msg.parameter,
msg.pop,
msg.parent,
msg.ang_num,
msg.rigs,
msg.rigf,
msg.rigm,
msg.rign,
msg.rigx,
msg.effs,
msg.efff
);
}, false);
/**
* Estimated Learning Algorithm
* @param {String} seq - String with the aminoacid's type sequence.
* @param {Array} ang - The angle sequence in radians.
* @param {int} l - The limit of loops (stop criteria).
* @param {Object} parameter - The parameters object {rigidity: Array, efficiency: Array}.
* @param {int} pop - The size of the population (number of solutions per loop).
* @param {float} parent - The percentage of the population that will be reference to new solutions.
* @param {int} ang_num - Number of angles changed per solution.
* @param {string} rigs - The expression that changes rigidity on successes.
* @param {string} rigf - The expression that changes rigidity on fails.
* @param {float} rigm - Maximum value for rigidity.
* @param {int} rign - Number of neightbors affected by rigidity.
* @param {string} rigx - The expression that changes neightbors rigidity value.
* @param {string} effs - The expression that changes efficiency on successes.
* @param {string} efff - The expression that changes efficiency on fails.
*/
var Ela = function(seq, ang, l, parameter, pop, parent, ang_num, rigs, rigf, rigm, rign, rigx, effs, efff){
var n = 2;
var min_p = new Protein({'seq': seq, 'ang': ang});
var adjustParametersSuccess = function(p, e0, e1, a){
//TODO use e0 and e1 to adjust parameters
//var dif = e1 - e0;
for(var i = 0; i < a.length; ++i){
parameter[a[i]].rigidity = parameter[a[i]].rigidity + eval(rigs);
if(parameter[a[i]].rigidity > rigm || parameter[a[i]].rigidity < 1)
parameter[a[i]].rigidity = 1;
for(var n = 1; n <= rign; ++n){
if(parameter[a[i] + n]){
var x = parameter[a[i] + n].rigidity;
parameter[a[i] + n].rigidity = x + eval(rigs) * eval(rigx);
if(parameter[a[i] + n].rigidity > rigm || parameter[a[i] + n].rigidity < 1)
parameter[a[i] + n].rigidity = 1;
}
}
for(var n = 1; n <= rign; ++n){
if(parameter[a[i] - n]){
var x = parameter[a[i] - n].rigidity;
parameter[a[i] - n].rigidity = x + eval(rigs) * eval(rigx);
if(parameter[a[i] - n].rigidity > rigm || parameter[a[i] - n].rigidity < 1)
parameter[a[i] - n].rigidity = 1;
}
}
parameter[a[i]].efficiency = parameter[a[i]].efficiency + eval(effs);
if(parameter[a[i]].efficiency > seq.length || parameter[a[i]].efficiency < 1)
parameter[a[i]].efficiency = 1;
}
};
var adjustParametersFail = function(p, e0, e1, a){
//TODO use e0 and e1 to adjust parameters
//for(var i = 1; i < p.length - 1; ++i){
for(var i = 0; i < a.length; ++i){
parameter[a[i]].rigidity = parameter[a[i]].rigidity + eval(rigf);
if(parameter[a[i]].rigidity > rigm || parameter[a[i]].rigidity < 1)
parameter[a[i]].rigidity = 1;
for(var n = 1; n <= rign; ++n){
if(parameter[a[i] + n]){
var x = parameter[a[i] + n].rigidity;
parameter[a[i] + n].rigidity = x + eval(rigs) * eval(rigx);
if(parameter[a[i] + n].rigidity > rigm || parameter[a[i] + n].rigidity < 1)
parameter[a[i] + n].rigidity = 1;
}
}
for(var n = 1; n <= rign; ++n){
if(parameter[a[i] - n]){
var x = parameter[a[i] - n].rigidity;
parameter[a[i] - n].rigidity = x + eval(rigs) * eval(rigx);
if(parameter[a[i] - n].rigidity > rigm || parameter[a[i] - n].rigidity < 1)
parameter[a[i] - n].rigidity = 1;
}
}
parameter[a[i]].efficiency = parameter[a[i]].efficiency + eval(efff);
if (parameter[a[i]].efficiency > seq.length || parameter[a[i]].efficiency < 1)
parameter[a[i]].efficiency = 1;
}
};
//ANGLES
var delta = 2 * Math.PI; // 360 deg
var randomGauss = function(p, a){
var array = p.getAngle();
for(var i = 0; i < a.length; ++i){
array[a[i]] += delta * gaussRandom(0, 1/parameter[a[i]].rigidity);
}
return array;
};
var chooseAngles = function(p, n){
var array = [], pa = parameter.slice();
for(var i = 1; i < pa.length; ++i){
pa[i].i = i;
}
var sumpick = function(){
var sum = 0;
for(var i = 1; i < pa.length; ++i){
pa[i].low = sum;
sum += pa[i].efficiency;
pa[i].up = sum;
}
var r = Math.random() * sum;
for(var i = 1; i < pa.length; ++i){
if(pa[i].low <= r && r < pa[i].up) {
array.push(pa[i].i);
pa.splice(i, 1);
return;
}
}
}
var c = 0;
while(c < n){
sumpick();
c++;
}
return array;
};
//TESTS
var adjustParameters = function(p, a){
if(p.energy < min_p.energy) {
adjustParametersSuccess(p, min_p.energy, p.energy, a);
min_p = p;
} else {
adjustParametersFail(p, min_p.energy, p.energy, a);
}
};
//init popupation
var population = [];
for(var i = 0; i < pop * parent; ++i){
population[i] = new Protein({'seq': seq, 'ang': ang});
}
//loop
var t = 0;
for(var t = 0; t < l; ++t){
var newpop = [];
for(var i = 0; i < pop; ++i){
var refp = population[parseInt(i * parent)];
var a = chooseAngles(refp, ang_num );
var p = new Protein({
ang: randomGauss(refp, a),
seq: seq
});
adjustParameters(p, a);
newpop.push(p);
}
population = newpop;
population.sort(function(a, b){
return a.energy - b.energy;
});
if(t%100 == 0) {
var msg = JSON.stringify({
data: min_p.energy,
parameter: parameter
});
self.postMessage(msg);
}
}
var msg = JSON.stringify({
energy: min_p.energy,
ang: min_p.getAngle(),
parameter: parameter
});
self.postMessage(msg);
};