const Array2D adjust_quant_indices(const Array2D& qIndices, const int qMatrix) {
  Array2D aQIndices(qIndices.ranges());
  // Adjust all the quantisers in qIndices
  std::transform(qIndices.data(), qIndices.data()+qIndices.num_elements(),
                 aQIndices.data(),
                 std::bind2nd(std::ptr_fun(adjust_quant_index), qMatrix) );
  return aQIndices;
}
const Array2D inverse_quantise_block(const Array2D& block, int q) {
  // Construct a new array with same size as block
  Array2D inverseQuantisedBlock(block.ranges());
  const int blockHeight = block.shape()[0];
  const int blockWidth = block.shape()[1];
  for (int y=0; y<blockHeight; ++y) {
    for (int x=0; x<blockWidth; ++x) {
      inverseQuantisedBlock[y][x] = scale(block[y][x], q);
    }
  }
  return inverseQuantisedBlock;
}
const Array2D clip(const Array2D& values, const int min_value, const int max_value) {
  Array2D result(values.ranges());
  const Index height = values.shape()[0];
  const Index width = values.shape()[1];
  for (int y=0; y<height; ++y) {
    for (int x=0; x<width; ++x) {
      if (values[y][x]<min_value) result[y][x] = min_value;
      else if (values[y][x]>max_value) result[y][x] =  max_value;
      else result[y][x] = values[y][x];
    }
  }
  return result;
}
// Quantise a subband in in-place transform order
// This version of quantise_subbands assumes multiple quantisers per subband.
// It may be used for either quantising slices or for quantising subbands with codeblocks
const Array2D quantise_subbands(const Array2D& coefficients, const BlockVector& qIndices) {
  const Index transformHeight = coefficients.shape()[0];
  const Index transformWidth = coefficients.shape()[1];
  // TO DO: Check numberOfSubbands=3n+1 ?
  const int numberOfSubbands = qIndices.size();
  const int waveletDepth = (numberOfSubbands-1)/3;
  Index stride, offset; // stride is subsampling factor, offset is subsampling phase
  Array2D result(coefficients.ranges());

  // Create a view of the coefficients, representing the LL subband, quantise it,
  // then assign the result a view of the results array. This puts the quantised
  // LL subband into the result array in in-place transform order.
  // ArrayIndices2D objects specify the subset of array elements within a view,
  // that is they specify the subsampling factor and subsampling phase.
  stride = pow(2, waveletDepth);
  const ArrayIndices2D LLindices = // LLindices specifies the samples in the LL subband
    indices[Range(0,transformHeight,stride)][Range(0,transformWidth,stride)];
  result[LLindices] =
    quantise_LLSubband(coefficients[LLindices], qIndices[0]);

  // Next quantise the other subbands
  // Note: Level numbers go from zero for the lowest ("DC") frequencies to depth for
  // the high frequencies. This corresponds to the convention in the VC-2 specification.
  // Subands go from zero ("DC") to numberOfSubbands-1 for HH at the highest level
  for (char level=1, band=1; level<=waveletDepth; ++level) {
    stride = pow(2, waveletDepth+1-level);
    offset = stride/2;
    // Create a view of coefficients corresponding to a subband, then quantise it
    //Quantise HL subband
    const ArrayIndices2D HLindices = // HLindices specifies the samples in the HL subband
      indices[Range(0,transformHeight,stride)][Range(offset,transformWidth,stride)];
    result[HLindices] = quantise_block(coefficients[HLindices], qIndices[band++]);
    //Quantise LH subband
    const ArrayIndices2D LHindices = // LHindices specifies the samples in the LH subband
      indices[Range(offset,transformHeight,stride)][Range(0,transformWidth,stride)];
    result[LHindices] = quantise_block(coefficients[LHindices], qIndices[band++]);
    //Quantise HH subband
    const ArrayIndices2D HHindices = // HHindices specifies the samples in the HH subband
      indices[Range(offset,transformHeight,stride)][Range(offset,transformWidth,stride)];
    result[HHindices] = quantise_block(coefficients[HHindices], qIndices[band++]);
  }

  return result;
}