PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ compute_gserialized_stats_mode()

static void compute_gserialized_stats_mode ( VacAttrStats *  stats,
AnalyzeAttrFetchFunc  fetchfunc,
int  sample_rows,
double  total_rows,
int  mode 
)
static

The gserialized_analyze_nd sets this function as a callback on the stats object when called by the ANALYZE command.

ANALYZE then gathers the requisite number of sample rows and then calls this function.

We could also pass stats->extra_data in from gserialized_analyze_nd (things like the column type or other stuff from the system catalogs) but so far we don't use that capability.

Our job is to build some statistics on the sample data for use by operator estimators.

We will populate an n-d histogram using the provided sample rows. The selectivity estimators (sel and j_oinsel) can then use the histogram

Definition at line 1366 of file gserialized_estimate.c.

1368{
1369 MemoryContext old_context;
1370 int d, i; /* Counters */
1371 int notnull_cnt = 0; /* # not null rows in the sample */
1372 int null_cnt = 0; /* # null rows in the sample */
1373 int histogram_features = 0; /* # rows that actually got counted in the histogram */
1374
1375 ND_STATS *nd_stats; /* Our histogram */
1376 size_t nd_stats_size; /* Size to allocate */
1377
1378 double total_width = 0; /* # of bytes used by sample */
1379 double total_sample_volume = 0; /* Area/volume coverage of the sample */
1380 double total_cell_count = 0; /* # of cells in histogram affected by sample */
1381
1382 ND_BOX sum; /* Sum of extents of sample boxes */
1383 ND_BOX avg; /* Avg of extents of sample boxes */
1384 ND_BOX stddev; /* StdDev of extents of sample boxes */
1385
1386 const ND_BOX **sample_boxes; /* ND_BOXes for each of the sample features */
1387 ND_BOX sample_extent; /* Extent of the raw sample */
1388 int histo_size[ND_DIMS]; /* histogram nrows, ncols, etc */
1389 ND_BOX histo_extent; /* Spatial extent of the histogram */
1390 ND_BOX histo_extent_new; /* Temporary variable */
1391 int histo_cells_target; /* Number of cells we will shoot for, given the stats target */
1392 int histo_cells; /* Number of cells in the histogram */
1393 int histo_cells_new = 1; /* Temporary variable */
1394
1395 int ndims = 2; /* Dimensionality of the sample */
1396 int histo_ndims = 0; /* Dimensionality of the histogram */
1397 double sample_distribution[ND_DIMS]; /* How homogeneous is distribution of sample in each axis? */
1398 double total_distribution; /* Total of sample_distribution */
1399
1400 int stats_slot; /* What slot is this data going into? (2D vs ND) */
1401 int stats_kind; /* And this is what? (2D vs ND) */
1402
1403 /* Initialize sum and stddev */
1404 nd_box_init(&sum);
1405 nd_box_init(&stddev);
1406 nd_box_init(&avg);
1407 nd_box_init(&histo_extent);
1408 nd_box_init(&histo_extent_new);
1409
1410 /*
1411 * This is where gserialized_analyze_nd
1412 * should put its' custom parameters.
1413 */
1414 /* void *mystats = stats->extra_data; */
1415
1416 POSTGIS_DEBUG(2, "compute_gserialized_stats called");
1417 POSTGIS_DEBUGF(3, " # sample_rows: %d", sample_rows);
1418 POSTGIS_DEBUGF(3, " estimate of total_rows: %.6g", total_rows);
1419
1420 /*
1421 * We might need less space, but don't think
1422 * its worth saving...
1423 */
1424 sample_boxes = palloc(sizeof(ND_BOX*) * sample_rows);
1425
1426 /*
1427 * First scan:
1428 * o read boxes
1429 * o find dimensionality of the sample
1430 * o find extent of the sample
1431 * o count null-infinite/not-null values
1432 * o compute total_width
1433 * o compute total features's box area (for avgFeatureArea)
1434 * o sum features box coordinates (for standard deviation)
1435 */
1436 for ( i = 0; i < sample_rows; i++ )
1437 {
1438 Datum datum;
1439 GSERIALIZED *geom;
1440 GBOX gbox;
1441 ND_BOX *nd_box;
1442 bool is_null;
1443 bool is_copy;
1444
1445 datum = fetchfunc(stats, i, &is_null);
1446
1447 /* Skip all NULLs. */
1448 if ( is_null )
1449 {
1450 POSTGIS_DEBUGF(4, " skipped null geometry %d", i);
1451 null_cnt++;
1452 continue;
1453 }
1454
1455 /* Read the bounds from the gserialized. */
1456 geom = (GSERIALIZED *)PG_DETOAST_DATUM(datum);
1457 is_copy = VARATT_IS_EXTENDED(datum);
1458 if ( LW_FAILURE == gserialized_get_gbox_p(geom, &gbox) )
1459 {
1460 /* Skip empties too. */
1461 POSTGIS_DEBUGF(3, " skipped empty geometry %d", i);
1462 continue;
1463 }
1464
1465 /* If we're in 2D mode, zero out the higher dimensions for "safety" */
1466 if ( mode == 2 )
1467 gbox.zmin = gbox.zmax = gbox.mmin = gbox.mmax = 0.0;
1468
1469 /* Check bounds for validity (finite and not NaN) */
1470 if ( ! gbox_is_valid(&gbox) )
1471 {
1472 POSTGIS_DEBUGF(3, " skipped infinite/nan geometry %d", i);
1473 continue;
1474 }
1475
1476 /*
1477 * In N-D mode, set the ndims to the maximum dimensionality found
1478 * in the sample. Otherwise, leave at ndims == 2.
1479 */
1480 if ( mode != 2 )
1481 ndims = Max(gbox_ndims(&gbox), ndims);
1482
1483 /* Convert gbox to n-d box */
1484 nd_box = palloc(sizeof(ND_BOX));
1485 nd_box_from_gbox(&gbox, nd_box);
1486
1487 /* Cache n-d bounding box */
1488 sample_boxes[notnull_cnt] = nd_box;
1489
1490 /* Initialize sample extent before merging first entry */
1491 if ( ! notnull_cnt )
1492 nd_box_init_bounds(&sample_extent);
1493
1494 /* Add current sample to overall sample extent */
1495 nd_box_merge(nd_box, &sample_extent);
1496
1497 /* How many bytes does this sample use? */
1498 total_width += VARSIZE(geom);
1499
1500 /* Add bounds coordinates to sums for stddev calculation */
1501 for ( d = 0; d < ndims; d++ )
1502 {
1503 sum.min[d] += nd_box->min[d];
1504 sum.max[d] += nd_box->max[d];
1505 }
1506
1507 /* Increment our "good feature" count */
1508 notnull_cnt++;
1509
1510 /* Free up memory if our sample geometry was copied */
1511 if ( is_copy )
1512 pfree(geom);
1513
1514 /* Give backend a chance of interrupting us */
1515 vacuum_delay_point();
1516 }
1517
1518 /*
1519 * We'll build a histogram having stats->attr->attstattarget cells
1520 * on each side, within reason... we'll use ndims*10000 as the
1521 * maximum number of cells.
1522 * Also, if we're sampling a relatively small table, we'll try to ensure that
1523 * we have an average of 5 features for each cell so the histogram isn't
1524 * so sparse.
1525 */
1526 histo_cells_target = (int)pow((double)(stats->attr->attstattarget), (double)ndims);
1527 histo_cells_target = Min(histo_cells_target, ndims * 10000);
1528 histo_cells_target = Min(histo_cells_target, (int)(total_rows/5));
1529 POSTGIS_DEBUGF(3, " stats->attr->attstattarget: %d", stats->attr->attstattarget);
1530 POSTGIS_DEBUGF(3, " target # of histogram cells: %d", histo_cells_target);
1531
1532 /* If there's no useful features, we can't work out stats */
1533 if ( ! notnull_cnt )
1534 {
1535 Oid relation_oid = stats->attr->attrelid;
1536 char *relation_name = get_rel_name(relation_oid);
1537 elog(NOTICE,
1538 "PostGIS: Unable to compute statistics for \"%s.%s\": No non-null/empty features",
1539 relation_name ? relation_name : "(NULL)",
1540 stats->attr->attname.data);
1541 stats->stats_valid = false;
1542 return;
1543 }
1544
1545 POSTGIS_DEBUGF(3, " sample_extent: %s", nd_box_to_json(&sample_extent, ndims));
1546
1547 /*
1548 * Second scan:
1549 * o compute standard deviation
1550 */
1551 for ( d = 0; d < ndims; d++ )
1552 {
1553 /* Calculate average bounds values */
1554 avg.min[d] = sum.min[d] / notnull_cnt;
1555 avg.max[d] = sum.max[d] / notnull_cnt;
1556
1557 /* Calculate standard deviation for this dimension bounds */
1558 for ( i = 0; i < notnull_cnt; i++ )
1559 {
1560 const ND_BOX *ndb = sample_boxes[i];
1561 stddev.min[d] += (ndb->min[d] - avg.min[d]) * (ndb->min[d] - avg.min[d]);
1562 stddev.max[d] += (ndb->max[d] - avg.max[d]) * (ndb->max[d] - avg.max[d]);
1563 }
1564 stddev.min[d] = sqrt(stddev.min[d] / notnull_cnt);
1565 stddev.max[d] = sqrt(stddev.max[d] / notnull_cnt);
1566
1567 /* Histogram bounds for this dimension bounds is avg +/- SDFACTOR * stdev */
1568 histo_extent.min[d] = Max(avg.min[d] - SDFACTOR * stddev.min[d], sample_extent.min[d]);
1569 histo_extent.max[d] = Min(avg.max[d] + SDFACTOR * stddev.max[d], sample_extent.max[d]);
1570 }
1571
1572 /*
1573 * Third scan:
1574 * o skip hard deviants
1575 * o compute new histogram box
1576 */
1577 nd_box_init_bounds(&histo_extent_new);
1578 for ( i = 0; i < notnull_cnt; i++ )
1579 {
1580 const ND_BOX *ndb = sample_boxes[i];
1581 /* Skip any hard deviants (boxes entirely outside our histo_extent */
1582 if ( ! nd_box_intersects(&histo_extent, ndb, ndims) )
1583 {
1584 POSTGIS_DEBUGF(4, " feature %d is a hard deviant, skipped", i);
1585 sample_boxes[i] = NULL;
1586 continue;
1587 }
1588 /* Expand our new box to fit all the other features. */
1589 nd_box_merge(ndb, &histo_extent_new);
1590 }
1591 /*
1592 * Expand the box slightly (1%) to avoid edge effects
1593 * with objects that are on the boundary
1594 */
1595 nd_box_expand(&histo_extent_new, 0.01);
1596 histo_extent = histo_extent_new;
1597
1598 /*
1599 * How should we allocate our histogram cells to the
1600 * different dimensions? We can't do it by raw dimensional width,
1601 * because in x/y/z space, the z can have different units
1602 * from the x/y. Similarly for x/y/t space.
1603 * So, we instead calculate how much features overlap
1604 * each other in their dimension to figure out which
1605 * dimensions have useful selectivity characteristics (more
1606 * variability in density) and therefor would find
1607 * more cells useful (to distinguish between dense places and
1608 * homogeneous places).
1609 */
1610 nd_box_array_distribution(sample_boxes, notnull_cnt, &histo_extent, ndims,
1611 sample_distribution);
1612
1613 /*
1614 * The sample_distribution array now tells us how spread out the
1615 * data is in each dimension, so we use that data to allocate
1616 * the histogram cells we have available.
1617 * At this point, histo_cells_target is the approximate target number
1618 * of cells.
1619 */
1620
1621 /*
1622 * Some dimensions have basically a uniform distribution, we want
1623 * to allocate no cells to those dimensions, only to dimensions
1624 * that have some interesting differences in data distribution.
1625 * Here we count up the number of interesting dimensions
1626 */
1627 for ( d = 0; d < ndims; d++ )
1628 {
1629 if ( sample_distribution[d] > 0 )
1630 histo_ndims++;
1631 }
1632
1633 if ( histo_ndims == 0 )
1634 {
1635 /* Special case: all our dimensions had low variability! */
1636 /* We just divide the cells up evenly */
1637 POSTGIS_DEBUG(3, " special case: no axes have variability");
1638 histo_cells_new = 1;
1639 for ( d = 0; d < ndims; d++ )
1640 {
1641 histo_size[d] = (int)pow((double)histo_cells_target, 1/(double)ndims);
1642 if ( ! histo_size[d] )
1643 histo_size[d] = 1;
1644 POSTGIS_DEBUGF(3, " histo_size[d]: %d", histo_size[d]);
1645 histo_cells_new *= histo_size[d];
1646 }
1647 POSTGIS_DEBUGF(3, " histo_cells_new: %d", histo_cells_new);
1648 }
1649 else
1650 {
1651 /*
1652 * We're going to express the amount of variability in each dimension
1653 * as a proportion of the total variability and allocate cells in that
1654 * dimension relative to that proportion.
1655 */
1656 POSTGIS_DEBUG(3, " allocating histogram axes based on axis variability");
1657 total_distribution = total_double(sample_distribution, ndims); /* First get the total */
1658 POSTGIS_DEBUGF(3, " total_distribution: %.8g", total_distribution);
1659 histo_cells_new = 1; /* For the number of cells in the final histogram */
1660 for ( d = 0; d < ndims; d++ )
1661 {
1662 if ( sample_distribution[d] == 0 ) /* Uninteresting dimensions don't get any room */
1663 {
1664 histo_size[d] = 1;
1665 }
1666 else /* Interesting dimension */
1667 {
1668 /* How does this dims variability compare to the total? */
1669 float edge_ratio = (float)sample_distribution[d] / (float)total_distribution;
1670 /*
1671 * Scale the target cells number by the # of dims and ratio,
1672 * then take the appropriate root to get the estimated number of cells
1673 * on this axis (eg, pow(0.5) for 2d, pow(0.333) for 3d, pow(0.25) for 4d)
1674 */
1675 histo_size[d] = (int)pow(histo_cells_target * histo_ndims * edge_ratio, 1/(double)histo_ndims);
1676 /* If something goes awry, just give this dim one slot */
1677 if ( ! histo_size[d] )
1678 histo_size[d] = 1;
1679 }
1680 histo_cells_new *= histo_size[d];
1681 }
1682 POSTGIS_DEBUGF(3, " histo_cells_new: %d", histo_cells_new);
1683 }
1684
1685 /* Update histo_cells to the actual number of cells we need to allocate */
1686 histo_cells = histo_cells_new;
1687 POSTGIS_DEBUGF(3, " histo_cells: %d", histo_cells);
1688
1689 /*
1690 * Create the histogram (ND_STATS) in the stats memory context
1691 */
1692 old_context = MemoryContextSwitchTo(stats->anl_context);
1693 nd_stats_size = sizeof(ND_STATS) + ((histo_cells - 1) * sizeof(float4));
1694 nd_stats = palloc(nd_stats_size);
1695 memset(nd_stats, 0, nd_stats_size); /* Initialize all values to 0 */
1696 MemoryContextSwitchTo(old_context);
1697
1698 /* Initialize the #ND_STATS objects */
1699 nd_stats->ndims = ndims;
1700 nd_stats->extent = histo_extent;
1701 nd_stats->sample_features = sample_rows;
1702 nd_stats->table_features = total_rows;
1703 nd_stats->not_null_features = notnull_cnt;
1704 /* Copy in the histogram dimensions */
1705 for ( d = 0; d < ndims; d++ )
1706 nd_stats->size[d] = histo_size[d];
1707
1708 /*
1709 * Fourth scan:
1710 * o fill histogram values with the proportion of
1711 * features' bbox overlaps: a feature's bvol
1712 * can fully overlap (1) or partially overlap
1713 * (fraction of 1) an histogram cell.
1714 *
1715 * Note that we are filling each cell with the "portion of
1716 * the feature's box that overlaps the cell". So, if we sum
1717 * up the values in the histogram, we could get the
1718 * histogram feature count.
1719 *
1720 */
1721 for ( i = 0; i < notnull_cnt; i++ )
1722 {
1723 const ND_BOX *nd_box;
1724 ND_IBOX nd_ibox;
1725 int at[ND_DIMS];
1726 int d;
1727 double num_cells = 0;
1728 double tmp_volume = 1.0;
1729 double min[ND_DIMS] = {0.0, 0.0, 0.0, 0.0};
1730 double max[ND_DIMS] = {0.0, 0.0, 0.0, 0.0};
1731 double cellsize[ND_DIMS] = {0.0, 0.0, 0.0, 0.0};
1732
1733 nd_box = sample_boxes[i];
1734 if ( ! nd_box ) continue; /* Skip Null'ed out hard deviants */
1735
1736 /* Give backend a chance of interrupting us */
1737 vacuum_delay_point();
1738
1739 /* Find the cells that overlap with this box and put them into the ND_IBOX */
1740 nd_box_overlap(nd_stats, nd_box, &nd_ibox);
1741 memset(at, 0, sizeof(int)*ND_DIMS);
1742
1743 POSTGIS_DEBUGF(3, " feature %d: ibox (%d, %d, %d, %d) (%d, %d, %d, %d)", i,
1744 nd_ibox.min[0], nd_ibox.min[1], nd_ibox.min[2], nd_ibox.min[3],
1745 nd_ibox.max[0], nd_ibox.max[1], nd_ibox.max[2], nd_ibox.max[3]);
1746
1747 for ( d = 0; d < nd_stats->ndims; d++ )
1748 {
1749 /* Initialize the starting values */
1750 at[d] = nd_ibox.min[d];
1751 min[d] = nd_stats->extent.min[d];
1752 max[d] = nd_stats->extent.max[d];
1753 cellsize[d] = (max[d] - min[d])/(nd_stats->size[d]);
1754
1755 /* What's the volume (area) of this feature's box? */
1756 tmp_volume *= (nd_box->max[d] - nd_box->min[d]);
1757 }
1758
1759 /* Add feature volume (area) to our total */
1760 total_sample_volume += tmp_volume;
1761
1762 /*
1763 * Move through all the overlaped histogram cells values and
1764 * add the box overlap proportion to them.
1765 */
1766 do
1767 {
1768 ND_BOX nd_cell = { {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0} };
1769 double ratio;
1770 /* Create a box for this histogram cell */
1771 for ( d = 0; d < nd_stats->ndims; d++ )
1772 {
1773 nd_cell.min[d] = min[d] + (at[d]+0) * cellsize[d];
1774 nd_cell.max[d] = min[d] + (at[d]+1) * cellsize[d];
1775 }
1776
1777 /*
1778 * If a feature box is completely inside one cell the ratio will be
1779 * 1.0. If a feature box is 50% in two cells, each cell will get
1780 * 0.5 added on.
1781 */
1782 ratio = nd_box_ratio(&nd_cell, nd_box, nd_stats->ndims);
1783 nd_stats->value[nd_stats_value_index(nd_stats, at)] += ratio;
1784 num_cells += ratio;
1785 POSTGIS_DEBUGF(3, " ratio (%.8g) num_cells (%.8g)", ratio, num_cells);
1786 POSTGIS_DEBUGF(3, " at (%d, %d, %d, %d)", at[0], at[1], at[2], at[3]);
1787 }
1788 while ( nd_increment(&nd_ibox, nd_stats->ndims, at) );
1789
1790 /* Keep track of overall number of overlaps counted */
1791 total_cell_count += num_cells;
1792 /* How many features have we added to this histogram? */
1793 histogram_features++;
1794 }
1795
1796 POSTGIS_DEBUGF(3, " histogram_features: %d", histogram_features);
1797 POSTGIS_DEBUGF(3, " sample_rows: %d", sample_rows);
1798 POSTGIS_DEBUGF(3, " table_rows: %.6g", total_rows);
1799
1800 /* Error out if we got no sample information */
1801 if ( ! histogram_features )
1802 {
1803 POSTGIS_DEBUG(3, " no stats have been gathered");
1804 elog(NOTICE, " no features lie in the stats histogram, invalid stats");
1805 stats->stats_valid = false;
1806 return;
1807 }
1808
1809 nd_stats->histogram_features = histogram_features;
1810 nd_stats->histogram_cells = histo_cells;
1811 nd_stats->cells_covered = total_cell_count;
1812
1813 /* Put this histogram data into the right slot/kind */
1814 if ( mode == 2 )
1815 {
1816 stats_slot = STATISTIC_SLOT_2D;
1817 stats_kind = STATISTIC_KIND_2D;
1818 }
1819 else
1820 {
1821 stats_slot = STATISTIC_SLOT_ND;
1822 stats_kind = STATISTIC_KIND_ND;
1823 }
1824
1825 /* Write the statistics data */
1826 stats->stakind[stats_slot] = stats_kind;
1827 stats->staop[stats_slot] = InvalidOid;
1828 stats->stanumbers[stats_slot] = (float4*)nd_stats;
1829 stats->numnumbers[stats_slot] = nd_stats_size/sizeof(float4);
1830 stats->stanullfrac = (float4)null_cnt/sample_rows;
1831 stats->stawidth = total_width/notnull_cnt;
1832 stats->stadistinct = -1.0;
1833 stats->stats_valid = true;
1834
1835 POSTGIS_DEBUGF(3, " out: slot 0: kind %d (STATISTIC_KIND_ND)", stats->stakind[0]);
1836 POSTGIS_DEBUGF(3, " out: slot 0: op %d (InvalidOid)", stats->staop[0]);
1837 POSTGIS_DEBUGF(3, " out: slot 0: numnumbers %d", stats->numnumbers[0]);
1838 POSTGIS_DEBUGF(3, " out: null fraction: %f=%d/%d", stats->stanullfrac, null_cnt, sample_rows);
1839 POSTGIS_DEBUGF(3, " out: average width: %d bytes", stats->stawidth);
1840 POSTGIS_DEBUG (3, " out: distinct values: all (no check done)");
1841 POSTGIS_DEBUGF(3, " out: %s", nd_stats_to_json(nd_stats));
1842 /*
1843 POSTGIS_DEBUGF(3, " out histogram:\n%s", nd_stats_to_grid(nd_stats));
1844 */
1845
1846 return;
1847}
int gbox_is_valid(const GBOX *gbox)
Return false if any of the dimensions is NaN or infinite.
Definition gbox.c:197
int gserialized_get_gbox_p(const GSERIALIZED *g, GBOX *gbox)
Read the box from the GSERIALIZED or calculate it if necessary.
Definition gserialized.c:65
struct ND_STATS_T ND_STATS
N-dimensional statistics structure.
static int nd_box_intersects(const ND_BOX *a, const ND_BOX *b, int ndims)
Return true if ND_BOX a overlaps b, false otherwise.
static int nd_box_init_bounds(ND_BOX *a)
Prepare an ND_BOX for bounds calculation: set the maxes to the smallest thing possible and the mins t...
static int nd_increment(ND_IBOX *ibox, int ndims, int *counter)
Given an n-d index array (counter), and a domain to increment it in (ibox) increment it by one,...
#define STATISTIC_SLOT_ND
static int gbox_ndims(const GBOX *gbox)
Given that geodetic boxes are X/Y/Z regardless of the underlying geometry dimensionality and other bo...
static char * nd_box_to_json(const ND_BOX *nd_box, int ndims)
Convert an ND_BOX to a JSON string for printing.
static char * nd_stats_to_json(const ND_STATS *nd_stats)
Convert an ND_STATS to a JSON representation for external use.
#define ND_DIMS
The maximum number of dimensions our code can handle.
#define STATISTIC_KIND_2D
static int nd_box_merge(const ND_BOX *source, ND_BOX *target)
Create a printable view of the ND_STATS histogram.
#define STATISTIC_KIND_ND
static double total_double(const double *vals, int nvals)
Given double array, return sum of values.
#define SDFACTOR
static void nd_box_from_gbox(const GBOX *gbox, ND_BOX *nd_box)
Set the values of an ND_BOX from a GBOX.
static int nd_box_init(ND_BOX *a)
Zero out an ND_BOX.
static int nd_box_expand(ND_BOX *nd_box, double expansion_factor)
Expand an ND_BOX ever so slightly.
static int nd_box_overlap(const ND_STATS *nd_stats, const ND_BOX *nd_box, ND_IBOX *nd_ibox)
What stats cells overlap with this ND_BOX? Put the lowest cell addresses in ND_IBOX->min and the high...
static double nd_box_ratio(const ND_BOX *b1, const ND_BOX *b2, int ndims)
Returns the proportion of b2 that is covered by b1.
static int nd_stats_value_index(const ND_STATS *stats, int *indexes)
Given a position in the n-d histogram (i,j,k) return the position in the 1-d values array.
#define STATISTIC_SLOT_2D
static int nd_box_array_distribution(const ND_BOX **nd_boxes, int num_boxes, const ND_BOX *extent, int ndims, double *distribution)
Calculate how much a set of boxes is homogenously distributed or contentrated within one dimension,...
#define LW_FAILURE
Definition liblwgeom.h:110
double zmax
Definition liblwgeom.h:345
double zmin
Definition liblwgeom.h:344
double mmax
Definition liblwgeom.h:347
double mmin
Definition liblwgeom.h:346
float4 max[ND_DIMS]
float4 min[ND_DIMS]
N-dimensional box type for calculations, to avoid doing explicit axis conversions from GBOX in all ca...
int max[ND_DIMS]
int min[ND_DIMS]
N-dimensional box index type.
float4 size[ND_DIMS]
N-dimensional statistics structure.

