var MAKE_STORE_FUNCTION_NAME = MAKE_STORE_FUNCTION_NAME || 'makeNeuronStore' var DBG = DBG || false; var DBG1 = true; var DEFAULT_NEURON = { value: '', charge: 0, maxCharge: 1.5, // DEFAULT_CONFIG.config_max_neuron_charge, uiShape: "circle", ui: { cx: 0, cy: 0 }, source: [], next: [], } function makeDefaultNeuronsStoreState() { return { receptor: [], mapReceptorChar: {}, neuron: [], connection: [], doubleConn: [], // connections between two nodes charge: [], // TODO: list of [ { charge: number, nodeType: (receptor|neuron), nodeIdx: int }, ... ] groupd by node (type/idx) inputReadPos: 0, animPos: 0, doAnim: true, uiOutputHeight: 300, } } function makeNeuronStore() { DBG && console.log("DBG:NeuronStore:makeNeuronStore"); var _state = makeDefaultNeuronsStoreState() var _config = {} var _inputText = '' var _animIntervalID = null var _callback = null function stateReset(inputText, config) { _inputText = inputText _config = config _state = makeDefaultNeuronsStoreState() var distinct = function (value, idx, self) { return (idx === self.indexOf(value)); }; var foundLetters = inputText.split("").filter(distinct); _state.receptor = foundLetters.sort().map(makeReceptor); _state.mapReceptorChar = _state.receptor.map(function (node) { return node.value; }); if (_animIntervalID) clearInterval(_animIntervalID) _notifySubscribers(); } function readCharFromInput() { if (_state.inputReadPos >= _inputText.length) return null; var char = _inputText.charAt(_state.inputReadPos) _state.inputReadPos += 1 return char; } function forwardAnim() { DBG1 && console.log("DBG:NeuronStore:forwardAnim:doAnim = '" + (_state.doAnim ? 1 : 0) + "'"); if (!_state.doAnim) return; // 1. read from input if its time // 2. check overcharged nodes // 2.1 check overcharged Receptor // 2.2 check overcharged Neuron // 3. move all charges (Receptor -> Connection, Connection -> Neuron, Neuron -> Connection) // 4. discharge all // ad.2. TODO: what to do with Charge when create new Neuron? // - idea 1: use Charge to create new Neuron: rm Charge, add Neuron, add Connection // 1. read from input if its time if (0 === _state.animPos % _config.config_read_speed_multiplier) { // read from input = add charge to receptor with given letter var char = readCharFromInput() if (null === char) { DBG1 && console.log("DBG:NeuronStore:forwardAnim:1(readInput): STOP - end of input", { inputLength: _inputText.length, animPos: _state.animPos }) _state.doAnim = false _notifySubscribers() return; } var foundReceptorIdx = getReceptorIdx(char) DBG1 && console.log("DBG:NeuronStore:forwardAnim:1(readInput): char('" + char + "', [" + char.charCodeAt(0) + "])", { animPos: _state.animPos, char, len: _inputText.length, doAnim: _state.doAnim, foundReceptorIdx }) if (-1 === foundReceptorIdx) { DBG1 && console.warn("BUG: receptor '" + char + "' not found (NeuronStore:forwardAnim:readInput)") _state.doAnim = false _notifySubscribers() return; } chargeAdd(_config.config_charge_receptor_at_input, { type: 'receptor', idx: foundReceptorIdx }) _state.animPos += 1 _notifySubscribers() return; } // 2. check overcharged nodes // 2.1 check overcharged Neuron // 2.1.1 is overcharged Neuron // 2.1.1.1 is another Neuron with Charge // 2.1.1.2 ! another Neuron with Charge // 2.1.2 ! overcharged Neuron // 2.2 check overcharged Receptor { // check overcharged nodes var overchargedNeuronIdx = _state.neuron.reduce(function (ret, neuron, idx) { var charge = getNeuronCharge(idx) if (charge < neuron.maxCharge) return ret; ret.push({ idx: idx, charge: charge }) return ret; }, []) var overchargedReceptorIdx = _state.receptor.reduce(function (ret, receptor, idx) { var charge = getReceptorCharge(idx) if (charge < _config.config_max_receptor_charge) return ret; ret.push({ idx: idx, charge: charge }) return ret; }, []) if (overchargedNeuronIdx.length > 0) { var overcharged = overchargedNeuronIdx[0] var firstNeuron = _state.neuron[overcharged.idx] var secondNeuronWithCharge = _state.neuron.reduce(function (ret, neuron, idx) { // find neuron with max charge if (idx === overcharged.idx) return ret; // skip firstNeuron var charge = getNeuronCharge(idx) if (!charge) return ret; // skip Neuron without charge if (null === ret) return { idx: idx, charge: charge } return (charge > ret.charge) ? { idx: idx, charge: charge } : ret; }, null) DBG1 && console.log("TODO:NeuronStore:forwardAnim:2.1(check overcharged)/neuron.1", { overcharged, firstNeuron, secondNeuronWithCharge }) if (null !== secondNeuronWithCharge) { // is already exists - check doubleConn: { from: [ neuronIdx, neuronIdx ], to: neuronIdx } var existingConn = _state.doubleConn.reduce(function (ret, dblConn) { if (ret) return ret; if (dblConn.from[0] === overcharged.idx && dblConn.from[1] === secondNeuronWithCharge.idx) return dblConn; // if (dblConn.from[1] === overcharged.idx && dblConn.from[0] === secondNeuronWithCharge.idx) return dblConn; return ret; }, null) var toNode = _state.neuron[secondNeuronWithCharge.idx] DBG1 && console.log("TODO:NeuronStore:forwardAnim:2.1(check overcharged)/neuron.2(secondNeuronWithCharge)", { from: firstNeuron.value, to: toNode.value, existingConn }) if (existingConn) { // charge Neuron existingConn.to var idxNewNeuron = existingConn.to chargeRemove({ type: 'neuron', idx: overcharged.idx }) chargeRemove({ type: 'neuron', idx: secondNeuronWithCharge.idx }) switch (_config.config_strategy_overcharge) { case "REMOVE_CHARGE": break; case "LEAVE_HALF_CHARGE": { chargeAdd(overcharged.charge / 2, { type: 'neuron', idx: overcharged.idx }) chargeAdd(secondNeuronWithCharge.charge / 2, { type: 'neuron', idx: secondNeuronWithCharge.idx }) } break; case "LEAVE_ALMOST_MAX": { chargeAdd(getNeuronAlmostMaxCharge(overcharged.idx), { type: 'neuron', idx: overcharged.idx }) chargeAdd(getNeuronAlmostMaxCharge(secondNeuronWithCharge.idx), { type: 'neuron', idx: secondNeuronWithCharge.idx }) } break; } chargeAdd(overcharged.charge + secondNeuronWithCharge.charge, { type: 'neuron', idx: existingConn.to }) // _state.animPos += 1 // dischargeAll() _notifySubscribers() return; } else { // create new var newNeuron = makeNeuronFromTwoNeurons(overcharged.idx, overcharged.charge, secondNeuronWithCharge.idx, secondNeuronWithCharge.charge) if (!newNeuron) { DBG1 && console.log("TODO:NeuronStore:forwardAnim:2(check overcharged)/neuron.2.1(!newNeuron)", { overcharged }) // _state.animPos += 1 dischargeAll() _notifySubscribers() return; } else { _state.neuron.push(newNeuron) updateOuputHeight(newNeuron) var idxNewNeuron = _state.neuron.length - 1 _state.connection.push({ fromType: 'neuron', fromIdx: overcharged.idx, toIdx: idxNewNeuron, timesCreated: 1 }) _state.connection.push({ fromType: 'neuron', fromIdx: secondNeuronWithCharge.idx, toIdx: idxNewNeuron, timesCreated: 1 }) _state.doubleConn.push({ from: [overcharged.idx, secondNeuronWithCharge.idx], to: idxNewNeuron, connIdx: [_state.connection.length - 2, _state.connection.length - 1] }) chargeRemove({ type: 'neuron', idx: overcharged.idx }) chargeRemove({ type: 'neuron', idx: secondNeuronWithCharge.idx }) switch (_config.config_strategy_overcharge) { case "REMOVE_CHARGE": break; case "LEAVE_HALF_CHARGE": { chargeAdd(overcharged.charge / 2, { type: 'neuron', idx: overcharged.idx }) chargeAdd(secondNeuronWithCharge.charge / 2, { type: 'neuron', idx: secondNeuronWithCharge.idx }) } break; case "LEAVE_ALMOST_MAX": { // chargeAdd(getNeuronAlmostMaxCharge(overcharged.idx), { type: 'neuron', idx: overcharged.idx }) // chargeAdd(getNeuronAlmostMaxCharge(secondNeuronWithCharge.idx), { type: 'neuron', idx: secondNeuronWithCharge.idx }) var fromCharge = getNeuronAlmostMaxCharge(overcharged.idx) var toCharge = getNeuronAlmostMaxCharge(secondNeuronWithCharge.idx) chargeAdd((fromCharge + toCharge) / 2, { type: 'dbl_conn', idx: _state.doubleConn.length - 1, fromCharge: fromCharge, toCharge: toCharge }) } break; } // _state.animPos += 1 // dischargeAll() _notifySubscribers() return; } } // // _state.animPos += 1 // // dischargeAll() // _notifySubscribers() // return; } else { // !secondNeuronWithCharge // TODO: check if already exists! if yes then charge else create new var idxFoundConnection = _state.connection.reduce(function (ret, conn, idx) { if (ret > -1) return ret; if (conn.fromType === 'neuron' && conn.fromIdx === overcharged.idx) return idx; return ret; }, -1) DBG1 && console.log("TODO:NeuronStore:forwardAnim:2(check overcharged)/neuron.2(!secondNeuronWithCharge)", { idxFoundConnection }) if (-1 === idxFoundConnection) { var newNeuron = makeNeuronFromOneNeuron(overcharged.idx, overcharged.charge) if (!newNeuron) { DBG1 && console.log("TODO:NeuronStore:forwardAnim:2(check overcharged)/neuron.2.1(!newNeuron)", { overcharged }) // _state.animPos += 1 dischargeAll() _notifySubscribers() return; } else { _state.neuron.push(newNeuron) updateOuputHeight(newNeuron) var idxNewNeuron = _state.neuron.length - 1 _state.connection.push({ fromType: 'neuron', fromIdx: overcharged.idx, toIdx: idxNewNeuron, timesCreated: 1 }) chargeRemove({ type: 'neuron', idx: overcharged.idx }) switch (_config.config_strategy_overcharge) { case "REMOVE_CHARGE": break; case "LEAVE_HALF_CHARGE": { chargeAdd(overcharged.charge / 2, { type: 'neuron', idx: overcharged.idx }) } break; case "LEAVE_ALMOST_MAX": { chargeAdd(getNeuronAlmostMaxCharge(overcharged.idx), { type: 'neuron', idx: overcharged.idx }) } break; } _notifySubscribers() return; } } else { _state.connection[idxFoundConnection].timesCreated += 1 // chargeMove(overcharged.charge, { type: 'receptor', idx: overcharged.idx }, { type: 'connection', idx: idxFoundConnection }) chargeRemove({ type: 'neuron', idx: overcharged.idx }) switch (_config.config_strategy_overcharge) { case "REMOVE_CHARGE": break; case "LEAVE_HALF_CHARGE": { chargeAdd(overcharged.charge / 2, { type: 'neuron', idx: overcharged.idx }) } break; case "LEAVE_ALMOST_MAX": { chargeAdd(getNeuronAlmostMaxCharge(overcharged.idx), { type: 'neuron', idx: overcharged.idx }) } break; } chargeAdd(overcharged.charge, { type: 'connection', idx: idxFoundConnection }) } _notifySubscribers() return; } // _notifySubscribers() // return; } if (overchargedReceptorIdx.length > 0) { // TODO: while ? if (1 === overchargedReceptorIdx.length) { var overcharged = overchargedReceptorIdx.shift() // Restriction: only one connection between nodes { var idxFoundConnection = _state.connection.reduce(function (ret, conn, idx) { if (ret > -1) return ret; if (conn.fromType === 'receptor' && conn.fromIdx === overcharged.idx) return idx; return ret; }, -1) DBG1 && console.log("DBG:NeuronStore:forwardAnim:2(check overcharged)/receptor", { idxFoundConnection, from: { type: 'receptor', idx: overcharged.idx }, conn: [].concat(_state.connection) }) if (-1 === idxFoundConnection) { var newNeuron = makeNeuronFromOneReceptor(overcharged.idx, overcharged.charge) _state.neuron.push(newNeuron) var idxNewNeuron = _state.neuron.length - 1 _state.connection.push({ fromType: 'receptor', fromIdx: overcharged.idx, toIdx: idxNewNeuron, timesCreated: 1 }) idxFoundConnection = _state.connection.length - 1 chargeRemove({ type: 'receptor', idx: overcharged.idx }) // switch (_config.config_strategy_overcharge) { // case "REMOVE_CHARGE": break; // case "LEAVE_HALF_CHARGE": { // chargeAdd(overcharged.charge / 2, { type: 'receptor', idx: overcharged.idx }) // } break; // case "LEAVE_ALMOST_MAX": { // chargeAdd(getReceptorAlmostMaxCharge(overcharged.idx), { type: 'receptor', idx: overcharged.idx }) // } break; // } chargeAdd(overcharged.charge, { type: 'connection', idx: idxFoundConnection }) } else { _state.connection[idxFoundConnection].timesCreated += 1 // chargeMove(overcharged.charge, { type: 'receptor', idx: overcharged.idx }, { type: 'connection', idx: idxFoundConnection }) chargeRemove({ type: 'receptor', idx: overcharged.idx }) // switch (_config.config_strategy_overcharge) { // case "REMOVE_CHARGE": break; // case "LEAVE_HALF_CHARGE": { // chargeAdd(overcharged.charge / 2, { type: 'receptor', idx: overcharged.idx }) // } break; // case "LEAVE_ALMOST_MAX": { // chargeAdd(getReceptorAlmostMaxCharge(overcharged.idx), { type: 'receptor', idx: overcharged.idx }) // } break; // } chargeAdd(overcharged.charge, { type: 'connection', idx: idxFoundConnection }) } } // _state.animPos += 1 // dischargeAll() _notifySubscribers() return; } else { DBG1 && console.log("TODO:NeuronStore:forwardAnim:2(check overcharged)/receptor", { TODO: "more then 1 receptor overcharged!" }) } } // DBG1 && console.log("DBG:NeuronStore:forwardAnim:2(check overcharged)", { overchargedNeuronIdx, overchargedReceptorIdx }) } { // 3. move all charges (Receptor -> Connection, Connection -> Neuron, Neuron -> Connection) DBG1 && console.log("TODO:NeuronStore:forwardAnim:3(move all charges)", { charge: [].concat(_state.charge) }) var isChargeTypeConnection = function (charge) { if ("connection" === charge.nodeType) return true; if ("dbl_conn" === charge.nodeType) return true; return false; } var toAddChargeNeuronIdxList = _state.charge.filter(isChargeTypeConnection).map(function (charge) { DBG1 && console.log("TODO:NeuronStore:forwardAnim:3(move all charges).LOOP", { charge }) switch (charge.nodeType) { case "connection": return { charge: charge.charge, toIdx: _state.connection[charge.nodeIdx].toIdx }; case "dbl_conn": return { charge: charge.charge, toIdx: _state.doubleConn[charge.nodeIdx].to }; } return null; }) _state.charge = _state.charge.filter(function (charge) { return !isChargeTypeConnection(charge); }) toAddChargeNeuronIdxList.forEach(function (toAddCharge) { chargeAdd(toAddCharge.charge, { type: 'neuron', idx: toAddCharge.toIdx }) }) } { // 4. discharge all dischargeAll() } _state.animPos += 1 _notifySubscribers(); } function dischargeAll() { _state.charge = _state.charge.map(function (charge) { return Object.assign({}, charge, { charge: Math.max(0, charge.charge - _config.config_discharge_per_tick), }) }).filter(function (charge) { return charge.charge > 0; }) } function makeNeuronFromTwoNeurons(fromNeuronIdx, fromNeuronCharge, toNeuronIdx, toNeuronCharge) { var fromNode = _state.neuron[fromNeuronIdx] var toNode = _state.neuron[toNeuronIdx] var maxCharge = getNewNeuronMaxCharge(fromNode) DBG1 && console.log("DBG:NeuronStore:makeNeuronFromTwoNeurons", { fromNode, toNode, maxCharge }) if (maxCharge < _config.config_discharge_per_tick) return null; var uiNewNodePos = { cx: 0, cy: 0 } { // closer to node with more charge (first) var xDiff = Math.abs(fromNode.ui.cx - toNode.ui.cx) var isFirstOnRight = (fromNode.ui.cx > toNode.ui.cx) // fromNeuronCharge + toNeuronCharge -- xDiff // toNeuronCharge -- x ==> x = toNeuronCharge * xDiff / (fromNeuronCharge + toNeuronCharge) var xToFirst = (toNeuronCharge * xDiff) / (fromNeuronCharge + toNeuronCharge) uiNewNodePos.cx = fromNode.ui.cx + (isFirstOnRight ? -1 : 1) * xToFirst } uiNewNodePos.cy = (fromNode.ui.cy != toNode.ui.cy) ? Math.max(fromNode.ui.cy, toNode.ui.cy) + 10 + _config.ui_space_y / 2 : fromNode.ui.cy + 10 + _config.ui_space_y ; uiNewNodePos.cy = _state.neuron.reduce(function (ret, neuron) { if (uiNewNodePos.cx < neuron.ui.cx - 10) return ret; if (uiNewNodePos.cx > neuron.ui.cx + 10) return ret; if (ret < neuron.ui.cy - 10) return ret; if (ret > neuron.ui.cy + 10) return ret; return ret + 10 + _config.ui_space_y; }, uiNewNodePos.cy) DBG1 && console.log("DBG:NeuronStore:makeNeuronFromTwoNeurons", { uiNewNodePos, fromNode, toNode, newNodeMaxCharge: getNewNeuronMaxCharge(fromNode) }) // var value = '' + (_state.neuron.length + 1); var value = [fromNode.value, toNode.value].join('') return Object.assign({}, DEFAULT_NEURON, { value: value, charge: 0, maxCharge: getNewNeuronMaxCharge(fromNode), uiShape: "ellipse", ui: Object.assign({}, uiNewNodePos, { rx: 10, ry: 10, }), }); } function makeNeuronFromOneReceptor(fromReceptorIdx, charge) { var sourceNode = _state.receptor[fromReceptorIdx] // var value = '' + (_state.neuron.length + 1); var value = [sourceNode.value, ""].join('') // TODO: same name what Receptor DBG1 && console.log("DBG:NeuronStore:makeNeuronFromOneReceptor", { sourceNode, newNodeMaxCharge: getNewNeuronMaxCharge(sourceNode) }) return Object.assign({}, DEFAULT_NEURON, { value: value, charge: 0, maxCharge: getNewNeuronMaxCharge(sourceNode), uiShape: "ellipse", ui: { cx: sourceNode.ui.cx, cy: sourceNode.ui.cy + 10 + _config.ui_space_y, rx: 10, ry: 10, }, }); } function makeNeuronFromOneNeuron(fromNeuronIdx, charge) { var sourceNode = _state.neuron[fromNeuronIdx] // var value = '' + (_state.neuron.length + 1); var value = [sourceNode.value, "^"].join('') var maxCharge = getNewNeuronMaxCharge(sourceNode) if (maxCharge < _config.config_discharge_per_tick) return null; DBG1 && console.log("DBG:NeuronStore:makeNeuronFromOneNeuron", { sourceNode, newNodeMaxCharge: maxCharge }) return Object.assign({}, DEFAULT_NEURON, { value: value, charge: 0, maxCharge: maxCharge, uiShape: "ellipse", ui: { cx: sourceNode.ui.cx, cy: sourceNode.ui.cy + 10 + _config.ui_space_y, rx: 10, ry: 10, }, }); } function getNewNeuronMaxCharge(sourceNode) { // return sourceNode.maxCharge * _config.config_discharge_max_in_new_neuron_from_one; return sourceNode.maxCharge - _config.config_discharge_per_tick; } function chargeAdd(charge, to) { var foundChargeIdx = _state.charge.reduce(function (ret, charge, idx) { if (charge.nodeType === to.type && charge.nodeIdx === to.idx) return idx; return ret; }, -1) DBG1 && console.log("DBG:NeuronStore:chargeAdd", { charge, to, foundChargeIdx }) if (-1 === foundChargeIdx) { _state.charge.push({ charge: charge, nodeType: to.type, nodeIdx: to.idx }) foundChargeIdx = _state.charge.length - 1 } else { _state.charge[foundChargeIdx].charge += charge } if ('dbl_conn' === to.type) { if (!_state.charge[foundChargeIdx].hasOwnProperty('fromCharge')) _state.charge[foundChargeIdx].fromCharge = 0 if (!_state.charge[foundChargeIdx].hasOwnProperty('toCharge')) _state.charge[foundChargeIdx].toCharge = 0 _state.charge[foundChargeIdx].fromCharge += to.fromCharge _state.charge[foundChargeIdx].toCharge += to.toCharge } DBG1 && console.log("DBG:NeuronStore:chargeAdd.2", { state_charge: [].concat(_state.charge) }) return foundChargeIdx; } function chargeRemove(from) { _state.charge = _state.charge.filter(function (item) { return !(from.type === item.nodeType && from.idx === item.nodeIdx); }) } function updateOuputHeight(newNeuron) { if (newNeuron.ui.cy + 30 > _state.uiOutputHeight) { _state.uiOutputHeight = newNeuron.ui.cy + 30 } } function dispatch(payload) { DBG1 && console.log("DBG:NeuronStore:dispatch('" + payload.type + "')", payload); switch (payload.type) { case 'INIT': stateReset(payload.inputText, payload.config); startAnimation(); break; case 'PAUSE': _state.doAnim = false; _notifySubscribers(); break; case 'PLAY': _state.doAnim = true; break; default: { DBG1 && console.warn("Not implemented dispatch action type '" + payload.type + "'") } } } function subscribe(callback) { _callback = callback; // TODO: array return unsubscribe; } function unsubscribe() { _callback = null } function _notifySubscribers() { if (_callback) _callback() } function makeReceptor(value, idx, arr) { // usage: [].map(makeReceptor) var totalReceptors = arr.length; var cx = Math.ceil(_config.ui_output_width / (totalReceptors + 1)); var r = Math.min(Math.ceil(_config.ui_output_width / (totalReceptors + 10) / 2), _config.ui_max_receptor_r); var xCenter = cx + cx * idx - r; return Object.assign({}, DEFAULT_NEURON, { value: value, maxCharge: _config.config_max_receptor_charge, uiShape: "circle", ui: { cx: xCenter, cy: 40, r: r, }, next: [], }) } function getReceptorIdx(char) { return _state.mapReceptorChar.indexOf(char) } function startAnimation() { _state.doAnim = true if (_animIntervalID) clearInterval(_animIntervalID) _animIntervalID = setInterval(forwardAnim, _config.config_anim_speed) } function getReceptorCharge(idx) { return _state.charge.filter(function (charge) { return ('receptor' === charge.nodeType && idx === charge.nodeIdx); }).reduce(function (ret, charge) { return ret + charge.charge; }, 0) } function getNeuronCharge(idx) { return _state.charge.filter(function (charge) { return ('neuron' === charge.nodeType && idx === charge.nodeIdx); }).reduce(function (ret, charge) { return ret + charge.charge; }, 0) } function getReceptorAlmostMaxCharge(idx) { return _state.receptor[idx].maxCharge - _config.config_discharge_per_tick; } function getNeuronAlmostMaxCharge(idx) { DBG1 && console.log("DBG:getNeuronAlmostMaxCharge(" + idx + ")", { charge: _state.neuron[idx].maxCharge - _config.config_discharge_per_tick }) return _state.neuron[idx].maxCharge - _config.config_discharge_per_tick; } function getNodesChargeState() { var receptor = [].concat(_state.receptor); var neuron = [].concat(_state.neuron); _state.charge.forEach(function (charge) { // _state.charge: [ { charge: number, nodeType: (receptor|neuron), nodeIdx: int }, ... ] groupd by node (type/idx) switch (charge.nodeType) { case 'receptor': receptor[charge.nodeIdx].charge = charge.charge; break; case 'neuron': neuron[charge.nodeIdx].charge = charge.charge; break; } }) function getNodeInfoFunction(type) { return function _getNodeInfo(node) { return { type: type, value: node.value, charge: node.charge, } } } return receptor.map(getNodeInfoFunction('receptor')) .concat( neuron.map(getNodeInfoFunction('neuron')) ) ; } return { subscribe: subscribe, dispatch: dispatch, getState: function () { return _state; }, getNodesChargeState: getNodesChargeState, getListReceptor: function () { return _state.receptor; }, getListNeuron: function () { return _state.neuron; }, getReceptor: function (idx) { return _state.receptor[idx]; }, getNeuron: function (idx) { return _state.neuron[idx]; }, getConnection: function (idx) { return _state.connection[idx]; }, getDoubleConnection: function (idx) { return _state.doubleConn[idx]; }, getCharge: function (idx) { return _state.charge[idx]; }, getListConnection: function () { return _state.connection; }, getListCharge: function () { return _state.charge; }, getReceptorCharge: getReceptorCharge, getNeuronCharge: getNeuronCharge, } } global[MAKE_STORE_FUNCTION_NAME] = makeNeuronStore // export default makeNeuronStore