Repository: sympy/sympy

Issue:
sympy.physics.vector.vector.Vector.diff() seems to produce unnecessarily long derivatives
I noticed this when working on this arbitrary example:

```python
import sympy as sm
import sympy.physics.mechanics as me
a, b, c, d, e, f = sm.symbols('a, b, c, d, e, f')
alpha, beta = sm.symbols('alpha, beta')

A = me.ReferenceFrame('A')
B = me.ReferenceFrame('B')
C = me.ReferenceFrame('C')

B.orient_axis(A, alpha, A.x)
C.orient_axis(B, beta, B.y)

v = a*A.x + b*A.y + c*B.x + d*B.y + e*C.x + f*C.y
```

```python
>>> v.diff(alpha, A)
v.diff(alpha, A)
(d*sin(alpha)**2 + d*cos(alpha)**2)*B.z + (-(e*sin(alpha)*sin(beta) + f*cos(alpha))*sin(beta)*cos(alpha) + (e*sin(beta)*cos(alpha) - f*sin(alpha))*sin(alpha)*sin(beta))*C.x + ((e*sin(alpha)*sin(beta) + f*cos(alpha))*sin(alpha) + (e*sin(beta)*cos(alpha) - f*sin(alpha))*cos(alpha))*C.y + ((e*sin(alpha)*sin(beta) + f*cos(alpha))*cos(alpha)*cos(beta) - (e*sin(beta)*cos(alpha) - f*sin(alpha))*sin(alpha)*cos(beta))*C.z
```

```pycon
>>> v.diff(alpha, A).simplify()
d*B.z - f*sin(beta)*C.x + e*sin(beta)*C.y + f*cos(beta)*C.z
```

```pycon
>>> v.express(A).diff(alpha, A)
(-d*sin(alpha) + e*sin(beta)*cos(alpha) - f*sin(alpha))*A.y + (d*cos(alpha) + e*sin(alpha)*sin(beta) + f*cos(alpha))*A.z
```

I guess in the first case it tries to compute the product rule for each component. I'm not sure if expressing in the frame would always result in simpler equations in all cases. If so, then maybe that's what `.diff()` should do.





Discussion:

Patch:
diff --git a/.mailmap b/.mailmap
index 24c64a770b..80034d3596 100644
--- a/.mailmap
+++ b/.mailmap
@@ -629,7 +629,7 @@ Kristian Brünn <hello@kristianbrunn.com> Kristianmitk <hello@kristianbrunn.com>
 Krit Karan <kritkaran.b13@iiits.in> <kritkaran94@users.noreply.github.com>
 Kshitij <kshitijparwani.mat18@itbhu.ac.in> Kshitij Parwani <44468674+P-Kshitij@users.noreply.github.com>
 Kshitij Saraogi <KshitijSaraogi@gmail.com>
-Kuldeep Borkar Jr <kuldeepborkarjr765@gmail.com> Kuldeep Borkar Jr <74557588+KuldeepBorkar@users.noreply.github.com>
+Kuldeep Borkar Jr <kuldeepborkarjr765@gmail.com>
 Kumar Krishna Agrawal <kumar.1994.14@gmail.com>
 Kunal Arora <kunalarora.135@gmail.com>
 Kunal Singh <ksingh19136@gmail.com> kunal singh <ksingh19136@gmail.com>
diff --git a/sympy/physics/vector/vector.py b/sympy/physics/vector/vector.py
index a29db2fb6e..a04f9b1ebc 100644
--- a/sympy/physics/vector/vector.py
+++ b/sympy/physics/vector/vector.py
@@ -522,6 +522,8 @@ def diff(self, var, frame, var_in_dcm=True):
         >>> N = ReferenceFrame('N')
         >>> A = N.orientnew('A', 'Axis', [q1, N.y])
         >>> A.x.diff(t, N)
+        - sin(q1)*q1'*N.x - cos(q1)*q1'*N.z
+        >>> A.x.diff(t, N).express(A)
         - q1'*A.z
         >>> B = ReferenceFrame('B')
         >>> u1, u2 = dynamicsymbols('u1, u2')
@@ -553,7 +555,7 @@ def diff(self, var, frame, var_in_dcm=True):
                 else:  # else express in the frame
                     reexp_vec_comp = Vector([vector_component]).express(frame)
                     deriv = reexp_vec_comp.args[0][0].diff(var)
-                    inlist += Vector([(deriv, frame)]).express(component_frame).args
+                    inlist += Vector([(deriv, frame)]).args
 
         return Vector(inlist)
 
diff --git a/sympy/stats/__init__.py b/sympy/stats/__init__.py
index 5b87ad2192..90d86d142e 100644
--- a/sympy/stats/__init__.py
+++ b/sympy/stats/__init__.py
@@ -24,7 +24,7 @@
 ========
 
 >>> from sympy.stats import P, E, variance, Die, Normal
->>> from sympy import simplify
+>>> from sympy import Eq, simplify
 >>> X, Y = Die('X', 6), Die('Y', 6) # Define two six sided dice
 >>> Z = Normal('Z', 0, 1) # Declare a Normal random variable with mean 0, std 1
 >>> P(X>3) # Probability X is greater than 3
