def test_pow_operations_CMG():
    x = CMG(1, np.array([1, 0]))
    f = x**2 + 2**x + x**x**x**2**x
    x2 = CMG(3.0, np.array([1, 0]))
    f2 = x2.__rpow__(x2)
    assert f.val == 4.0
    assert np.array_equal(f.grad, np.array([4.386294361119891, 0.]))
    assert f2.val == 27.0
    assert np.array_equal(f2.grad, np.array([56.66253179403897, 0.]))
def sin(x):
    try:
        val = np.sin(x.val)
        grad = np.cos(x.val) * x.grad
        y = CMGobject(val, grad)
        return y
    except AttributeError:
        return np.sin(x)  # if x is a constant
def log(x, base=np.e):  # handles ln(x) == log(x) because default base = np.e
    try:
        val = np.log(x.val) / np.log(base)
        grad = (1 / (x.val * np.log(base))) * x.grad
        y = CMGobject(val, grad)
        return y
    except AttributeError:
        return np.log(x) / np.log(base)
def exp(x):
    try:
        val = np.exp(x.val)
        grad = np.exp(x.val) * x.grad
        y = CMGobject(val, grad)
        return y
    except AttributeError:
        return np.exp(x)
def arctan(x):
    try:
        val = np.arctan(x.val)
        grad = ((1 + x.val**2)**(-2)) * x.grad
        y = CMGobject(val, grad)
        return y
    except AttributeError:
        return np.arctan(x)  # if x is a constant
def arccos(x):
    try:
        val = np.arccos(x.val)
        grad = -((1 - x.val**2)**(-0.5)) * x.grad
        y = CMGobject(val, grad)
        return y
    except AttributeError:
        return np.arccos(x)
def tan(x):
    try:
        val = np.tan(x.val)
        grad = ((np.cos(x.val))**(-2)) * x.grad
        y = CMGobject(val, grad)
        return y
    except AttributeError:
        return np.tan(x)
def cos(x):
    try:
        val = np.cos(x.val)
        grad = -np.sin(x.val) * x.grad
        y = CMGobject(val, grad)
        return y
    except AttributeError:
        return np.cos(x)
def test_repr_CMG():
    x = CMG(3, np.array([1, 0]))
    assert x.__repr__() == 'CMGobject(val = 3.0, grad = [1 0])'