References ND_STATS_T::cells_covered, ND_STATS_T::extent, gbox_is_valid(), gbox_ndims(), gserialized_get_gbox_p(), ND_STATS_T::histogram_cells, ND_STATS_T::histogram_features, LW_FAILURE, ND_BOX_T::max, ND_IBOX_T::max, ND_BOX_T::min, ND_IBOX_T::min, GBOX::mmax, GBOX::mmin, nd_box_array_distribution(), nd_box_expand(), nd_box_from_gbox(), nd_box_init(), nd_box_init_bounds(), nd_box_intersects(), nd_box_merge(), nd_box_overlap(), nd_box_ratio(), nd_box_to_json(), ND_DIMS, nd_increment(), nd_stats_to_json(), nd_stats_value_index(), ND_STATS_T::ndims, ND_STATS_T::not_null_features, ND_STATS_T::sample_features, SDFACTOR, ND_STATS_T::size, STATISTIC_KIND_2D, STATISTIC_KIND_ND, STATISTIC_SLOT_2D, STATISTIC_SLOT_ND, ND_STATS_T::table_features, total_double(), ND_STATS_T::value, GBOX::zmax, and GBOX::zmin.

Referenced by compute_gserialized_stats().

Here is the call graph for this function:
Here is the caller graph for this function: