Hoa central
Uniform.php
Go to the documentation of this file.
1 <?php
2 
37 namespace Hoa\Compiler\Llk\Sampler;
38 
39 use Hoa\Compiler;
40 use Hoa\Math;
41 use Hoa\Visitor;
42 
55 class Uniform extends Sampler
56 {
62  protected $_data = [];
63 
69  protected $_length = 5;
70 
71 
72 
80  public function __construct(
81  Compiler\Llk\Parser $compiler,
82  Visitor\Visit $tokenSampler,
83  $length = 5
84  ) {
85  parent::__construct($compiler, $tokenSampler);
86 
87  foreach ($this->_rules as $name => $_) {
88  $this->_data[$name] = [];
89  }
90 
91  $this->setLength($length);
92  $this->_sampler = new Math\Sampler\Random();
93 
94  return;
95  }
96 
104  public function uniform(Compiler\Llk\Rule $rule = null, $n = -1)
105  {
106  if (null === $rule && -1 === $n) {
107  $rule = $this->_rules[$this->_rootRuleName];
108  $n = $this->getLength();
109  }
110 
111  $data = &$this->_data[$rule->getName()][$n];
112  $computed = $data['n'];
113 
114  if (0 === $n || 0 === $computed) {
115  return null;
116  }
117 
118  if ($rule instanceof Compiler\Llk\Rule\Choice) {
119  $children = $rule->getContent();
120  $stat = [];
121 
122  foreach ($children as $c => $child) {
123  $stat[$c] = $this->_data[$child][$n]['n'];
124  }
125 
126  $i = $this->_sampler->getInteger(1, $computed);
127 
128  for ($e = 0, $b = $stat[$e], $max = count($stat) - 1;
129  $e < $max && $i > $b;
130  $b += $stat[++$e]);
131 
132  return $this->uniform($this->_rules[$children[$e]], $n);
133  } elseif ($rule instanceof Compiler\Llk\Rule\Concatenation) {
134  $children = $rule->getContent();
135  $out = null;
136  $Γ = $data['Γ'];
137  $γ = $Γ[$this->_sampler->getInteger(0, count($Γ) - 1)];
138 
139  foreach ($children as $i => $child) {
140  $out .= $this->uniform($this->_rules[$child], $γ[$i]);
141  }
142 
143  return $out;
144  } elseif ($rule instanceof Compiler\Llk\Rule\Repetition) {
145  $out = null;
146  $stat = &$data['xy'];
147  $child = $this->_rules[$rule->getContent()];
148  $b = 0;
149  $i = $this->_sampler->getInteger(1, $computed);
150 
151  foreach ($stat as $α => $st) {
152  if ($i <= $b += $st['n']) {
153  break;
154  }
155  }
156 
157  $Γ = &$st['Γ'];
158  $γ = &$Γ[$this->_sampler->getInteger(0, count($Γ) - 1)];
159 
160  for ($j = 0; $j < $α; ++$j) {
161  $out .= $this->uniform($child, $γ[$j]);
162  }
163 
164  return $out;
165  } elseif ($rule instanceof Compiler\Llk\Rule\Token) {
166  return $this->generateToken($rule);
167  }
168 
169  return null;
170  }
171 
179  public function count(Compiler\Llk\Rule $rule = null, $n = -1)
180  {
181  if (null === $rule || -1 === $n) {
182  return 0;
183  }
184 
185  $ruleName = $rule->getName();
186 
187  if (isset($this->_data[$ruleName][$n])) {
188  return $this->_data[$ruleName][$n]['n'];
189  }
190 
191  $this->_data[$ruleName][$n] = ['n' => 0];
192  $out = &$this->_data[$ruleName][$n]['n'];
193  $rule = $this->_rules[$ruleName];
194 
195  if ($rule instanceof Compiler\Llk\Rule\Choice) {
196  foreach ($rule->getContent() as $child) {
197  $out += $this->count($this->_rules[$child], $n);
198  }
199  } elseif ($rule instanceof Compiler\Llk\Rule\Concatenation) {
200  $children = $rule->getContent();
202  count($children),
203  $n
204  );
205  $this->_data[$ruleName][$n]['Γ'] = [];
206  $handle = &$this->_data[$ruleName][$n]['Γ'];
207 
208  foreach ($Γ as $γ) {
209  $oout = 1;
210 
211  foreach ($γ as $α => $_γ) {
212  $oout *= $this->count($this->_rules[$children[$α]], $_γ);
213  }
214 
215  if (0 !== $oout) {
216  $handle[] = $γ;
217  }
218 
219  $out += $oout;
220  }
221  } elseif ($rule instanceof Compiler\Llk\Rule\Repetition) {
222  $this->_data[$ruleName][$n]['xy'] = [];
223  $handle = &$this->_data[$ruleName][$n]['xy'];
224  $child = $this->_rules[$rule->getContent()];
225  $x = $rule->getMin();
226  $y = $rule->getMax();
227 
228  if (-1 === $y) {
229  $y = $n;
230  } else {
231  $y = min($n, $y);
232  }
233 
234  if (0 === $x && $x === $y) {
235  $out = 1;
236  } else {
237  for ($α = $x; $α <= $y; ++$α) {
238  $ut = 0;
239  $handle[$α] = ['n' => 0, 'Γ' => []];
240  $Γ = new Math\Combinatorics\Combination\Gamma($α, $n);
241 
242  foreach ($Γ as $γ) {
243  $oout = 1;
244 
245  foreach ($γ as $β => $_γ) {
246  $oout *= $this->count($child, $_γ);
247  }
248 
249  if (0 !== $oout) {
250  $handle[$α]['Γ'][] = $γ;
251  }
252 
253  $ut += $oout;
254  }
255 
256  $handle[$α]['n'] = $ut;
257  $out += $ut;
258  }
259  }
260  } elseif ($rule instanceof Compiler\Llk\Rule\Token) {
261  $out = Math\Util::δ($n, 1);
262  }
263 
264  return $out;
265  }
266 
274  public function setLength($length)
275  {
276  if (0 >= $length) {
277  throw new Exception(
278  'Length must be greater than 0, given %d.',
279  0,
280  $length
281  );
282  }
283 
284  $old = $this->_length;
285  $this->_length = $length;
286  $this->count(
287  $this->_compiler->getRule($this->_rootRuleName),
288  $length
289  );
290 
291  return $old;
292  }
293 
299  public function getLength()
300  {
301  return $this->_length;
302  }
303 }
__construct(Compiler\Llk\Parser $compiler, Visitor\Visit $tokenSampler, $length=5)
Definition: Uniform.php:80
static δ($i, $j)
Definition: Util.php:55
generateToken(Compiler\Llk\Rule\Token $token)
Definition: Sampler.php:188
uniform(Compiler\Llk\Rule $rule=null, $n=-1)
Definition: Uniform.php:104
count(Compiler\Llk\Rule $rule=null, $n=-1)
Definition: Uniform.php:179