import copy
from absl.testing import parameterized
import numpy as np

from tensorflow.python.eager import context
from tensorflow.python.eager import def_function
from tensorflow.python.framework import constant_op
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import errors
from tensorflow.python.framework import errors_impl
from tensorflow.python.framework import tensor_shape
from tensorflow.python.framework import tensor_spec
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops.ragged import row_partition
from tensorflow.python.ops.ragged.row_partition import RowPartition
from tensorflow.python.ops.ragged.row_partition import RowPartitionSpec
from tensorflow.python.platform import googletest

def _get_specified_row_partition():
  """Needed for merge_with_spec tests. Normally, nvals isn't set."""
  return RowPartition(
      row_splits=constant_op.constant([0, 3, 8], dtype=dtypes.int64),
      nrows=constant_op.constant(2, dtype=dtypes.int64),
      nvals=constant_op.constant(8, dtype=dtypes.int64),
      internal=row_partition._row_partition_factory_key)

@test_util.run_all_in_graph_and_eager_modes
class RowPartitionTest(test_util.TensorFlowTestCase, parameterized.TestCase):
  #=============================================================================
  # RowPartition class docstring examples
  #=============================================================================

  def testClassDocStringExamples(self):
    # From section: "Component Tensors"
    rp = RowPartition.from_row_splits(row_splits=[0, 4, 4, 7, 8, 8])
    self.assertAllEqual(rp.row_splits(), [0, 4, 4, 7, 8, 8])
    del rp

    # From section: "Alternative Row-Partitioning Schemes"
    rt1 = RowPartition.from_row_splits(row_splits=[0, 4, 4, 7, 8, 8])
    rt2 = RowPartition.from_row_lengths(row_lengths=[4, 0, 3, 1, 0])
    rt3 = RowPartition.from_value_rowids(
        value_rowids=[0, 0, 0, 0, 2, 2, 2, 3], nrows=5)
    rt4 = RowPartition.from_row_starts(row_starts=[0, 4, 4, 7, 8], nvals=8)
    rt5 = RowPartition.from_row_limits(row_limits=[4, 4, 7, 8, 8])
    for rp in (rt1, rt2, rt3, rt4, rt5):
      self.assertAllEqual(rp.row_splits(), [0, 4, 4, 7, 8, 8])
    del rt1, rt2, rt3, rt4, rt5

    # From section: "Multiple Ragged Dimensions"
    inner_rt = RowPartition.from_row_splits(row_splits=[0, 4, 4, 7, 8, 8])
    outer_rt = RowPartition.from_row_splits(row_splits=[0, 3, 3, 5])
    del inner_rt, outer_rt

  #=============================================================================
  # RowPartition Constructor (private)
  #=============================================================================

  def testRowPartitionConstruction(self):
    row_splits = constant_op.constant([0, 2, 2, 5, 6, 7], dtypes.int64)
    rp = RowPartition(
        row_splits=row_splits,
        internal=row_partition._row_partition_factory_key)
    self.assertAllEqual(rp.row_splits(), [0, 2, 2, 5, 6, 7])

  def testRowPartitionConstructionErrors(self):
    row_splits = constant_op.constant([0, 2, 2, 5, 6, 7], dtypes.int64)

    with self.assertRaisesRegex(ValueError,
                                'RowPartition constructor is private'):
      RowPartition(row_splits=row_splits)

    with self.assertRaisesRegex(TypeError,
                                'Row-partitioning argument must be a Tensor'):
      RowPartition(
          row_splits=[0, 2, 2, 5, 6, 7],
          internal=row_partition._row_partition_factory_key)

    with self.assertRaisesRegex(ValueError, r'Shape \(6, 1\) must have rank 1'):
      RowPartition(
          row_splits=array_ops.expand_dims(row_splits, 1),
          internal=row_partition._row_partition_factory_key)

    with self.assertRaisesRegex(TypeError,
                                'Cached value must be a Tensor or None.'):
      RowPartition(
          row_splits=row_splits,
          row_lengths=[2, 3, 4],
          internal=row_partition._row_partition_factory_key)

    with self.assertRaisesRegex(ValueError, 'Inconsistent dtype'):
      RowPartition(
          row_splits=constant_op.constant([0, 3], dtypes.int64),
          nrows=constant_op.constant(1, dtypes.int32),
          internal=row_partition._row_partition_factory_key)

  #=============================================================================
  # RowPartition Factory Ops
  #=============================================================================

  def testFromValueRowIdsWithDerivedNRows(self):
    # nrows is known at graph creation time.
    value_rowids = constant_op.constant([0, 0, 2, 2, 2, 3, 4], dtypes.int64)
    # TODO(martinz): add nrows
    rp = RowPartition.from_value_rowids(value_rowids, validate=False)
    self.assertEqual(rp.dtype, dtypes.int64)

    rp_row_splits = rp.row_splits()
    rp_value_rowids = rp.value_rowids()
    rp_nrows = rp.nrows()

    self.assertIs(rp_value_rowids, value_rowids)  # value_rowids
    self.assertAllEqual(rp_value_rowids, value_rowids)
    self.assertAllEqual(rp_nrows, 5)
    self.assertAllEqual(rp_row_splits, [0, 2, 2, 5, 6, 7])

  def testFromValueRowIdsWithDerivedNRowsDynamic(self):
    # nrows is not known at graph creation time.
    value_rowids = constant_op.constant([0, 0, 2, 2, 2, 3, 4], dtypes.int64)
    value_rowids = array_ops.placeholder_with_default(value_rowids, shape=None)

    rp = RowPartition.from_value_rowids(value_rowids, validate=False)

    rp_value_rowids = rp.value_rowids()
    rp_nrows = rp.nrows()

    self.assertIs(rp_value_rowids, value_rowids)  # value_rowids
    self.assertAllEqual(rp_value_rowids, value_rowids)
    self.assertAllEqual(rp_nrows, 5)

  def testFromValueRowIdsWithExplicitNRows(self):
    value_rowids = constant_op.constant([0, 0, 2, 2, 2, 3, 4], dtypes.int64)
    nrows = constant_op.constant(7, dtypes.int64)

    rp = RowPartition.from_value_rowids(value_rowids, nrows, validate=False)

    rp_value_rowids = rp.value_rowids()
    rp_nrows = rp.nrows()
    rp_row_splits = rp.row_splits()

    self.assertIs(rp_value_rowids, value_rowids)  # value_rowids
    self.assertIs(rp_nrows, nrows)  # nrows
    self.assertAllEqual(rp_row_splits, [0, 2, 2, 5, 6, 7, 7, 7])

  def testFromValueRowIdsWithExplicitNRowsEqualToDefault(self):
    value_rowids = constant_op.constant([0, 0, 2, 2, 2, 3, 4], dtypes.int64)
    nrows = constant_op.constant(5, dtypes.int64)

    rp = RowPartition.from_value_rowids(value_rowids, nrows, validate=False)

    rp_value_rowids = rp.value_rowids()
    rp_nrows = rp.nrows()
    rp_row_splits = rp.row_splits()

    self.assertIs(rp_value_rowids, value_rowids)  # value_rowids
    self.assertIs(rp_nrows, nrows)  # nrows
    self.assertAllEqual(rp_value_rowids, value_rowids)
    self.assertAllEqual(rp_nrows, nrows)
    self.assertAllEqual(rp_row_splits, [0, 2, 2, 5, 6, 7])

  def testFromValueRowIdsWithEmptyValues(self):
    rp = RowPartition.from_value_rowids([])
    rp_nrows = rp.nrows()
    self.assertEqual(rp.dtype, dtypes.int64)
    self.assertEqual(rp.value_rowids().shape.as_list(), [0])
    self.assertAllEqual(rp_nrows, 0)

  def testFromRowSplits(self):
    row_splits = constant_op.constant([0, 2, 2, 5, 6, 7], dtypes.int64)

    rp = RowPartition.from_row_splits(row_splits, validate=False)
    self.assertEqual(rp.dtype, dtypes.int64)

    rp_row_splits = rp.row_splits()
    rp_nrows = rp.nrows()

    self.assertIs(rp_row_splits, row_splits)
    self.assertAllEqual(rp_nrows, 5)

  def testFromRowSplitsWithDifferentSplitTypes(self):
    splits1 = [0, 2, 2, 5, 6, 7]
    splits2 = np.array([0, 2, 2, 5, 6, 7], np.int64)
    splits3 = np.array([0, 2, 2, 5, 6, 7], np.int32)
    splits4 = constant_op.constant([0, 2, 2, 5, 6, 7], dtypes.int64)
    splits5 = constant_op.constant([0, 2, 2, 5, 6, 7], dtypes.int32)
    rt1 = RowPartition.from_row_splits(splits1)
    rt2 = RowPartition.from_row_splits(splits2)
    rt3 = RowPartition.from_row_splits(splits3)
    rt4 = RowPartition.from_row_splits(splits4)
    rt5 = RowPartition.from_row_splits(splits5)
    self.assertEqual(rt1.row_splits().dtype, dtypes.int64)
    self.assertEqual(rt2.row_splits().dtype, dtypes.int64)
    self.assertEqual(rt3.row_splits().dtype, dtypes.int32)
    self.assertEqual(rt4.row_splits().dtype, dtypes.int64)
    self.assertEqual(rt5.row_splits().dtype, dtypes.int32)

  def testFromRowSplitsWithEmptySplits(self):
    err_msg = 'row_splits tensor may not be empty'
    with self.assertRaisesRegex(ValueError, err_msg):
      RowPartition.from_row_splits([])

  def testFromRowStarts(self):
    nvals = constant_op.constant(7)
    row_starts = constant_op.constant([0, 2, 2, 5, 6], dtypes.int64)

    rp = RowPartition.from_row_starts(row_starts, nvals, validate=False)
    self.assertEqual(rp.dtype, dtypes.int64)

    rp_row_starts = rp.row_starts()
    rp_row_splits = rp.row_splits()
    rp_nrows = rp.nrows()

    self.assertAllEqual(rp_nrows, 5)
    self.assertAllEqual(rp_row_starts, row_starts)
    self.assertAllEqual(rp_row_splits, [0, 2, 2, 5, 6, 7])

  def testFromRowLimits(self):
    row_limits = constant_op.constant([2, 2, 5, 6, 7], dtypes.int64)

    rp = RowPartition.from_row_limits(row_limits, validate=False)
    self.assertEqual(rp.dtype, dtypes.int64)

    rp_row_limits = rp.row_limits()
    rp_row_splits = rp.row_splits()
    rp_nrows = rp.nrows()

    self.assertAllEqual(rp_nrows, 5)
    self.assertAllEqual(rp_row_limits, row_limits)
    self.assertAllEqual(rp_row_splits, [0, 2, 2, 5, 6, 7])

  def testFromRowLengths(self):
    row_lengths = constant_op.constant([2, 0, 3, 1, 1], dtypes.int64)

    rp = RowPartition.from_row_lengths(row_lengths, validate=False)
    self.assertEqual(rp.dtype, dtypes.int64)

    rp_row_lengths = rp.row_lengths()
    rp_nrows = rp.nrows()

    self.assertIs(rp_row_lengths, row_lengths)  # nrows
    self.assertAllEqual(rp_nrows, 5)
    self.assertAllEqual(rp_row_lengths, row_lengths)

  def testFromUniformRowLength(self):
    nvals = 16
    a1 = RowPartition.from_uniform_row_length(
        nvals=nvals, uniform_row_length=2)
    self.assertAllEqual(a1.uniform_row_length(), 2)
    self.assertAllEqual(a1.nrows(), 8)

  def testFromUniformRowLengthWithEmptyValues(self):
    a = RowPartition.from_uniform_row_length(
        nvals=0, uniform_row_length=0, nrows=10)
    self.assertEqual(self.evaluate(a.nvals()), 0)
    self.assertEqual(self.evaluate(a.nrows()), 10)

  def testFromUniformRowLengthWithPlaceholders1(self):
    nvals = array_ops.placeholder_with_default(
        constant_op.constant(6, dtype=dtypes.int64), None)
    rt1 = RowPartition.from_uniform_row_length(
        nvals=nvals, uniform_row_length=3)
    const_nvals1 = self.evaluate(rt1.nvals())
    self.assertEqual(const_nvals1, 6)

  def testFromUniformRowLengthWithPlaceholders2(self):
    nvals = array_ops.placeholder_with_default(6, None)
    ph_rowlen = array_ops.placeholder_with_default(3, None)
    rt2 = RowPartition.from_uniform_row_length(
        nvals=nvals, uniform_row_length=ph_rowlen)
    const_nvals2 = self.evaluate(rt2.nvals())
    self.assertEqual(const_nvals2, 6)

  def testFromValueRowIdsWithBadNRows(self):
    value_rowids = constant_op.constant([0, 0, 2, 2, 2, 3, 4], dtypes.int64)
    nrows = constant_op.constant(5, dtypes.int64)

    with self.assertRaisesRegex(ValueError, r'Expected nrows >= 0; got -2'):
      RowPartition.from_value_rowids(
          value_rowids=array_ops.placeholder_with_default(value_rowids, None),
          nrows=-2)

    with self.assertRaisesRegex(
        ValueError, r'Expected nrows >= value_rowids\[-1\] \+ 1; got nrows=2, '
        r'value_rowids\[-1\]=4'):
      RowPartition.from_value_rowids(value_rowids=value_rowids, nrows=2)

    with self.assertRaisesRegex(
        ValueError, r'Expected nrows >= value_rowids\[-1\] \+ 1; got nrows=4, '
        r'value_rowids\[-1\]=4'):
      RowPartition.from_value_rowids(value_rowids=value_rowids, nrows=4)

    with self.assertRaisesRegex(ValueError, r'Shape \(7, 1\) must have rank 1'):
      RowPartition.from_value_rowids(
          value_rowids=array_ops.expand_dims(value_rowids, 1), nrows=nrows)

    with self.assertRaisesRegex(ValueError, r'Shape \(1,\) must have rank 0'):
      RowPartition.from_value_rowids(
          value_rowids=value_rowids, nrows=array_ops.expand_dims(nrows, 0))

  #=============================================================================
  # RowPartition.__str__
  #=============================================================================
  def testRowPartitionStr(self):
    row_splits = [0, 2, 5, 6, 6, 7]
    rp = RowPartition.from_row_splits(row_splits, validate=False)
    if context.executing_eagerly():
      expected_repr = 'tf.RowPartition(row_splits=[0 2 5 6 6 7])'
    else:
      expected_repr = ('tf.RowPartition(row_splits='
                       'Tensor("RowPartitionFromRowSplits/row_splits:0", '
                       'shape=(6,), dtype=int64))')
    self.assertEqual(repr(rp), expected_repr)
    self.assertEqual(str(rp), expected_repr)

  def testRowPartitionStrUniformRowLength(self):
    rp = RowPartition.from_uniform_row_length(5, nvals=10, nrows=2)
    if context.executing_eagerly():
      expected_repr = ('tf.RowPartition(nrows=2, uniform_row_length=5)')
    else:
      expected_repr = (
          'tf.RowPartition(nrows='
          'Tensor("RowPartitionFromUniformRowLength/'
          'nrows:0", shape=(), dtype=int64), '
          'uniform_row_length=Tensor("RowPartitionFromUniformRowLength/'
          'uniform_row_length:0", shape=(), dtype=int64))')
    self.assertEqual(repr(rp), expected_repr)
    self.assertEqual(str(rp), expected_repr)

  @parameterized.parameters([
      # from_value_rowids
      {
          'descr': 'bad rank for value_rowids',
          'factory': RowPartition.from_value_rowids,
          'value_rowids': [[1, 2], [3, 4]],
          'nrows': 10
      },
      {
          'descr': 'bad rank for nrows',
          'factory': RowPartition.from_value_rowids,
          'value_rowids': [1, 2, 3, 4],
          'nrows': [10]
      },
      {
          'descr': 'negative value_rowid',
          'factory': RowPartition.from_value_rowids,
          'value_rowids': [-5, 2, 3, 4],
          'nrows': 10
      },
      {
          'descr': 'non-monotonic-increasing value_rowid',
          'factory': RowPartition.from_value_rowids,
          'value_rowids': [4, 3, 2, 1],
          'nrows': 10
      },
      {
          'descr': 'value_rowid > nrows',
          'factory': RowPartition.from_value_rowids,
          'value_rowids': [1, 2, 3, 4],
          'nrows': 2
      },

      # from_row_splits
      {
          'descr': 'bad rank for row_splits',
          'factory': RowPartition.from_row_splits,
          'row_splits': [[1, 2], [3, 4]]
      },
      {
          'descr': 'row_splits[0] != 0',
          'factory': RowPartition.from_row_splits,
          'row_splits': [2, 3, 4]
      },
      {
          'descr': 'non-monotonic-increasing row_splits',
          'factory': RowPartition.from_row_splits,
          'row_splits': [0, 3, 2, 4]
      },

      # from_row_lengths
      {
          'descr': 'bad rank for row_lengths',
          'factory': RowPartition.from_row_lengths,
          'row_lengths': [[1, 2], [1, 0]]
      },
      {
          'descr': 'negatve row_lengths',
          'factory': RowPartition.from_row_lengths,
          'row_lengths': [3, -1, 2]
      },

      # from_row_starts
      {
          'descr': 'bad rank for row_starts',
          'factory': RowPartition.from_row_starts,
          'nvals': 2,
          'row_starts': [[1, 2], [3, 4]]
      },
      {
          'descr': 'row_starts[0] != 0',
          'factory': RowPartition.from_row_starts,
          'nvals': 5,
          'row_starts': [2, 3, 4]
      },
      {
          'descr': 'non-monotonic-increasing row_starts',
          'factory': RowPartition.from_row_starts,
          'nvals': 4,
          'row_starts': [0, 3, 2, 4]
      },
      {
          'descr': 'row_starts[0] > nvals',
          'factory': RowPartition.from_row_starts,
          'nvals': 4,
          'row_starts': [0, 2, 3, 5]
      },

      # from_row_limits
      {
          'descr': 'bad rank for row_limits',
          'factory': RowPartition.from_row_limits,
          'row_limits': [[1, 2], [3, 4]]
      },
      {
          'descr': 'row_limits[0] < 0',
          'factory': RowPartition.from_row_limits,
          'row_limits': [-1, 3, 4]
      },
      {
          'descr': 'non-monotonic-increasing row_limits',
          'factory': RowPartition.from_row_limits,
          'row_limits': [0, 3, 2, 4]
      },

      # from_uniform_row_length
      {
          'descr': 'rowlen * nrows != nvals (1)',
          'factory': RowPartition.from_uniform_row_length,
          'nvals': 5,
          'uniform_row_length': 3
      },
      {
          'descr': 'rowlen * nrows != nvals (2)',
          'factory': RowPartition.from_uniform_row_length,
          'nvals': 5,
          'uniform_row_length': 6
      },
      {
          'descr': 'rowlen * nrows != nvals (3)',
          'factory': RowPartition.from_uniform_row_length,
          'nvals': 6,
          'uniform_row_length': 3,
          'nrows': 3
      },
      {
          'descr': 'rowlen must be a scalar',
          'factory': RowPartition.from_uniform_row_length,
          'nvals': 4,
          'uniform_row_length': [2]
      },
      {
          'descr': 'rowlen must be nonnegative',
          'factory': RowPartition.from_uniform_row_length,
          'nvals': 4,
          'uniform_row_length': -1
      },
  ])
  def testFactoryValidation(self, descr, factory, **kwargs):
    # When input tensors have shape information, some of these errors will be
    # detected statically.
    with self.assertRaises((errors.InvalidArgumentError, ValueError)):
      partition = factory(**kwargs)
      self.evaluate(partition.row_splits())

    # Remove shape information (by wrapping tensors in placeholders), and check
    # that we detect the errors when the graph is run.
    if not context.executing_eagerly():

      def wrap_arg(v):
        return array_ops.placeholder_with_default(
            constant_op.constant(v, dtype=dtypes.int64),
            tensor_shape.TensorShape(None))

      kwargs = dict((k, wrap_arg(v)) for (k, v) in kwargs.items())

      with self.assertRaises(errors.InvalidArgumentError):
        partition = factory(**kwargs)
        self.evaluate(partition.row_splits())

  @parameterized.named_parameters([
      ('FromRowSplits', lambda: RowPartition.from_row_splits([0, 2, 8]),
       ['row_splits']),
      ('FromRowLengths', lambda: RowPartition.from_row_lengths([3, 0, 8]),
       ['row_splits', 'row_lengths']),
      ('FromValueRowIds',
       lambda: RowPartition.from_value_rowids([0, 0, 3, 4, 4, 4]),
       ['row_splits', 'value_rowids', 'row_lengths', 'nrows']),
      ('FromRowStarts',
       lambda: RowPartition.from_row_starts([0, 3, 7], nvals=10),
       ['row_splits']),
      ('FromRowLimits', lambda: RowPartition.from_row_limits([3, 7, 10]),
       ['row_splits']),
  ])
  def testPrecomputedSplits(self, rp_factory, expected_encodings):
    rp = rp_factory()
    self.assertEqual(rp._has_precomputed_row_splits(),
                     'row_splits' in expected_encodings)
    self.assertEqual(rp._has_precomputed_row_lengths(),
                     'row_lengths' in expected_encodings)
    self.assertEqual(rp._has_precomputed_value_rowids(),
                     'value_rowids' in expected_encodings)
    self.assertEqual(rp._has_precomputed_nrows(), 'nrows' in expected_encodings)

  def testWithPrecomputedSplits(self):
    rp = RowPartition.from_row_splits([0, 2, 8])

    rp_with_row_splits = rp._with_precomputed_row_splits()
    self.assertTrue(rp_with_row_splits._has_precomputed_row_splits())

    self.assertFalse(rp._has_precomputed_row_lengths())
    rp_with_row_lengths = rp._with_precomputed_row_lengths()
    self.assertTrue(rp_with_row_lengths._has_precomputed_row_lengths())

    self.assertFalse(rp._has_precomputed_value_rowids())
    rp_with_value_rowids = rp._with_precomputed_value_rowids()
    self.assertTrue(rp_with_value_rowids._has_precomputed_value_rowids())

    self.assertFalse(rp._has_precomputed_nrows())
    rp_with_nrows = rp._with_precomputed_nrows()
    self.assertTrue(rp_with_nrows._has_precomputed_nrows())

    self.assertFalse(rp._has_precomputed_nvals())
    rp_with_nvals = rp._with_precomputed_nvals()
    self.assertTrue(rp_with_nvals._has_precomputed_nvals())

  @parameterized.named_parameters([
      dict(
          testcase_name='FromRowSplitsAndRowSplits',
          x=lambda: RowPartition.from_row_splits([0, 3, 8]),
          y=lambda: RowPartition.from_row_splits([0, 3, 8]),
          expected_encodings=['row_splits']),
      dict(
          testcase_name='FromRowSplitsAndUniformRowLength',
          x=lambda: RowPartition.from_row_splits([0, 3, 6]),
          y=lambda: RowPartition.from_uniform_row_length(3, nvals=6),
          expected_encodings=['row_splits', 'uniform_row_length', 'nrows']),
      dict(
          testcase_name='FromRowSplitsAndRowLengths',
          x=lambda: RowPartition.from_row_splits([0, 3, 8]),
          y=lambda: RowPartition.from_row_lengths([3, 5]),
          expected_encodings=['row_splits', 'row_lengths']),
      dict(
          testcase_name='FromRowSplitsAndValueRowIds',
          x=lambda: RowPartition.from_row_splits([0, 3, 8]),
          y=lambda: RowPartition.from_value_rowids([0, 0, 0, 1, 1, 1, 1, 1]),
          expected_encodings=[
              'row_splits', 'row_lengths', 'value_rowids', 'nrows'
          ]),
      dict(
          testcase_name='FromRowSplitsAndRowSplitsPlusNRows',
          x=lambda: RowPartition.from_row_splits([0, 3, 8]),
          y=lambda: RowPartition.from_row_splits([0, 3, 8]).
          _with_precomputed_nrows(),
          expected_encodings=['row_splits', 'nrows']),
  ])
  def testMergePrecomputedEncodings(self, x, y, expected_encodings):
    x = x()
    y = y()
    for validate in (True, False):
      result = x._merge_precomputed_encodings(y, validate)
      self.assertEqual(result._has_precomputed_row_splits(),
                       'row_splits' in expected_encodings)
      self.assertEqual(result._has_precomputed_row_lengths(),
                       'row_lengths' in expected_encodings)
      self.assertEqual(result._has_precomputed_value_rowids(),
                       'value_rowids' in expected_encodings)
      self.assertEqual(result._has_precomputed_nrows(),
                       'nrows' in expected_encodings)
      self.assertEqual(result.uniform_row_length() is not None,
                       'uniform_row_length' in expected_encodings)
      for r in (x, y):
        if (r._has_precomputed_row_splits() and
            result._has_precomputed_row_splits()):
          self.assertAllEqual(r.row_splits(), result.row_splits())
        if (r._has_precomputed_row_lengths() and
            result._has_precomputed_row_lengths()):
          self.assertAllEqual(r.row_lengths(), result.row_lengths())
        if (r._has_precomputed_value_rowids() and
            result._has_precomputed_value_rowids()):
          self.assertAllEqual(r.value_rowids(), result.value_rowids())
        if r._has_precomputed_nrows() and result._has_precomputed_nrows():
          self.assertAllEqual(r.nrows(), result.nrows())
        if (r.uniform_row_length() is not None and
            result.uniform_row_length() is not None):
          self.assertAllEqual(r.uniform_row_length(),
                              result.uniform_row_length())

  def testMergePrecomputedEncodingsFastPaths(self):
    # Same object: x gets returned as-is.
    x = RowPartition.from_row_splits([0, 3, 8, 8])
    self.assertIs(x._merge_precomputed_encodings(x), x)

    # Same encoding tensor objects: x gets returned as-is.
    y = RowPartition.from_row_splits(x.row_splits(), validate=False)
    self.assertIs(x._merge_precomputed_encodings(y), x)

  def testMergePrecomputedEncodingsWithMatchingTensors(self):
    # The encoding tensors for `a` are a superset of the encoding tensors
    # for `b`, and where they overlap, they the same tensor objects.
    a = RowPartition.from_value_rowids([0, 0, 3, 4, 4, 4])
    b = RowPartition.from_row_splits(a.row_splits(), validate=False)
    self.assertIs(a._merge_precomputed_encodings(b), a)
    self.assertIs(b._merge_precomputed_encodings(a), a)
    self.assertIsNot(a, b)

  @parameterized.named_parameters([
      dict(
          testcase_name='RowSplitMismatch',
          x=lambda: RowPartition.from_row_splits([0, 3, 8]),
          y=lambda: RowPartition.from_row_splits([0, 3, 8, 9]),
          message='incompatible row_splits'),
      dict(
          testcase_name='RowLengthMismatch',
          x=lambda: RowPartition.from_row_lengths([2, 0, 2]),
          y=lambda: RowPartition.from_row_lengths([2, 0, 2, 1]),
          message='incompatible row_splits'),  # row_splits is checked first
      dict(
          testcase_name='ValueRowIdMismatch',
          x=lambda: RowPartition.from_value_rowids([0, 3, 3, 4]),
          y=lambda: RowPartition.from_value_rowids([0, 3, 4]),
          message='incompatible value_rowids'),
  ])
  def testMergePrecomputedEncodingStaticErrors(self, x, y, message):
    if context.executing_eagerly():
      return
    # Errors that are caught by static shape checks.
    x = x()
    y = y()
    with self.assertRaisesRegex(ValueError, message):
      x._merge_precomputed_encodings(y).row_splits()
    with self.assertRaisesRegex(ValueError, message):
      y._merge_precomputed_encodings(x).row_splits()

  @parameterized.named_parameters([
      dict(
          testcase_name='NRowsMismatchAlt',
          x=lambda: RowPartition.from_uniform_row_length(5, nrows=4, nvals=20),
          y=lambda: RowPartition.from_uniform_row_length(5, nrows=3, nvals=15),
          message='incompatible nrows'),
      dict(
          testcase_name='UniformRowLengthMismatch',
          x=lambda: RowPartition.from_uniform_row_length(5, nvals=20),
          y=lambda: RowPartition.from_uniform_row_length(2, nvals=8),
          message='incompatible (nvals|uniform_row_length)'),
      dict(
          testcase_name='RowSplitMismatch',
          x=lambda: RowPartition.from_row_splits([0, 3, 8]),
          y=lambda: RowPartition.from_row_splits([0, 5, 8]),
          message='incompatible row_splits'),
      dict(
          testcase_name='RowLengthMismatch',
          x=lambda: RowPartition.from_row_lengths([2, 0, 2]),
          y=lambda: RowPartition.from_row_lengths([0, 0, 2]),
          message='incompatible (row_splits|nvals)'),
      dict(
          testcase_name='ValueRowIdMismatch',
          x=lambda: RowPartition.from_value_rowids([0, 3, 3]),
          y=lambda: RowPartition.from_value_rowids([0, 0, 3]),
          message='incompatible row_splits'),  # row_splits is checked first
  ])
  def testMergePrecomputedEncodingRuntimeErrors(self, x, y, message):
    # Errors that are caught by runtime value checks.
    x = x()
    y = y()
    with self.assertRaisesRegex(errors.InvalidArgumentError, message):
      self.evaluate(x._merge_precomputed_encodings(y).row_splits())
    with self.assertRaisesRegex(errors.InvalidArgumentError, message):
      self.evaluate(y._merge_precomputed_encodings(x).row_splits())

  @parameterized.named_parameters([
      # It throws the right error, but it still complains.
      dict(
          testcase_name='NRowsMismatch',
          x=lambda: RowPartition.from_uniform_row_length(5, nvals=20),
          y=lambda: RowPartition.from_uniform_row_length(5, nvals=15),
          message='incompatible nvals',
          emessage='incompatible nrows'),
  ])
  def testMergePrecomputedEncodingStaticErrors2(self, x, y,
                                                message, emessage):
    # Message error and type varies depending upon eager execution.
    x = x()
    y = y()

    error_type = errors_impl.InvalidArgumentError
    expected_message = emessage if context.executing_eagerly() else message
    with self.assertRaisesRegex(error_type, expected_message):
      self.evaluate(x._merge_precomputed_encodings(y).row_splits())
    with self.assertRaisesRegex(error_type, expected_message):
      self.evaluate(y._merge_precomputed_encodings(x).row_splits())

  @parameterized.named_parameters([
      dict(
          testcase_name='NoneSpecified',
          rp=(lambda: RowPartition.from_row_splits([0, 3, 8])),
          spec=RowPartitionSpec(nrows=None, nvals=None, dtype=dtypes.int64)),
      dict(
          testcase_name='NRowsSpecified',
          rp=(lambda: RowPartition.from_row_splits([0, 3, 8])),
          spec=RowPartitionSpec(nrows=2, nvals=None, dtype=dtypes.int64)),
      dict(
          testcase_name='NValsSpecified',
          rp=_get_specified_row_partition,
          spec=RowPartitionSpec(nrows=None, nvals=8, dtype=dtypes.int64))
  ])
  def testMergeWithSpecNoop(self, rp, spec):
    rp = rp()
    actual = rp._merge_with_spec(spec)
    self.assertAllEqual(actual.row_splits(), rp.row_splits())
    self.assertAllEqual(actual.static_nrows, rp.static_nrows)
    self.assertAllEqual(actual.static_nvals, rp.static_nvals)

  @parameterized.named_parameters([
      dict(
          testcase_name='NRowsNValsUpdated',
          rp=(lambda: RowPartition.from_row_splits([0, 3, 8])),
          spec=RowPartitionSpec(nrows=2, nvals=8, dtype=dtypes.int64),
          expected=_get_specified_row_partition),
      dict(
          testcase_name='NValsUpdated',
          rp=(lambda: RowPartition.from_row_splits([0, 3, 8])),
          spec=RowPartitionSpec(nrows=None, nvals=8, dtype=dtypes.int64),
          expected=_get_specified_row_partition)])
  def testMergeWithSpecUpdate(self, rp, spec, expected):
    rp = rp()
    expected = expected()
    actual = rp._merge_with_spec(spec)
    self.assertAllEqual(actual.row_splits(), expected.row_splits())
    self.assertAllEqual(actual.static_nrows, expected.static_nrows)
    self.assertAllEqual(actual.static_nvals, expected.static_nvals)

  @parameterized.named_parameters([
      dict(
          testcase_name='from_uniform_row_length',
          x=lambda: RowPartition.from_uniform_row_length(5, nvals=20),
          expected=True),
      dict(
          testcase_name='from_row_splits',
          x=lambda: RowPartition.from_row_splits([0, 3, 8]),
          expected=False),
      dict(
          testcase_name='from_row_lengths',
          x=lambda: RowPartition.from_row_lengths([2, 0, 2]),
          expected=False),
      dict(
          testcase_name='from_row_lengths_uniform',
          x=lambda: RowPartition.from_row_lengths([3, 3, 3]),
          expected=False),
  ])
  def testIsUniform(self, x, expected):
    x = x()
    self.assertEqual(expected, x.is_uniform())

  @parameterized.named_parameters([
      dict(
          testcase_name='doc_example',
          x=lambda: RowPartition.from_row_lengths([3, 2, 0, 2]),
          expected=[0, 1, 2, 0, 1, 0, 1]),
      dict(
          testcase_name='from_uniform_row_length',
          x=lambda: RowPartition.from_uniform_row_length(4, nvals=12),
          expected=[0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]),
      dict(
          testcase_name='from_row_splits',
          x=lambda: RowPartition.from_row_splits([0, 3, 8]),
          expected=[0, 1, 2, 0, 1, 2, 3, 4]),
  ])
  def testOffsetsInRows(self, x, expected):
    x = x()
    actual = x.offsets_in_rows()
    self.assertAllEqual(expected, actual)

  def testFromUniformRowLengthBugConvertToTensor(self):
    # This originally failed to run because nrows was dtypes.int32. I think
    # we may need to consider the semantics of the type of a RowPartition
    # if preferred_dtype is unspecified. Also, looking at convert_to_tensor:
    # dtype specifies the type of the output.
    # preferred_dtype/dtype_hint is a suggestion, and dtype_hint is the new
    # name.
    nrows = constant_op.constant(3, dtype=dtypes.int32)
    nvals = constant_op.constant(12, dtype=dtypes.int64)
    row_length = constant_op.constant(4, dtype=dtypes.int64)
    rp = RowPartition.from_uniform_row_length(row_length, nvals=nvals,
                                              nrows=nrows, dtype=dtypes.int64)
    self.assertEqual(rp.nrows().dtype, dtypes.int64)

  def testFromUniformRowLengthNvalDynamic(self):
    # A key question is whether if nrows and uniform_row_length are known,
    # and nvals is given but not known statically, should we determine nvals?
    # TODO(martinz): Uncomment after nvals is fixed.
    # @def_function.function(
    #     input_signature=[tensor_spec.TensorSpec(None, dtypes.int32)])
    # def foo(nvals):
    #   rp = RowPartition.from_uniform_row_length(12, nvals=nvals, nrows=3)
    #   nval_output = tensor_util.constant_value(rp.nvals())
    #   self.assertEqual(nval_output, 36)
    # foo(constant_op.constant(36, dtype=dtypes.int32))
    pass

  def testFromUniformRowLengthNvalDynamicNoValidate(self):
    # A key question is whether if nrows and uniform_row_length are known,
    # and nvals is given but not known statically, should we determine nvals?
    # TODO(martinz): Uncomment after nvals is fixed.
    # @def_function.function(
    #     input_signature=[tensor_spec.TensorSpec(None, dtypes.int32)])
    # def foo(nvals):
    #   rp = RowPartition.from_uniform_row_length(12, nvals=nvals, nrows=3,
    #                                             validate=False)
    #   nval_output = tensor_util.constant_value(rp.nvals())
    #   self.assertEqual(nval_output, 36)
    # foo(constant_op.constant(36, dtype=dtypes.int32))
    pass

  def testFromUniformRowLengthNvalDynamicWrong(self):
    # A key question is whether if nrows and uniform_row_length are known,
    # and nvals is given but not known statically and WRONG,
    # what should we do? We add a check, but checks are only checked for
    # row_splits.
    @def_function.function(
        input_signature=[tensor_spec.TensorSpec(None, dtypes.int32)])
    def foo(nvals):
      rp = RowPartition.from_uniform_row_length(12, nvals=nvals, nrows=3)
      return rp.nvals()

    with self.assertRaises(errors.InvalidArgumentError):
      nvals = foo(constant_op.constant(7, dtype=dtypes.int32))
      self.evaluate(nvals)

  def testFromUniformRowLengthNvalDynamicWrongRowSplits(self):
    # A key question is whether if nrows and uniform_row_length are known,
    # and nvals is given but not known statically and WRONG,
    # what should we do?
    # A key question is whether if nrows and uniform_row_length are known,
    # and nvals is given but not known statically and WRONG,
    # what should we do? We add a check, but checks are only checked for
    # row_splits.
    @def_function.function(
        input_signature=[tensor_spec.TensorSpec(None, dtypes.int32)])
    def foo(nvals):
      rp = RowPartition.from_uniform_row_length(12, nvals=nvals, nrows=3)
      return rp.row_splits()

    with self.assertRaises(errors.InvalidArgumentError):
      rs = foo(constant_op.constant(7, dtype=dtypes.int32))
      self.evaluate(rs)

  def testFromUniformRowPartitionNrows(self):
    rp = RowPartition.from_uniform_row_length(3, nrows=4)
    self.assertAllEqual(4, rp.nrows())
    self.assertAllEqual(3, rp.uniform_row_length())
    self.assertAllEqual(12, rp.static_nvals)

  def testFromUniformRowPartitionNvalsStatic(self):
    rp = RowPartition.from_uniform_row_length(3, nvals=12)
    self.assertAllEqual(4, rp.static_nrows)
    self.assertAllEqual(3, rp.static_uniform_row_length)
    self.assertAllEqual(12, rp.static_nvals)

  def testFromUniformRowPartitionNvalsStaticNoValidate(self):
    rp = RowPartition.from_uniform_row_length(3, nrows=4, nvals=12,
                                              validate=False)
    self.assertAllEqual(4, rp.static_nrows)
    self.assertAllEqual(3, rp.static_uniform_row_length)
    self.assertAllEqual(12, rp.static_nvals)

  def testFromUniformRowPartitionNvalsIs(self):
    # TODO(martinz): Uncomment after nvals is fixed.
    # nvals = constant_op.constant(12)
    # rp = RowPartition.from_uniform_row_length(3, nvals=nvals)
    # self.assertIs(rp.nvals(), nvals)
    pass

  def testFromUniformRowPartitionRowStartsStatic(self):
    rp = RowPartition.from_row_starts([0, 3, 6], nvals=12)
    self.assertAllEqual(12, rp.static_nvals)

  def testStaticNrows(self):
    rp = RowPartition.from_row_splits([0, 3, 4, 5])
    static_nrows = rp.static_nrows
    self.assertIsInstance(static_nrows, int)
    self.assertAllEqual(3, static_nrows)

  def testStaticNrowsUnknown(self):
    @def_function.function(
        input_signature=[tensor_spec.TensorSpec(None, dtypes.int32)])
    def foo(rs):
      rp = RowPartition.from_row_splits(rs)
      static_nrows = rp.static_nrows
      self.assertIsNone(static_nrows)
    foo(array_ops.constant([0, 3, 4, 5], dtype=dtypes.int32))

