PageRenderTime 89ms CodeModel.GetById 63ms RepoModel.GetById 2ms app.codeStats 0ms

/vol2/vol2-csharp-examples/AIFH-Vol2/Examples/GP/EvaluateExpression.cs

https://gitlab.com/alvinahmadov2/aifh
C# | 334 lines | 206 code | 30 blank | 98 comment | 18 complexity | 182df98384f3e2d26ae3fb2aaa132e78 MD5 | raw file
  1. // Artificial Intelligence for Humans
  2. // Volume 2: Nature-Inspired Algorithms
  3. // C# Version
  4. // http://www.aifh.org
  5. // http://www.jeffheaton.com
  6. //
  7. // Code repository:
  8. // https://github.com/jeffheaton/aifh
  9. //
  10. // Copyright 2014 by Jeff Heaton
  11. //
  12. // Licensed under the Apache License, Version 2.0 (the "License");
  13. // you may not use this file except in compliance with the License.
  14. // You may obtain a copy of the License at
  15. //
  16. // http://www.apache.org/licenses/LICENSE-2.0
  17. //
  18. // Unless required by applicable law or agreed to in writing, software
  19. // distributed under the License is distributed on an "AS IS" BASIS,
  20. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  21. // See the License for the specific language governing permissions and
  22. // limitations under the License.
  23. //
  24. // For more information on Heaton Research copyrights, licenses
  25. // and trademarks visit:
  26. // http://www.heatonresearch.com/copyright
  27. //
  28. using System;
  29. using System.Globalization;
  30. using System.Text;
  31. using AIFH_Vol2.Core;
  32. using AIFH_Vol2.Core.Genetic.Trees;
  33. using AIFH_Vol2.Core.Randomize;
  34. namespace AIFH_Vol2.Examples.GP
  35. {
  36. /// <summary>
  37. /// Evaluate expression. This class shows how to construct a tree evaluator that will evaluate the following
  38. /// operators:
  39. ///
  40. /// add, sub, div, mul, negative, power, sqrt, as well as variables.
  41. ///
  42. /// This class could easily be modified to support additional operators.
  43. /// </summary>
  44. public class EvaluateExpression : EvaluateTree
  45. {
  46. /// <summary>
  47. /// The opcode for add.
  48. /// </summary>
  49. public const int OPCODE_ADD = 0;
  50. /// <summary>
  51. /// The opcode for subtract.
  52. /// </summary>
  53. public const int OPCODE_SUB = 1;
  54. /// <summary>
  55. /// The opcode for divide.
  56. /// </summary>
  57. public const int OPCODE_DIV = 2;
  58. /// <summary>
  59. /// The opcode for multiply.
  60. /// </summary>
  61. public const int OPCODE_MUL = 3;
  62. /// <summary>
  63. /// The opcode for negative.
  64. /// </summary>
  65. public const int OPCODE_NEG = 4;
  66. /// <summary>
  67. /// The opcode for raise to the power.
  68. /// </summary>
  69. public const int OPCODE_POWER = 5;
  70. /// <summary>
  71. /// The opcode for square root.
  72. /// </summary>
  73. public const int OPCODE_SQRT = 6;
  74. /// <summary>
  75. /// The start of the constant and variable opcodes.
  76. /// </summary>
  77. public const int OPCODE_VAR_CONST = 7;
  78. /// <summary>
  79. /// The constant values.
  80. /// </summary>
  81. private readonly double[] constValues;
  82. /// <summary>
  83. /// The number of variables.
  84. /// </summary>
  85. private readonly int varCount;
  86. /// <summary>
  87. /// The constructor.
  88. /// </summary>
  89. /// <param name="rnd">A random number generator.</param>
  90. /// <param name="numConst">The number of constants.</param>
  91. /// <param name="numVar">The number of variables.</param>
  92. /// <param name="minConstValue">The minimum amount for a constant.</param>
  93. /// <param name="maxConstValue">The maximum amount for a constant.</param>
  94. public EvaluateExpression(IGenerateRandom rnd, int numConst, int numVar, double minConstValue,
  95. double maxConstValue)
  96. {
  97. constValues = new double[numConst];
  98. varCount = numVar;
  99. for (int i = 0; i < constValues.Length; i++)
  100. {
  101. constValues[i] = rnd.NextDouble(minConstValue, maxConstValue);
  102. }
  103. }
  104. /**
  105. * Construct an evaluator with 1 variable, and 100 constants ranging between (-5,5)
  106. *
  107. * @param rnd A random number generator.
  108. */
  109. public EvaluateExpression(IGenerateRandom rnd)
  110. : this(rnd, 100, 1, -5, 5)
  111. {
  112. }
  113. /// <inheritdoc />
  114. public override int VarConstOpcode
  115. {
  116. get { return OPCODE_VAR_CONST; }
  117. }
  118. /// <inheritdoc />
  119. public override int NumConst
  120. {
  121. get { return constValues.Length; }
  122. }
  123. /// <inheritdoc />
  124. public override int NumVar
  125. {
  126. get { return varCount; }
  127. }
  128. /// <inheritdoc />
  129. public override int DetermineChildCount(int opcode)
  130. {
  131. switch (opcode)
  132. {
  133. case OPCODE_ADD:
  134. return 2;
  135. case OPCODE_SUB:
  136. return 2;
  137. case OPCODE_DIV:
  138. return 2;
  139. case OPCODE_MUL:
  140. return 2;
  141. case OPCODE_NEG:
  142. return 1;
  143. case OPCODE_POWER:
  144. return 2;
  145. case OPCODE_SQRT:
  146. return 1;
  147. default:
  148. return 0;
  149. }
  150. }
  151. /// <summary>
  152. /// Get the text for an opcode.
  153. /// </summary>
  154. /// <param name="opcode">The opcode.</param>
  155. /// <returns>The text for the opcode.</returns>
  156. public String GetOpcodeText(int opcode)
  157. {
  158. switch (opcode)
  159. {
  160. case OPCODE_NEG:
  161. return "-";
  162. case OPCODE_ADD:
  163. return "+";
  164. case OPCODE_SUB:
  165. return "-";
  166. case OPCODE_DIV:
  167. return "/";
  168. case OPCODE_MUL:
  169. return "*";
  170. case OPCODE_POWER:
  171. return "^";
  172. case OPCODE_SQRT:
  173. return "sqrt";
  174. default:
  175. int index = opcode - OPCODE_VAR_CONST;
  176. if (index >= (constValues.Length + varCount))
  177. {
  178. throw new AIFHError("Invalid opcode: " + opcode);
  179. }
  180. if (index < varCount)
  181. {
  182. return "" + ((char)('a' + index));
  183. }
  184. return constValues[index - varCount].ToString(CultureInfo.InvariantCulture);
  185. }
  186. }
  187. /// <summary>
  188. /// Display an expression as LISP (the programming language)
  189. /// </summary>
  190. /// <param name="node">The root node.</param>
  191. /// <returns>The LISP for the expression.</returns>
  192. public String DisplayExpressionLISP(TreeGenomeNode node)
  193. {
  194. var result = new StringBuilder();
  195. if (DetermineChildCount(node.Opcode) == 0)
  196. {
  197. result.Append(GetOpcodeText(node.Opcode));
  198. }
  199. else
  200. {
  201. result.Append("(");
  202. result.Append(GetOpcodeText(node.Opcode));
  203. foreach (TreeGenomeNode child in node.Children)
  204. {
  205. result.Append(" ");
  206. result.Append(DisplayExpressionLISP(child));
  207. }
  208. result.Append(")");
  209. }
  210. return result.ToString();
  211. }
  212. /// <summary>
  213. /// Display an expression as normal infix.
  214. /// </summary>
  215. /// <param name="node">The root node.</param>
  216. /// <returns>The infix string.</returns>
  217. public String DisplayExpressionNormal(TreeGenomeNode node)
  218. {
  219. var result = new StringBuilder();
  220. if (DetermineChildCount(node.Opcode) == 0)
  221. {
  222. result.Append(GetOpcodeText(node.Opcode));
  223. }
  224. else
  225. {
  226. int childCount = DetermineChildCount(node.Opcode);
  227. if (childCount == 0)
  228. {
  229. result.Append(GetOpcodeText(node.Opcode));
  230. }
  231. else
  232. {
  233. String name = GetOpcodeText(node.Opcode);
  234. if (name.Length > 1)
  235. {
  236. result.Append(name);
  237. result.Append("(");
  238. bool first = true;
  239. foreach (TreeGenomeNode child in node.Children)
  240. {
  241. if (!first)
  242. {
  243. result.Append(",");
  244. }
  245. result.Append(DisplayExpressionNormal(child));
  246. first = false;
  247. }
  248. result.Append(")");
  249. }
  250. else
  251. {
  252. result.Append("(");
  253. if (childCount == 2)
  254. {
  255. result.Append(DisplayExpressionNormal(node.Children[0]));
  256. result.Append(name);
  257. result.Append(DisplayExpressionNormal(node.Children[1]));
  258. result.Append(")");
  259. }
  260. else
  261. {
  262. result.Append(name);
  263. result.Append(DisplayExpressionNormal(node.Children[0]));
  264. result.Append(")");
  265. }
  266. }
  267. }
  268. }
  269. return result.ToString();
  270. }
  271. /// <inheritdoc />
  272. public override double Evaluate(TreeGenomeNode node, double[] varValues)
  273. {
  274. switch (node.Opcode)
  275. {
  276. case OPCODE_NEG:
  277. return -(Evaluate(node.Children[0], varValues));
  278. case OPCODE_ADD:
  279. return Evaluate(node.Children[0], varValues) + Evaluate(node.Children[1], varValues);
  280. case OPCODE_SUB:
  281. return Evaluate(node.Children[0], varValues) - Evaluate(node.Children[1], varValues);
  282. case OPCODE_DIV:
  283. return Evaluate(node.Children[0], varValues) / Evaluate(node.Children[1], varValues);
  284. case OPCODE_MUL:
  285. return Evaluate(node.Children[0], varValues) * Evaluate(node.Children[1], varValues);
  286. case OPCODE_POWER:
  287. return Math.Pow(Evaluate(node.Children[0], varValues), Evaluate(node.Children[1], varValues));
  288. case OPCODE_SQRT:
  289. return Math.Sqrt(Evaluate(node.Children[0], varValues));
  290. default:
  291. int index = node.Opcode - OPCODE_VAR_CONST;
  292. if (index >= (constValues.Length + varCount))
  293. {
  294. throw new AIFHError("Invalid opcode: " + node.Opcode);
  295. }
  296. if (index < varCount)
  297. {
  298. return varValues[index];
  299. }
  300. return constValues[index - varCount];
  301. }
  302. }
  303. }
  304. }