Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #983 | Add Round function and implement the conversion to C, Fortran, and Python #996

Open
wants to merge 39 commits into
base: devel
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
8260ef1
Issue #983 | Add Round function and implement the conversion to C and…
Oct 15, 2021
c617738
Merge branch 'master' into master
nandiniraja348 Oct 15, 2021
d02c02a
Issue #983 | Add an import for randint in tests
Oct 16, 2021
c65cf40
Remove slots
Oct 16, 2021
cc8e2c4
Merge branch 'master' into master
EmilyBourne Dec 15, 2021
f8a9898
Merge branch 'master' into master
EmilyBourne May 2, 2022
85085bd
Put back slots. Fix merge
EmilyBourne May 2, 2022
bf79ca9
Add type check
EmilyBourne May 2, 2022
1c9640d
Correct merge
EmilyBourne May 2, 2022
25a7c95
Add ndigits argument to class
EmilyBourne May 2, 2022
ddef46d
Add missing slots
EmilyBourne May 2, 2022
3700029
Save ndigits. Use default python precision (instead of numpy precision)
EmilyBourne May 2, 2022
0d9e30d
Add more tests
EmilyBourne May 2, 2022
86a4ed8
Test middle case
EmilyBourne May 2, 2022
d857efc
Merge branch 'master' into master
EmilyBourne May 30, 2022
5526c55
Merge branch 'master' into master
EmilyBourne Jul 16, 2022
99e73ee
Update performance comparison
github-actions[bot] Jul 16, 2022
9944bd0
Try and prevent trigger
EmilyBourne Jul 16, 2022
5e2da50
Add printing functions
EmilyBourne Jul 16, 2022
e6524df
Prevent bench trigger
EmilyBourne Jul 16, 2022
0e5a57f
Correct typo
EmilyBourne Jul 16, 2022
a581983
Use banker's round
EmilyBourne Jul 16, 2022
5ac8200
Match python behaviour
EmilyBourne Jul 16, 2022
d24bb62
Typo. Missing import
EmilyBourne Jul 16, 2022
cadd954
Use pyc_bankers_round with ndigits argument
EmilyBourne Jul 16, 2022
0a3f405
Add tests. Add failing test in C
EmilyBourne Jul 16, 2022
8993b89
Remove debugging info
EmilyBourne Jul 16, 2022
1870ec2
Ensure developer mode is temporary
EmilyBourne Jul 16, 2022
f8ce870
Make into interface
EmilyBourne Jul 16, 2022
af5f147
Simplify statement
EmilyBourne Jul 16, 2022
f1b02cd
Merge branch 'master' into master
EmilyBourne Jul 19, 2022
8bbc357
Merge branch 'master' into master
yguclu Jul 19, 2022
a087bac
Correct expected dtype
EmilyBourne Jul 20, 2022
95017a8
Add missing functions
EmilyBourne Jul 20, 2022
09ac6cc
Add int tests
EmilyBourne Jul 20, 2022
55d95a2
Handle unexpected precision
EmilyBourne Jul 20, 2022
a4a947f
Correct cast
EmilyBourne Jul 20, 2022
c279c52
Correct stupid typo
EmilyBourne Jul 20, 2022
a786f87
Merge branch 'master' into master
yguclu Mar 5, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/bench.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Benchmarks

on:
push:
branches: [ master ]
branches: [ pyccel:master ]

jobs:

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/master.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: master_tests

on:
push:
branches: [ master ]
branches: [ pyccel:master ]

jobs:

Expand Down
50 changes: 25 additions & 25 deletions performance.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
# Performance Comparison (as of Tue Jun 14 13:19:45 UTC 2022)
# Performance Comparison (as of Sat Jul 16 08:44:11 UTC 2022)
## Compilation time
Algorithm | python | pythran | numba | pyccel | pyccel_c
------------------------- | ------------------------- | ------------------------- | ------------------------- | ------------------------- | -------------------------
Ackermann | - | 3.70 | 0.48 | 1.53 | 1.37
Bellman Ford | - | 5.05 | 1.00 | 2.21 | 2.16
Dijkstra | - | 6.25 | 1.30 | 2.34 | -
Euler | - | 7.64 | 1.52 | 2.29 | 2.27
Midpoint Explicit | - | 8.69 | 2.21 | 2.79 | 2.69
Midpoint Fixed | - | 9.61 | 2.65 | 2.77 | 2.70
RK4 | - | 9.16 | 2.62 | 3.18 | -
FD - L Convection | - | 3.95 | 0.43 | 2.04 | 2.03
FD - NL Convection | - | 4.15 | 0.44 | 2.11 | 2.34
FD - Poisson | - | 10.87 | 1.00 | 2.35 | 2.21
FD - Laplace | - | 18.45 | 2.12 | 2.90 | -
M-D | - | 15.12 | 5.81 | 3.69 | 3.29
Ackermann | - | 3.32 | 0.39 | 1.39 | 1.29
Bellman Ford | - | 4.43 | 0.86 | 1.99 | 2.02
Dijkstra | - | 5.71 | 1.23 | 2.07 | -
Euler | - | 6.60 | 1.36 | 2.00 | 1.98
Midpoint Explicit | - | 7.59 | 1.94 | 2.39 | 2.44
Midpoint Fixed | - | 9.13 | 2.28 | 2.55 | 2.46
RK4 | - | 8.26 | 2.36 | 3.12 | -
FD - L Convection | - | 3.54 | 0.39 | 1.96 | 1.86
FD - NL Convection | - | 3.50 | 0.39 | 1.88 | 1.86
FD - Poisson | - | 9.20 | 0.86 | 2.14 | 1.98
FD - Laplace | - | 16.55 | 1.89 | 2.59 | -
M-D | - | 11.96 | 5.13 | 2.88 | 2.58