@test_util.run_all_in_graph_and_eager_modes
class RowPartitionSpecTest(test_util.TensorFlowTestCase,
                           parameterized.TestCase):

  def testDefaultConstruction(self):
    spec = RowPartitionSpec()
    self.assertIsNone(spec.nrows)
    self.assertIsNone(spec.nvals)
    self.assertIsNone(spec.uniform_row_length)
    self.assertEqual(spec.dtype, dtypes.int64)

  @parameterized.parameters([
      (None, None, None, dtypes.int64, None, None, None, dtypes.int64),
      (5, None, None, dtypes.int32, 5, None, None, dtypes.int32),
      (None, 20, None, dtypes.int64, None, 20, None, dtypes.int64),
      (None, None, 8, dtypes.int64, None, None, 8, dtypes.int64),
      (5, None, 8, dtypes.int64, 5, 40, 8, dtypes.int64),  # nvals inferred
      (None, 20, 4, dtypes.int32, 5, 20, 4, dtypes.int32),  # nrows inferred
      (0, None, None, dtypes.int32, 0, 0, None, dtypes.int32),  # nvals inferred
      (None, None, 0, dtypes.int32, None, 0, 0, dtypes.int32),  # nvals inferred
  ])  # pyformat: disable
  def testConstruction(self, nrows, nvals, uniform_row_length, dtype,
                       expected_nrows, expected_nvals,
                       expected_uniform_row_length, expected_dtype):
    spec = RowPartitionSpec(nrows, nvals, uniform_row_length, dtype)
    self.assertEqual(spec.nrows, expected_nrows)
    self.assertEqual(spec.nvals, expected_nvals)
    self.assertEqual(spec.uniform_row_length, expected_uniform_row_length)
    self.assertEqual(spec.dtype, expected_dtype)

  @parameterized.parameters([
      dict(dtype=dtypes.float32, error='dtype must be tf.int32 or tf.int64'),
      dict(nrows=0, nvals=5, error='.* not compatible .*'),
      dict(uniform_row_length=0, nvals=5, error='.* not compatible .*'),
      dict(nvals=11, uniform_row_length=5, error='.* not compatible .*'),
      dict(
          nrows=8, nvals=10, uniform_row_length=5,
          error='.* not compatible .*'),
  ])
  def testConstructionError(self,
                            nrows=None,
                            nvals=None,
                            uniform_row_length=None,
                            dtype=dtypes.int64,
                            error=None):
    with self.assertRaisesRegex(ValueError, error):
      RowPartitionSpec(nrows, nvals, uniform_row_length, dtype)

  @parameterized.parameters([
      RowPartitionSpec(),
      RowPartitionSpec(dtype=dtypes.int64),
      RowPartitionSpec(uniform_row_length=3)
  ])  # pyformat: disable

  def testDeepcopy(self, spec):
    spec = RowPartitionSpec()
    spec_b = copy.deepcopy(spec)
    self.assertEqual(repr(spec), repr(spec_b))

  def testValueType(self):
    spec = RowPartitionSpec()
    self.assertEqual(spec.value_type, RowPartition)

  @parameterized.parameters([
      dict(
          spec=RowPartitionSpec(),
          expected=(tensor_shape.TensorShape([None]),
                    tensor_shape.TensorShape([None]),
                    tensor_shape.TensorShape([None]), dtypes.int64)),
      dict(
          spec=RowPartitionSpec(dtype=dtypes.int32),
          expected=(tensor_shape.TensorShape([None]),
                    tensor_shape.TensorShape([None]),
                    tensor_shape.TensorShape([None]), dtypes.int32)),
      dict(
          spec=RowPartitionSpec(nrows=8, nvals=13),
          expected=(tensor_shape.TensorShape([8]),
                    tensor_shape.TensorShape([13]),
                    tensor_shape.TensorShape([None]), dtypes.int64)),
      dict(
          spec=RowPartitionSpec(nrows=8, uniform_row_length=2),
          expected=(
              tensor_shape.TensorShape([8]),
              tensor_shape.TensorShape([16]),  # inferred
              tensor_shape.TensorShape([2]),
              dtypes.int64)),
  ])
  def testSerialize(self, spec, expected):
    serialization = spec._serialize()
    # TensorShape has an unconventional definition of equality, so we can't use
    # assertEqual directly here.  But repr() is deterministic and lossless for
    # the expected values, so we can use that instead.
    self.assertEqual(repr(serialization), repr(expected))

  @parameterized.parameters([
      dict(
          spec=RowPartitionSpec(),
          expected=tensor_spec.TensorSpec([None], dtypes.int64)),
      dict(
          spec=RowPartitionSpec(dtype=dtypes.int32),
          expected=tensor_spec.TensorSpec([None], dtypes.int32)),
      dict(
          spec=RowPartitionSpec(nrows=17, dtype=dtypes.int32),
          expected=tensor_spec.TensorSpec([18], dtypes.int32)),
      dict(
          spec=RowPartitionSpec(nvals=10, uniform_row_length=2),
          expected=tensor_spec.TensorSpec([6], dtypes.int64)),  # inferred nrow
  ])
  def testComponentSpecs(self, spec, expected):
    self.assertEqual(spec._component_specs, expected)

  @parameterized.parameters([
      dict(
          rp_factory=lambda: RowPartition.from_row_splits([0, 3, 7]),
          components=[0, 3, 7]),
  ])
  def testToFromComponents(self, rp_factory, components):
    rp = rp_factory()
    spec = rp._type_spec
    actual_components = spec._to_components(rp)
    self.assertAllEqual(actual_components, components)
    rp_reconstructed = spec._from_components(actual_components)
    _assert_row_partition_equal(self, rp, rp_reconstructed)

  @parameterized.parameters([
      (RowPartitionSpec(), RowPartitionSpec()),
      (RowPartitionSpec(nrows=8), RowPartitionSpec(nrows=8)),
      (RowPartitionSpec(nrows=8), RowPartitionSpec(nrows=None)),
      (RowPartitionSpec(nvals=8), RowPartitionSpec(nvals=8)),
      (RowPartitionSpec(nvals=8), RowPartitionSpec(nvals=None)),
      (RowPartitionSpec(uniform_row_length=8),
       RowPartitionSpec(uniform_row_length=8)),
      (RowPartitionSpec(uniform_row_length=8),
       RowPartitionSpec(uniform_row_length=None)),
      (RowPartitionSpec(nvals=12), RowPartitionSpec(uniform_row_length=3)),
      (RowPartitionSpec(nrows=12), RowPartitionSpec(uniform_row_length=72)),
      (RowPartitionSpec(nrows=5), RowPartitionSpec(nvals=15)),
      (RowPartitionSpec(nvals=0), RowPartitionSpec(nrows=0)),
      (RowPartitionSpec(nvals=0), RowPartitionSpec(uniform_row_length=0)),
  ])
  def testIsCompatibleWith(self, spec1, spec2):
    self.assertTrue(spec1.is_compatible_with(spec2))

  @parameterized.parameters([
      (RowPartitionSpec(), RowPartitionSpec(dtype=dtypes.int32)),
      (RowPartitionSpec(nvals=5), RowPartitionSpec(uniform_row_length=3)),
      (RowPartitionSpec(nrows=7,
                        nvals=12), RowPartitionSpec(uniform_row_length=3)),
      (RowPartitionSpec(nvals=5), RowPartitionSpec(nrows=0)),
      (RowPartitionSpec(nvals=5), RowPartitionSpec(uniform_row_length=0)),
  ])
  def testIsNotCompatibleWith(self, spec1, spec2):
    self.assertFalse(spec1.is_compatible_with(spec2))

  @parameterized.parameters([
      dict(
          spec1=RowPartitionSpec(nrows=8, nvals=3, dtype=dtypes.int32),
          spec2=RowPartitionSpec(nrows=8, nvals=3, dtype=dtypes.int32),
          expected=RowPartitionSpec(nrows=8, nvals=3, dtype=dtypes.int32)),
      dict(
          spec1=RowPartitionSpec(nrows=8, nvals=None),
          spec2=RowPartitionSpec(nrows=None, nvals=8),
          expected=RowPartitionSpec(nrows=None, nvals=None)),
      dict(
          spec1=RowPartitionSpec(nrows=8, nvals=33),
          spec2=RowPartitionSpec(nrows=3, nvals=13),
          expected=RowPartitionSpec(nrows=None, nvals=None)),
      dict(
          spec1=RowPartitionSpec(nrows=12, uniform_row_length=3),
          spec2=RowPartitionSpec(nrows=3, uniform_row_length=3),
          expected=RowPartitionSpec(nrows=None, uniform_row_length=3)),
      dict(
          spec1=RowPartitionSpec(5, 35, 7),
          spec2=RowPartitionSpec(8, 80, 10),
          expected=RowPartitionSpec(None, None, None)),
  ])
  def testMostSpecificCompatibleType(self, spec1, spec2, expected):
    actual = spec1.most_specific_compatible_type(spec2)
    self.assertEqual(actual, expected)

  @parameterized.parameters([
      (RowPartitionSpec(), RowPartitionSpec(dtype=dtypes.int32)),
  ])
  def testMostSpecificCompatibleTypeError(self, spec1, spec2):
    with self.assertRaisesRegex(ValueError, 'No TypeSpec is compatible'):
      spec1.most_specific_compatible_type(spec2)

  def testNumRowsInt64(self):
    row_splits = array_ops.constant([0, 2, 3, 5], dtype=dtypes.int64)
    values = RowPartition.from_row_splits(row_splits)
    nrows = values.nrows()
    self.assertEqual(dtypes.int64, nrows.dtype)

  def testFromValue(self):
    self.assertEqual(
        RowPartitionSpec.from_value(RowPartition.from_row_splits([0, 2, 8, 8])),
        RowPartitionSpec(nrows=3))
    self.assertEqual(
        RowPartitionSpec.from_value(
            RowPartition.from_row_lengths([5, 3, 0, 2])),
        RowPartitionSpec(nrows=4))
    self.assertEqual(
        RowPartitionSpec.from_value(
            RowPartition.from_value_rowids([0, 2, 2, 8])),
        RowPartitionSpec(nrows=9, nvals=4))
    self.assertEqual(
        RowPartitionSpec.from_value(
            RowPartition.from_uniform_row_length(
                nvals=12, uniform_row_length=3)),
        RowPartitionSpec(nvals=12, uniform_row_length=3))

  @parameterized.parameters([
      dict(original=RowPartitionSpec(),
           dtype=dtypes.int32,
           expected=RowPartitionSpec(dtype=dtypes.int32)),
      dict(original=RowPartitionSpec(dtype=dtypes.int32),
           dtype=dtypes.int64,
           expected=RowPartitionSpec()),
      dict(original=RowPartitionSpec(nvals=20, nrows=4, uniform_row_length=5),
           dtype=dtypes.int32,
           expected=RowPartitionSpec(nvals=20, nrows=4, uniform_row_length=5,
                                     dtype=dtypes.int32)),
  ])
  def testWithDType(self, original, dtype, expected):
    actual = original.with_dtype(dtype)
    self.assertEqual(actual, expected)

  @parameterized.parameters([
      dict(a=RowPartitionSpec(),
           b=RowPartitionSpec(nrows=3, uniform_row_length=5),
           expected=RowPartitionSpec(nrows=3, uniform_row_length=5)),
      dict(a=RowPartitionSpec(nrows=3),
           b=RowPartitionSpec(uniform_row_length=5),
           expected=RowPartitionSpec(nrows=3, uniform_row_length=5)),
      dict(a=RowPartitionSpec(nvals=20),
           b=RowPartitionSpec(nrows=3),
           expected=RowPartitionSpec(nvals=20, nrows=3)),
      dict(a=RowPartitionSpec(nvals=20, dtype=dtypes.int32),
           b=RowPartitionSpec(nrows=3, dtype=dtypes.int32),
           expected=RowPartitionSpec(nvals=20, nrows=3, dtype=dtypes.int32)),
  ])
  def testMergeWith(self, a, b, expected):
    actual = a._merge_with(b)
    actual_rev = b._merge_with(a)
    self.assertEqual(actual, expected)
    self.assertEqual(actual_rev, expected)

  @parameterized.parameters([
      dict(a=RowPartitionSpec(nrows=3, nvals=10),
           b=RowPartitionSpec(uniform_row_length=5),
           error_type=ValueError,
           error_regex='Merging incompatible RowPartitionSpecs'),
      dict(a=RowPartitionSpec(uniform_row_length=5, dtype=dtypes.int32),
           b=RowPartitionSpec(uniform_row_length=5, dtype=dtypes.int64),
           error_type=ValueError,
           error_regex='Merging RowPartitionSpecs with incompatible dtypes'),
  ])
  def testMergeWithRaises(self, a, b, error_type, error_regex):
    with self.assertRaisesRegex(error_type, error_regex):
      a._merge_with(b)

