Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from .version import __version__
from . import attr_enum
from .dtypes import *
from . import serialize

# Import built-in hooks
from .builtin_hooks import *
Expand Down
2 changes: 0 additions & 2 deletions dace/codegen/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
compiles each target separately, links all targets to one binary, and
returns the corresponding CompiledSDFG object. """

from __future__ import print_function

import collections
import os
import six
Expand Down
1 change: 0 additions & 1 deletion dace/codegen/cppunparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@
##########################################################################
### END OF astunparse LICENSES

from __future__ import print_function, unicode_literals
from functools import lru_cache
import inspect
import six
Expand Down
6 changes: 3 additions & 3 deletions dace/codegen/targets/cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def copy_expr(
if offset is None:
s = None
elif not isinstance(offset, subsets.Subset):
s = subsets.Indices(offset)
s = subsets.Range.from_indices(offset)
else:
s = offset
o = None
Expand Down Expand Up @@ -529,7 +529,7 @@ def cpp_array_expr(sdfg,
framecode: Optional['DaCeCodeGenerator'] = None):
""" Converts an Indices/Range object to a C++ array access string. """
subset = memlet.subset if not use_other_subset else memlet.other_subset
s = subset if relative_offset else subsets.Indices(offset)
s = subset if relative_offset else subsets.Range.from_indices(offset)
o = offset if relative_offset else None
desc = (sdfg.arrays[memlet.data] if referenced_array is None else referenced_array)
offset_cppstr = cpp_offset_expr(desc, s, o, packed_veclen, indices=indices)
Expand Down Expand Up @@ -578,7 +578,7 @@ def cpp_ptr_expr(sdfg,
codegen: 'TargetCodeGenerator' = None):
""" Converts a memlet to a C++ pointer expression. """
subset = memlet.subset if not use_other_subset else memlet.other_subset
s = subset if relative_offset else subsets.Indices(offset)
s = subset if relative_offset else subsets.Range.from_indices(offset)
o = offset if relative_offset else None
desc = sdfg.arrays[memlet.data]
if isinstance(indices, str):
Expand Down
1 change: 0 additions & 1 deletion dace/frontend/operations.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# Copyright 2019-2021 ETH Zurich and the DaCe authors. All rights reserved.
from __future__ import print_function
from functools import partial
from itertools import chain, repeat

Expand Down
16 changes: 8 additions & 8 deletions dace/frontend/python/memlet_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ def pyexpr_to_symbolic(defined_arrays_and_symbols: Dict[str, Any], expr_ast: ast
def _ndslice_to_subset(ndslice):
is_tuple = [isinstance(x, tuple) for x in ndslice]
if not any(is_tuple):
return subsets.Indices(ndslice)
else:
if not all(is_tuple):
# If a mix of ranges and indices is found, convert to range
for i in range(len(ndslice)):
if not is_tuple[i]:
ndslice[i] = (ndslice[i], ndslice[i], 1)
return subsets.Range(ndslice)
return subsets.Range.from_indices(ndslice)

if not all(is_tuple):
# If a mix of ranges and indices is found, convert to range
for i in range(len(ndslice)):
if not is_tuple[i]:
ndslice[i] = (ndslice[i], ndslice[i], 1)
return subsets.Range(ndslice)


def _parse_dim_atom(das, atom):
Expand Down
173 changes: 93 additions & 80 deletions dace/frontend/python/newast.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from collections import OrderedDict
import copy
import itertools
import networkx as nx
import re
import sys
import time
Expand All @@ -15,7 +14,6 @@

import dace
from dace import data, dtypes, subsets, symbolic, sdfg as sd
from dace import sourcemap
from dace.config import Config
from dace.frontend.common import op_repository as oprepo
from dace.frontend.python import astutils
Expand Down Expand Up @@ -475,7 +473,7 @@ def add_indirection_subgraph(sdfg: SDFG,
arr = sdfg.arrays[arrname]
subset = subsets.Range.from_array(arr)
else:
subset = subsets.Indices(access)
subset = subsets.Range.from_indices(access)
# Memlet to load the indirection index
indexMemlet = Memlet.simple(arrname, subset)
input_index_memlets.append(indexMemlet)
Expand Down Expand Up @@ -1771,8 +1769,8 @@ def _inject_consume_memlets(self, dec, entry, inputs, internal_node, sdfg: SDFG,
# Inject element to internal SDFG arrays
ntrans = f'consume_{stream_name}'
ntrans, _ = sdfg.add_array(ntrans, [1], self.sdfg.arrays[stream_name].dtype, find_new_name=True)
internal_memlet = dace.Memlet.simple(ntrans, subsets.Indices([0]))
external_memlet = dace.Memlet.simple(stream_name, subsets.Indices([0]), num_accesses=-1)
internal_memlet = dace.Memlet.simple(ntrans, subsets.Range.from_indices([0]))
external_memlet = dace.Memlet.simple(stream_name, subsets.Range.from_indices([0]), num_accesses=-1)

# Inject to internal tasklet
if not dec.endswith('scope'):
Expand Down Expand Up @@ -5290,82 +5288,97 @@ def _add_read_slice(self, array: str, node: ast.Subscript, expr: MemletExpr):
# Make copy slicing state
rnode = self.current_state.add_read(array, debuginfo=self.current_lineinfo)
return self._array_indirection_subgraph(rnode, expr)

is_index = False
if isinstance(expr.subset, subsets.Indices):
is_index = True
other_subset = subsets.Range([(i, i, 1) for i in expr.subset])
else:
is_index = False
if isinstance(expr.subset, subsets.Indices):
is_index = True
other_subset = subsets.Range([(i, i, 1) for i in expr.subset])
else:
other_subset = copy.deepcopy(expr.subset)
strides = list(arrobj.strides)

# Make new axes and squeeze for scalar subsets (as per numpy behavior)
# For example: A[0, np.newaxis, 5:7] results in a 1x2 ndarray
new_axes = []
if expr.new_axes:
new_axes = other_subset.unsqueeze(expr.new_axes)
for i in new_axes:
strides.insert(i, 1)
length = len(other_subset)
nsqz = other_subset.squeeze(ignore_indices=new_axes)
sqz = [i for i in range(length) if i not in nsqz]
for i in reversed(sqz):
strides.pop(i)
if not strides:
strides = None

if is_index:
tmp = self.get_target_name(default=f'{array}_index')
tmp, tmparr = self.sdfg.add_scalar(tmp,
arrobj.dtype,
arrobj.storage,
transient=True,
find_new_name=True)
else:
for i in range(len(other_subset.ranges)):
rb, re, rs = other_subset.ranges[i]
if (rs < 0) == True:
raise DaceSyntaxError(
self, node, 'Negative strides are not supported in subscripts. '
'Please use a Map scope to express this operation.')
re = re - rb
rb = 0
if rs != 1:
# NOTE: We use the identity floor(A/B) = ceiling((A + 1) / B) - 1
# because Range.size() uses the ceiling method and that way we avoid
# false negatives when testing the equality of data shapes.
# re = re // rs
re = sympy.ceiling((re + 1) / rs) - 1
strides[i] *= rs
rs = 1
other_subset.ranges[i] = (rb, re, rs)

tmp, tmparr = self.sdfg.add_view(array,
other_subset.size(),
arrobj.dtype,
storage=arrobj.storage,
strides=strides,
find_new_name=True)
self.views[tmp] = (array,
Memlet(data=array,
subset=str(expr.subset),
other_subset=str(other_subset),
volume=expr.accesses,
wcr=expr.wcr))
self.variables[tmp] = tmp
if not isinstance(tmparr, data.View):
rnode = self.current_state.add_read(array, debuginfo=self.current_lineinfo)
wnode = self.current_state.add_write(tmp, debuginfo=self.current_lineinfo)
# NOTE: We convert the subsets to string because keeping the original symbolic information causes
# equality check failures, e.g., in LoopToMap.
self.current_state.add_nedge(
rnode, wnode,
Memlet(data=array,
subset=str(expr.subset),
other_subset=str(other_subset),
volume=expr.accesses,
wcr=expr.wcr))
return tmp

def range_is_index(range: subsets.Range) -> bool:
"""
Check if the given subset range is an index.

