Reputation: 47
I have a question about the Python code below, which is copied from Appendix A of paper: https://arxiv.org/abs/1305.1878.
What happens in the line M=next(XD+XD.T for XD in (self.X.dot(Derivative()),))
?
Why is using the in-built function next()
needed here?
class singleNeutrinoSolution(object):
'''Most likely neutrino momentum for tt-->lepton+jets'''
def __init(self, b , mu, #Lorentz vectors
metX, metY, #Momentum imbalance
sigma2, #Momentum imlance unc. 2X2 matrix
mW2=mW**2,mT2=mT**2):
self.solutionSet=nuSolutionSet(b,mu,mW2,mT2)
S2=np.vstack([np.vstack([np.linalg.inv(sigma2),[0,0]]).T,[0,0,0]])
V0 = np.outer([metX, metY, 0], [0, 0, 1])
deltaNu=V0-self.solutionSet.H
self.X=np.dot(deltaNu.T,S2).dot(deltaNu)
M=next(XD+XD.T for XD in (self.X.dot(Derivative()),))
solutions=intersection_ellipses(M,UnitCircle())
self.solutions=sorted(solutions,key=self.calcX2)
def calcX2(self,t):
return np.dot(t,self.X).dot(t)
@property
def chi2(self):
return self.calcX2(self.solutions[0])
@property
def nu(self):
'''Solution for neutrino momentum'''
return self.solutionSet.H.dot(self.solution[0])
Upvotes: 1
Views: 43
Reputation: 36249
As the generator reveals, the result of the expression self.X.dot(Derivative())
is needed two times, XD
and XD.T
. So the whole next
+ generator expression could also be written as two statements (which is a lot clearer):
XD = self.X.dot(Derivative())
M = XD + XD.T
Perhaps the authors wanted to save one line of code, but if that results in obfuscation like the presented next
approach, this is a bad idea regarding readability (lines of code is generally a bad measure for code quality).
Note that starting with Python 3.9, you could also use an assignment expression(1):
M = (XD := self.X.dot(Derivative())) + XD.T
but I don't recommend it either. The two statements version is the most readable and that counts the most (especially when published as part of an academic paper).
(1) It's not exactly the same, since the assignment expression will leak XD
into the local namespace while the generator won't (as it uses its own namespace).
Upvotes: 1
Reputation: 23139
In this line,
M=next(XD+XD.T for XD in (self.X.dot(Derivative()),))
the author wanted to reuse the result of self.X.dot(Derivative())
in an expression as the variable XD
twice.
The next
function returns the first value from an iterable, which in this case is a single-iteration loop (a generator expression) over a single-item tuple,
(self.X.dot(Derivative()),)
where self.X.dot(Derivative())
is the only item. Using a loop has the side effect of assigning the name XD
to the current value of the iterable.
The author could have simply written
XD = self.X.dot(Derivative())
M = XD + XD.T
but they thought they were too "clever" for this.
Upvotes: 1