summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedGrammar.java
blob: 8733723513b0d96a72053896bbb5538cca91f2ed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
package bjc.utils.gen;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.function.Function;

import bjc.utils.funcdata.FunctionalList;

/**
 * A random grammar, where certain rules will come up morre often than
 * others.
 * 
 * @author ben
 *
 * @param <E> The values that make up sentances of this grammar.
 */
public class WeightedGrammar<E> {
	protected Map<E, WeightedRandom<FunctionalList<E>>>	rules;
	protected Map<E, WeightedGrammar<E>>				subgrammars;
	private Random sr;

	/**
	 * Create a new weighted grammar that uses the specified source of randomness.
	 */
	public WeightedGrammar(Random src) {
		this();
		sr = src;
	}
	
	/**
	 * Create a new weighted grammar.
	 */
	public WeightedGrammar() {
		rules = new HashMap<>();
	}

	/**
	 * Add a case to an already existing rule.
	 * 
	 * @param rule The rule to add a case to.
	 * @param prob The probability for this rule to be chosen.
	 * @param cse The case being added.
	 */
	public void addCase(E rule, int prob, FunctionalList<E> cse) {
		WeightedRandom<FunctionalList<E>> rn = rules.get(rule);

		rn.addProb(prob, cse);
	}

	/**
	 * Add a new rule with no cases.
	 * @param name The name of the rule to add.
	 * @return Whether or not the rule was succesfully added.
	 */
	public boolean addRule(E name) {
		if(sr == null) {
			sr = new Random();
		}
		return addRule(name, new WeightedRandom<>(sr));
	}

	/**
	 * Add a new rule with a set of cases.
	 * @param name The name of the rule to add.
	 * @param rnd The set of cases for the rule.
	 * @return Whether or not the rule was succesfully added.
	 */
	public boolean addRule(E name, WeightedRandom<FunctionalList<E>> rnd) {
		if (rules.containsKey(name)) {
			return false;
		} else {
			rules.put(name, rnd);
			return true;
		}
	}

	/**
	 * Add a subgrammar.
	 * @param name The name of the subgrammar.
	 * @param subG The subgrammar to add.
	 * @return Whether or not the subgrammar was succesfully added.
	 */
	public boolean addSubGrammar(E name, WeightedGrammar<E> subG) {
		if (subgrammars.containsKey(name)) {
			return false;
		} else {
			subgrammars.put(name, subG);
			return true;
		}
	}

	/**
	 * Generate a set of debug sentences for the specified rule.
	 * 		Only generates sentances one layer deep.
	 * @param rl The rule to test.
	 * @return A set of sentances generated by the specified rule.
	 */
	public FunctionalList<FunctionalList<E>> debugVals(E rl) {
		FunctionalList<FunctionalList<E>> fl = new FunctionalList<>();

		WeightedRandom<FunctionalList<E>> random = rules.get(rl);

		for (int i = 0; i < 10; i++) {
			fl.add(random.genVal());
		}

		return fl;
	}

	/**
	 * Generate a generic sentance from a initial rule.
	 * 
	 * @param initRule The initial rule to start with.
	 * @param f The function to transform grammar output into something.
	 * @param spacer The spacer element to add in between output tokens.
	 * @return A randomly generated sentance from the specified initial rule.
	 */
	public <T> FunctionalList<T> genGeneric(E initRule, Function<E, T> f,
			T spacer) {
		FunctionalList<T> r = new FunctionalList<>();

		if (subgrammars.containsKey(initRule)) {
			subgrammars.get(initRule).genGeneric(initRule, f, spacer)
					.forEach(rp -> {
						r.add(rp);
						r.add(spacer);
					});
		} else if (rules.containsKey(initRule)) {
			rules.get(initRule).genVal().forEach(
					rp -> genGeneric(rp, f, spacer).forEach(rp2 -> {
						r.add(rp2);
						r.add(spacer);
					}));
		} else {
			r.add(f.apply(initRule));
			r.add(spacer);
		}

		return r;
	}

	/**
	 * Generate a random list of grammar elements from a given initial rule.
	 * @param initRule The initial rule to start with.
	 * @param spacer The item to use to space the list.
	 * @return A list of random grammar elements generated by the specified rule.
	 */
	public FunctionalList<E> genList(E initRule, E spacer) {
		return genGeneric(initRule, s -> s, spacer);
	}

	/**
	 * Get the subgrammar with the specified name.
	 * @param name The name of the subgrammar to get.
	 * @return The subgrammar with the specified name.
	 */
	public WeightedGrammar<E> getSubGrammar(E name) {
		return subgrammars.get(name);
	}

	/**
	 * Remove a rule with the specified name.
	 * @param name The name of the rule to remove.
	 */
	public void removeRule(E name) {
		rules.remove(name);
	}

	/**
	 * Remove a subgrammar with the specified name.
	 * @param name The name of the subgrammar to remove.
	 */
	public void removeSubgrammar(E name) {
		subgrammars.remove(name);
	}
}