... | ... |
@@ -471,32 +471,16 @@ class BalancingLearner(BaseLearner): |
471 | 471 |
|
472 | 472 |
# Learner2D and helper functions. |
473 | 473 |
|
474 |
-def triangle_area(points): |
|
475 |
- """The area of a triangle span by `points`. |
|
476 |
- |
|
477 |
- Parameters |
|
478 |
- ---------- |
|
479 |
- points : numpy array |
|
480 |
- A sequence of the positions of the vertices of the triangle, |
|
481 |
- with shape (..., 3, ndim). |
|
482 |
- |
|
483 |
- Returns |
|
484 |
- ------- |
|
485 |
- area : numpy array |
|
486 |
- Areas of the triangles. |
|
487 |
- """ |
|
488 |
- a, b, c = np.rollaxis(points, 1) |
|
489 |
- return 0.5 * np.cross(b - a, c - a, axis=1) |
|
490 |
- |
|
491 |
- |
|
492 |
-def _deviation_from_linear_estimate(ip): |
|
474 |
+def _losses_per_triangle(ip): |
|
493 | 475 |
tri = ip.tri |
476 |
+ vs = ip.values.ravel() |
|
477 |
+ |
|
494 | 478 |
gradients = interpolate.interpnd.estimate_gradients_2d_global( |
495 |
- tri, ip.values.ravel(), tol=1e-6) |
|
479 |
+ tri, vs, tol=1e-6) |
|
496 | 480 |
p = tri.points[tri.vertices] |
497 | 481 |
g = gradients[tri.vertices] |
498 |
- v = ip.values.ravel()[tri.vertices] |
|
499 |
- ndim = p.shape[1] |
|
482 |
+ v = vs[tri.vertices] |
|
483 |
+ ndim = p.shape[-1] |
|
500 | 484 |
|
501 | 485 |
dev = 0 |
502 | 486 |
for j in range(ndim): |
... | ... |
@@ -505,10 +489,15 @@ def _deviation_from_linear_estimate(ip): |
505 | 489 |
dev += abs(vest - v).max(axis=1) |
506 | 490 |
|
507 | 491 |
q = p[:, :-1, :] - p[:, -1, None, :] |
508 |
- vol = abs(q[:, 0, 0] * q[:, 1, 1] - q[:, 0, 1] * q[:, 1, 0]) |
|
509 |
- vol /= special.gamma(1 + ndim) |
|
510 |
- return dev * vol |
|
492 |
+ areas = abs(q[:, 0, 0] * q[:, 1, 1] - q[:, 0, 1] * q[:, 1, 0]) |
|
493 |
+ areas /= special.gamma(1 + ndim) |
|
494 |
+ areas = np.sqrt(areas) |
|
511 | 495 |
|
496 |
+ vs_scale = vs[tri.vertices].ptp() |
|
497 |
+ if vs_scale != 0: |
|
498 |
+ dev /= vs_scale |
|
499 |
+ |
|
500 |
+ return dev * areas + areas**2 |
|
512 | 501 |
|
513 | 502 |
class Learner2D(BaseLearner): |
514 | 503 |
"""Learns and predicts a function 'f: ℝ^2 → ℝ'. |
... | ... |
@@ -561,9 +550,8 @@ class Learner2D(BaseLearner): |
561 | 550 |
self._stack = [] |
562 | 551 |
self._interp = {} |
563 | 552 |
|
564 |
- x, y = np.array(self.bounds) |
|
565 |
- xy_scale = np.array([x.ptp(), y.ptp()]) / 2 |
|
566 |
- xy_mean = np.array([x.mean(), y.mean()]) |
|
553 |
+ xy_mean = np.mean(self.bounds, axis=1) |
|
554 |
+ xy_scale = np.ptp(self.bounds, axis=1) |
|
567 | 555 |
|
568 | 556 |
def scale(points): |
569 | 557 |
return (points - xy_mean) / xy_scale |
... | ... |
@@ -662,14 +650,6 @@ class Learner2D(BaseLearner): |
662 | 650 |
self._stack.pop(i) |
663 | 651 |
break |
664 | 652 |
|
665 |
- def _losses_per_triangle(self, ip): |
|
666 |
- dev = _deviation_from_linear_estimate(ip) |
|
667 |
- ps = ip.tri.points[ip.tri.vertices] |
|
668 |
- vs = ip.values[ip.tri.vertices] |
|
669 |
- triangle_size = triangle_area(ps) / 4 # /4 because the area=4 |
|
670 |
- losses = np.hypot(dev / vs.ptp(), 0.5 * triangle_size) |
|
671 |
- return losses |
|
672 |
- |
|
673 | 653 |
def _fill_stack(self, stack_till=None): |
674 | 654 |
if stack_till is None: |
675 | 655 |
stack_till = 1 |
... | ... |
@@ -681,7 +661,7 @@ class Learner2D(BaseLearner): |
681 | 661 |
ip = self.ip_combined() |
682 | 662 |
tri = ip.tri |
683 | 663 |
|
684 |
- losses = self._losses_per_triangle(ip) |
|
664 |
+ losses = _losses_per_triangle(ip) |
|
685 | 665 |
|
686 | 666 |
def point_exists(p): |
687 | 667 |
eps = np.finfo(float).eps * self.points_combined.ptp() * 100 |
... | ... |
@@ -761,7 +741,7 @@ class Learner2D(BaseLearner): |
761 | 741 |
if n <= 4 or bounds_are_not_done: |
762 | 742 |
return np.inf |
763 | 743 |
ip = self.ip() if real else self.ip_combined() |
764 |
- losses = self._losses_per_triangle(ip) |
|
744 |
+ losses = _losses_per_triangle(ip) |
|
765 | 745 |
return losses.max() |
766 | 746 |
|
767 | 747 |
def remove_unfinished(self): |
... | ... |
@@ -774,8 +754,8 @@ class Learner2D(BaseLearner): |
774 | 754 |
x, y = self.bounds |
775 | 755 |
lbrt = x[0], y[0], x[1], y[1] |
776 | 756 |
if self.n_real >= 4: |
777 |
- x = np.linspace(-1, 1, n_x) |
|
778 |
- y = np.linspace(-1, 1, n_y) |
|
757 |
+ x = np.linspace(-0.5, 0.5, n_x) |
|
758 |
+ y = np.linspace(-0.5, 0.5, n_y) |
|
779 | 759 |
ip = self.ip() |
780 | 760 |
z = ip(x[:, None], y[None, :]) |
781 | 761 |
return hv.Image(np.rot90(z), bounds=lbrt) |