[sympy] Implementation of erfc and it's tests (#1703)

14 views
Skip to first unread message

Ramana Venkata

unread,
Dec 28, 2012, 4:37:34 AM12/28/12
to sympy/sympy

You can merge this Pull Request by running:

  git pull https://github.com/idlike2dream/sympy error

Or view, comment on, or merge it at:

  https://github.com/sympy/sympy/pull/1703

Commit Summary

  • Implementation of erfc and it's tests

File Changes

  • M sympy/core/tests/test_args.py (3)
  • M sympy/functions/__init__.py (2)
  • M sympy/functions/special/error_functions.py (128)
  • M sympy/functions/special/tests/test_error_functions.py (32)

Patch Links


Reply to this email directly or view it on GitHub.

Tom Bachmann

unread,
Dec 28, 2012, 5:03:23 AM12/28/12
to sympy/sympy

In sympy/functions/special/error_functions.py:

> @@ -153,6 +156,131 @@ def _eval_as_leading_term(self, x):
>          else:
>              return self.func(arg)
>  
> +class erfc(Function):
> +    """
> +        Complementary Error Function:
> +
> +      The function is defined as erfc(x) = 1-erf(x)
> +
> +      or in ASCII::

better use latex

Tom Bachmann

unread,
Dec 28, 2012, 5:05:09 AM12/28/12
to sympy/sympy

In sympy/functions/special/error_functions.py:

> +            k = C.floor((n - 1)/S(2))
> +            if len(previous_terms) > 2:
> +                return -previous_terms[-2] * x**2 * (n - 2)/(n*k)
> +            else:
> +                return -2*(-1)**k * x**n/(n*C.factorial(k)*sqrt(S.Pi))
> +
> +    def _eval_conjugate(self):
> +        return self.func(self.args[0].conjugate())
> +
> +    def _eval_is_real(self):
> +        return self.args[0].is_real
> +
> +    def _eval_rewrite_as_erf(self, z):
> +        return S.One - erf(z)
> +
> +    def _eval_as_leading_term(self, x):

not sure this is used anywhere. Maybe we should avoid adding it to new functions...

Ramana Venkata

unread,
Dec 28, 2012, 5:12:21 AM12/28/12
to sympy/sympy

In sympy/functions/special/error_functions.py:

> +            k = C.floor((n - 1)/S(2))
> +            if len(previous_terms) > 2:
> +                return -previous_terms[-2] * x**2 * (n - 2)/(n*k)
> +            else:
> +                return -2*(-1)**k * x**n/(n*C.factorial(k)*sqrt(S.Pi))
> +
> +    def _eval_conjugate(self):
> +        return self.func(self.args[0].conjugate())
> +
> +    def _eval_is_real(self):
> +        return self.args[0].is_real
> +
> +    def _eval_rewrite_as_erf(self, z):
> +        return S.One - erf(z)
> +
> +    def _eval_as_leading_term(self, x):

Pardon I didn't get it. What should be avoided??

Ramana Venkata

unread,
Dec 28, 2012, 5:15:05 AM12/28/12
to sympy/sympy

In sympy/functions/special/error_functions.py:

> +            k = C.floor((n - 1)/S(2))
> +            if len(previous_terms) > 2:
> +                return -previous_terms[-2] * x**2 * (n - 2)/(n*k)
> +            else:
> +                return -2*(-1)**k * x**n/(n*C.factorial(k)*sqrt(S.Pi))
> +
> +    def _eval_conjugate(self):
> +        return self.func(self.args[0].conjugate())
> +
> +    def _eval_is_real(self):
> +        return self.args[0].is_real
> +
> +    def _eval_rewrite_as_erf(self, z):
> +        return S.One - erf(z)
> +
> +    def _eval_as_leading_term(self, x):

I wrote it because it was implemented in erf function.

Ramana Venkata

unread,
Dec 28, 2012, 5:18:38 AM12/28/12
to sympy/sympy

In sympy/functions/special/error_functions.py:

> @@ -153,6 +156,131 @@ def _eval_as_leading_term(self, x):
>          else:
>              return self.func(arg)
>  
> +class erfc(Function):
> +    """
> +        Complementary Error Function:
> +
> +      The function is defined as erfc(x) = 1-erf(x)
> +
> +      or in ASCII::

