-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extended functionality in EnsembleParameters
- Loading branch information
Showing
5 changed files
with
330 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/** | ||
* Immutable class for storing a min/max scalar range | ||
*/ | ||
|
||
export class MinMax { | ||
readonly min: number; | ||
readonly max: number; | ||
|
||
constructor(min: number, max: number) { | ||
this.min = min; | ||
this.max = max; | ||
} | ||
|
||
static createInvalid(): MinMax { | ||
return new MinMax(Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY); | ||
} | ||
|
||
static fromNumericValues(values: Iterable<number>): MinMax { | ||
let min = Number.POSITIVE_INFINITY; | ||
let max = Number.NEGATIVE_INFINITY; | ||
for (const v of values) { | ||
if (v < min) { | ||
min = v; | ||
} | ||
if (v > max) { | ||
max = v; | ||
} | ||
} | ||
|
||
if (min <= max) { | ||
return new MinMax(min, max); | ||
} else { | ||
return MinMax.createInvalid(); | ||
} | ||
} | ||
|
||
/** | ||
* Returns a new MinMax object that is extend to include values from other min/max range | ||
* Will handle invalid ranges (min > max) in both this and the other object. | ||
*/ | ||
extendedBy(otherMinMax: MinMax): MinMax { | ||
if (!otherMinMax.isValid()) { | ||
return new MinMax(this.min, this.max); | ||
} | ||
if (!this.isValid()) { | ||
return new MinMax(otherMinMax.min, otherMinMax.max); | ||
} | ||
|
||
const newMin = Math.min(this.min, otherMinMax.min); | ||
const newMax = Math.max(this.max, otherMinMax.max); | ||
return new MinMax(newMin, newMax); | ||
} | ||
|
||
/** | ||
* Returns true if the range is valid, i.e. if minimum <= maximum | ||
*/ | ||
isValid(): boolean { | ||
if (this.min <= this.max) { | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { EnsembleParameters, Parameter, ParameterIdent, ParameterType } from "@framework/EnsembleParameters"; | ||
import { MinMax } from "@lib/utils/MinMax"; | ||
|
||
// prettier-ignore | ||
const PARAM_ARR: Parameter[] = [ | ||
{type: ParameterType.CONTINUOUS, name: "cparam_10", groupName: null, description: "desc10", isConstant: false, isLogarithmic: false, realizations: [1,2,3], values: [11, 12, 19]}, | ||
{type: ParameterType.CONTINUOUS, name: "cparam_20", groupName: null, description: "desc20", isConstant: false, isLogarithmic: false, realizations: [1,2,3], values: [21, 22, 29]}, | ||
{type: ParameterType.CONTINUOUS, name: "cparam_50", groupName: "grp1", description: "desc50g1", isConstant: false, isLogarithmic: false, realizations: [1,2,3], values: [51, 52, 54]}, | ||
{type: ParameterType.CONTINUOUS, name: "cparam_50", groupName: "grp2", description: "desc50g2", isConstant: false, isLogarithmic: false, realizations: [1,2,3], values: [55, 56, 59]}, | ||
|
||
{type: ParameterType.DISCRETE, name: "dparam_A", groupName: null, description: "descA", isConstant: false, realizations: [1,2,3], values: [1, 2, 3]}, | ||
{type: ParameterType.DISCRETE, name: "dparam_B", groupName: null, description: "descB", isConstant: false, realizations: [1,2,3], values: ["A", "B", "C"]}, | ||
]; | ||
|
||
|
||
describe("EnsembleParameters tests", () => { | ||
test("Get list of parameter idents", () => { | ||
const ensParams = new EnsembleParameters(PARAM_ARR); | ||
{ | ||
const allIdents = ensParams.getParameterIdents(null); | ||
expect(allIdents.length).toEqual(6); | ||
expect(allIdents[0]).toEqual(ParameterIdent.fromNameAndGroup("cparam_10", null)); | ||
expect(allIdents[1]).toEqual(ParameterIdent.fromNameAndGroup("cparam_20", null)); | ||
expect(allIdents[2]).toEqual(ParameterIdent.fromNameAndGroup("cparam_50", "grp1")); | ||
expect(allIdents[3]).toEqual(ParameterIdent.fromNameAndGroup("cparam_50", "grp2")); | ||
expect(allIdents[4]).toEqual(ParameterIdent.fromNameAndGroup("dparam_A", null)); | ||
expect(allIdents[5]).toEqual(ParameterIdent.fromNameAndGroup("dparam_B", null)); | ||
} | ||
{ | ||
const contIdents = ensParams.getParameterIdents(ParameterType.CONTINUOUS); | ||
expect(contIdents.length).toEqual(4); | ||
expect(contIdents[0]).toEqual(ParameterIdent.fromNameAndGroup("cparam_10", null)); | ||
expect(contIdents[1]).toEqual(ParameterIdent.fromNameAndGroup("cparam_20", null)); | ||
expect(contIdents[2]).toEqual(ParameterIdent.fromNameAndGroup("cparam_50", "grp1")); | ||
expect(contIdents[3]).toEqual(ParameterIdent.fromNameAndGroup("cparam_50", "grp2")); | ||
} | ||
{ | ||
const discIdents = ensParams.getParameterIdents(ParameterType.DISCRETE); | ||
expect(discIdents.length).toEqual(2); | ||
expect(discIdents[0]).toEqual(ParameterIdent.fromNameAndGroup("dparam_A", null)); | ||
expect(discIdents[1]).toEqual(ParameterIdent.fromNameAndGroup("dparam_B", null)); | ||
} | ||
}); | ||
|
||
test("Check for parameter existence", () => { | ||
const ensParams = new EnsembleParameters(PARAM_ARR); | ||
|
||
expect(ensParams.hasParameter(ParameterIdent.fromNameAndGroup("cparam_10", null))).toBe(true); | ||
expect(ensParams.hasParameter(ParameterIdent.fromNameAndGroup("cparam_50", "grp1"))).toBe(true); | ||
expect(ensParams.hasParameter(ParameterIdent.fromNameAndGroup("cparam_50", "grp2"))).toBe(true); | ||
|
||
expect(ensParams.hasParameter(ParameterIdent.fromNameAndGroup("aName", "aGroup"))).toBe(false); | ||
expect(ensParams.hasParameter(ParameterIdent.fromNameAndGroup("", ""))).toBe(false); | ||
expect(ensParams.hasParameter(ParameterIdent.fromNameAndGroup("cparam_10", ""))).toBe(false); | ||
expect(ensParams.hasParameter(ParameterIdent.fromNameAndGroup("cparam_50", null))).toBe(false); | ||
}); | ||
|
||
test("Get parameters", () => { | ||
const ensParams = new EnsembleParameters(PARAM_ARR); | ||
{ | ||
const par = ensParams.getParameter(ParameterIdent.fromNameAndGroup("cparam_10", null)); | ||
expect(par.type).toEqual(ParameterType.CONTINUOUS); | ||
expect(par.name).toEqual("cparam_10"); | ||
expect(par.groupName).toEqual(null); | ||
expect(par.values).toEqual([11, 12, 19]); | ||
} | ||
{ | ||
const par = ensParams.getParameter(ParameterIdent.fromNameAndGroup("cparam_50", "grp2")); | ||
expect(par.type).toEqual(ParameterType.CONTINUOUS); | ||
expect(par.name).toEqual("cparam_50"); | ||
expect(par.groupName).toEqual("grp2"); | ||
expect(par.values).toEqual([55, 56, 59]); | ||
} | ||
{ | ||
const par = ensParams.getParameter(ParameterIdent.fromNameAndGroup("dparam_B", null)); | ||
expect(par.type).toEqual(ParameterType.DISCRETE); | ||
expect(par.name).toEqual("dparam_B"); | ||
expect(par.groupName).toEqual(null); | ||
expect(par.values).toEqual(["A", "B", "C"]); | ||
} | ||
}); | ||
|
||
test("Check that getting non-existing parameter throws", () => { | ||
const ensParams = new EnsembleParameters(PARAM_ARR); | ||
expect(() => ensParams.getParameter(ParameterIdent.fromNameAndGroup("someBogusName", null))).toThrow(); | ||
}); | ||
|
||
test("Test getting min/max values for continuous parameter", () => { | ||
const ensParams = new EnsembleParameters(PARAM_ARR); | ||
{ | ||
const minMax = ensParams.getContinuousParameterMinMax(ParameterIdent.fromNameAndGroup("cparam_10", null)); | ||
expect(minMax).toEqual(new MinMax(11, 19)); | ||
} | ||
{ | ||
const minMax = ensParams.getContinuousParameterMinMax(ParameterIdent.fromNameAndGroup("cparam_50", "grp1")); | ||
expect(minMax).toEqual(new MinMax(51, 54)); | ||
} | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { MinMax } from "@lib/utils/MinMax"; | ||
|
||
describe("MinMax tests", () => { | ||
test("Check validity of MinMax instances", () => { | ||
expect(new MinMax(0, 1).isValid()).toBe(true); | ||
expect(new MinMax(-1, -1).isValid()).toBe(true); | ||
expect(new MinMax(0, Number.POSITIVE_INFINITY).isValid()).toBe(true); | ||
expect(new MinMax(Number.NEGATIVE_INFINITY, 0).isValid()).toBe(true); | ||
|
||
expect(MinMax.createInvalid().isValid()).toBe(false); | ||
expect(new MinMax(1, 0).isValid()).toBe(false); | ||
expect(new MinMax(0, Number.NaN).isValid()).toBe(false); | ||
expect(new MinMax(Number.NaN, 0).isValid()).toBe(false); | ||
expect(new MinMax(Number.NaN, Number.NaN).isValid()).toBe(false); | ||
}); | ||
|
||
test("Check construction from numeric values", () => { | ||
expect(MinMax.fromNumericValues([]).isValid()).toBe(false); | ||
expect(MinMax.fromNumericValues([1])).toEqual(new MinMax(1, 1)); | ||
expect(MinMax.fromNumericValues([0, 1, 2, 3, 4])).toEqual(new MinMax(0, 4)); | ||
|
||
expect(MinMax.fromNumericValues(new Float32Array([0, 1, 2, 3, 4]))).toEqual(new MinMax(0, 4)); | ||
expect(MinMax.fromNumericValues(new Set<number>([0, 1, 2, 3, 4]))).toEqual(new MinMax(0, 4)); | ||
|
||
const bogusArray = [1, undefined, 2, Number.NaN, 3, 4]; | ||
expect(MinMax.fromNumericValues(bogusArray as number[])).toEqual(new MinMax(1, 4)); | ||
}); | ||
|
||
test("Check extending by another MinMax object", () => { | ||
const validMinMaxA = new MinMax(0, 1); | ||
const validMinMaxB = new MinMax(10, 11); | ||
const invalidMinMax = MinMax.createInvalid(); | ||
|
||
expect(validMinMaxA.extendedBy(validMinMaxA)).toEqual(validMinMaxA); | ||
expect(invalidMinMax.extendedBy(validMinMaxA)).toEqual(validMinMaxA); | ||
expect(validMinMaxA.extendedBy(invalidMinMax)).toEqual(validMinMaxA); | ||
|
||
expect(validMinMaxA.extendedBy(validMinMaxB)).toEqual(new MinMax(0, 11)); | ||
|
||
expect(invalidMinMax.extendedBy(invalidMinMax).isValid()).toBe(false); | ||
}); | ||
}); |