420 lines
15 KiB
C#
420 lines
15 KiB
C#
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Globalization;
|
||
|
using System.IO;
|
||
|
using System.Linq;
|
||
|
using System.Text.RegularExpressions;
|
||
|
|
||
|
abstract public class LSystemGeneralWordBuilder
|
||
|
{
|
||
|
abstract public LSystemNode createLSystemNode(string name, int values_number);
|
||
|
abstract public void fillArguments(LSystemNode node, string[] arguments_strings);
|
||
|
}
|
||
|
public class LSystemWordBuilder : LSystemGeneralWordBuilder
|
||
|
{
|
||
|
public override LSystemNode createLSystemNode(string name, int values_number)
|
||
|
{
|
||
|
return new LSystemNode(new LSystemNodeLiteral(name, values_number));
|
||
|
}
|
||
|
|
||
|
|
||
|
public override void fillArguments(LSystemNode node, string[] arguments_strings)
|
||
|
{
|
||
|
for (int i = 0; i < arguments_strings.Length; i++)
|
||
|
{
|
||
|
node.literal.values[i] = float.Parse(arguments_strings[i], NumberStyles.Any, CultureInfo.InvariantCulture);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public class LSystemWordGeneratorBuilder : LSystemGeneralWordBuilder
|
||
|
{
|
||
|
public Dictionary<string, int> variableIndex { get; }
|
||
|
public LSystemWordGeneratorBuilder(Dictionary<string, int> variable_index)
|
||
|
{
|
||
|
this.variableIndex = variable_index;
|
||
|
}
|
||
|
public override LSystemNode createLSystemNode(string name, int values_number)
|
||
|
{
|
||
|
return new LSystemNodeGenerator(name, values_number);
|
||
|
}
|
||
|
|
||
|
public override void fillArguments(LSystemNode node, string[] arguments_strings)
|
||
|
{
|
||
|
MathExpression[] expressions = arguments_strings.Select(argument => new MathExpression(variableIndex, argument)).ToArray();
|
||
|
LSystemNodeGenerator ng = (LSystemNodeGenerator)node;
|
||
|
ng.fillArguments(expressions);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
public class LSystemFileParser
|
||
|
{
|
||
|
//LSystemWordParser wordParser;
|
||
|
//LSystemRulesParser ruleParser;
|
||
|
|
||
|
//public LSystemFileParser(LSystemWordParser wordParser, LSystemRulesParser ruleParser) {
|
||
|
// this.wordParser = wordParser;
|
||
|
// this.ruleParser = ruleParser;
|
||
|
//}
|
||
|
public static int countParenthesisEnd(string line, char opening_char, char closing_char)
|
||
|
{
|
||
|
var parenthesises_number = 1;
|
||
|
var length = -1;
|
||
|
while (parenthesises_number > 0)
|
||
|
{
|
||
|
length++;
|
||
|
var c = line[1 + length];
|
||
|
if (c == opening_char)
|
||
|
{
|
||
|
parenthesises_number++;
|
||
|
}
|
||
|
if (c == closing_char)
|
||
|
{
|
||
|
parenthesises_number--;
|
||
|
}
|
||
|
}
|
||
|
return length;
|
||
|
}
|
||
|
public static bool parenthesisCheck(string line)
|
||
|
{
|
||
|
var parenthesises_number = 0;
|
||
|
var brackets_number = 0;
|
||
|
foreach (var s in line)
|
||
|
{
|
||
|
if (s == '(')
|
||
|
{
|
||
|
parenthesises_number++;
|
||
|
}
|
||
|
if (s == ')')
|
||
|
{
|
||
|
parenthesises_number--;
|
||
|
}
|
||
|
if (s == '[')
|
||
|
{
|
||
|
brackets_number++;
|
||
|
}
|
||
|
if (s == ']')
|
||
|
{
|
||
|
brackets_number--;
|
||
|
}
|
||
|
if (brackets_number < 0 || parenthesises_number < 0)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
return (brackets_number == 0 && parenthesises_number == 0);
|
||
|
}
|
||
|
|
||
|
public static LSystemNode parseWord(string line, LSystemGeneralWordBuilder builder)
|
||
|
{
|
||
|
var read_characters = 0;
|
||
|
LSystemNode node;
|
||
|
if (line[0] == '[')
|
||
|
{
|
||
|
node = builder.createLSystemNode("", 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
var literal_name = line.Substring(0, 1);
|
||
|
if (line.Length > 1 && line[1] == '(')
|
||
|
{
|
||
|
var length = countParenthesisEnd(line.Substring(1), '(', ')');
|
||
|
var values_string = line.Substring(2, length).Split(',');
|
||
|
node = builder.createLSystemNode(literal_name, values_string.Length);
|
||
|
|
||
|
builder.fillArguments(node, values_string);
|
||
|
//Leter and: (, )
|
||
|
read_characters += length + 3;
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
read_characters += 1;
|
||
|
node = builder.createLSystemNode(line.Substring(0, 1), 0);
|
||
|
}
|
||
|
}
|
||
|
while (line.Length > read_characters && line[read_characters] == '[')
|
||
|
{
|
||
|
|
||
|
var brackets_number = 1;
|
||
|
var length = countParenthesisEnd(line.Substring(read_characters), '[', ']');
|
||
|
var child_node = parseWord(line.Substring(read_characters + 1, length), builder);
|
||
|
read_characters += length + 2;
|
||
|
child_node.parent = node;
|
||
|
node.children.Add(child_node);
|
||
|
}
|
||
|
if (read_characters < line.Length)
|
||
|
{
|
||
|
var child_node = parseWord(line.Substring(read_characters), builder);
|
||
|
child_node.parent = node;
|
||
|
node.mainChild = (child_node);
|
||
|
}
|
||
|
return node;
|
||
|
}
|
||
|
|
||
|
public static LSystemNodeLiteralVariable parseContextLiteral(string line)
|
||
|
{
|
||
|
var name = line.Substring(0, 1);
|
||
|
var varable_index = new Dictionary<string, int>();
|
||
|
if (line.Length > 1)
|
||
|
{
|
||
|
foreach (var i in line.Substring(2, line.Length - 3).Split(',').Select((name, Index) => new { name, Index }))
|
||
|
{
|
||
|
varable_index.Add(i.name, i.Index);
|
||
|
};
|
||
|
}
|
||
|
return new LSystemNodeLiteralVariable(name, varable_index.Count, varable_index);
|
||
|
}
|
||
|
|
||
|
public static LSystemNodeLiteralVariable[] parseSuccessorsContext(string line)
|
||
|
{
|
||
|
List<LSystemNodeLiteralVariable> result = new List<LSystemNodeLiteralVariable>();
|
||
|
bool bracketStarted = false;
|
||
|
int bracketStartedIndex = 0;
|
||
|
for (int i = 0; i < line.Length; i++)
|
||
|
{
|
||
|
if (line[i] == ']')
|
||
|
{
|
||
|
if (!bracketStarted)
|
||
|
{
|
||
|
throw new Exception("invalid syntax");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result.Add(parseContextLiteral(line.Substring(bracketStartedIndex, i - bracketStartedIndex)));
|
||
|
bracketStarted = false;
|
||
|
}
|
||
|
}
|
||
|
else if (line[i] == '[')
|
||
|
{
|
||
|
if (bracketStarted)
|
||
|
{
|
||
|
throw new Exception("invalid syntax");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bracketStarted = true;
|
||
|
bracketStartedIndex = i + 1;
|
||
|
}
|
||
|
}
|
||
|
else if (!bracketStarted)
|
||
|
{
|
||
|
result.Add(parseContextLiteral(line.Substring(i)));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return result.ToArray();
|
||
|
}
|
||
|
//private static String[] parseIgnore(string line) {
|
||
|
// var items = line.Trim().Split(' ');
|
||
|
// var resut = List
|
||
|
|
||
|
//}
|
||
|
|
||
|
public static LSystemEvaluator parseLSystem(StreamReader sr)
|
||
|
{
|
||
|
string line;
|
||
|
int line_number = 0;
|
||
|
var ignored = new String[0];
|
||
|
LSystemNode axiom = null;
|
||
|
List<LSystemRule> rules = null;
|
||
|
while ((line = sr.ReadLine()) != null)
|
||
|
{
|
||
|
line_number++;
|
||
|
if (line.Trim() == "#axiom")
|
||
|
{
|
||
|
line = sr.ReadLine();
|
||
|
if (!parenthesisCheck(line))
|
||
|
{
|
||
|
throw new Exception(String.Format("In line {0} invalid syntax", line_number));
|
||
|
}
|
||
|
axiom = parseWord(line, new LSystemWordBuilder());
|
||
|
}
|
||
|
if (line.Trim().Split(' ')[0].Trim() == "#ignore")
|
||
|
{
|
||
|
ignored = line.Trim().Split(' ').Where(x => x != "#ignore" && x.Length > 0).Select(x => x.Trim()).ToArray();
|
||
|
}
|
||
|
if (line.Trim() == "#rules")
|
||
|
{
|
||
|
rules = parseLSystemRules(sr);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
return new LSystemEvaluator(axiom, rules, ignored);
|
||
|
}
|
||
|
|
||
|
private static List<LSystemRule> parseLSystemRules(StreamReader sr)
|
||
|
{
|
||
|
List<LSystemRule> rules = new List<LSystemRule>();
|
||
|
Regex separator = new Regex(@"-(\d*\.?\d*){1}>");
|
||
|
Regex weight_regex = new Regex(@"p=(\d+\.?\d*){1}");
|
||
|
string line;
|
||
|
while ((line = sr.ReadLine()) != null && line.Trim() != "#rules end")
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
if (line.Length == 0 || line[0] == '#')
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
MathExpressionComparison[] conditions = new MathExpressionComparison[0];
|
||
|
var split = separator.Match(line);
|
||
|
var line_parts = line.Split(new string[] { split.Value }, StringSplitOptions.None);
|
||
|
// check conditions;
|
||
|
//parse predecesor
|
||
|
var _t = line_parts[0].Split(':');
|
||
|
var predecesor_string = _t[0];
|
||
|
LSystemNodeLiteralVariable predecesor;
|
||
|
LSystemContext context;
|
||
|
//check if contains < or >
|
||
|
|
||
|
// check context
|
||
|
getPredecesorContext(predecesor_string, out predecesor, out context);
|
||
|
|
||
|
if (_t.Length > 1)
|
||
|
{
|
||
|
conditions = _t[1].Trim().Split(';').Select(text => MathExpressionComparasionParser.parse(predecesor.variableIndex, text.Trim())).ToArray();
|
||
|
}
|
||
|
// tochastic rule parsing
|
||
|
var sucsessor_string = line_parts[1];
|
||
|
var probabilities_list = new List<float>();
|
||
|
var consequents_list = new List<LSystemNodeGenerator>();
|
||
|
if (sucsessor_string.Trim() == "#stochastic")
|
||
|
{
|
||
|
while ((line = sr.ReadLine()) != null && line.Trim() != "#stochastic end")
|
||
|
{
|
||
|
if (line[0] == '#')
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
var weight_string = weight_regex.Match(line);
|
||
|
var weight = float.Parse(weight_string.Value.Substring(2), NumberStyles.Any, CultureInfo.InvariantCulture);
|
||
|
probabilities_list.Add(weight);
|
||
|
|
||
|
var prob_len = weight_string.Value.Length;
|
||
|
consequents_list.Add((LSystemNodeGenerator)parseWord(line.Substring(prob_len).Trim(), new LSystemWordGeneratorBuilder(predecesor.variableIndex)));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
consequents_list.Add((LSystemNodeGenerator)parseWord(sucsessor_string.Trim(), new LSystemWordGeneratorBuilder(predecesor.variableIndex)));
|
||
|
}
|
||
|
//context
|
||
|
if (context != null)
|
||
|
{
|
||
|
if (consequents_list.Count > 1)
|
||
|
{
|
||
|
rules.Add(new LSystemRuleParametricStochasticContext(predecesor, conditions, consequents_list.ToArray(), probabilities_list.ToArray(), context));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rules.Add(new LSystemRuleParametricStochasticContext(predecesor, conditions, consequents_list[0], context));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (consequents_list.Count > 1)
|
||
|
{
|
||
|
rules.Add(new LSystemRuleParametricStochastic(predecesor, conditions, consequents_list.ToArray(), probabilities_list.ToArray()));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rules.Add(new LSystemRuleParametric(predecesor, conditions, consequents_list[0]));
|
||
|
}
|
||
|
}
|
||
|
//var conditions = parts[0];
|
||
|
//var result
|
||
|
}
|
||
|
catch (Exception e)
|
||
|
{
|
||
|
sr.Close();
|
||
|
throw new Exception(String.Format("error in {0} with a message \n {1}", line, e.Message));
|
||
|
}
|
||
|
}
|
||
|
return rules;
|
||
|
}
|
||
|
|
||
|
private static void getPredecesorContext(string predecesor_string, out LSystemNodeLiteralVariable predecesor, out LSystemContext context)
|
||
|
{
|
||
|
string partent_context_str = null;
|
||
|
string child_context_str = null;
|
||
|
string mid_context_str = null;
|
||
|
int mid_start = 0;
|
||
|
|
||
|
for (int i = 0; i < predecesor_string.Length; i++)
|
||
|
{
|
||
|
if (predecesor_string[i] == '<' && partent_context_str == null)
|
||
|
{
|
||
|
partent_context_str = predecesor_string.Substring(0, i).Trim();
|
||
|
mid_start = i + 1;
|
||
|
//Console.WriteLine(i);
|
||
|
}
|
||
|
if (predecesor_string[i] == '>' && child_context_str == null)
|
||
|
{
|
||
|
child_context_str = predecesor_string.Substring(i + 1).Trim();
|
||
|
mid_context_str = predecesor_string.Substring(mid_start, i - mid_start).Trim();
|
||
|
//Console.WriteLine(i);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
if (mid_context_str == null)
|
||
|
{
|
||
|
mid_context_str = predecesor_string.Substring(mid_start).Trim();
|
||
|
}
|
||
|
LSystemNodeLiteralVariable parent = null;
|
||
|
LSystemNodeLiteralVariable[] children = null;
|
||
|
predecesor = LSystemFileParser.parseContextLiteral(mid_context_str);
|
||
|
if (partent_context_str != null)
|
||
|
{
|
||
|
parent = LSystemFileParser.parseContextLiteral(partent_context_str);
|
||
|
foreach (KeyValuePair<string, int> kvp in new Dictionary<string, int>(predecesor.variableIndex))
|
||
|
{
|
||
|
//textBox3.Text += ("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
|
||
|
predecesor.variableIndex[kvp.Key] = kvp.Value + parent.variableIndex.Count;
|
||
|
}
|
||
|
foreach (KeyValuePair<string, int> kvp in parent.variableIndex)
|
||
|
{
|
||
|
//textBox3.Text += ("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
|
||
|
predecesor.variableIndex.Add(kvp.Key, kvp.Value);
|
||
|
}
|
||
|
}
|
||
|
if (child_context_str != null)
|
||
|
{
|
||
|
int size = predecesor.variableIndex.Count;
|
||
|
children = LSystemFileParser.parseSuccessorsContext(child_context_str);
|
||
|
int offset = 0;
|
||
|
foreach (var child in children)
|
||
|
{
|
||
|
|
||
|
foreach (KeyValuePair<string, int> kvp in child.variableIndex)
|
||
|
{
|
||
|
//textBox3.Text += ("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
|
||
|
predecesor.variableIndex.Add(kvp.Key, kvp.Value + size + offset);
|
||
|
}
|
||
|
offset += child.variableIndex.Count;
|
||
|
}
|
||
|
}
|
||
|
if (child_context_str != null)
|
||
|
{
|
||
|
if (partent_context_str != null)
|
||
|
{
|
||
|
context = new LSystemContext(parent, children);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
context = new LSystemContext();
|
||
|
context.setOnlySucceeding(children);
|
||
|
}
|
||
|
}
|
||
|
else if (partent_context_str != null)
|
||
|
{
|
||
|
context = new LSystemContext();
|
||
|
context.setOnlyPreceding(parent);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
context = null;
|
||
|
}
|
||
|
}
|
||
|
}
|