fine I'll do it.

raoulb

unread,
Dec 28, 2012, 7:34:06 AM12/28/12
to sympy/sympy

Looks fine so far.
I'll handle the tractable stuff once this is in.

raoulb

unread,
Dec 28, 2012, 7:38:21 AM12/28/12
to sympy/sympy

In sympy/functions/special/error_functions.py:

> +            k = C.floor((n - 1)/S(2))
> +            if len(previous_terms) > 2:
> +                return -previous_terms[-2] * x**2 * (n - 2)/(n*k)
> +            else:
> +                return -2*(-1)**k * x**n/(n*C.factorial(k)*sqrt(S.Pi))
> +
> +    def _eval_conjugate(self):
> +        return self.func(self.args[0].conjugate())
> +
> +    def _eval_is_real(self):
> +        return self.args[0].is_real
> +
> +    def _eval_rewrite_as_erf(self, z):
> +        return S.One - erf(z)
> +
> +    def _eval_as_leading_term(self, x):

Doing a git grep "_eval_as_leading_term(" shows only definitions and one call in core:

sympy/core/expr.py:        obj = self._eval_as_leading_term(x)

raoulb

unread,
Dec 28, 2012, 10:55:21 AM12/28/12
to sympy/sympy

In sympy/functions/special/error_functions.py:

> +            raise ArgumentIndexError(self, argindex)
> +
> +    @classmethod
> +    def eval(cls, arg):
> +        if arg.is_Number:
> +            if arg is S.NaN:
> +                return S.NaN
> +            elif arg is S.Infinity:
> +                return S.Zero
> +            elif arg is S.NegativeInfinity:
> +                return S(2)
> +            elif arg is S.Zero:
> +                return S.One
> +
> +        t = arg.extract_multiplicatively(S.ImaginaryUnit)
> +        if t == S.Infinity or t == S.NegativeInfinity:

I think one should compare with is instead of == here.

raoulb

unread,
Dec 28, 2012, 10:58:42 AM12/28/12
to sympy/sympy

In sympy/functions/special/tests/test_error_functions.py:

> +    assert erfc(-oo) == 2
> +
> +    assert erfc(0) == 1
> +
> +    assert erfc(I*oo) == -oo*I
> +    assert erfc(-I*oo) == oo*I
> +
> +    assert erfc(I).is_real is False
> +    assert erfc(0).is_real is True
> +
> +    assert conjugate(erfc(z)) == erfc(conjugate(z))
> +
> +    assert erfc(x).as_leading_term(x) == S.One
> +    assert erfc(1/x).as_leading_term(x) == erfc(1/x)
> +
> +    assert erfc(z).rewrite('erf') == 1 - erf(z)

Add the same test for rewrite of erf in terms of erfc.

raoulb

unread,
Dec 28, 2012, 11:01:53 AM12/28/12
to sympy/sympy

In sympy/functions/special/error_functions.py:

> +
> +    .. [1] http://en.wikipedia.org/wiki/Error_function
> +    .. [3] http://mathworld.wolfram.com/Erfc.html
> +    .. [4] http://functions.wolfram.com/GammaBetaErf/Erfc
> +    """
> +
> +    nargs = 1
> +
> +    def fdiff(self, argindex=1):
> +        if argindex == 1:
> +            return -2*C.exp(-self.args[0]**2)/sqrt(S.Pi)
> +        else:
> +            raise ArgumentIndexError(self, argindex)
> +
> +    @classmethod
> +    def eval(cls, arg):

We should add erfc(-z) --> 2 - erfc(z).

raoulb

unread,
Dec 28, 2012, 11:05:55 AM12/28/12
to sympy/sympy

In sympy/functions/special/error_functions.py:

> +    def _eval_conjugate(self):
> +        return self.func(self.args[0].conjugate())
> +
> +    def _eval_is_real(self):
> +        return self.args[0].is_real
> +
> +    def _eval_rewrite_as_erf(self, z):
> +        return S.One - erf(z)
> +
> +    def _eval_as_leading_term(self, x):
> +        arg = self.args[0].as_leading_term(x)
> +
> +        if x in arg.free_symbols and C.Order(1, x).contains(arg):
> +            return S.One
> +        else:
> +            return self.func(arg)
>  

We could add the _as_real_imag splitting method. (You can compare to the implementation in sin.)

raoulb

unread,
Dec 28, 2012, 11:22:50 AM12/28/12
to sympy/sympy

Other ideas:

  • Rewrite to Fresnel functions: add _eval_rewrite_as_fresnel and have both _eval_rewrite_as_fresnels and _eval_rewrite_as_fresnelc dispatch to it.

  • (After adding erfi): rewrite between erfc <-> erfi

  • For the examples section: erfc(x/(2*sqrt(t))) solves the heat equation u_t(x,t) = u_xx(x,t)

Aaron Meurer

unread,
Dec 28, 2012, 8:59:19 PM12/28/12
to sympy/sympy
On Dec 28, 2012, at 9:22 AM, raoulb <notifi...@github.com> wrote:

Other ideas:

-

Rewrite to Fresnel functions: add _eval_rewrite_as_fresnel and have both
_eval_rewrite_as_fresnels and _eval_rewrite_as_fresnelc dispatch to it.
-

(After adding erfi): rewrite between erfc <-> erfi
-

For the examples section: erfc(x/(2*sqrt(t))) solves the heat
equation u_t(x,t)
= u_xx(x,t)


With what boundary conditions?




Reply to this email directly or view it on
GitHub<https://github.com/sympy/sympy/pull/1703#issuecomment-11735191>.

raoulb

unread,
Dec 29, 2012, 8:11:57 AM12/29/12
to sympy/sympy

In sympy/functions/special/error_functions.py:

> @@ -23,20 +23,23 @@ class erf(Function):
>  

You need raw strings now (because of TeX backslashes):
replace the tsrating """ by r""".

Aaron Meurer

unread,
Dec 29, 2012, 9:37:42 AM12/29/12
to sympy/sympy

SymPy Bot Summary: :x: Could not fetch the branch idlike2dream/error.
@idlike2dream: Please make sure that idlike2dream/error has been pushed to GitHub and run the sympy-bot tests again.

Aaron Meurer

unread,
Dec 29, 2012, 4:55:28 PM12/29/12
to sympy/sympy

SymPy Bot Summary: :red_circle: Failed after merging idlike2dream/error (618ec48) into master (2abef4f).
@idlike2dream: Please fix the test failures.
:red_circle:Python 2.5.0-final-0: fail
:red_circle:Python 2.6.6-final-0: fail
:red_circle:Python 2.7.2-final-0: fail
:red_circle:Python 2.6.8-final-0: fail
:red_circle:Python 2.7.3-final-0: fail
:red_circle:PyPy 2.0.0-beta-1; 2.7.3-final-42: fail
:red_circle:Python 3.2.2-final-0: fail
:red_circle:Python 3.3.0-final-0: fail
:red_circle:Python 3.2.3-final-0: fail
:red_circle:Python 3.3.0-final-0: fail
:red_circle:Python 3.3.0-final-0: fail
:eight_spoked_asterisk:**Sphinx 1.1.3:** pass

Aaron Meurer

unread,
Jan 1, 2013, 4:53:42 AM1/1/13
to sympy/sympy

As I noted on the mailing list, let's go with erfinv to match mpmath and numpy/scipy.

Aaron Meurer

unread,
Jan 2, 2013, 5:22:26 AM1/2/13
to sympy/sympy

SymPy Bot Summary: :exclamation: There were merge conflicts (could not merge idlike2dream/error (3e5bf1c) into master (c3e9d56)); could not test the branch.
@idlike2dream: Please rebase or merge your branch with master. See the report for a list of the merge conflicts.

Reply all
Reply to author
Forward
0 new messages