def _assert_row_partition_equal(test_class, actual, expected):
  assert isinstance(test_class, test_util.TensorFlowTestCase)
  assert isinstance(actual, RowPartition)
  assert isinstance(expected, RowPartition)

  test_class.assertEqual(actual._has_precomputed_row_splits(),
                         expected._has_precomputed_row_splits())
  test_class.assertEqual(actual._has_precomputed_row_lengths(),
                         expected._has_precomputed_row_lengths())
  test_class.assertEqual(actual._has_precomputed_value_rowids(),
                         expected._has_precomputed_value_rowids())
  test_class.assertEqual(actual._has_precomputed_nrows(),
                         expected._has_precomputed_nrows())
  test_class.assertEqual(actual.uniform_row_length() is None,
                         expected.uniform_row_length() is None)

  if expected._has_precomputed_row_splits():
    test_class.assertAllEqual(actual.row_splits(), expected.row_splits())
  if expected._has_precomputed_row_lengths():
    test_class.assertAllEqual(actual.row_lengths(), expected.row_lengths())
  if expected._has_precomputed_value_rowids():
    test_class.assertAllEqual(actual.value_rowids(), expected.value_rowids())
  if expected._has_precomputed_nrows():
    test_class.assertAllEqual(actual.nrows(), expected.nrows())
  if expected.uniform_row_length() is not None:
    test_class.assertAllEqual(actual.uniform_row_length(),
                              expected.uniform_row_length())