Conditions for an index are as follows:
- tile_size of each range has to be 1
- the range increment has to be 1
- start/stop element of the range have to be equal
"""
for r, t in zip(range.ranges, range.tile_sizes):
if t != 1 or r[2] != 1 or r[0] != r[1]:
return False
return True

# We also check the type of the slice attribute of the node
# in order to distinguish between A[0] and A[0:1], which are semantically different in numpy
# (the former is an index, the latter is a slice).
is_index = range_is_index(expr.subset) and not isinstance(node.slice, ast.Slice)
other_subset = copy.deepcopy(expr.subset)
strides = list(arrobj.strides)

# Make new axes and squeeze for scalar subsets (as per numpy behavior)
# For example: A[0, np.newaxis, 5:7] results in a 1x2 ndarray
new_axes = []
if expr.new_axes:
new_axes = other_subset.unsqueeze(expr.new_axes)
for i in new_axes:
strides.insert(i, 1)
length = len(other_subset)
nsqz = other_subset.squeeze(ignore_indices=new_axes)
sqz = [i for i in range(length) if i not in nsqz]
for i in reversed(sqz):
strides.pop(i)
if not strides:
strides = None

if is_index:
tmp = self.get_target_name(default=f'{array}_index')
tmp, tmparr = self.sdfg.add_scalar(tmp, arrobj.dtype, arrobj.storage, transient=True, find_new_name=True)
else:
for i in range(len(other_subset.ranges)):
rb, re, rs = other_subset.ranges[i]
if (rs < 0) == True:
raise DaceSyntaxError(
self, node, 'Negative strides are not supported in subscripts. '
'Please use a Map scope to express this operation.')
re = re - rb
rb = 0
if rs != 1:
# NOTE: We use the identity floor(A/B) = ceiling((A + 1) / B) - 1
# because Range.size() uses the ceiling method and that way we avoid
# false negatives when testing the equality of data shapes.
# re = re // rs
re = sympy.ceiling((re + 1) / rs) - 1
strides[i] *= rs
rs = 1
other_subset.ranges[i] = (rb, re, rs)

tmp, tmparr = self.sdfg.add_view(array,
other_subset.size(),
arrobj.dtype,
storage=arrobj.storage,
strides=strides,
find_new_name=True)
self.views[tmp] = (array,
Memlet(data=array,
subset=str(expr.subset),
other_subset=str(other_subset),
volume=expr.accesses,
wcr=expr.wcr))
self.variables[tmp] = tmp
if not isinstance(tmparr, data.View):
rnode = self.current_state.add_read(array, debuginfo=self.current_lineinfo)
wnode = self.current_state.add_write(tmp, debuginfo=self.current_lineinfo)
# NOTE: We convert the subsets to string because keeping the original symbolic information causes
# equality check failures, e.g., in LoopToMap.
self.current_state.add_nedge(
rnode, wnode,
Memlet(data=array,
subset=str(expr.subset),
other_subset=str(other_subset),
volume=expr.accesses,
wcr=expr.wcr))
return tmp

def _parse_subscript_slice(self,
s: ast.AST,
Expand Down
1 change: 0 additions & 1 deletion dace/frontend/python/wrappers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Copyright 2019-2021 ETH Zurich and the DaCe authors. All rights reserved.
""" Types and wrappers used in DaCe's Python frontend. """
from __future__ import print_function
import numpy
import itertools
from collections import deque
Expand Down
4 changes: 2 additions & 2 deletions dace/libraries/mpi/nodes/redistribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ def expansion(node, parent_state, parent_sdfg):

