/// <summary> /// Method to convert a given categorical domain into a sepecific <see cref="CategoricalEncodingBase"/>. /// See: http://www.kdnuggets.com/2015/12/beyond-one-hot-exploration-categorical-variables.html. /// </summary> /// <typeparam name="T"> /// Domain value type. /// </typeparam> /// <param name="parameterName"> /// Name of the parameter that uses <paramref name="domain"/>. /// </param> /// <param name="domain"> /// The <see cref="DomainBase{T}"/>. /// </param> /// <returns> /// The <see cref="ConvertedCategory{T}"/>. /// </returns> public ConvertedCategory <T> Encode <T>(string parameterName, CategoricalDomain <T> domain) { if (string.IsNullOrWhiteSpace(parameterName)) { throw new ArgumentException("String \"parameterName\" must not be null, empty, or whitespace.", nameof(parameterName)); } if (ReferenceEquals(domain, null)) { throw new ArgumentNullException(nameof(domain)); } this.ValidateDomain(domain); var categoryValues = domain.PossibleValues.ToArray(); var categoryToDoubleRepresentation = new Dictionary <T, double[]>(); var domainRepresentationLength = this.NumberOfGeneratedColumns(domain); for (var index = 0; index < categoryValues.Length; index++) { var currentCategoricalValue = categoryValues[index]; var singleValueEncoding = this.EncodeNextValue(index, domainRepresentationLength); categoryToDoubleRepresentation.Add(currentCategoricalValue, singleValueEncoding); } var categoryEncoding = new ConvertedCategory <T>(parameterName, categoryToDoubleRepresentation, domain); return(categoryEncoding); }
/// <summary> /// Creates a <see cref="CategoricalDomain{T}"/> consisting of <paramref name="members"/> strings of the form /// "CategoricalValue_{number}". Iteration starts at 1. /// </summary> /// <param name="members">Number of categories.</param> /// <returns>The created <see cref="CategoricalDomain{T}"/>.</returns> private CategoricalDomain <string> GetTestDomain(int members) { var domainMembers = Enumerable.Range(1, members).Select(m => $"CategoricalValue_{m}").ToList(); var domain = new CategoricalDomain <string>(domainMembers); return(domain); }
/// <summary> /// Converts this node to an <see cref="OrNode{T}"/>. /// </summary> /// <typeparam name="T">The type of values the represented parameter can take.</typeparam> /// <returns>The converted <see cref="OrNode{T}"/>.</returns> /// <exception cref="XmlException">Thrown if the object was read from XML in such a way that it /// does not represent a valid <see cref="IParameterTreeNode"/> object.</exception> protected override IParameterTreeNode ConvertToParameterTreeNode<T>() { // Cast domain to correct type. CategoricalDomain<T> categoricalDomain = this.domain.ConvertToParameterTreeDomain() as CategoricalDomain<T>; if (categoricalDomain == null) { throw new XmlException( $"Domain of OR node '{this.id}' was not of type {typeof(CategoricalDomain<T>)} as expected."); } // Create OR node. var node = new OrNode<T>(this.id, categoricalDomain); // Add children: foreach (var choice in this.choice) { // Check activator is of correct type. if (!(choice.Item is T)) { throw new XmlException( $"OR node '{this.id}' had a choice of type {choice.Item.GetType()} instead of {typeof(T)}."); } // Add child. node.AddChild((T)choice.Item, choice.child.ConvertToParameterTreeNode()); } return node; }
/// <summary> /// Creates a <see cref="ParameterTree"/> consisting of a single node with categorical domain. /// </summary> /// <typeparam name="T">Type of the categorical domain.</typeparam> /// <param name="domain">The categorical domain.</param> /// <returns>The created <see cref="ParameterTree"/>.</returns> private ParameterTree SingleCategoryTree <T>(CategoricalDomain <T> domain) { var root = new ValueNode <T>("CategoricalFeature", domain); var tree = new ParameterTree(root); return(tree); }
public override void MutateGeneValueThrowsExceptionForWrongType() { IDomain domain = new CategoricalDomain <int>(new List <int> { 1 }); Assert.Throws <ArgumentOutOfRangeException>(() => domain.MutateGeneValue(new Allele <double>(1.0), CategoricalDomainTest.dummyVariancePercentage)); }
public override void ContainsGeneValueReturnsFalseForWrongType() { IDomain domain = new CategoricalDomain <int>(new List <int> { 1 }); Assert.False( domain.ContainsGeneValue(new Allele <double>(1.0)), $"Wrong type is categorized as legal gene value."); }
public void ToStringShowsAllCategories() { IDomain domain = new CategoricalDomain <int>(new List <int> { 1, -4, 17 }); Assert.Equal( "{1, -4, 17}", domain.ToString()); }
public void ContainsGeneValueReturnsTrueForSubtype() { DomainBase <object> objectDomain = new CategoricalDomain <object>(new List <object> { "a1" }); var stringAllele = new Allele <string>("a1"); Assert.True( objectDomain.ContainsGeneValue(stringAllele), $"{stringAllele} was not identified as legal value of domain {objectDomain}."); }
/// <summary> /// Initializes a new instance of the <see cref="GenomeTransformationTest"/> class. /// Serves as test initialize method. /// </summary> public GenomeTransformationTest() { this._categoricalDomain = new CategoricalDomain <int>(Enumerable.Range(0, 10).ToList()); var root = new AndNode(); var contNode = new ValueNode <double>("continuous", new ContinuousDomain()); var categoricalNode = new ValueNode <int>("test", this._categoricalDomain); root.AddChild(contNode); root.AddChild(categoricalNode); this._tree = new ParameterTree(root); }
/// <summary> /// Initializes a new instance of the <see cref="OrNode{T}" /> class. /// </summary> /// <param name="identifier">The parameter's identifier. Must be unique.</param> /// <param name="domain">The parameter's domain. It must either contain value types or strings.</param> /// <exception cref="ArgumentException">Thrown if the type contained in the domain is a reference type /// which is not a string.</exception> public OrNode(string identifier, CategoricalDomain <T> domain) : base(identifier) { // Check the type of the OR node. We cannot handle arbitrary reference types because the internal // dictionary would fail on serialization then. Another option would have been to provide an // IEqualityComparer independent of the reference, but it is assumed that the demand for reference // type OR nodes is not that high anyway. if (!typeof(T).IsValueType && !typeof(T).Equals(typeof(string))) { throw new ArgumentException( "OrNodes may only be built for value types and strings.", "domain"); } this._domain = domain; }
/// <summary> /// Tries to retrieve the cached encoding for the given <paramref name="category"/>, or encodes + stores it in <see cref="EncodedCategories"/>. /// </summary> /// <typeparam name="T"> /// The type of <paramref name="category"/> domain. /// </typeparam> /// <param name="identifier"> /// The identifier. /// </param> /// <param name="category"> /// The encoding. /// </param> /// <returns> /// The <see cref="ConvertedCategory{T}"/>. /// </returns> protected IConvertedCategory EncodeNodeCategory <T>(string identifier, CategoricalDomain <T> category) { // only lock on the affected dictionary. this is the only block form which dictionary is accessed. lock (this._transformationAndEncodingLock) { if (this.EncodedCategories.ContainsKey(identifier)) { return(this.EncodedCategories[identifier] as IConvertedCategory); } // only local variables/reading access in CategoricalEncoding. No need to lock in there. var encoding = this.CategoricalEncoding.Encode(identifier, category); this.EncodedCategories.Add(identifier, encoding); return(encoding); } }
public void PossibleValuesAreIndependentFromProvidedList() { // Create CategoricalDomain var provided = new List <int>(CategoricalDomainTest.categories); this._categoricalDomain = new CategoricalDomain <int>(provided); // Check that values are correctly set. Assert.True(TestUtils.SetsAreEquivalent(this._categoricalDomain.PossibleValues, provided)); // Change the list that was used for initialization. provided.Add(4); // It should now be different from the possible values. Assert.False( TestUtils.SetsAreEquivalent(this._categoricalDomain.PossibleValues, provided), $"Values of categorical domain have been changed externally."); }
/// <summary> /// Builds a <see cref="ParameterTree"/> which consists of integer value nodes "1intDom" and "2intDom" and a /// categorical domain which is dependent on "1intDom". /// </summary> /// <returns>The created <see cref="ParameterTree"/>.</returns> private ParameterTree BuildCategoricalDomainParameterTree() { // Create the nodes. IntegerDomain allIntegers = new IntegerDomain(); var catDomain = new CategoricalDomain <int>(new List <int> { 1, 2, 3, 4, 5, 6 }); ValueNode <int> a = new ValueNode <int>("1intDom", allIntegers); ValueNode <int> b = new ValueNode <int>("2intDom", allIntegers); ValueNode <int> c = new ValueNode <int>("3catDom", catDomain); AndNode root = new AndNode(); // Create connections. a.SetChild(c); root.AddChild(a); root.AddChild(b); // Return instantiated tree. return(new ParameterTree(root)); }
public void MutateDoesNotDepartFromUniformDistribution() { // Set up categorical domain with integer values 0 - 3. var possibleValues = new List <int> { 0, 1, 2, 3 }; CategoricalDomain <int> domain = new CategoricalDomain <int>(possibleValues); // Remember which values were generated for a lot of iterations. double[] observations = new double[CategoricalDomainTest.triesForRandomTests]; Allele <int> geneValue = new Allele <int>(1); for (int i = 0; i < CategoricalDomainTest.triesForRandomTests; i++) { observations[i] = (int)domain.MutateGeneValue(geneValue, CategoricalDomainTest.dummyVariancePercentage).GetValue(); } // Apply the Chi-Squared test. ChiSquareTest uniformTest = new ChiSquareTest(observations, new UniformDiscreteDistribution(0, 3)); Assert.False( uniformTest.Significant, $"Mutation was found to not produce a uniform distribution by the Chi-Squared test with significance level {uniformTest.Size}."); }
/// <summary> /// Constructs a node of the subclass of <see cref="ParameterNodeBase{T}"/> that one wants to test. /// </summary> /// <typeparam name="T">The parameter's type.</typeparam> /// <param name="identifier">The parameter's identifier.</param> /// <param name="domain">The parameter's domain.</param> /// <returns>The constructed node.</returns> protected abstract ParameterNodeBase <T> ConstructNode <T>(string identifier, CategoricalDomain <T> domain);
/// <summary> /// Constructs an <see cref="OrNode{T}"/>. /// </summary> /// <typeparam name="T">The parameter's type.</typeparam> /// <param name="identifier">The identifier.</param> /// <param name="domain">The parameter's domain.</param> /// <returns>The constructed node.</returns> protected override ParameterNodeBase <T> ConstructNode <T>(string identifier, CategoricalDomain <T> domain) { return(new OrNode <T>(identifier, domain)); }
/// <summary> /// Initializes a new instance of the <see cref="ConvertedCategory{T}"/> class. /// </summary> /// <param name="parameterName"> /// The name of the represented parameter. /// </param> /// <param name="categoryValues"> /// The column representation for each <typeparamref name="T"/> in <see cref="CategoricalDomain{T}.PossibleValues"/>. /// </param> /// <param name="underlyingDomain"> /// The underlying <see cref="CategoricalDomain{T}"/>. /// </param> public ConvertedCategory(string parameterName, Dictionary <T, double[]> categoryValues, CategoricalDomain <T> underlyingDomain) { if (string.IsNullOrWhiteSpace(parameterName)) { throw new ArgumentException("String \"parameterName\" must not be null, empty, or whitespace.", nameof(parameterName)); } if (categoryValues is null) { throw new ArgumentNullException(nameof(categoryValues)); } var prevLength = -1; foreach (var mappingValuePair in categoryValues) { if (mappingValuePair.Key == null || (prevLength >= 0 && prevLength != mappingValuePair.Value.Length)) { throw new ArgumentException("All category values need to be initialized and of the same length.", nameof(categoryValues)); } prevLength = mappingValuePair.Value.Length; } var distinctRepresentations = categoryValues.Select(cv => cv.Value).Distinct(new DoubleArrayEqualityComparer()).Count(); if (categoryValues.Count != distinctRepresentations) { throw new ArgumentException("Double Representations of features need to be distinct."); } this.ParameterName = parameterName; this.UnderlyingCategoricalDomain = underlyingDomain ?? throw new ArgumentException("Domain musn't be null.", nameof(underlyingDomain)); this.CategoryValues = categoryValues; this.ColumnCount = this.CategoryValues.Any() ? this.CategoryValues.First().Value.Length : -1; ((IConvertedCategory)this).Initialize(); }
/// <summary> /// Initializes a new instance of the <see cref="CategoricalDomainTest"/> class. /// </summary> public CategoricalDomainTest() { this._categoricalDomain = new CategoricalDomain <int>(CategoricalDomainTest.categories); }