## Execution time
Algorithm | python | pythran | numba | pyccel | pyccel_c
------------------------- | ------------------------- | ------------------------- | ------------------------- | ------------------------- | -------------------------
Ackermann (ms) | 528.00 $\pm$ 16.00 | 18.10 $\pm$ 1.20 | 34.60 $\pm$ 1.70 | 3.65 $\pm$ 0.12 | 4.15 $\pm$ 0.14
Bellman Ford (ns) | 77200.00 $\pm$ 3900.00 | 470.00 $\pm$ 18.00 | 639.00 $\pm$ 22.00 | 282.00 $\pm$ 11.00 | 603.00 $\pm$ 53.00
Dijkstra (ns) | 40600.00 $\pm$ 1200.00 | 418.00 $\pm$ 21.00 | 418.00 $\pm$ 27.00 | 350.00 $\pm$ 12.00 | -
Euler (ms) | 72.20 $\pm$ 5.10 | 0.75 $\pm$ 0.03 | 1.02 $\pm$ 0.04 | 0.24 $\pm$ 0.02 | 3.62 $\pm$ 0.13
Midpoint Explicit (ms) | 147.00 $\pm$ 9.00 | 1.66 $\pm$ 0.05 | 2.69 $\pm$ 0.08 | 0.31 $\pm$ 0.01 | 6.54 $\pm$ 0.58
Midpoint Fixed (ms) | 721.00 $\pm$ 45.00 | 9.49 $\pm$ 0.32 | 14.90 $\pm$ 0.60 | 1.09 $\pm$ 0.03 | 26.50 $\pm$ 0.90
RK4 (ms) | 324.00 $\pm$ 17.00 | 2.48 $\pm$ 0.08 | 5.21 $\pm$ 0.21 | 0.94 $\pm$ 0.03 | -
FD - L Convection (ms) | 2560.00 $\pm$ 50.00 | 2.09 $\pm$ 0.04 | 11.60 $\pm$ 0.60 | 2.35 $\pm$ 0.09 | 2.25 $\pm$ 0.06
FD - NL Convection (ms) | 3760.00 $\pm$ 130.00 | 2.05 $\pm$ 0.06 | 11.70 $\pm$ 0.60 | 2.05 $\pm$ 0.13 | 2.33 $\pm$ 0.07
FD - Poisson (ms) | 5670.00 $\pm$ 180.00 | 3.78 $\pm$ 0.11 | 14.40 $\pm$ 0.80 | 5.06 $\pm$ 0.12 | 3.61 $\pm$ 0.12
FD - Laplace (\textmu s) | 112.00 $\pm$ 8.00 | 3.15 $\pm$ 0.14 | 12.20 $\pm$ 0.30 | 2.79 $\pm$ 0.14 | -
M-D (ms) | 66800.00 $\pm$ 1700.00 | 77.80 $\pm$ 2.60 | 280.00 $\pm$ 16.00 | 69.50 $\pm$ 1.80 | 82.40 $\pm$ 4.50
Ackermann (ms) | 478.00 $\pm$ 15.00 | 18.70 $\pm$ 0.10 | 31.20 $\pm$ 0.40 | 10.60 $\pm$ 0.00 | 10.20 $\pm$ 0.10
Bellman Ford (ns) | 66400.00 $\pm$ 3100.00 | 379.00 $\pm$ 1.00 | 563.00 $\pm$ 14.00 | 239.00 $\pm$ 7.00 | 487.00 $\pm$ 6.00
Dijkstra (ns) | 34100.00 $\pm$ 500.00 | 360.00 $\pm$ 6.00 | 344.00 $\pm$ 3.00 | 274.00 $\pm$ 0.00 | -
Euler (ms) | 57.60 $\pm$ 0.80 | 0.59 $\pm$ 0.01 | 1.11 $\pm$ 0.02 | 0.14 $\pm$ 0.00 | 3.12 $\pm$ 0.07
Midpoint Explicit (ms) | 118.00 $\pm$ 2.00 | 1.36 $\pm$ 0.02 | 2.85 $\pm$ 0.07 | 0.17 $\pm$ 0.00 | 5.60 $\pm$ 0.17
Midpoint Fixed (ms) | 588.00 $\pm$ 18.00 | 8.72 $\pm$ 0.06 | 15.90 $\pm$ 0.30 | 0.68 $\pm$ 0.01 | 25.10 $\pm$ 0.80
RK4 (ms) | 275.00 $\pm$ 22.00 | 1.87 $\pm$ 0.00 | 5.76 $\pm$ 0.17 | 0.79 $\pm$ 0.04 | -
FD - L Convection (ms) | 2190.00 $\pm$ 60.00 | 1.48 $\pm$ 0.03 | 9.39 $\pm$ 0.06 | 1.65 $\pm$ 0.02 | 1.57 $\pm$ 0.02
FD - NL Convection (ms) | 3150.00 $\pm$ 90.00 | 1.96 $\pm$ 0.03 | 9.25 $\pm$ 0.06 | 1.72 $\pm$ 0.01 | 1.84 $\pm$ 0.02
FD - Poisson (ms) | 4570.00 $\pm$ 170.00 | 2.06 $\pm$ 0.03 | 10.50 $\pm$ 0.10 | 3.97 $\pm$ 0.11 | 1.78 $\pm$ 0.01
FD - Laplace (\textmu s) | 60.90 $\pm$ 2.90 | 2.36 $\pm$ 0.03 | 8.72 $\pm$ 0.13 | 2.22 $\pm$ 0.03 | -
M-D (ms) | 52500.00 $\pm$ 600.00 | 55.20 $\pm$ 0.50 | 219.00 $\pm$ 1.00 | 48.20 $\pm$ 0.20 | 61.60 $\pm$ 0.60
48 changes: 46 additions & 2 deletions pyccel/ast/builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
from .literals import LiteralInteger, LiteralFloat, LiteralComplex, Nil
from .literals import Literal, LiteralImaginaryUnit, get_default_literal_value
from .literals import LiteralString
from .operators import PyccelAdd, PyccelAnd, PyccelMul, PyccelIsNot
from .operators import PyccelMinus, PyccelUnarySub, PyccelNot
from .operators import PyccelAdd, PyccelAnd, PyccelMul, PyccelIsNot, PyccelDiv
from .operators import PyccelMinus, PyccelUnarySub, PyccelNot, PyccelPow
from .variable import IndexedElement