@@ -84,7 +84,7 @@
 3. If you want to create a Finite Random Variable:
 
 >>> from sympy.stats import FiniteRV, P, E
->>> from sympy import Rational, Eq
+>>> from sympy import Rational
 >>> pmf = {1: Rational(1, 3), 2: Rational(1, 6), 3: Rational(1, 4), 4: Rational(1, 4)}
 >>> X = FiniteRV('X', pmf)
 >>> E(X)
diff --git a/sympy/stats/stochastic_process_types.py b/sympy/stats/stochastic_process_types.py
index 1a08fa4178..cbd645d9e3 100644
--- a/sympy/stats/stochastic_process_types.py
+++ b/sympy/stats/stochastic_process_types.py
@@ -1,7 +1,9 @@
 import random
+
 import itertools
 from typing import (Sequence as tSequence, Union as tUnion, List as tList,
         Tuple as tTuple, Set as tSet)
+
 from sympy.concrete.summations import Sum
 from sympy.core.add import Add
 from sympy.core.basic import Basic
@@ -906,6 +908,8 @@ class DiscreteMarkovChain(DiscreteTimeStochasticProcess, MarkovProcess):
 
     Symbolic probability queries are also supported
 
+    >>> from sympy import symbols, Matrix, Rational, Eq, Gt
+    >>> from sympy.stats import P, DiscreteMarkovChain
     >>> a, b, c, d = symbols('a b c d')
     >>> T = Matrix([[Rational(1, 10), Rational(4, 10), Rational(5, 10)], [Rational(3, 10), Rational(4, 10), Rational(3, 10)], [Rational(7, 10), Rational(2, 10), Rational(1, 10)]])
     >>> Y = DiscreteMarkovChain("Y", [0, 1, 2], T)
@@ -1550,7 +1554,8 @@ class ContinuousMarkovChain(ContinuousTimeStochasticProcess, MarkovProcess):
 
     Symbolic probability queries are also supported
 
-    >>> from sympy import symbols
+    >>> from sympy import S, symbols, Matrix, Rational, Eq, Gt
+    >>> from sympy.stats import P, ContinuousMarkovChain
     >>> a,b,c,d = symbols('a b c d')
     >>> G = Matrix([[-S(1), Rational(1, 10), Rational(9, 10)], [Rational(2, 5), -S(1), Rational(3, 5)], [Rational(1, 2), Rational(1, 2), -S(1)]])
     >>> C = ContinuousMarkovChain('C', state_space=[0, 1, 2], gen_mat=G)
@@ -2251,9 +2256,8 @@ def split(self, l1, l2):
 class WienerProcess(CountingProcess):
     """
     The Wiener process is a real valued continuous-time stochastic process.
-    In physics it is used to study Brownian motion and it is often also called
-    Brownian motion due to its historical connection with physical process of the
-    same name originally observed by Scottish botanist Robert Brown.
+    In physics it is used to study Brownian motion and therefore also known as
+    Brownian Motion.
 
     Parameters
     ==========


Test patch:
diff --git a/sympy/physics/vector/tests/test_vector.py b/sympy/physics/vector/tests/test_vector.py
index 0df9ea93e4..713884345a 100644
--- a/sympy/physics/vector/tests/test_vector.py
+++ b/sympy/physics/vector/tests/test_vector.py
@@ -81,7 +81,7 @@ def test_Vector_diffs():
 
     assert v1.dt(N) == q2d * A.x + q2 * q3d * A.y + q3d * N.y
     assert v1.dt(A) == q2d * A.x + q3 * q3d * N.x + q3d * N.y
-    assert v1.dt(B) == (q2d * A.x + q3 * q3d * N.x + q3d *\
+    assert v1.dt(B) == (q2d * A.x + q3 * q3d * N.x + q3d *
                         N.y - q3 * cos(q3) * q2d * N.z)
     assert v2.dt(N) == (q2d * A.x + (q2 + q3) * q3d * A.y + q3d * B.x + q3d *
                         N.y)
@@ -132,6 +132,24 @@ def test_Vector_diffs():
     assert v4.diff(q2d, B) == A.x - q3 * cos(q3) * N.z
     assert v4.diff(q3d, B) == B.x + q3 * N.x + N.y
 
+    # diff() should only express vector components in the derivative frame if
+    # the orientation of the component's frame depends on the variable
+    v6 = q2**2*N.y + q2**2*A.y + q2**2*B.y
+    # already expressed in N
+    n_measy = 2*q2
+    # A_C_N does not depend on q2, so don't express in N
+    a_measy = 2*q2
+    # B_C_N depends on q2, so express in N
+    b_measx = (q2**2*B.y).dot(N.x).diff(q2)
+    b_measy = (q2**2*B.y).dot(N.y).diff(q2)
+    b_measz = (q2**2*B.y).dot(N.z).diff(q2)
+    n_comp, a_comp = v6.diff(q2, N).args
+    assert len(v6.diff(q2, N).args) == 2  # only N and A parts
+    assert n_comp[1] == N
+    assert a_comp[1] == A
+    assert n_comp[0] == Matrix([b_measx, b_measy + n_measy, b_measz])
+    assert a_comp[0] == Matrix([0, a_measy, 0])
+
 
 def test_vector_var_in_dcm():