if __name__ == '__main__':
  googletest.main()


from django.shortcuts import render, redirect, HttpResponse
from django.http.response import JsonResponse
from django.contrib import messages
from Eshopapp.models import Product, Cart, WishList

def addtocart(request):

    if request.method == 'POST':
        if request.user.is_authenticated:
            product_id = int(request.POST.get('product_id'))
            product_check = Product.objects.get(id=product_id)
            if(product_check):
                if (Cart.objects.filter(user=request.user.id, product_id=product_id)):
                    return JsonResponse({'status': 'Already in Cart.'})
                else:
                    product_qty = int(request.POST.get('product_qty'))
                    if product_check.quantity >= product_qty:
                        Cart.objects.create(
                            user=request.user, product_id=product_id, product_qty=product_qty)
                        return JsonResponse({'status': 'Product added successfully.'})
                    else:
                        return JsonResponse({'status': 'Only '+str(product_check.quantity)+' quantity available.'})
            else:
                return JsonResponse({'status': 'No such product found.'})
        else:
            return JsonResponse({'status': 'Login to Continue..!!'})
    else:
        return redirect('/')

def cartview(request):
    if request.user.is_authenticated:
        cart = Cart.objects.filter(user=request.user)
        context = {'cart': cart}
        return render(request, 'Eshopapp/cart/cart.html', context)
    else:
        return redirect('/')