pyccel_stage = PyccelStage()
Expand All @@ -47,6 +47,7 @@
'PythonZip',
'PythonMax',
'PythonMin',
'PythonRound',
'python_builtin_datatype'
)

Expand Down Expand Up @@ -354,6 +355,48 @@ def arg(self):
def __str__(self):
return 'float({0})'.format(str(self.arg))

# ===========================================================================
class PythonRound(PyccelAstNode):
EmilyBourne marked this conversation as resolved.
Show resolved Hide resolved
""" Represents a call to Python's native round() function.
"""
__slots__ = ('_arg', '_ndigits', '_dtype', '_precision')
name = 'round'
_rank = 0
_shape = ()
_order = None
_attribute_nodes = ('_arg','_ndigits')

def __init__(self, number, ndigits = None):
aihya marked this conversation as resolved.
Show resolved Hide resolved
self._arg = number
if ndigits is None:
self._dtype = NativeInteger()
self._ndigits = None
else:
self._dtype = NativeFloat()
self._ndigits = ndigits
self._precision = -1
super().__init__()

@property
def arg(self):
""" Number to be rounded
"""
return self._arg

@property
def ndigits(self):
""" Number of digits to which the argument is rounded
"""
return self._ndigits

def get_round_with_0_digits(self):
""" Get expression returning the same value but containing
a call to PyccelRound with ndigits=None
"""
assert self.ndigits is not None
factor = PyccelPow(LiteralFloat(10), self.ndigits)
return PyccelDiv(PythonRound(PyccelMul(self.arg, factor)), factor)

#==============================================================================
class PythonInt(PyccelAstNode):
""" Represents a call to Python's native int() function.
Expand Down Expand Up @@ -925,4 +968,5 @@ def python_builtin_datatype(name):
'not' : PyccelNot,
'map' : PythonMap,
'type' : PythonType,
'round' : PythonRound,
}
8 changes: 8 additions & 0 deletions pyccel/codegen/printing/ccode.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,14 @@ def _print_PythonAbs(self, expr):
func = "labs"
return "{}({})".format(func, self._print(expr.arg))

def _print_PythonRound(self, expr):
if expr.ndigits is None:
self.add_import(c_imports['math'])
arg = self._print(expr.arg)
return f"lrint({arg})"
else:
return self._print(expr.get_round_with_0_digits())

def _print_PythonMin(self, expr):
arg = expr.args[0]
if arg.dtype is NativeFloat() and len(arg) == 2:
Expand Down
14 changes: 14 additions & 0 deletions pyccel/codegen/printing/fcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,20 @@ def _print_PythonAbs(self, expr):
"""
return "abs({})".format(self._print(expr.arg))

def _print_PythonRound(self, expr):
""" print the python builtin function round
args : variable
"""
arg = self._print(expr.arg)
self._additional_imports.add(Import('pyc_math_f90', Module('pyc_math_f90',(),())))
if expr.ndigits:
ndigits = self._print(expr.ndigits)
return f"pyc_bankers_round({arg}, {ndigits})"
else:
prec = self.print_kind(expr)
zero = self._print(LiteralInteger(0))
return f"Int(pyc_bankers_round({arg}, {zero}), kind={prec})"

def _print_PythonTuple(self, expr):
shape = tuple(reversed(expr.shape))
if len(shape)>1:
Expand Down
8 changes: 8 additions & 0 deletions pyccel/codegen/printing/pycode.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,14 @@ def _print_PythonConjugate(self, expr):
def _print_PythonPrint(self, expr):
return 'print({})\n'.format(', '.join(self._print(a) for a in expr.expr))

def _print_PythonRound(self, expr):
arg = self._print(expr.arg)
if expr.ndigits:
ndigits = self._print(expr.ndigits)
return f'round({arg}, {ndigits})'
else:
return f'round({arg})'

