Hoa central
RealdomArray.php
Go to the documentation of this file.
1 <?php
2 
37 namespace Hoa\Realdom;
38 
39 use Hoa\Math;
40 
50 class RealdomArray extends Realdom
51 {
57  const NAME = 'array';
58 
64  protected $_arguments = [
65  'Constarray pairs',
66  'Integer length'
67  ];
68 
69 
70 
76  protected function construct()
77  {
78  parent::construct();
79 
80  $this->adjustLength();
81 
82  return;
83  }
84 
90  public function reset()
91  {
92  $this->resetArguments();
93 
94  return;
95  }
96 
103  protected function _predicate($q)
104  {
105  if (!is_array($q)) {
106  return false;
107  }
108 
109  $count = count($q);
110 
111  if (false === $this['length']->predicate($count)) {
112  return false;
113  }
114 
115  $pairs = $this['pairs']['pairs'];
116  $out = 0 === $count;
117  $constraints = &$this->getConstraints();
118 
119  foreach ($q as $_key => $_value) {
120  $out = false;
121 
122  foreach ($pairs as $pair) {
123  $key = $pair[0];
124  $value = $pair[1];
125 
126  if (false === $key->predicate($_key)) {
127  continue;
128  }
129 
130  if (false === $value->predicate($_value)) {
131  continue;
132  }
133 
134  $out = true;
135 
136  break;
137  }
138 
139  if (false === $out) {
140  return false;
141  }
142 
143  if (isset($constraints['key'])) {
144  $out = true;
145 
146  foreach ($constraints['key'] as $kPair) {
147  $key = $kPair[0];
148  $value = $kPair[1];
149 
150  if (false === $key->predicate($_key)) {
151  continue;
152  }
153 
154  $out = $value->predicate($_value) && $out;
155  }
156  }
157 
158  if (false === $out) {
159  return $out;
160  }
161  }
162 
163  if (true === $this->is('unique') &&
164  $count !== count(array_unique($q, SORT_REGULAR))) {
165  return false;
166  }
167 
168  if (true === $this->is('sorted')) {
169  $previous = array_shift($q);
170 
171  foreach ($q as $value) {
172  if ($previous > $value) {
173  return false;
174  }
175 
176  $previous = $value;
177  }
178  }
179 
180  if (true === $this->is('rsorted')) {
181  $previous = array_shift($q);
182 
183  foreach ($q as $value) {
184  if ($previous < $value) {
185  return false;
186  }
187 
188  $previous = $value;
189  }
190  }
191 
192  if (true === $this->is('ksorted')) {
193  reset($q);
194  $previous = key($q);
195 
196  foreach ($q as $key => $_) {
197  if ($previous > $key) {
198  return false;
199  }
200 
201  $previous = $key;
202  }
203  }
204 
205  if (true === $this->is('krsorted')) {
206  reset($q);
207  $previous = key($q);
208 
209  foreach ($q as $key => $_) {
210  if ($previous < $key) {
211  return false;
212  }
213 
214  $previous = $key;
215  }
216  }
217 
218  return $out;
219  }
220 
228  protected function _sample(Math\Sampler $sampler)
229  {
230  $length = $this['length']->sample($sampler);
231 
232  if (0 > $length) {
233  return false;
234  }
235 
236  $constraints = &$this->getConstraints();
237  $out = [];
238  $pairs = [];
239  $unique = true === $this->is('unique');
240 
241  foreach ($this['pairs']['pairs'] as $pair) {
242  $key = clone $pair[0];
243  $value = clone $pair[1];
244  $i = 0;
245 
246  foreach ($key as $realdom) {
247  if ($realdom instanceof IRealdom\Finite &&
248  $length > $realdom->getSize()) {
249  unset($key[$i--]);
250  }
251 
252  ++$i;
253  }
254 
255  if (0 >= count($key)) {
256  continue;
257  }
258 
259  if (true === $unique) {
260  $i = 0;
261 
262  foreach ($value as $realdom) {
263  if ($realdom instanceof IRealdom\Finite &&
264  $length > $realdom->getSize()) {
265  unset($value[$i--]);
266  }
267 
268  ++$i;
269  }
270 
271  if (0 >= count($value)) {
272  continue;
273  }
274  }
275 
276  $pairs[] = [$key, $value];
277  }
278 
279  if (isset($constraints['key'])) {
280  foreach ($constraints['key'] as $kPair) {
281  $_key = $kPair[0]->sample($sampler);
282  $_value = $kPair[1]->sample($sampler);
283 
284  foreach ($pairs as $pair) {
285  $keyRealdoms = [];
286  $valueRealdoms = [];
287 
288  foreach ($pair[0] as $realdom) {
289  if (true === $realdom->predicate($_key)) {
290  $keyRealdoms[] = $realdom;
291  }
292  }
293 
294  foreach ($pair[1] as $realdom) {
295  if (true === $realdom->predicate($_value)) {
296  $valueRealdoms[] = $realdom;
297  }
298  }
299 
300  if (empty($keyRealdoms) || empty($valueRealdoms)) {
301  continue;
302  }
303 
304  foreach ($keyRealdoms as $realdom) {
305  if ($realdom instanceof IRealdom\Nonconvex) {
306  $realdom->discredit($_key);
307  }
308  }
309 
310  if (false === $unique) {
311  continue;
312  }
313 
314  foreach ($valueRealdoms as $realdom) {
315  if ($realdom instanceof IRealdom\Nonconvex) {
316  $realdom->discredit($_value);
317  }
318  }
319  }
320 
321  $out[$_key] = $_value;
322  }
323  }
324 
325  $count = count($pairs) - 1;
326 
327  for ($i = 0, $length -= count($out); $i < $length; ++$i) {
328  if (0 > $count) {
329  throw new Exception\Inconsistent(
330  'There is no enought data to sample.',
331  0
332  );
333  }
334 
335  $pair = $pairs[$sampler->getInteger(0, $count)];
336  $key = $pair[0]->sample($sampler);
337  $value = $pair[1]->sample($sampler);
338 
339  foreach ($pairs as $p => $_pair) {
340  $j = 0;
341 
342  foreach ($_pair[0] as $realdom) {
343  if (!($realdom instanceof IRealdom\Nonconvex) ||
344  false === $realdom->predicate($key)) {
345  continue;
346  }
347 
348  $realdom->discredit($key);
349 
350  if ($realdom instanceof IRealdom\Finite) {
351  if (0 === $realdom->getSize()) {
352  unset($_pair[0][$j--]);
353  }
354  }
355 
356  ++$j;
357  }
358 
359  if (0 === count($_pair[0])) {
360  unset($pairs[$p]);
361  --$count;
362  }
363 
364  if (false === $unique) {
365  continue;
366  }
367 
368  foreach ($_pair[1] as $realdom) {
369  if ($realdom instanceof IRealdom\Nonconvex &&
370  true === $realdom->predicate($value)) {
371  $realdom->discredit($value);
372  }
373  }
374  }
375 
376  $out[$key] = $value;
377  }
378 
379  ksort($out);
380 
381  /*
382  if(true === $this->is('sorted'))
383  asort($out);
384 
385  if(true === $this->is('rsorted'))
386  arsort($out);
387 
388  if(true === $this->is('ksorted'))
389  ksort($out);
390 
391  if(true === $this->is('krsorted'))
392  krsort($out);
393  */
394 
395  return $out;
396  }
397 
407  protected function _propagateConstraints(
408  $type,
409  $index,
410  Array &$constraints
411  ) {
412  if ('key' !== $type) {
413  return;
414  }
415 
416  if (!isset($constraints['key'][$index])) {
417  return;
418  }
419 
420  $pairs = $this['pairs']['pairs'];
421  $_pair = &$constraints['key'][$index];
422  $key = &$_pair[0][0];
423  $values = $_pair[1];
424 
425  if (!($key instanceof IRealdom\Constant)) {
426  return;
427  }
428 
429  $_key = $key->getConstantValue();
430 
431  foreach ($pairs as $p => $pair) {
432  $i = 0;
433 
434  foreach ($pair[0] as $realdom) {
435  if (false === $realdom->predicate($_key)) {
436  unset($pair[0][$i--]);
437  }
438 
439  ++$i;
440  }
441 
442  if (0 === count($pair[0])) {
443  unset($pairs[$p]);
444  }
445  }
446 
447  if (0 === count($pairs)) {
448  throw new Exception\Inconsistent(
449  'The constraint %s[%s] = %s is not consistent because the ' .
450  'key %2$s does not satisfy the array description.',
451  1,
452  [
453  $this->getHolder()->getName(),
454  $_key,
455  $this->getPraspelVisitor()->visit($values)
456  ]
457  );
458  }
459 
460  $this->adjustLength();
461 
462  $minSize = count($constraints['key']);
463  $length = $this['length'];
464 
465  if ($length instanceof IRealdom\Constant) {
466  if ($minSize > $length->getConstantValue()) {
467  throw new Exception\Inconsistent(
468  'There is too many declared keys compared to the array ' .
469  'size (%d > %d).',
470  2,
471  [$minSize, $length->getConstantValue()]
472  );
473  }
474  } elseif (
475  $length instanceof IRealdom\Interval &&
476  $minSize > $length->getUpperBound()
477  ) {
478  throw new Exception\Inconsistent(
479  'There is too many declared keys compared to the array size ' .
480  '(%d ∉ %s).',
481  3,
482  [$minSize, $this->getPraspelVisitor()->visit($length)]
483  );
484  }
485 
486 
487  return;
488  }
489 
496  protected function adjustLength()
497  {
498  $pairs = $this['pairs']['pairs'];
499  $length = $this['length'];
500  $maxSize = -1;
501 
502  foreach ($pairs as $pair) {
503  foreach ($pair[0] as $realdom) {
504  if ($realdom instanceof IRealdom\Finite) {
505  $size = $realdom->getSize();
506 
507  if ($maxSize < $size) {
508  $maxSize = $size;
509  }
510  }
511  }
512  }
513 
514  if (-1 === $maxSize) {
515  return;
516  }
517 
518  if ($length instanceof IRealdom\Constant) {
519  if ($maxSize < $length->getConstantValue()) {
520  throw new Exception\Inconsistent(
521  'There is no enough key to sample (%d < %d).',
522  4,
523  [$maxSize, $length->getConstantValue()]
524  );
525  }
526  }
527 
528  if ($length instanceof IRealdom\Interval) {
529  if ($maxSize < $length->getLowerBound()) {
530  throw new Exception\Inconsistent(
531  'There is no enough key to sample (%d ∉ %s).',
532  5,
533  [$maxSize, $this->getPraspelVisitor()->visit($length)]
534  );
535  }
536 
537  if ($maxSize < $length->getUpperBound()) {
538  $length->reduceRightTo($maxSize);
539  }
540  }
541 
542  return;
543  }
544 }
_propagateConstraints($type, $index, Array &$constraints)
_sample(Math\Sampler $sampler)
is($qualifier)
Definition: Realdom.php:807