def delete_cart_item(request):
    if request.method == 'POST':
        pord_id = request.POST.get('product_id')
        if (Cart.objects.filter(user=request.user, product__id=pord_id)):
            Cart.objects.filter(user=request.user, product__id=pord_id).delete()
            return JsonResponse({'status':'Product removed successfully.'})
    else:
        return redirect('/')

def update_cart(request):
    if request.method == 'POST':
        prod_id = request.POST.get('product_id')
        print(prod_id)
        if Cart.objects.filter(user=request.user, product__id=prod_id):
            prod_qty = request.POST.get('product_qty')
            print(prod_qty)
            cart = Cart.objects.get(product__id=prod_id, user=request.user)
            cart.product_qty = prod_qty
            cart.save()

        else:
            return JsonResponse({'status':'something went wrong.'})
    return redirect('/')


from flask.ext.principal import UserNeed, identity_loaded, RoleNeed, Permission, Principal
from flask.ext.login import current_user

# Needs
be_admin = RoleNeed('admin')
be_logged = RoleNeed('loginUser')

# Permissions
# Permission objects are used mostly to check for requirements.
# e.g. @admin_permission.require(http_exception=401)
# decorates a function, checks if the calling user is an administrator
# and returns a HTTP 401 code if it is not.
admin_perm = Permission(be_admin)
logged_perm = Permission(be_logged)

