Skip to content

Commit

Permalink
created a parameter database that uses JSON input. Tested but not use…
Browse files Browse the repository at this point in the history
…d yet.
  • Loading branch information
CarrKnight committed Feb 14, 2015
1 parent f7ce7f3 commit b541bca
Show file tree
Hide file tree
Showing 8 changed files with 674 additions and 41 deletions.
201 changes: 185 additions & 16 deletions docs/yackm/notes/labnotes.html

Large diffs are not rendered by default.

74 changes: 74 additions & 0 deletions lib/model/engine/number_generator.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
part of lancaster.model;

/**
* sometimes the user needs a number, but the JSON field is actually a map. The number
* generator is supposed to turn it into a number
*/
typedef num NumberGenerator(JsonObject leaf, Random random);



final NumberGenerator DEFAULT_UNIFORM = (JsonObject leaf,Random random)
{
assert(leaf.type == "uniform");
//read max and min from the list!
num maximum= leaf["max"];
num minimum= leaf["min"];

return random.nextDouble() * (maximum-minimum) + minimum;
};



final NumberGenerator DEFAULT_NORMAL = (JsonObject leaf,Random random)
{

//here I use the ratio-of-uniforms method
//see here: http://stackoverflow.com/questions/13001485/implementing-the-ratio-of-uniforms-for-normal-distribution-in-c
assert(leaf.type == "normal");
//read the two parameters from the list
num mu= leaf.mean;
num sigma= leaf.sigma;

while(true)
{
double u=random.nextDouble();
double v=1.7156*(random.nextDouble()-0.5);
double x=u-0.449871;
double y=v.abs()+0.386595;
double q=x*x+y*(0.19600*y-0.25472*x);
if(!(q>0.27597 && (q>0.27846 || v*v>-4*log(u)*u*u)))
return mu + sigma * (v/u);
}

};


/**
* random number generator that chooses at random from a list of numbers
*/
final NumberGenerator DEFAULT_EMPIRICAL= (JsonObject leaf,Random random)
{

//here I use the ratio-of-uniforms method
//see here: http://stackoverflow.com/questions/13001485/implementing-the-ratio-of-uniforms-for-normal-distribution-in-c
assert(leaf.type == "empirical");
//read the two parameters from the list
List<num> sample = leaf.sample;
assert(sample.length > 0);


return sample.elementAt(random.nextInt(sample.length));






};






190 changes: 190 additions & 0 deletions lib/model/engine/parameter_database.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
part of lancaster.model;