inp_symbols = [symbolic.symbol(f"__inp_s{i}") for i in range(len(inp_buffer.shape))]
out_symbols = [symbolic.symbol(f"__out_s{i}") for i in range(len(out_buffer.shape))]
inp_subset = subsets.Indices(inp_symbols)
out_subset = subsets.Indices(out_symbols)
inp_subset = subsets.Range.from_indices(inp_symbols)
out_subset = subsets.Range.from_indices(out_symbols)
inp_offset = cpp.cpp_offset_expr(inp_buffer, inp_subset)
out_offset = cpp.cpp_offset_expr(out_buffer, out_subset)
print(inp_offset)
Expand Down
30 changes: 16 additions & 14 deletions dace/subsets.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
# Copyright 2019-2025 ETH Zurich and the DaCe authors. All rights reserved.
import dace.serialize
from dace import data, symbolic, dtypes
import re
from dace import symbolic
import sympy as sp
from functools import reduce
import sympy.core.sympify
from typing import List, Optional, Sequence, Set, Union
import warnings
from dace.config import Config
Expand Down Expand Up @@ -322,8 +320,12 @@ def __init__(self, ranges):
self.tile_sizes = parsed_tiles

@staticmethod
def from_indices(indices: 'Indices'):
return Range([(i, i, 1) for i in indices.indices])
def from_indices(indices: Union["Indices", Sequence[int | str | symbolic.SymbolicType]]):
if isinstance(indices, Indices):
return Range([(i, i, 1) for i in indices.indices])

