-
Notifications
You must be signed in to change notification settings - Fork 171
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added implemation of the ConfigTree.
- Loading branch information
Showing
9 changed files
with
240 additions
and
1 deletion.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package net.finmath.util.config; | ||
|
||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.stream.Collectors; | ||
|
||
import net.finmath.util.config.nodes.ConfigNode; | ||
import net.finmath.util.config.nodes.Node; | ||
import net.finmath.util.config.nodes.SpecialNodes; | ||
import net.finmath.util.config.nodes.ValueNode; | ||
|
||
/** | ||
* Config Tree: A tree based representation of configurations that can be selected with a key-value map describing the selector. | ||
* | ||
* A configuration is a value (Object) assigned to a selector (Map<String, Object>). | ||
* A selector is a key-value map where certain properties (String) have certain values (Object). | ||
* Properties of the selector are checked in a fixed order, | ||
* such that a tree is formed, where each property corresponds to a level (depth) in the tree. | ||
* Each level has a special branch for DEFAULT VALUES, if the selector value does not match any value of other nodes. | ||
* | ||
* @author Christian Fries | ||
*/ | ||
public class ConfigTree { | ||
|
||
private final Node root; | ||
|
||
/** | ||
* Construct the tree. | ||
* | ||
* @param keyOrder Order in which the string keys of a selector define the levels of the tree. | ||
* @param configs A list, where each element is map of keys to object. The key "value" is interpreted as the configuration value. All other keys are interpreted as configuration properties. | ||
*/ | ||
public ConfigTree(List<String> keyOrder, List<Map<String, Object>> configs) { | ||
this.root = group(keyOrder, configs); | ||
} | ||
|
||
/** | ||
* Get the configuration for a given specification of the properties (selector). | ||
* | ||
* @param selector Maps the name (String) of a property to its value (Object). | ||
* @return The configuration value for the given selector. | ||
*/ | ||
public Object getConfig(Map<String, Object> selector) { | ||
|
||
Node node = this.root; | ||
|
||
while(node instanceof ConfigNode) { | ||
ConfigNode configNode = (ConfigNode)node; | ||
if(selector.containsKey(configNode.getKey()) && configNode.getValueToConfig().keySet().contains(selector.get(configNode.getKey()))) { | ||
node = configNode.getValueToConfig().get(selector.get(configNode.getKey())); | ||
} | ||
else { | ||
node = configNode.getValueToConfig().get(SpecialNodes.DEFAULT_VALUE); | ||
} | ||
} | ||
|
||
if(node instanceof ValueNode) { | ||
ValueNode valueNode = (ValueNode)node; | ||
return valueNode.getValue(); | ||
} | ||
else { | ||
throw new IllegalArgumentException("Unable to resolve configuration from the given properties."); | ||
} | ||
} | ||
|
||
/** | ||
* Helper for the constructor. Recursive contruction of the tree. | ||
* | ||
* @param keyOrder Given key order. | ||
* @param configs List of configs. | ||
* @return Node of the (sub-)tree for the given config key. | ||
*/ | ||
private Node group(List<String> keyOrder, List<Map<String, Object>> configs) { | ||
if(keyOrder.size() == 0) { | ||
if(configs.size() == 1) { | ||
Map<String, Object> config = configs.get(0); | ||
Object value = config.get("value"); | ||
return new ValueNode( value); | ||
} | ||
else { | ||
throw new IllegalArgumentException("Multiple configs for same values."); | ||
} | ||
} | ||
|
||
// Group all elements by the first key.... | ||
String key = keyOrder.get(0); | ||
Map<Object, List<Map<String, Object>>> grouped = configs.stream().collect(Collectors.groupingBy(map -> map.get(key))); | ||
|
||
// ...call group (recursive) for all values below this key... | ||
List<String> keyOrderRemain = keyOrder.subList(1, keyOrder.size()); | ||
Map<Object, Node> valueToConfig = grouped.entrySet().stream().collect(Collectors.toMap( | ||
Map.Entry::getKey, entry -> group(keyOrderRemain, entry.getValue()))); | ||
|
||
// ...create a ConfigNode for this key. | ||
return new ConfigNode(key, valueToConfig); | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
src/main/java/net/finmath/util/config/nodes/ConfigNode.java
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,23 @@ | ||
package net.finmath.util.config.nodes; | ||
|
||
import java.util.Map; | ||
|
||
public class ConfigNode implements Node { | ||
|
||
private final String key; | ||
private final Map<Object, Node> valueToConfig; | ||
|
||
public ConfigNode(String key, Map<Object, Node> valueToConfig) { | ||
super(); | ||
this.key = key; | ||
this.valueToConfig = valueToConfig; | ||
} | ||
|
||
public String getKey() { | ||
return key; | ||
} | ||
|
||
public Map<Object, Node> getValueToConfig() { | ||
return valueToConfig; | ||
} | ||
} |
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,3 @@ | ||
package net.finmath.util.config.nodes; | ||
|
||
public interface Node {} |
5 changes: 5 additions & 0 deletions
5
src/main/java/net/finmath/util/config/nodes/SpecialNodes.java
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,5 @@ | ||
package net.finmath.util.config.nodes; | ||
|
||
public enum SpecialNodes { | ||
DEFAULT_VALUE; | ||
} |
15 changes: 15 additions & 0 deletions
15
src/main/java/net/finmath/util/config/nodes/ValueNode.java
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,15 @@ | ||
package net.finmath.util.config.nodes; | ||
|
||
public class ValueNode implements Node { | ||
|
||
private final Object value; | ||
|
||
public ValueNode(Object value) { | ||
super(); | ||
this.value = value; | ||
} | ||
|
||
public Object getValue() { | ||
return value; | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
src/main/java/net/finmath/util/config/nodes/package-info.java
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,6 @@ | ||
/** | ||
* Utilities to manage configurations. | ||
* | ||
* @author Christian Fries | ||
*/ | ||
package net.finmath.util.config.nodes; |
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,6 @@ | ||
/** | ||
* Node implementation for the {@link net.finmath.util.config.ConfigTree}. | ||
* | ||
* @author Christian Fries | ||
*/ | ||
package net.finmath.util.config; |
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 |
---|---|---|
@@ -1,5 +1,5 @@ | ||
/** | ||
* Provides utility classes. | ||
* Some utilities. | ||
* | ||
* @author Christian Fries | ||
*/ | ||
|
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,84 @@ | ||
package net.finmath.util.config; | ||
|
||
import static org.junit.jupiter.api.Assertions.*; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
import org.junit.jupiter.api.Assertions; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import net.finmath.util.config.nodes.SpecialNodes; | ||
|
||
/** | ||
* Configuration Test | ||
* | ||
* @author Christian Fries | ||
*/ | ||
class ConfigTreeTest { | ||
|
||
@Test | ||
void test() { | ||
|
||
/** | ||
* Create a list of map of configs (this is the config file - each map is a row, the keys are the columns) | ||
*/ | ||
List<Object> prop1Values = List.of(0.5, 1.0, SpecialNodes.DEFAULT_VALUE); | ||
List<Object> prop2Values = List.of(1, 2, SpecialNodes.DEFAULT_VALUE); | ||
List<Object> prop3Values = List.of("a", "b", "c", SpecialNodes.DEFAULT_VALUE); | ||
|
||
Double valueForConfig = 0.0; | ||
List<Map<String, Object>> configs = new ArrayList<>(); | ||
for(Object prop1Value : prop1Values) { | ||
for(Object prop2Value : prop2Values) { | ||
for(Object prop3Value : prop3Values) { | ||
configs.add(Map.of( | ||
"prop1", prop1Value, | ||
"prop2", prop2Value, | ||
"prop3", prop3Value, | ||
"value", valueForConfig | ||
)); | ||
valueForConfig += 1.0; | ||
} | ||
} | ||
} | ||
|
||
System.out.println("Input Configurations"); | ||
configs.forEach(System.out::println); | ||
System.out.println("_".repeat(79)); | ||
|
||
// Build configTree | ||
ConfigTree configTree = new ConfigTree(List.of("prop1", "prop2", "prop3"), configs); | ||
|
||
// Fetch some stuff | ||
|
||
print(configTree, Map.of( | ||
"prop1", Double.valueOf(0.5), | ||
"prop2", Integer.valueOf(1), | ||
"prop3", String.valueOf("b") | ||
) | ||
,1.0); | ||
|
||
print(configTree, Map.of( | ||
"prop1", Double.valueOf(3), | ||
"prop2", Integer.valueOf(1), | ||
"prop3", String.valueOf("b") | ||
), | ||
25.0); | ||
|
||
print(configTree, Map.of( | ||
"prop1", Double.valueOf(0.5), | ||
"prop2", Integer.valueOf(1), | ||
"prop3", String.valueOf("a") | ||
), | ||
0.0); | ||
} | ||
|
||
private static void print(ConfigTree configTree, Map<String, Object> selector, Object expected) { | ||
Object value = configTree.getConfig(selector); | ||
System.out.print(value + "\tfor\t" + selector.toString()); | ||
Assertions.assertEquals(expected, value); | ||
System.out.println("\tOK"); | ||
} | ||
} |