class AdminPermission:
    """
    Class for wrap permission require decorator
    """
    def require(self, http_exception=403, func=None):
        if func is not None:
            def permission_func(func):
                func._permission = 'admin'
                req = admin_perm.require(http_exception=http_exception)
                func = req.__call__(func)
                return func
            return permission_func(func)

        else:
            def partial_check(func):
                return self.require(http_exception, func)
            return partial_check

class LoggedPermission:
    """
    Class for wrap permission require decorator
    """
    def require(self, http_exception=403, func=None):
        if func is not None:
            def permission_func(func):
                func._permission = 'logged'
                req = logged_perm.require(http_exception=http_exception)
                func = req.__call__(func)
                return func
            return permission_func(func)

        else:
            def partial_check(func):
                return self.require(http_exception, func)
            return partial_check

admin_permission = AdminPermission()
logged_permission = LoggedPermission()


class FusionAccessStandardResponse(object):

    @classmethod
    def validate_empty(cls, resp, set_name='DataSet'):
        return resp.get(set_name, [])

    @classmethod
    def validation(cls, resp):
        if not resp:
            raise Exception("Validation failed...Message:{}".format(resp))
        return [{"Id": resp}]

    @classmethod
    def site(cls, resp):
        sites = []
        for site in cls.validate_empty(resp, set_name='sites'):
            sites.append({
                "Id": site.get("siteId"),
                "Name": site.get("name"),
            })
        return sites

    @classmethod
    def cluster(cls, resp):
        clusters = []
        for cluster in cls.validate_empty(resp, set_name='clusters'):
            clusters.append({
                "Id": cluster.get("clusterId"),
                "Name": cluster.get("name"),
            })
        return clusters

    @classmethod
    def instance(cls, resp):
        instances = []
        for instance in cls.validate_empty(resp, set_name='instancesInfoList'):
            os_platform = instance.get("osPlatform")
            os_type = "windows" if os_platform == 0 else "linux"
            instances.append({
                "Id": instance.get("vmId"),
                "Name": instance.get("computerName"),
                "Status": instance.get("instanceState"),
                "OsType": os_type,
                "OperatingSystem": os_type,
                "Zone": instance.get("clusterId"),
                "OsName": instance.get("computerName"),
                "CPU": instance.get("VCpu"),
                "Memory": instance.get("memory") / 1024,
                "CreateTime": instance.get("createTime"),
                "NetworkAddress": {"private_ip": instance.get("ip")},
                "PrivateIpAddress": instance.get("ip"),
                "SystemDisk": instance.get("systemDisk"),
                "InstanceType": instance.get("templateId"),
            })
        return instances

    @classmethod
    def template(cls, resp):
        templates = []
        for template in cls.validate_empty(resp, set_name='templateInfoList'):
            templates.append({
                "Id": template.get("templateId"),
                "Name": template.get("templateName"),
                "Zone": template.get("clusterId"),
                "CPU": template.get("cores"),
                "Memory": template.get("memory") / 1024,
                "Disks": template.get("diskList"),
                "Nics": template.get("nicList"),
                "Datastores": template.get("datastoreIdList")
            })
        return templates

    @classmethod
    def datastore_by_template(cls, resp):
        datastores = []
        datastore_ids = []
        for ava_datastore in cls.validate_empty(resp, set_name='availDatastoreList'):
            for datastore in ava_datastore.get("datastoreList"):
                if datastore.get("datastoreId") not in datastore_ids:
                    datastores.append({
                        "Id": datastore.get("datastoreId"),
                        "Name": datastore.get("name")
                    })
                    datastore_ids.append(datastore.get("datastoreId"))
        return datastores

    @classmethod
    def datastore(cls, resp):
        datastores = []
        for datastore in cls.validate_empty(resp, set_name='datastoreList'):
            datastores.append({
                "Id": datastore.get("datastoreId"),
                "Name": datastore.get("name")
            })
        return datastores

    @classmethod
    def securitygroup(cls, resp):
        securitygroups = []
        for securitygroup in cls.validate_empty(resp, set_name='securityGroups'):
            securitygroups.append({
                "Id": securitygroup.get("sgId"),
                "Name": securitygroup.get("sgName"),
                "SecurityGroupDesc": securitygroup.get("sgDesc"),
                "Rule": securitygroup.get("rules")
            })
        if not securitygroups:  # fake security for test
            return [{
                "Id": 1,
                "Name": "fake-securitygroup",
                "SecurityGroupDesc": "fake-test",
                "Rule": "0.0.0.0/0"
            }]
        return securitygroups

    @classmethod
    def portgroup(cls, resp):
        portgroups = []
        for portgroup in cls.validate_empty(resp, set_name='portGroups'):
            portgroups.append({
                "Id": portgroup.get("portGroupId"),
                "Name": portgroup.get("portGroupName"),
                "dvSwitchId": portgroup.get("dvSwitchId"),
                "description": portgroup.get("description"),
                "vlanId": portgroup.get("vlanId")
            })
        return portgroups


import sqlite3
import pandas as pd
import questionary
from tabulate import tabulate

from db import DB
from habit import Habit
import analysis

