Convert dole code to follow project style

This commit is contained in:
Hornwitser committed 2020-10-23 21:22:45 +02:00
1 parent 8586dfb95f
commit ceade431ef
2 files changed
+172 -127

No files matched your search

+56 -43
View File
@@ -6,7 +6,8 @@ const { Gauge } = require("@clusterio/lib/prometheus");
const prometheusNNDoleGauge = new Gauge(
"clusterio_subspace_storage_nn_dole_gauge",
"Current demand being supplied by Neural Network ; 1 means all demand covered, 0.5 means about half of each supply is covered, 0 means no items are given",
"Current demand being supplied by Neural Network ; 1 means all demand covered, "+
"0.5 means about half of each supply is covered, 0 means no items are given",
{ labels: ["resource"] }
);
const prometheusDoleFactorGauge = new Gauge(
@@ -16,24 +17,24 @@ const prometheusDoleFactorGauge = new Gauge(
);
class NeuralDole {
getRequestStats(itemname,samples)
{
var sum=0;
samples=Math.min(samples,(this.stats[itemname] || []).length-1);
if (samples<1) return 0.1;
for (var i = 1; i <= samples; i++) {
sum+=this.stats[itemname][i].req;
getRequestStats(itemname, samples) {
let sum = 0;
samples = Math.min(samples, (this.stats[itemname] || []).length - 1);
if (samples < 1) {
return 0.1;
}
for (let i = 1; i <= samples; i++) {
sum += this.stats[itemname][i].req;
}
if (sum === 0) {
return 0.1;
}
return sum/samples;
return sum / samples;
}
constructor({
items,
}){
}) {
// Set some storage variables for the dole divider
this.items = items;
this.itemsLastTick = new Map(items._items);
@@ -50,11 +51,13 @@ class NeuralDole {
count,
this.dole[name],
this.itemsLastTick.get(name),
this.getRequestStats(name,5)
this.getRequestStats(name, 5)
);
this.stats[name]=this.stats[name] || [];
this.stats[name].unshift({ req: 0, given: 0 });//stats[name][0] is the one we currently collect
if (this.stats[name].length>10) this.stats[name].pop();//remove if too many samples in stats
this.stats[name] = this.stats[name] || [];
this.stats[name].unshift({ req: 0, given: 0 }); // stats[name][0] is the one we currently collect
if (this.stats[name].length>10) {
this.stats[name].pop(); // remove if too many samples in stats
}
this.dole[name] = magicData[0];
// DONE handle magicData[1] for graphing for our users
@@ -69,23 +72,22 @@ class NeuralDole {
this.items.getItemCount(object.name),
this.itemsLastTick.get(object.name) || 0,
this.dole[object.name],
this.carry[object.name+" "+object.instanceID] || 0,
this.lastRequest[object.name+"_"+object.instanceID+"_"+object.instanceName] || 0,
this.getRequestStats(object.name,5),
this.debt[object.name+" "+object.instanceID] || 0
this.carry[`${object.name} ${object.instanceID}`] || 0,
this.lastRequest[`${object.name}_${object.instanceID}_${object.instanceName}`] || 0,
this.getRequestStats(object.name, 5),
this.debt[`${object.name} ${object.instanceID}`] || 0
);
if ((this.stats[object.name] || []).length>0)
{
this.stats[object.name][0].req+=Number(object.count);
this.stats[object.name][0].given+=Number(magicData[0]);
if ((this.stats[object.name] || []).length > 0) {
this.stats[object.name][0].req += Number(object.count);
this.stats[object.name][0].given += Number(magicData[0]);
}
this.lastRequest[object.name+"_"+object.instanceID+"_"+object.instanceName] = object.count;
//0.Number of items to give in that dose
//1.New dole for item X
//2.New carry for item X slave Y
this.lastRequest[`${object.name}_${object.instanceID}_${object.instanceName}`] = object.count;
// 0. Number of items to give in that dose
// 1. New dole for item X
// 2. New carry for item X slave Y
this.dole[object.name] = magicData[1];
this.carry[object.name+" "+object.instanceID] = magicData[2];
this.debt[object.name+" "+object.instanceID] = magicData[3];
this.carry[`${object.name} ${object.instanceID}`] = magicData[2];
this.debt[`${object.name} ${object.instanceID}`] = magicData[3];
// Remove item from DB and send it
this.items.removeItem(object.name, magicData[0]);
@@ -94,39 +96,50 @@ class NeuralDole {
}
}
// If the server regularly can't fulfill requests, this number grows until it can. Then it slowly shrinks back down.
// If the server regularly can't fulfill requests, this number grows until
// it can. Then it slowly shrinks back down.
let _doleDivisionFactor = {};
function doleDivider({
object,
items,
logItemTransfers,
}){
}) {
let itemCount = items.getItemCount(object.name);
const doleDivisionRetardation = 10; //lower rates will equal more dramatic swings
const maxDoleDivision = 250; //a higher cap will divide the store more ways, but will take longer to recover as supplies increase
// lower rates will equal more dramatic swings
const doleDivisionRetardation = 10;
// a higher cap will divide the store more ways, but will take longer to
// recover as supplies increase
const maxDoleDivision = 250;
const originalCount = Number(object.count) || 0;
object.count /= ((_doleDivisionFactor[object.name]||0)+doleDivisionRetardation)/doleDivisionRetardation;
object.count /= ((_doleDivisionFactor[object.name] || 0) + doleDivisionRetardation) / doleDivisionRetardation;
object.count = Math.round(object.count);
if (logItemTransfers) {
console.info(`Serving ${object.count}/${originalCount} ${object.name} from ${itemCount} ${object.name} with dole division factor ${(_doleDivisionFactor[object.name]||0)} (real=${((_doleDivisionFactor[object.name]||0)+doleDivisionRetardation)/doleDivisionRetardation}), item is ${itemCount > object.count?"stocked":"short"}.`);
console.info(
`Serving ${object.count}/${originalCount} ${object.name} from ${itemCount} ${object.name} `+
`with dole division factor ${(_doleDivisionFactor[object.name]||0)} `+
`(real=${((_doleDivisionFactor[object.name] || 0) + doleDivisionRetardation) / doleDivisionRetardation}), `+
`item is ${itemCount > object.count?"stocked":"short"}.`
);
}
// Update existing items if item name already exists
if (itemCount > object.count) {
//If successful, increase dole
_doleDivisionFactor[object.name] = Math.max((_doleDivisionFactor[object.name]||0)||1, 1) - 1;
// If successful, increase dole
_doleDivisionFactor[object.name] = Math.max((_doleDivisionFactor[object.name] || 0) || 1, 1) - 1;
items.removeItem(object.name, object.count);
prometheusDoleFactorGauge.labels(object.name).set(_doleDivisionFactor[object.name] || 0);
return object.count;
} else {
// if we didn't have enough, attempt giving out a smaller amount next time
_doleDivisionFactor[object.name] = Math.min(maxDoleDivision, Math.max((_doleDivisionFactor[object.name]||0)||1, 1) * 2);
prometheusDoleFactorGauge.labels(object.name).set(_doleDivisionFactor[object.name] || 0);
return 0;
//console.log('failure out of ' + object.name + " | " + object.count + " from " + object.instanceID + " ("+object.instanceName+")");
}
// if we didn't have enough, attempt giving out a smaller amount next time
_doleDivisionFactor[object.name] = Math.min(
maxDoleDivision, Math.max((_doleDivisionFactor[object.name] || 0) || 1, 1) * 2
);
prometheusDoleFactorGauge.labels(object.name).set(_doleDivisionFactor[object.name] || 0);
return 0;
// console.log(`failure out of ${object.name}/${object.count} from ${object.instanceID} (${object.instanceName})`);
}
module.exports = {
+116 -84
View File
@@ -1,122 +1,154 @@
//Sigmoids...
// Sigmoids...
"use strict";
function sigmoid0(x)
{
return x/(1+Math.abs(x));
function sigmoid0(x) {
return x / (1 + Math.abs(x));
}
function sigmoid1(x)
{
if (x>=0.0) {
function sigmoid1(x) {
if (x >= 0.0) {
return 1.0;
} else {
return 0.0;
}
return 0.0;
}
function sigmoid2(x)
{
if (x>=0.0){
function sigmoid2(x) {
if (x >= 0.0) {
return x;
} else {
return 0.0;
}
return 0.0;
}
function sigmoid3(x)
{
function sigmoid3(x) {
return x;
}
//DOSE - Doses items for item X slave Y
//Numreq - number of items that are requested for item X for slave Y
//Instore - number of items for item X in master gauge (currently)
//store_last_tick - Number of items for item X in master gauge at time of last tick
//dole - Current dole for item X
//carry - carry for item X slave Y
//prev_req - Numreq for previous request for item X slave Y
//* doleinfo_last - Object with 2 values for last "tick period": numreq - total number or requests for item, numslave - number of slaves requesting that item
//debt - debt for item X slave Y
// DOSE - Doses items for item X slave Y
// Numreq - number of items that are requested for item X for slave Y
// Instore - number of items for item X in master gauge (currently)
// store_last_tick -
// Number of items for item X in master gauge at time of last tick
// dole - Current dole for item X
// carry - carry for item X slave Y
// prev_req - Numreq for previous request for item X slave Y
// * doleinfo_last -
// Object with 2 values for last "tick period": numreq - total number or
// requests for item, numslave - number of slaves requesting that item
// debt - debt for item X slave Y
//Returns: Array of 3 elements
//0.Number of items to give in that dose
//1.New dole for item X
//2.New carry for item X slave Y
//3.New debt
// Returns: Array of 3 elements
// 0.Number of items to give in that dose
// 1.New dole for item X
// 2.New carry for item X slave Y
// 3.New debt
function dose(numreq, instore, store_last_tick, dole, carry, prev_req, numreq_total_adj, debt) {
numreq=Number(numreq);
instore=Number(instore);
var instore_adj=instore;
numreq = Number(numreq);
instore = Number(instore);
let instore_adj = instore;
if (instore_adj === 0) {
instore_adj = 0.1;
}
var b=Math.trunc(prev_req/instore_adj*numreq);
var inp1=[numreq,instore_adj,store_last_tick/numreq,dole,carry];//0..4
var inp2=[prev_req/numreq,numreq/numreq_total_adj,store_last_tick/numreq_total_adj,prev_req/instore_adj,b,numreq_total_adj,store_last_tick,debt];//5..12
var inputs=inp1.concat(inp2);
var internal=new Array(20).fill(0);
var outputs=[0,0,0,0];
//NN: Please don't touch :), code is generated
let b = Math.trunc(prev_req / instore_adj * numreq);
let inp1 = [numreq, instore_adj, store_last_tick / numreq, dole, carry]; // 0..4
let inp2 = [
prev_req / numreq,
numreq / numreq_total_adj,
store_last_tick / numreq_total_adj,
prev_req/instore_adj,
b,
numreq_total_adj,
store_last_tick,
debt,
]; // 5..12
let inputs = inp1.concat(inp2);
let internal = new Array(20).fill(0);
let outputs = [0, 0, 0, 0];
// NN: Please don't touch :), code is generated
outputs[0]=inputs[7]*0.8058582544;
outputs[0]=sigmoid2(outputs[0]);
outputs[1]=sigmoid0(outputs[1]);
outputs[2]=sigmoid0(outputs[2]);
outputs[3]=inputs[6]*0.2294657379;
outputs[3]=sigmoid0(outputs[3]);
outputs[0] = inputs[7] * 0.8058582544;
outputs[0] = sigmoid2(outputs[0]);
outputs[1] = sigmoid0(outputs[1]);
outputs[2] = sigmoid0(outputs[2]);
outputs[3] = inputs[6] * 0.2294657379;
outputs[3] = sigmoid0(outputs[3]);
debt=debt || 0;
if (outputs[0]>0.99) outputs[0]=1.0;
debt = debt || 0;
if (outputs[0] > 0.99) {
outputs[0]=1.0;
}
var res1=Number(outputs[0])*numreq+outputs[3]+debt;
var res_capped=Math.round(res1);
let res1 = Number(outputs[0]) * numreq+outputs[3] + debt;
let res_capped = Math.round(res1);
if (res_capped>numreq) res_capped=numreq;
if (res_capped>instore) res_capped=instore;
if (res_capped<0) res_capped=0;
if (res_capped > numreq) { res_capped = numreq; }
if (res_capped > instore) { res_capped = instore; }
if (res_capped < 0) { res_capped = 0; }
res1=res1 || 0;
res_capped=res_capped || 0;//Safeguard against wrong values
debt=res1-res_capped;
debt_cap=Math.round(numreq*1.5)+5;
if (debt>debt_cap) debt=debt_cap;
res1 = res1 || 0;
res_capped = res_capped || 0; // Safeguard against wrong values
debt = res1 - res_capped;
debt_cap = Math.round(numreq * 1.5) + 5;
if (debt > debt_cap) {
debt = debt_cap;
}
carry=sigmoid0(outputs[2]*carry+outputs[0]) || 0;
return [res_capped,dole+outputs[1],carry,debt];
carry = sigmoid0(outputs[2] * carry + outputs[0]) || 0;
return [res_capped, dole + outputs[1], carry, debt];
}
//TICK - Updates values for item X, should be called once for each item for each round of all slaves requesting that item
//Instore - number of items for item X in master gauge (currently)
//dole - Current dole for item X
//store_last_tick - Number of items for item X in master gauge at time of last tick (not this one)
//* doleinfo_last - Object with 2 values for last "tick period": numreq - total number or requests for item, numslave - number of slaves requesting that item
//* doleinfo_new - Object with 2 values for new "tick period": numreq - total number or requests for item, numslave - number of slaves requesting that item
// TICK -
// Updates values for item X, should be called once for each item for
// each round of all slaves requesting that item Instore - number of
// items for item X in master gauge (currently)
// dole - Current dole for item X
// store_last_tick -
// Number of items for item X in master gauge at time of last tick (not this one)
// * doleinfo_last -
// Object with 2 values for last "tick period": numreq - total number or
// requests for item, numslave - number of slaves requesting that item
//
// * doleinfo_new -
// Object with 2 values for new "tick period": numreq - total number or
// requests for item, numslave - number of slaves requesting that item
//Returns: Array of 2 elements
//0.New dole for item X
//1.Guessed percentage average of items supplied in last 10 ticks
// Returns: Array of 2 elements
// 0.New dole for item X
// 1.Guessed percentage average of items supplied in last 10 ticks
function tick(instore, dole, store_last_tick, numreq_total_adj) {
var instore_adj=instore;
let instore_adj = instore;
if (instore_adj === 0) {
instore_adj = 0.1;
}
var inputs=[instore,dole,store_last_tick/instore_adj,store_last_tick/numreq_total_adj,store_last_tick,numreq_total_adj];
var internal=new Array(10).fill(0);
var outputs=[0,0];
//NN: Please don't touch :), code is generated
let inputs = [
instore,
dole,
store_last_tick / instore_adj,
store_last_tick / numreq_total_adj,
store_last_tick,
numreq_total_adj,
];
let internal = new Array(10).fill(0);
let outputs = [0, 0];
// NN: Please don't touch :), code is generated
outputs[0]=inputs[3]*0.9364774823;
outputs[0]=outputs[0]*0.4590721726;
outputs[0]=sigmoid2(outputs[0]);
outputs[1]=outputs[0]*1.828422785;
outputs[1]=sigmoid3(outputs[1]);
outputs[0] = inputs[3] * 0.9364774823;
outputs[0] = outputs[0] * 0.4590721726;
outputs[0] = sigmoid2(outputs[0]);
outputs[1] = outputs[0] * 1.828422785;
outputs[1] = sigmoid3(outputs[1]);
avg=outputs[1];
if (numreq_total_adj<0.11) avg=1;//When no item's are requested, result is 0.1 ; In that case there is no deficit, so return 1 = 100% demand fulfilled
if (avg>1) avg=1;
if (avg<0) avg=0;
avg = outputs[1];
if (numreq_total_adj < 0.11) {
// When no item's are requested, result is 0.1; In that case there is
// no deficit, so return 1 = 100% demand fulfilled
avg = 1;
}
if (avg > 1) { avg=1; }
if (avg < 0) { avg=0; }
return [sigmoid0(outputs[0]),avg];
return [sigmoid0(outputs[0]), avg];
}
module.exports = { dose, tick };