UNPKG

dasf-web

Version:

Web frontend components for the data analytics software framework (DASF)

209 lines (175 loc) 7.74 kB
import HashMap from "../../util/HashMap"; import ArrayUtils from '../../util/ArrayUtils'; export default class SprDatabase { private inputParametersMap: Map<string, string[]>; private outputRangeMap: Map<string, number[]>; public constructor(private dataMap: HashMap<object>, private inputParameters: string[], private outputParameters: string[], uniqueInputParameterMap: Map<string, Set<string>>, private labelMap : Map<string, Map<string, number>>) { this.inputParametersMap = this.setsToArrays(uniqueInputParameterMap); this.outputRangeMap = this.determineOutputRanges(dataMap, outputParameters); } private setsToArrays(setMap: Map<string, Set<string>>): Map<string, string[]> { let arrayMap: Map<string, string[]> = new Map(); for (let [key, set] of setMap) { let valueArray: string[] = [...set]; arrayMap.set(key, valueArray); } return arrayMap; } private determineOutputRanges(dataMap: HashMap<object>, outputParameters: string[]): Map<string, number[]> { let rangeMap: Map<string, number[]> = new Map(); // loop over all outputs and determine min/max ranges for (let output of dataMap.values()) { for (let outputParameter of outputParameters) { const outputValue: number | string = output[outputParameter]; let value: number = NaN; if(this.labelMap.has(outputParameter)) { value = this.getLabelMapping(outputParameter, outputValue as string); } else { value = outputValue as number; } if (isNaN(value)) { // ignore nan values continue; } if (rangeMap.has(outputParameter)) { // update range let range: number[] = rangeMap.get(outputParameter); range[0] = Math.min(range[0], value); range[1] = Math.max(range[1], value); } else { // init range rangeMap.set(outputParameter, [value, value]); } } } //check if every output parameter has a rangemap (in case of all NaN values add range [0,0]) outputParameters.forEach(element => { if(!rangeMap.has(element)){ rangeMap.set(element, [0, 0]); } }); return rangeMap; } public getOutputValueRange(outputParameter: string): number[] { return this.outputRangeMap.get(outputParameter); } /** * Returns the list of available input parameters */ public getInputParameters(): string[] { return ArrayUtils.clone(this.inputParameters); } public updateInputParameterValue(inputParameter: string, oldValue: string, newValue: string): void { if (!oldValue) { return; } let values: string[] = this.inputParametersMap.get(inputParameter); if (values) { var index = values.indexOf(oldValue); if (~index) { values[index] = newValue; } this.inputParametersMap.set(inputParameter, values); } // update datamap keys for (let key of [...this.dataMap.keys()]) { if (key[inputParameter] == oldValue) { // update the key let newKey = Object.assign({}, key); newKey[inputParameter] = newValue; this.dataMap.updateKey(key, newKey); } } } /** * Returns the list of available output parameters */ public getOutputParameters(): string[] { return ArrayUtils.clone(this.outputParameters); } public addNewOutputParameter(outputParameterName: string, getValue: (outputValues: object) => number): void { for(let outputValue of this.dataMap.values()) { let newValue = getValue(outputValue); if(newValue == null){ return; } outputValue[outputParameterName] = newValue; } // add new output parameter to output parameter list this.outputParameters.push(outputParameterName); this.outputRangeMap = this.determineOutputRanges(this.dataMap, this.outputParameters); } /** * Returns a list of unique values for the given parameter * * @param parameter - requested input parameter */ public getUniqueInputParameters(parameter: string): string[] { return this.inputParametersMap.get(parameter); } /** * Traverses the input-output relations in the order of the given parameters array, considering the fixedParameters mapping * @param parameters - permutation of input parameters * @param fixedParameters - mapping of fixed parameter values * @param callbackfn - callback called for each input-output relation */ public foreach(parameters: string[], fixedParameters: Map<string, string>, callbackfn: (input: object, output: object) => void): void { // create key instance and traverse the parameters let key: object = {}; // this.fixedParams.clear; if (fixedParameters && fixedParameters.size > 0) { for (let [parameter, value] of fixedParameters.entries()) { key[parameter] = value; // this.fixedParams.set(parameter, value); } } // ignore the fixed parameters if in parameters let parameterList: string[] = []; for (let p of parameters) { if (!fixedParameters.has(p)) { parameterList.push(p); } } // TODO: ensure valid parameters list (must be a permutation of 'this.inputparameters') this.traverseParameters(key, parameterList, callbackfn); } private traverseParameters(key: object, parameters: string[], callbackfn: (input: object, output: object) => void): void { // remove next parameter from stack let p = parameters[0]; // iterate over all unique values of this parameter for (let parameterValue of this.inputParametersMap.get(p)) { key[p] = parameterValue; // did we reach the end of the parameter stack? if (parameters.length == 1) { // last parameter - trigger callback let output = this.dataMap.get(key); if (output) { callbackfn(Object.assign({}, key), output) } else { // FIXME: here we could allow sparse data and simply skip non existing entries throw new Error('invalid data mapping, no output for input found: ' + JSON.stringify(key)); } } else { // still parameters left on the stack - continue traversing this.traverseParameters(key, parameters.slice(1), callbackfn); } } } /** * Provides a label mapping with the following structure: * ['outputKey' => ['label' => number]] * @returns */ public getLabelMap(): Map<string, Map<string, number>> { return this.labelMap; } public getLabelMapping(outputKey: string, outputValue: string): number { if(this.labelMap && this.labelMap.has(outputKey) && this.labelMap.get(outputKey).has(outputValue)) { return this.labelMap.get(outputKey).get(outputValue); } else { console.warn('unknown label mapping requested for ', [outputKey, outputValue]); return Number.NaN; } } }