/**
* Given a json file with all the parameters it organizes it in a simple database. Whatever else is in the parameters,
* "seed" is reserved and used as seed for the randomizer. If "seed" doesn't exist in JSON or is not a
* number then the current time will be used as seed
*
* a facade for a JsonObject tree; I don't let JsonObject out by itself mostly so I can keep a tight log
* on what comes out and in.
*/
class ParameterDatabase
{


final JsonObject _root;


final Map<String,NumberGenerator> _generators = new Map();


Random random;


/**
* navigate to [address]; returns null if the address is invalid
*/
ParameterDatabase(String json):
_root = new JsonObject.fromJsonString(json)
{

Object seedParameter = _root["seed"];
num seed;
if(seedParameter == null || !(seedParameter is num))
seed = new DateTime.now().millisecondsSinceEpoch;
else
seed = seedParameter;
random = new Random(seed.toInt());

//add default generators
_generators["normal"] = DEFAULT_NORMAL;
_generators["uniform"] = DEFAULT_UNIFORM;
_generators["empirical"] = DEFAULT_EMPIRICAL;

}
/**
* get whatever is at [address]. null if the address is invalid
*/
Object _getFieldAt(List<String> address)
{
Object leaf = _root;
for(String path in address)
{
leaf = leaf[path];
//if the path doesn't exist, return null
if(leaf == null)
return null;
}
return leaf;
}

/**
* navigate to [address]; returns null if the address is invalid
*/
Object _getFieldAtPath(String address)
{

return _getFieldAt(address.split("."));

}

Object _lookup(String fieldName, String bestPath, String fallbackPath)
{
//todo log

String address = bestPath.isEmpty ? fieldName : "$bestPath.$fieldName";
Object parameter =_getFieldAtPath(address);
if(parameter == null && fallbackPath != null)
{
address = "$fallbackPath.$fieldName";
parameter =_getFieldAtPath(address);
}
return parameter;
}

/**
* get the parameter as a string, if possible. If you are looking for the parameter in : <br>
* strategy1.strategy2.parameter <br>
* and if you don't find it then look in: <br>
* strategy3.parameter <br>
* then [fieldname] would be "parameter", [bestPath] would be "strategy1.strategy2" and [fallbackPath] would be "strategy3"
* Throws an exception if it's not in either. Throws also an exception if the parameter is not a string but rather a map
*/
String getAsString(String fieldName, String bestPath, [String fallbackPath=null])
{

Object parameter = _lookup(fieldName,bestPath,fallbackPath);

if(parameter ==null)
throw new Exception("Couldn't find the field neither as $bestPath.$fieldName nor $fallbackPath.$fieldName");

if(parameter is JsonObject)
throw new Exception("The parameter is a map, not a string! ${parameter.toString()}");

return parameter.toString();


}


/**
* if you need a number but you got a map it might be a random parameter. Check if it has a type and if so feed it to the
* randomizer
*/
num _generateNumber(JsonObject parameter)
{

String type = parameter["type"];
if(type == null)
throw new Exception(" you are trying to turn $parameter into a number.It iss neither a number nor has a type to randomize");

NumberGenerator generator = _generators[type];

if(generator == null)
throw new Exception("types of randomizers known: ${_generators.keys} , $type isn't one of them!");

return generator(parameter,random);



}



/**
* get the parameter as a number; If the field is a number, then it is returned immediately; if it is a map, it is fed to the number
* generator associated with its "type" field. <br>
* If you are looking for the parameter in : <br>
* strategy1.strategy2.parameter <br>
* and if you don't find it then look in: <br>
* strategy3.parameter <br>
* then [fieldname] would be "parameter", [bestPath] would be "strategy1.strategy2" and [fallbackPath] would be "strategy3"
* Throws an exception if it's not in either. Throws also an exception if the parameter is not a string but rather a map
*/
num getAsNumber(String fieldName, String bestPath, [String fallbackPath=null])
{

Object parameter = _lookup(fieldName,bestPath,fallbackPath);

if(parameter ==null)
throw new Exception("Couldn't find the field neither as $bestPath.$fieldName nor $fallbackPath.$fieldName");

if(parameter is JsonObject)
return _generateNumber(parameter);

if(parameter is String)
return num.parse(parameter);

return parameter;


}


/**
* set path.fieldName to value. Over-writes with no mercy. [path] must exists, even if [fieldname] doesn't
*/
void setField(String fieldName, String path, Object value )
{
JsonObject json = _getFieldAtPath(path);
json[fieldName] = value;

}

/**
* set path.fieldName to json. [path] must exists, even if [fieldname] doesn't
*/
void setFieldToJson(String fieldName, String path, String jsonValue )
{
JsonObject json = _getFieldAtPath(path);
json[fieldName] = new JsonObject.fromJsonString(jsonValue);

}






}
3 changes: 3 additions & 0 deletions lib/model/lancaster_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ library lancaster.model;
import 'dart:collection';
import 'dart:math';
import 'dart:async';
import 'package:json_object/json_object.dart';



Expand All @@ -23,6 +24,8 @@ import 'dart:async';
part 'engine/schedule.dart';
part 'engine/model.dart';
part 'engine/onemarket_scenario.dart';
part 'engine/parameter_database.dart';
part 'engine/number_generator.dart';

/***
* __ ___ ____ __ _ ____ ____
Expand Down
Loading

0 comments on commit b541bca

Please sign in to comment.