def _print_PyccelArraySize(self, expr):
arg = self._print(expr.arg)
index = self._print(expr.index)
Expand Down
8 changes: 5 additions & 3 deletions pyccel/commands/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,11 +221,13 @@ def pyccel(files=None, mpi=None, openmp=None, openacc=None, output_dir=None, com
# ...

# ...
# this will initialize the singelton ErrorsMode
# making this settings available everywhere
err_mode = ErrorsMode()
if args.developer_mode:
# this will initialize the singelton ErrorsMode
# making this settings available everywhere
err_mode = ErrorsMode()
err_mode.set_mode('developer')
else:
err_mode.set_mode('user')
# ...

base_dirpath = os.getcwd()
Expand Down
8 changes: 5 additions & 3 deletions pyccel/epyccel.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,11 +264,13 @@ def epyccel( python_function_or_module, **kwargs ):
comm = kwargs.pop('comm', None)
root = kwargs.pop('root', 0)
bcast = kwargs.pop('bcast', True)
# This will initialize the singleton ErrorsMode
# making this setting available everywhere
err_mode = ErrorsMode()
if kwargs.pop('developer_mode', None):
# This will initialize the singleton ErrorsMode
# making this setting available everywhere
err_mode = ErrorsMode()
err_mode.set_mode('developer')
else:
err_mode.set_mode('user')

# Parallel version
if comm is not None:
Expand Down
64 changes: 63 additions & 1 deletion pyccel/stdlib/math/pyc_math_f90.f90
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@

module pyc_math_f90

use ISO_C_BINDING
use, intrinsic :: ISO_C_BINDING

implicit none

private

real(C_DOUBLE), parameter, private :: pi = 4.0_C_DOUBLE * DATAN(1.0_C_DOUBLE)

interface pyc_gcd
Expand All @@ -26,6 +28,18 @@ module pyc_math_f90
module procedure pyc_lcm_8
end interface pyc_lcm

interface pyc_bankers_round
module procedure pyc_bankers_round_4
module procedure pyc_bankers_round_8
end interface pyc_bankers_round

public :: pyc_gcd, &
pyc_factorial, &
pyc_lcm, &
pyc_radians, &
pyc_degrees, &
pyc_bankers_round

contains

! Implementation of math factorial function
Expand Down Expand Up @@ -156,4 +170,52 @@ pure function pyc_degrees(rad) result(deg)

end function pyc_degrees

pure function pyc_bankers_round_4(arg, ndigits) result(rnd)

implicit none

real(C_DOUBLE), value :: arg
integer(C_INT32_T), value :: ndigits
real(C_DOUBLE) :: rnd

real(C_DOUBLE) :: diff

arg = arg * 10._C_DOUBLE**ndigits

rnd = nint(arg, kind=C_INT64_T)

diff = arg - rnd

if (ndigits <= 0 .and. (diff == 0.5_C_DOUBLE .or. diff == -0.5_C_DOUBLE)) then
rnd = nint(arg*0.5_C_DOUBLE, kind=C_INT64_T)*2_C_INT64_T
end if

rnd = rnd * 10._C_DOUBLE**(-ndigits)

end function pyc_bankers_round_4

pure function pyc_bankers_round_8(arg, ndigits) result(rnd)

implicit none

real(C_DOUBLE), value :: arg
integer(C_INT64_T), value :: ndigits
real(C_DOUBLE) :: rnd

real(C_DOUBLE) :: diff

arg = arg * 10._C_DOUBLE**ndigits

rnd = nint(arg, kind=C_INT64_T)

diff = arg - rnd

if (ndigits <= 0 .and. (diff == 0.5_C_DOUBLE .or. diff == -0.5_C_DOUBLE)) then
rnd = nint(arg*0.5_C_DOUBLE, kind=C_INT64_T)*2_C_INT64_T
end if

rnd = rnd * 10._C_DOUBLE**(-ndigits)

end function pyc_bankers_round_8

end module pyc_math_f90