def cli():
    """
    Main loop of the habit tracker program.
    """

    db = DB()

    stop = False
    while not stop:

        main_menu = questionary.select(
            "Welcome. What do you want to do?",
            choices=["Create habit", "Complete habit", "Analyze habits", "Delete habit", "Exit"]
        ).ask()

        if main_menu == "Create habit":

            name = questionary.text("What's the name of your new habit?").ask().lower()
            habit_created = False
            while not habit_created:
                if name == "":
                    print("\nPlease provide a name for your habit!\n")
                    name = questionary.text("What's the name of your new habit?").ask().lower()
                else:
                    habit_created = True

            desc = questionary.text("Please provide a short description of your habit.").ask()

            period = questionary.select(
                    "How often do you want to perform your habit?",
                    choices=["daily", "weekly", "monthly"]
                ).ask()

            goal = questionary.text(
                "Set a final goal: How often do you want to perform the habit? Please insert an integer number..."
            ).ask()
            habit_created = False
            while not habit_created:
                try:
                    if len(goal) > 5:  # prevents error if input is too large to be converted to int type
                        print("\nYou probably won't get that old ;). Please choose a reasonable goal.\n")
                        goal = questionary.text(
                            "Set a final goal: Insert an integer number between 2 and 99,999"
                        ).ask()
                    elif int(goal) < 2:  # prevents negative numbers/ 0/ 1, to asure that habits establish as intended
                        raise ValueError()
                    else:   # prevents input that is NOT a number like "bob"
                        Habit(name=name, desc=desc, period=period, goal=int(goal)).create_habit(db)
                        habit_created = True
                except (ValueError, TypeError):
                    print("\nYour goal must be an integer number larger than 1!\n")
                    goal = questionary.text(
                        "Set a final goal: How often do you want to perform the habit? Please insert a number..."
                    ).ask()
                except sqlite3.IntegrityError:
                    print(f"\nA habit with the name {name} already exists. Please choose a unique name:\n")
                    name = questionary.text("What's the name of your new habit?").ask().lower()

        elif main_menu == "Complete habit":
            habits = db.cur.execute("SELECT name FROM habits ORDER BY name").fetchall()
            habit_list = []
            for habit in habits:
                habit_list.append(*habit)  # the asterisk unpacks the tuple, so that habit_list truly is a list!
            habit_list.append("BACK TO MAIN MENU")
            selection = questionary.select(
                "Which habit do you want to check off today?",
                choices=habit_list
            ).ask()
            if selection == "BACK TO MAIN MENU":
                continue
            else:
                habit = Habit(selection).fetch_habit_data(db)
                habit.complete_habit(db)

        elif main_menu == "Analyze habits":
            selection = questionary.select(
                "What do you want to know about your habits?",
                choices=["View all habits", "View habits with periodicity ...", "View one habit ...",
                         "View personal records...", "View established habits", "BACK TO MAIN MENU"]
            ).ask()

            if selection == "BACK TO MAIN MENU":
                continue

            elif selection == "View all habits":
                habits = analysis.list_all_habits(db)
                format_print_outline(db, habits)

            elif selection == "View habits with periodicity ...":
                selection = questionary.select(
                    "Which filter do you want to apply?", choices=["daily", "weekly", "monthly", "BACK TO MAIN MENU"]
                ).ask()
                if selection == "BACK TO MAIN MENU":
                    continue
                else:
                    habits = analysis.list_filtered_habits(db, selection)
                    format_print_outline(db, habits)

            elif selection == "View one habit ...":
                habits = db.cur.execute("SELECT name FROM habits ORDER BY name").fetchall()
                habit_list = []
                for habit in habits:
                    habit_list.append(*habit)  # the asterisk unpacks the tuple, so that habit_list truly is a list!
                habit_list.append("BACK TO MAIN MENU")
                selection = questionary.select(
                    "Which habit do you want to display in detail?",
                    choices=habit_list
                ).ask()
                if selection == "BACK TO MAIN MENU":
                    continue
                else:
                    habit = analysis.view_single_habit(db, selection)  # turn argument back into type tuple --> (arg,)
                    print(habit)
                    format_print_grid(db, habit)

            elif selection == "View personal records...":
                selection = questionary.select(
                    "Please select what you want to display:",
                    choices=["View habits with the longest day streak!", "View habits with the closest goal!",
                             "BACK TO MAIN MENU"]
                ).ask()
                if selection == "BACK TO MAIN MENU":
                    continue
                elif selection == "View habits with the longest day streak!":
                    lon_str = analysis.view_longest_streaks(db)
                    print("\nYou have obtained the longest streak for these habits:\n")
                    format_print_grid(db, lon_str)
                elif selection == "View habits with the closest goal!":
                    cl_goal = analysis.view_closest_goal(db)
                    print("\nThese habits are closest to your final goal:\n")
                    format_print_grid(db, cl_goal)

            elif selection == "View established habits":
                habits = analysis.view_established_habits(db)
                print("\nThese habits are already established:\n")
                format_print_grid(db, habits)

        elif main_menu == "Delete habit":
            habits = db.cur.execute("SELECT name FROM habits ORDER BY name").fetchall()
            habit_list = []
            for habit in habits:
                habit_list.append(*habit)
            habit_list.append("BACK TO MAIN MENU")
            selection = questionary.select(
                "Which habit do you want to delete?",
                choices=habit_list
            ).ask()
            if selection == "BACK TO MAIN MENU":
                continue
            else:
                db.drop_habit((selection,))  # argument must be turned into type tuple --> (arg,)

        elif main_menu == "Exit":
            db.cur.close()
            db.db.close()
            stop = True

def format_print_grid(db, data):
    """
    Uses pandas DFs and tabulate to print data in a tidy format to CLI. Table format is "gird".
    :param db: name of the database connection
    :param data: an object that is returned by a method or function and needs to be printed to the console
    :return:
    """
    df = pd.DataFrame(data)
    headers = list(map(lambda x: x[0], db.cur.description))
    print(tabulate(df, headers=headers, tablefmt="grid"))

def format_print_outline(db, data):
    """
    Uses pandas DFs and tabulate to print data in a tidy format to CLI. Table format is "outline".
    :param db: name of the database connection
    :param data: an object that is returned by a method or function and needs to be printed to the console
    :return:
    """
    df = pd.DataFrame(data)
    headers = list(map(lambda x: x[0], db.cur.description))
    print(tabulate(df, headers=headers, tablefmt="outline"))

if __name__ == '__main__':
    cli()


# -*- coding:utf-8 -*-
# @author shaoguang.csg

import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
import copy

from DLAPP.FacialKeypointDetection.conf import *

def load_data(is_test=False):
    """
    load face image and keypoints from csv file
    :param is_test:
    :return:
    """
    filename = TEST_FILE if is_test else TRAIN_FILE
    df = pd.read_csv(filename)

    df = df.dropna()
    df['Image'] = df['Image'].apply(lambda image: np.fromstring(image, sep=" ", count=SIZE*SIZE)/255.0)
    x = np.vstack(df['Image']).reshape((-1, SIZE, SIZE, N_CHANNEL))

    if is_test:
        y = None
    else:
        y = df[df.columns[:-1]].values/SIZE

    return x, y

def flip_images(images, keypoints, direction='horizon'):
    """
    flip images according to specified direction
    :param images: (n, w, h, c)
    :param keypoints: (n,)
    :param direction:
    :return:
    """
    keypoints_ = copy.deepcopy(keypoints)
    keypoints_ = keypoints_.reshape((keypoints.shape[0], -1, 2))
    if direction == 'horizonal':
        images_ = np.flipud(images)
        keypoints_[:, :, 0] = 1.0-keypoints_[:, :, 0]
        return images_, keypoints_.reshape((keypoints.shape[0], -1))
    elif direction == 'vertical':
        images_ = np.fliplr(images)
        keypoints_[:, :, 1] = 1.0-keypoints_[:, :, 1]
        return images_, keypoints_.reshape((keypoints.shape[0], -1))
    else:
        print("Unsupport direction")

def visualize_face(images, keypoints, is_scale=True):
    """
    visualize images and keypoints in face
    :param images: numpy.ndarray
    :param keypoints:
    :return:
    """
    assert len(images.shape) == 3 and \
           len(keypoints.shape) == 2 and \
           images.shape[0] == keypoints.shape[0]

    if is_scale:
        images = copy.deepcopy(images)
        keypoints = copy.deepcopy(keypoints)
        images *= 255
        keypoints *= SIZE

    fig = plt.figure()

    num_image = images.shape[0]
    num_col = int(np.ceil(np.sqrt(num_image)))
    num_row = int(np.ceil(num_image*1.0/num_col))
    keypoints = keypoints.reshape((num_image,-1,2))

    for row in range(num_row):
        for col in range(num_col):
            index = row*num_col+col
            if index >= num_image:
                break
            fig.add_subplot(num_row, num_col, index+1)
            plt.imshow(images[index,:,:], cmap='gray')
            plt.scatter(keypoints[index,:,0], keypoints[index,:,1], s=20, color='red')

if __name__ == '__main__':
    x, y = load_data()
    visualize_face(x[:10,:,:,0], y[:10,:], is_scale=True)
    x_, y_ = flip_images(x[:10,:,:,0], y[:10,:], direction='vertical')
    visualize_face(x_, y_, is_scale=True)
    print("Finished")


import os
import subprocess

os.chdir(os.path.abspath(os.path.join(os.path.dirname(__file__), '../../..')))

def check_output_despite_error(args):
  """Get output of args from command line, even if there are errors.

  Args:
    args: a list of command line args.

  Returns:
    output as string.
  """
  try:
    output = subprocess.check_output(args, shell=True, stderr=subprocess.STDOUT)
  except subprocess.CalledProcessError as e:
    output = e.output
  return output.strip()

def main():
  # Get all py_test target, note bazel query result will also include
  # cuda_py_test etc.
  try:
    targets = subprocess.check_output([
        'bazel', 'query',
        'kind(py_test, //tensorflow/contrib/... + '
        '//tensorflow/python/... - '
        '//tensorflow/contrib/tensorboard/...)']).strip()
  except subprocess.CalledProcessError as e:
    targets = e.output
  targets = targets.decode("utf-8") if isinstance(targets, bytes) else targets

  # Only keep py_test targets, and filter out targets with 'no_pip' tag.
  valid_targets = []
  for target in targets.split('\n'):
    kind = check_output_despite_error(['buildozer', 'print kind', target])
    if kind == 'py_test':
      tags = check_output_despite_error(['buildozer', 'print tags', target])
      if 'no_pip' not in tags:
        valid_targets.append(target)

  # Get all BUILD files for all valid targets.
  build_files = set()
  for target in valid_targets:
    build_files.add(os.path.join(target[2:].split(':')[0], 'BUILD'))

  # Check if BUILD files load py_test.
  files_missing_load = []
  for build_file in build_files:
    updated_build_file = subprocess.check_output(
        ['buildozer', '-stdout', 'new_load //tensorflow:tensorflow.bzl py_test',
         build_file])
    with open(build_file, 'r') as f:
      if f.read() != updated_build_file:
        files_missing_load.append(build_file)

  if files_missing_load:
    raise RuntimeError('The following files are missing %s:\n %s' % (
        'load("//tensorflow:tensorflow.bzl", "py_test").\nThis load statement'
        ' is needed because otherwise pip tests will try to use their '
        'dependencies, which are not visible to them.',
        '\n'.join(files_missing_load)))
  else:
    print('TEST PASSED.')

if __name__ == '__main__':
  main()


from django.shortcuts import render
import requests
from .models import Product
from django.db.models import Q
from django.core.paginator import EmptyPage,Paginator,PageNotAnInteger
from django.shortcuts import render,get_object_or_404,redirect
from django.db.models import Count

url = "https://search.paytm.com/v2/search?userQuery=Micromax+TV&page_count=5&items_per_page=50"
# Create your views here.

def get_paytm_data():
    get_paytm_data = requests.get(url).json()
    print("++++++++++++++++++++++")
    product_data = {}
    product_list = []
    for product_item in get_paytm_data['grid_layout']:
        product_data['name'] = product_item['name']
        product_data['url'] = product_item['url']
        product_data['image'] = product_item['image_url']
        product_data['price'] = product_item['actual_price']
        product_list.append(product_data.copy())
    return product_list

