<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def complex_dtype(dtype, default=None):
 """Return complex counterpart of ``dtype`` if existing, else ``default``. Parameters dtype : Real or complex floating point data type. It can be given in any way the `numpy.dtype` constructor understands. default : Object to be returned if no complex counterpart is found for ``dtype``, except for ``None``, in which case an error is raised. Returns ------- complex_dtype : `numpy.dtype` The complex counterpart of ``dtype``. Raises ------ ValueError if there is no complex counterpart to the given data type and ``default == None``. Examples -------- Convert scalar dtypes: dtype('complex128') dtype('complex64') dtype('complex128') Dtypes with shape are also supported: dtype(('<c16', (3,))) dtype(('<c8', (3,))) """

    dtype, dtype_in = np.dtype(dtype), dtype

    if is_complex_floating_dtype(dtype):
        return dtype

    try:
        complex_base_dtype = TYPE_MAP_R2C[dtype.base]
    except KeyError:
        if default is not None:
            return default
        else:
            raise ValueError('no complex counterpart exists for `dtype` {}'
                             ''.format(dtype_repr(dtype_in)))
    else:
        return np.dtype((complex_base_dtype, dtype.shape))