AtomLinter / linter-flake8

Linting Python files on the fly using flake8 with Atom
MIT License
103 stars 45 forks source link

Flake8 rule 'E901' reported an invalid point #302

Closed MrYann closed 7 years ago

MrYann commented 7 years ago

Flake8 reported an invalid point for the rule E901, with the messge SyntaxError: invalid syntax.

from scipy.linalg import norm, solve, diagsvd
from scipy.sparse.linalg import svds
from numpy import eye

def non_linear_least_squares(x, F, R):
    '''
    Minimize l2_Norm(F(x)) + lambda * l2_norm(R(x))
    :param x: starting point
    :param F: residuals function
    :param R: regularization function
    '''
    iteration_states = []
    Fx = F(x)
    while True:
        l = options["reg_param"]()
        dx = options["new_step"](x, l)
        x = options["new_point"](x, dx)
        Fx_old, Fx = Fx, F(x)
        iteration_states.append({"l": l, "f": norm(Fx), "x": norm(x), "dx": norm(dx)})
        stop = stopping_rule(x, dx, Fx, Fx_old)
        if stop is not None:
            break

def stopping_rule(x, dx, Fx, Fx_old):
    if norm(dx) / (1 + norm(x)) < options["dx_tol"]:
        return "dx < {}%".format(options["dx_tol"])
    if norm(Fx - Fx_old) / (1 + norm(Fx_old)) < options["df_tol"]:
        return "df < {}%".format(options["df_tol"])
    if norm(Fx) < options["morozov"]:
        return "f < {}".format(options["morozov"])
    return None

###############################################################
#
# Minimization methods
#
def update_bfgs(B, dx, x, F, Fx, options):
    """
    :B  : Current Hessian approximation
    :dx : Step update for x (x = x + dx)
    :F  : Fidelity function
    :x  : Current point
    From "Descent Directions of quasi-newton methods for symmetric nonlinear equations", by Guang-ze, Dong-hui, Liqun, Shu-zi.
    So-called "cautious" update (easier to implement)
    """
    Fx_new = F(x + dx)
    g = F(x + (Fx_new - Fx)) - Fx
    y = g + (max(0, -(g.H @ dx) / norm(dx) + options["mu"] * Fx)) * dx
    return Fx_new, B - (B @ dx @ dx.H @ B) / (dx.H @ B @ dx) + (y.H @ y) / (y.H @ dx)

def normal_eq_direct(J, Fx, x, xo, l):
    '''
    Resolution of the normal equation - Direct solve
    dn = - (J.H @ J + l) \ (J.H @ Fx + l(xp-xo))
    :J  : Jacobian matrix
    :Fx : Fidelity term at current x
    :x  : Current x
    :xo : Initial point
    :l  : Regularization index
    '''
    return - solve(J.H @ J + l * eye(J.shape[1]), J.H @ Fx + l * (
        x - xo), sym_pos=True, overwrite_a=True, overwrite_b=True)

def normal_eq_cg():
    '''
    Conjugate gradient : Redundant with BFGS ?
    '''
    pass

def normal_eq_tsvd(J, Fx, x, xo, l):
    '''
    Resolution of the normal equation - TSVD (J = U@S@V.H)
    dx = - (J.H @ J + l) \ (J.H @ F + l(xp-xo))
    Trick: instead of the second l, use S, which gives
    dx = -V (S \ (U.H @ F + V.H @ (xp-xo)))
    :J  : Jacobian matrix
    :Fx : Fidelity term at current x
    :x  : Current x
    :xo : Initial point
    :l  : Regularization index
    '''
    U, s, Vh = svds(J, k=l)
    return - Vh.H @ diagsvd(1 / s, l) @ (U.H @ Fx + Vh @ (x - xo))

###############################################################
#
# regularization parameter methods
#
def reg_param_power(n):
    return 1 / 2**n

def reg_param_morozov():
    pass

###############################################################
#
# point update methods
#
def direction_trust_region(x, Fx, l, F, B, options):
    """
    :Fx : Fidelity term at current x
    :F  : Fidelity function
    :B  : Current Hessian approximation
    :x  : Current x
    :l  : Regularization index

    From "Descent Directions of quasi-newton methods for symmetric nonlinear equations", by Guang-ze, Dong-hui, Liqun, Shu-zi
    """
    # TODO: make an iterator out of this ?
    # TODO: check if norm or norm**2 should be used ???
    # compute direction d and augment l until condition holds (since lambda < 1)
    # unless condition already holds : in that case, reduce l and see if condition still holds
    def direction(l):
        Fx_new =
        return solve(B, (F(x + options["lambda"]**l * Fx) - Fx) / options["lambda"]**l, sym_pos=True, overwrite_a=True, overwrite_b=True)

    def condition_ok(l, d):
        return norm(x + options["lambda"]**l * d) - norm(Fx) <= -options["s1"] * norm(options["lambda"]**l * d) - options["s2"] * norm(options["lambda"]**l * Fx)

    d = direction(l)
    if condition_ok(d, l):  # regularisation is already high enough: let's try to reduce it
        while True:
            l_test = l - 1
            dx_test = direction(l_test)
            if condition_ok(dx_test, l_test):
                d, l = dx_test, l_test
            else:
                break
    else:  # regularisation not strong enough: let's up it
        while True:
            l = l + 1
            d = direction(l)
            if condition_ok(d, l):
                break
    return l, d

def point_update_fixed(x, dx, l):
    return x + l * dx

def point_update_anderson(x, dx):
    pass

# Default options values
options = {"dx_tol": 10**-6,
           "df_tol": 10**-6,
           "new_step": normal_eq_direct,
           "new_point": point_update_fixed,
           "reg_param": reg_param_power,
           "s1": 10**-5,
           "s2": 10**-5,
           "lambda": 0.5,
           "mu": 0.1,
           }

Debug information: Atom version: 1.12.6 Flake8 version: 2.5.1 (pep8: 1.7.0, pyflakes: 1.3.0, mccabe: 0.3.1) CPython 3.5.2 on Darwin

Arcanemagus commented 7 years ago

Please update your flake8 version (pip install -U flake8). This particular error should be fixed in flake8>=3.2.1.

MrYann commented 7 years ago

Blazing fast reaction : ) Bravo. I merely reported the issue because flake8 told me to himself.

However, I use the conda python distribution where flake8 version 2.5.1 is the latest available. So I guess I will leave it at that.

Thanx again.

Arcanemagus commented 7 years ago

Yea, being stuck on old versions is one of the main reasons that was moved from a giant red error box in Atom to a "regular" linter message: So the information is still presented to the user, but if nothing can be done about it then at worst it is no more intrusive than a regular message.

Thanks for taking the time to report it!