indices = [symbolic.pystr_to_symbolic(i) for i in indices]
return Range([(i, i, 1) for i in indices])

def to_json(self):
ret = []
Expand Down Expand Up @@ -498,9 +500,9 @@ def offset(self, other, negative, indices=None, offset_end=True):
return
if not isinstance(other, Subset):
if isinstance(other, (list, tuple)):
other = Indices(other)
other = Range.from_indices(other)
else:
other = Indices([other for _ in self.ranges])
other = Range.from_indices([other for _ in self.ranges])
mult = -1 if negative else 1
if indices is None:
indices = set(range(len(self.ranges)))
Expand All @@ -516,9 +518,9 @@ def offset_new(self, other, negative, indices=None, offset_end=True):
return Range(self.ranges)
if not isinstance(other, Subset):
if isinstance(other, (list, tuple)):
other = Indices(other)
other = Range.from_indices(other)
else:
other = Indices([other for _ in self.ranges])
other = Range.from_indices([other for _ in self.ranges])
mult = -1 if negative else 1
if indices is None:
indices = set(range(len(self.ranges)))
Expand Down Expand Up @@ -716,7 +718,7 @@ def from_string(string):
tsize = tokens[3]
else:
tsize = 1
except sympy.SympifyError:
except sp.SympifyError:
raise SyntaxError("Invalid range: {}".format(string))
# Append range
ranges.append((begin, end, step, tsize))
Expand Down Expand Up @@ -1148,9 +1150,9 @@ def bounding_box_union(subset_a: Subset, subset_b: Subset) -> Range:
elif len(brb.free_symbols) == 0:
minrb = brb
else:
minrb = sympy.Min(arb, brb)
minrb = sp.Min(arb, brb)
else:
minrb = sympy.Min(arb, brb)
minrb = sp.Min(arb, brb)

try:
maxre = max(are, bre)
Expand All @@ -1161,9 +1163,9 @@ def bounding_box_union(subset_a: Subset, subset_b: Subset) -> Range:
elif len(bre.free_symbols) == 0:
maxre = are
else:
maxre = sympy.Max(are, bre)
maxre = sp.Max(are, bre)
else:
maxre = sympy.Max(are, bre)
maxre = sp.Max(are, bre)

result.append((minrb, maxre, 1))

Expand Down
Loading