# Path: katdal/chunkstore.py
# class PlaceholderChunk:
#     """Chunk returned to indicate missing data."""
# 
#     def __init__(self, shape, dtype):
#         self.shape = shape
#         self.dtype = np.dtype(dtype)
# 
#     def __getitem__(self, index):
#         # Create an array with a zero-sized dtype, so that it takes no memory
#         dummy = np.empty(self.shape, dtype=[])
#         new_shape = dummy[index].shape
#         return PlaceholderChunk(new_shape, self.dtype)
# 
# Path: katdal/flags.py
# DATA_LOST = 1 << DATA_LOST_BIT
# 
# Path: katdal/van_vleck.py
# def autocorr_lookup_table(levels, size=4000):
#     """Lookup table that corrects complex autocorrelation quantisation effects.
# 
#     This maps the variance of a quantised complex voltage signal to the variance
#     of the unquantised signal under the assumption that the signal is proper
#     (circularly-symmetric) complex normally distributed.
# 
#     Parameters
#     ----------
#     levels : sequence of float
#         Quantisation levels for real and imaginary components of voltage signal
#     size : int, optional
#         Size of lookup table
# 
#     Returns
#     -------
#     quantised_autocorr_table, true_autocorr_table : array of float, shape (`size`,)
#         Lookup table associating quantised autocorrelations and unquantised
#         autocorrelations (i.e. power/variance of complex signals)
#     """
#     # Terminology:
#     # x = Proper complex normal voltage signal (zero-mean)
#     # rxx = Power (variance) *per* real/imag component of unquantised / true x
#     # sxx = Power (variance) *per* real/imag component of quantised x
#     abs_levels = np.abs(levels)
#     sxx_min_nonzero = abs_levels[abs_levels > 0].min() ** 2
#     sxx_max = abs_levels.max() ** 2
#     # Sweep across range of true power values, placing more table entries at tricky lower end
#     rxx_grid = np.r_[np.logspace(-2.4, 0, size // 2, endpoint=False),
#                      np.logspace(0, np.log10(sxx_max / sxx_min_nonzero) + 8, size - 2 - size // 2)]
#     # Shift the table to place inflection point at minimum non-zero sxx
#     rxx_grid *= sxx_min_nonzero
#     # Map true power to expected quantised power
#     sxx_mean = _squared_quant_norm0_mean(levels, rxx_grid)
#     # Extend quantised power values to its maximum range
#     sxx_table = np.r_[0., sxx_mean, sxx_max]
#     # Replace asymptotic with linear decay at bottom end, and clip unbounded growth at top end
#     rxx_table = np.r_[0., rxx_grid, rxx_grid[-1]]
#     # The factor 2 converts power per real/imag component to power/variance of complex signal
#     return 2. * sxx_table, 2. * rxx_table