def product_list(request):
    products = get_paytm_data()
    duplicate_obj = Product.objects.filter(name=products)
    for item in products:
        if not Product.objects.filter(name=item['name']).exists():
            product_obj = Product.objects.create(**item)
            product_obj.save()
    prd_list=Product.objects.all()
    query=request.GET.get("q")
    if query:
        prd_list=prd_list.filter(Q(name__icontains=query) | Q(price__icontains=query)).distinct()
    paginator=Paginator(prd_list,50)
    page_number=request.GET.get('page')
    try:
        prd_list=paginator.page(page_number)
    except PageNotAnInteger:
        prd_list=paginator.page(1)
    except EmptyPage:
        prd_list=paginator.page(paginator.num_pages)
    return render(request, 'index.html', {'products': products,'prd_list':prd_list})


# 프로그래머스_레벨 2_위장
# 220720

from collections import defaultdict

def solution(clothes):
    answer = 1

    # defaultdict를 이용하여 부위별 의상 수를 count
    clothes_dict = defaultdict(int)
    for a, b in clothes: clothes_dict[b] += 1

    # 각 부위별 의상을 +1하여 모두 곱함
    # +1하는 이유는 그 부위를 안 입을 수도 있기 때문
    for i in list(clothes_dict.values()):
        answer *= (i+1)

    # 마지막에 -1하여 리턴하는 이유는 모든 부위를 안 입는 경우를 제거하기 위함
    return answer - 1

프로그래머스/레벨 2_위장.py


from nltk.corpus import brown,gutenberg
from collections import Counter

import matplotlib.pyplot as plt
import math

def q1():
    puncs = set((',', '.', '--', '-', '!', '?', ':', ';', '``', "''", '(', ')', '[', ']'))
    word_list_brown = (x.lower() for x in brown.words() if x not in puncs)
    word_list_gutenberg = (x.lower() for x in gutenberg.words() if x not in puncs)

    token_counts_brown = Counter(word_list_brown)
    token_counts_gutenberg = Counter(word_list_gutenberg)

    # print(token_counts_brown.most_common(20))
    # print(token_counts_gutenberg.most_common(20))

    token_counts = token_counts_brown + token_counts_gutenberg

    # rank200
    rank_200 = token_counts.most_common(200)
    rank_num = []
    for i in range(200):
        rank_num.append(rank_200[i][1])

    x = [i for i in range(1,201)]

    # .plot()作图需指定x轴和y轴的数据
    plt.plot([math.log(i) for i in x], [math.log(y) for y in rank_num])
    plt.show()
    plt.savefig('zipf.png')

if __name__ == "__main__":
    q1()


import argparse
import os
import subprocess
from statistics import mean
import urllib.request

def fetch_pdb(pdb_id):
    url_string = "http://files.rcsb.org/download/{0}.pdb".format(pdb_id)
    outfilename = pdb_id + ".pdb"
    try:
        urllib.request.urlretrieve(url_string, outfilename)
    except Exception as e:
        print(e)

def remove_tag(pdbfile, tag, outfile):
    """
    tag can be water or ligand
    if tag is water, HOH used
    if tag is ligand, HETATM used
    """
    if tag == "water":
        tag = "HOH"

    if tag == "ligand":
        tag = "HETATM"

    clean_list = []
    with open(pdbfile, 'r') as inf:
        for line in inf:
            if tag in line:
                pass
            else:
                clean_list.append(line)

    with open(outfile, 'w') as out:
        for line in clean_list:
            out.write(line)

def protein_preparation(pdbfile: str, outpdbqtfile: str):
    python_exe = r"C:\Users\shien\miniconda3\python.exe"
    adt = r"C:\Users\shien\miniconda3\Lib\site-packages\AutoDockTools_py3-1.5.7.post1-py3.9.egg\AutoDockTools\Utilities24"
    alter_conf = os.path.join(adt, "prepare_pdb_split_alt_confs.py")
    protein_prep = os.path.join(adt, "prepare_receptor4.py")

    # cmd list to treat the residue with alter conformation
    cmd = f' "{python_exe}" "{alter_conf}" -r "{pdbfile}" '
    cmd_return = subprocess.run(cmd, capture_output=False, shell=True)
    pdbbase = pdbfile.split(".")[0]
    clean_file = pdbbase + "_A.pdb"

    # cmd list format raises errors, therefore one string
    cmd = f' "{python_exe}" "{protein_prep}" -r "{clean_file}" -A bonds_hydrogens -e -o "{outpdbqtfile}" '
    cmd_return = subprocess.run(cmd, capture_output=False, shell=True)
    # output = cmd_return.stdout.decode('utf-8')
    # print(cmd)

    if cmd_return.returncode != 0:
        raise ValueError('Protein prep  failed')

    return True

def box_center_info(fname, extend):
    X = []
    Y = []
    Z = []
    with open(fname) as inf:
        for line in inf:
            if line.startswith('HETATM'):
                clean = line.strip()
                # print(clean.split())
                X.append(float(clean.split()[6]))
                Y.append(float(clean.split()[7]))
                Z.append(float(clean.split()[8]))
    x = mean(X)
    y = mean(Y)
    z = mean(Z)

    x_max = max(X) + extend
    x_min = min(X) - extend
    y_max = max(Y) + extend
    y_min = min(Y) - extend
    z_max = max(Z) + extend
    z_min = min(Z) - extend

    size_x = x_max - x_min
    size_y = y_max - y_min
    size_z = z_max - z_min

    return x, y, z, size_x, size_y, size_z

def config_gen(config_filename, complex_filename):
    center_x, center_y, center_z, size_x, size_y, size_z = box_center_info(complex_filename, 5)
    content = """center_x = {0}
center_y = {1}
center_z = {2}
size_x = {3}
size_y = {4}
size_z = {5}
seed = 303030
cpu = 1
num_modes = 10
energy_range = 2
exhaustiveness = 48
verbosity = 0
    """.format(center_x, center_y, center_z, size_x, size_y, size_z)
    #print(content)

    with open(config_filename, 'w') as out:
        out.write(content)
    return 0

def process(pdbid):
    nowater_name = pdbid + "_noW.pdb"
    noligand_name = pdbid + "_nolig.pdb"
    config_filename = "config.txt"
    fetch_pdb(pdbid)
    remove_tag(pdbid + ".pdb", "water", nowater_name)
    config_gen(config_filename, nowater_name)
    remove_tag(nowater_name, "ligand", noligand_name)
    protein_preparation(noligand_name, "receptor.pdbqt")

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--version', '-v', action='version',
                    version='%(prog)s version : v 1.0', help='show the FBDDsuit version')
    parser.add_argument("--pdbid", "-pdb", type=str)
    args = parser.parse_args()
    print(args.pdbid)
    process(args.pdbid)

if __name__ == '__main__':
    main()


class Puzzle:
    decode = {
        '1': 1, '2': 2, '3': 3, '4': 4,
        '5': 5, '6': 6, '7': 7, '8': 8,
        '9': 9, 'a': 10, 'b': 11, 'c': 12,
        'd': 13, 'e': 14, 'f': 15, '0': 0,
        'g': 16, ' ': -1,
    }

    def __init__ (self, filename):
        self.base = 3
        self.encoding = '1byte'

        with open(filename) as fo:
            lines = fo.readlines()
        data = []
        for line in map(lambda line: line.strip('\n'), lines):
            if len(line)>0 and line[0]=='#':
                elements = line.strip().split(' ')
                if   elements[0]=='#base': self.base = int(elements[1])
                elif elements[0]=='#encoding': self.encoding = elements[1]
                continue

            ldata = []
            for char in line:
                ldata.append(Puzzle.decode[char.lower()])
            if len(ldata)!=0:
                data.append(ldata)
        self.data = data

        self.size = self.base*self.base

    def index (self, x, y):
        if x<0 or x>=self.size: raise Exception('Illegal x value of %s/%s' %(x, type(x)))
        if y<0 or y>=self.size: raise Exception('Illegal y value of %s/%s' %(y, type(y)))

        return self.data[y][x]

    def validate (self):
        data = self.data

        if len(data)!=self.size: return False
        for row in data:
            if len(row)!=self.size: return False
            for cell in row:
                if cell<-1 or cell>self.size: return False

        # rows
        for y in range(self.size):
            cells = set()
            for x in range(self.size):
                cell = self.index(x, y)
                if cell==-1: continue
                if cell in cells: return False
                cells.add(cell)

        # columns
        for x in range(self.size):
            cells = set()
            for y in range(self.size):
                cell = self.index(x, y)
                if cell==-1: continue
                if cell in cells: return False
                cells.add(cell)

        # groups
        for a in range(self.size):
            cells = set()
            for b in range(self.size):
                i = a*self.size+b
                x = i%self.size
                y = i//self.size
                cell = self.index(x, y)
                if cell==-1: continue
                if cell in cells: return False
                cells.add(cell)

        return True

    def print (self):
        line = ('+'+('-'*self.base))*self.base+'+'
        data = self.data
        for y in range(len(data)):
            row = data[y]
            if y%self.base==0: print(line)
            for x in range(len(row)):
                cell = row[x]
                if x%self.base==0: print('|', end='')
                print(' ' if cell==-1 else cell, end='')
            print('|')
        print(line)

if __name__ == "__main__":
    filename = '../var/samples/example1.txt'
    puzzle = Puzzle(filename);
    print('Validation:', puzzle.validate())
    puzzle.print()


# Creating the Class named 'Mobile'
class Mobile:

    # Initializing the member variable. This is self calling constructor whenever the object is created this constructor is self called.
    def __init__(self, m):      # Parameterized self constructor.
        self.model = m

    # Defining the member function/method
    def show_model(self, p):
        price = p
        print('Model Name: ', self.model, '\nPrice: ', p)

obj_1 = Mobile('Redmi Note 5 Pro')                # Creating the object named as obj_1 for class Mobile.
                                                  # self constructor takes the parameter so we need to pass the parameter while instatiating the object.
obj_1.show_model(10000)              # Accessing  the method using the object which is inside the 'Mobile' class.

# Creating multiple object for same class and checking the memory address for each object.

obj_2 = Mobile('Samsung')
obj_2.show_model(2000)

obj_3 = Mobile("Oppo")
obj_3.show_model(3000)

# Checking Memory address of each object.. Each object is instantiated with different memory address space.
print('obj_1 Memory address: ', id(obj_1))
print('obj_2 Memory address: ', id(obj_2))
print('obj_3 Memory address: ', id(obj_3))