import itertools
import logging
import dask.array as da
import numba
import numpy as np
import toolz
from dask.array.rechunk import intersect_chunks
from dask.highlevelgraph import HighLevelGraph
from .chunkstore import PlaceholderChunk
from .flags import DATA_LOST
from .van_vleck import autocorr_lookup_table
        Correlation products. If given, compute both (scaled) `weights` and
        `unscaled_weights` by dividing or multiplying by the autocorrelations
        as needed. If `None`, the stored weights become `weights` and
        `unscaled_weights` is `None`, i.e. disabled (useful for testing).
    stored_weights_are_scaled : bool, optional
        True if the weights in the chunk store are already scaled by
        the autocorrelations. This determines how (scaled) `weights`
        and `unscaled_weights` are obtained from the stored weights.
        Should be True if `corrprods` is `None`.
    van_vleck : {'off', 'autocorr'}, optional
        Type of Van Vleck (quantisation) correction to perform
    index : tuple of slice, optional
        Slice expression to apply to each array before combining them. At the
        moment this can only have two elements (no slicing of baselines),
        because ``weights_channel`` only has time and frequency dimensions.

    Attributes
    ----------
    vis_prefix : string
        Prefix of correlator_data / visibility array, viz. its S3 bucket name
    """

    def __init__(self, store, chunk_info, corrprods=None,
                 stored_weights_are_scaled=True, van_vleck='off', index=()):
        self.store = store
        self.vis_prefix = chunk_info['correlator_data']['prefix']
        darray = {}
        for array, info in chunk_info.items():
            array_name = store.join(info['prefix'], array)
            chunk_args = (array_name, info['chunks'], info['dtype'])

# Path: katdal/chunkstore.py
# class PlaceholderChunk:
#     """Chunk returned to indicate missing data."""
# 
#     def __init__(self, shape, dtype):
#         self.shape = shape
#         self.dtype = np.dtype(dtype)
# 
#     def __getitem__(self, index):
#         # Create an array with a zero-sized dtype, so that it takes no memory
#         dummy = np.empty(self.shape, dtype=[])
#         new_shape = dummy[index].shape
#         return PlaceholderChunk(new_shape, self.dtype)
# 
# Path: katdal/flags.py
# DATA_LOST = 1 << DATA_LOST_BIT
# 
# Path: katdal/van_vleck.py
# def autocorr_lookup_table(levels, size=4000):
#     """Lookup table that corrects complex autocorrelation quantisation effects.
# 
#     This maps the variance of a quantised complex voltage signal to the variance
#     of the unquantised signal under the assumption that the signal is proper
#     (circularly-symmetric) complex normally distributed.
# 
#     Parameters
#     ----------
#     levels : sequence of float
#         Quantisation levels for real and imaginary components of voltage signal
#     size : int, optional
#         Size of lookup table
# 
#     Returns
#     -------
#     quantised_autocorr_table, true_autocorr_table : array of float, shape (`size`,)
#         Lookup table associating quantised autocorrelations and unquantised
#         autocorrelations (i.e. power/variance of complex signals)
#     """
#     # Terminology:
#     # x = Proper complex normal voltage signal (zero-mean)
#     # rxx = Power (variance) *per* real/imag component of unquantised / true x
#     # sxx = Power (variance) *per* real/imag component of quantised x
#     abs_levels = np.abs(levels)
#     sxx_min_nonzero = abs_levels[abs_levels > 0].min() ** 2
#     sxx_max = abs_levels.max() ** 2
#     # Sweep across range of true power values, placing more table entries at tricky lower end
#     rxx_grid = np.r_[np.logspace(-2.4, 0, size // 2, endpoint=False),
#                      np.logspace(0, np.log10(sxx_max / sxx_min_nonzero) + 8, size - 2 - size // 2)]
#     # Shift the table to place inflection point at minimum non-zero sxx
#     rxx_grid *= sxx_min_nonzero
#     # Map true power to expected quantised power
#     sxx_mean = _squared_quant_norm0_mean(levels, rxx_grid)
#     # Extend quantised power values to its maximum range
#     sxx_table = np.r_[0., sxx_mean, sxx_max]
#     # Replace asymptotic with linear decay at bottom end, and clip unbounded growth at top end
#     rxx_table = np.r_[0., rxx_grid, rxx_grid[-1]]
#     # The factor 2 converts power per real/imag component to power/variance of complex signal
#     return 2. * sxx_table, 2. * rxx_table


# Path: katdal/vis_flags_weights.py
import itertools
import logging
import dask.array as da
import numba
import numpy as np
import toolz
from dask.array.rechunk import intersect_chunks
from dask.highlevelgraph import HighLevelGraph
from .chunkstore import PlaceholderChunk
from .flags import DATA_LOST
from .van_vleck import autocorr_lookup_table

        Correlation products. If given, compute both (scaled) `weights` and
        `unscaled_weights` by dividing or multiplying by the autocorrelations
        as needed. If `None`, the stored weights become `weights` and
        `unscaled_weights` is `None`, i.e. disabled (useful for testing).
    stored_weights_are_scaled : bool, optional
        True if the weights in the chunk store are already scaled by
        the autocorrelations. This determines how (scaled) `weights`
        and `unscaled_weights` are obtained from the stored weights.
        Should be True if `corrprods` is `None`.
    van_vleck : {'off', 'autocorr'}, optional
        Type of Van Vleck (quantisation) correction to perform
    index : tuple of slice, optional
        Slice expression to apply to each array before combining them. At the
        moment this can only have two elements (no slicing of baselines),
        because ``weights_channel`` only has time and frequency dimensions.

    Attributes
    ----------
    vis_prefix : string
        Prefix of correlator_data / visibility array, viz. its S3 bucket name
    """

    def __init__(self, store, chunk_info, corrprods=None,
                 stored_weights_are_scaled=True, van_vleck='off', index=()):
        self.store = store
        self.vis_prefix = chunk_info['correlator_data']['prefix']
        darray = {}
        for array, info in chunk_info.items():
            array_name = store.join(info['prefix'], array)
            chunk_args = (array_name, info['chunks'], info['dtype'])

            errors = DATA_LOST if array == 'flags' else 'placeholder'