Automatic option for moving the water based on DEM in MODFLOW 6 - flopy

Is there any automatic option in MODFLOW6-FloPy to route the rejected infiltration from the UZF cells to the SFR reaches based on the DEM and grid cells elevations?

Everything that follows assumes you are familiar with python and flopy.
I think the python below will help you out, I wrote it to essentially accomplish what you are asking for. You'll likely need to make a few edits to get inputs and outputs into the form your particular application requires.
It requires a couple of inputs:
elev_arr: this is a 2D numpy array that contains the land surface elevations. For the model that I used this in, I had a saved file that had all of the land surface elevations called 'top1.txt'. I used this file directly in MODFLOW array. If, in your model, your land surface elevations occur in different layers, you'll need to account for that.
ibnd: gives the extent of the active cells in the elevation array
sfr_dat: is a list of tuples, where each tuple contains (lay, row, col). The order of this list matters! This list should be in the same order as the data appearing in the packagedata block of the SFR input file.
sfrlayout_conn_candidate_elev: a value that is greater than all of your active cell's maximum elevation
The function determine_runoff_conns_4mvr generates and returns a 2D numpy array that is analogous to the IRUNBND array used in UZF1. I put this function into its own python script called mvr_conns and then imported it. The value at each position of the numpy array returned by determine_runoff_conns_4mvr corresponds to the SFR reach (identified by its index in the SFR PackageData block) that rejected infiltration will be routed to, which I think is what you want.
A note about lakes: if you have any, the script below will require some modification. I only had 1 lake and I dealt with it in a very non-robust manner (because I could get away with that). I have to leave this fix to you as an exercise if you have more than one lake.
So, for the MVR package, you'll need to process the array that is returned by determine_runoff_conns_4mvr. Here is how I did it, but you may need to alter for your purposes. Basically, the information contained in static_mvrperioddata can be passed to the perioddata argument when instantiating the MVR package with flopy.
# This function uses the top elevation array and SFR locations to calculate the irunbnd array from the UZF1 package.
import mvr_conns
# Of course in MF6, MVR now handles these runoff connections
irunbnd = mvr_conns.determine_runoff_conns_4mvr(pth) # at this point, irunbnd is 1-based, compensate below
iuzno = 0
k = 0 # Hard-wire the layer no.
for i in range(0, iuzfbnd.shape[0]):
for j in range(0,iuzfbnd.shape[1]):
if irunbnd[i,j] > 0: # This is a uzf -> sfr connection
static_mvrperioddata.append(['UZF-1', iuzno, 'SFR-1', irunbnd[i, j] - 1, 'FACTOR', 1.])
iuzno += 1
elif irunbnd[i, j] < 0: # This is a uzf -> lak connection
static_mvrperioddata.append(['UZF-1', iuzno, 'RES-1', abs(irunbnd[i, j]) - 1, 'FACTOR', 1.])
iuzno += 1
Here is the base function:
def determine_runoff_conns_4mvr(pth):
elev_arr = np.loadtxt(os.path.join(pth,'dis_support','top1.txt'), dtype=np.float)
ibnd = np.loadtxt(os.path.join(pth,'bas_support','ibnd1.txt'), dtype=np.int)
# Get the sfr information stored in a companion script
sfr_dat = sfrinfo.get_sfrlist()
sfrlayout = np.zeros_like(ibnd)
for i, rchx in enumerate(sfr_dat):
row = rchx[1]
col = rchx[2]
sfrlayout[row - 1, col - 1] = i + 1
sfrlayout_new = sfrlayout.copy()
nrow = 64
ncol = 133
stop_candidate = False
for i in np.arange(0, nrow):
for j in np.arange(0, ncol):
# Check to ensure current cell is active
if ibnd[i, j] == 0:
continue
# Check to make sure it is not a stream cell
if not sfrlayout[i, j] == 0:
continue
# Recursively trace path by steepest decent back to a stream
curr_i = i
curr_j = j
sfrlayout_conn_candidate_elev = 10000.
while True:
direc = 0
min_elev = elev_arr[curr_i, curr_j]
# Look straight left
if curr_j > 0:
if not sfrlayout[curr_i, curr_j - 1] == 0 and not ibnd[curr_i, curr_j - 1] == 0: # Step in if neighbor is a stream cell
if elev_arr[curr_i, curr_j - 1] > 0 and (elev_arr[curr_i, curr_j - 1] < elev_arr[curr_i, curr_j] and
elev_arr[curr_i, curr_j - 1] < sfrlayout_conn_candidate_elev):
sfrlayout_conn_candidate = sfrlayout[curr_i, curr_j - 1]
sfrlayout_conn_candidate_elev = elev_arr[curr_i, curr_j - 1]
stop_candidate = True
elif not elev_arr[curr_i, curr_j - 1] == 0 and not ibnd[curr_i, curr_j - 1] == 0: # Step here if neighbor is not an sfr cell
if elev_arr[curr_i, curr_j - 1] < elev_arr[curr_i, curr_j] and elev_arr[curr_i, curr_j - 1] < min_elev:
elevcm1 = elev_arr[curr_i, curr_j - 1]
min_elev = elevcm1
direc = 2
# Look up and left
if curr_j > 0 and curr_i > 0:
if not sfrlayout[curr_i - 1, curr_j - 1] == 0 and not ibnd[curr_i - 1, curr_j - 1] == 0: # Step in if neighbor is a stream cell
if elev_arr[curr_i - 1, curr_j - 1] > 0 and (elev_arr[curr_i - 1, curr_j - 1] < elev_arr[curr_i, curr_j] and
elev_arr[curr_i - 1, curr_j - 1] < sfrlayout_conn_candidate_elev):
sfrlayout_conn_candidate = sfrlayout[curr_i - 1, curr_j - 1]
sfrlayout_conn_candidate_elev = elev_arr[curr_i - 1, curr_j - 1]
stop_candidate = True
elif not elev_arr[curr_i - 1, curr_j - 1] == 0 and not ibnd[curr_i - 1, curr_j - 1] == 0: # Step here if neighbor is not an sfr cell
if elev_arr[curr_i - 1, curr_j - 1] < elev_arr[curr_i, curr_j] and elev_arr[curr_i - 1, curr_j - 1] < min_elev:
elevrm1cm1 = elev_arr[curr_i - 1, curr_j - 1]
min_elev = elevrm1cm1
direc = 5
# Look straight right
if curr_j < ncol - 1:
if not sfrlayout[curr_i, curr_j + 1] == 0 and not ibnd[curr_i, curr_j + 1] == 0: # Step in if neighbor is a stream cell
if elev_arr[curr_i, curr_j + 1] > 0 and (elev_arr[curr_i, curr_j + 1] < elev_arr[curr_i, curr_j] and
elev_arr[curr_i, curr_j + 1] < sfrlayout_conn_candidate_elev):
sfrlayout_conn_candidate = sfrlayout[curr_i, curr_j + 1]
sfrlayout_conn_candidate_elev = elev_arr[curr_i, curr_j + 1]
stop_candidate = True
elif not elev_arr[curr_i, curr_j + 1] == 0 and not ibnd[curr_i, curr_j + 1] == 0: # Step here if neighbor is not an sfr cell
if elev_arr[curr_i, curr_j + 1] < elev_arr[curr_i, curr_j] and elev_arr[curr_i, curr_j + 1] < min_elev:
elevcm1 = elev_arr[curr_i, curr_j + 1]
min_elev = elevcm1
direc = 4
# Look straight right and down
if curr_i < nrow - 1 and curr_j < ncol - 1:
if not sfrlayout[curr_i + 1, curr_j + 1] == 0 and not ibnd[curr_i + 1, curr_j + 1] == 0: # Step in if neighbor is a stream cell
if elev_arr[curr_i + 1, curr_j + 1] > 0 and (elev_arr[curr_i + 1, curr_j + 1] < elev_arr[curr_i, curr_j] and
elev_arr[curr_i + 1, curr_j + 1] < sfrlayout_conn_candidate_elev):
sfrlayout_conn_candidate = sfrlayout[curr_i + 1, curr_j + 1]
sfrlayout_conn_candidate_elev = elev_arr[curr_i + 1, curr_j + 1]
stop_candidate = True
elif not elev_arr[curr_i + 1, curr_j + 1] == 0 and not ibnd[curr_i + 1, curr_j + 1] == 0: # Step here if neighbor is not an sfr cell
if elev_arr[curr_i + 1, curr_j + 1] < elev_arr[curr_i, curr_j] and elev_arr[curr_i + 1, curr_j + 1] < min_elev:
elevrp1cp1 = elev_arr[curr_i + 1, curr_j + 1]
min_elev = elevrp1cp1
direc = 7
# Look straight up
if curr_i > 0:
if not sfrlayout[curr_i - 1, curr_j] == 0 and not ibnd[curr_i - 1, curr_j] == 0: # Step in if neighbor is a stream cell
if elev_arr[curr_i - 1, curr_j] > 0 and (elev_arr[curr_i - 1, curr_j] < elev_arr[curr_i, curr_j] and
elev_arr[curr_i - 1, curr_j] < sfrlayout_conn_candidate_elev):
sfrlayout_conn_candidate = sfrlayout[curr_i - 1, curr_j]
sfrlayout_conn_candidate_elev = elev_arr[curr_i - 1, curr_j]
stop_candidate = True
elif not elev_arr[curr_i - 1, curr_j] == 0 and not ibnd[curr_i - 1, curr_j] == 0: # Step here if neighbor is not an sfr cell
if elev_arr[curr_i - 1, curr_j] < elev_arr[curr_i, curr_j] and elev_arr[curr_i - 1, curr_j] < min_elev:
elevcm1 = elev_arr[curr_i - 1, curr_j]
min_elev = elevcm1
direc = 3
# Look up and right
if curr_i > 0 and curr_j < ncol - 1:
if not sfrlayout[curr_i - 1, curr_j + 1] == 0 and not ibnd[curr_i - 1, curr_j + 1] == 0: # Step in if neighbor is a stream cell
if elev_arr[curr_i - 1, curr_j + 1] > 0 and (elev_arr[curr_i - 1, curr_j + 1] < elev_arr[curr_i, curr_j] and
elev_arr[curr_i - 1, curr_j + 1] < sfrlayout_conn_candidate_elev):
sfrlayout_conn_candidate = sfrlayout[curr_i - 1, curr_j + 1]
sfrlayout_conn_candidate_elev = elev_arr[curr_i - 1, curr_j + 1]
stop_candidate = True
elif not elev_arr[curr_i - 1, curr_j + 1] == 0 and not ibnd[curr_i - 1, curr_j + 1] == 0: # Step here if neighbor is not an sfr cell
if elev_arr[curr_i - 1, curr_j + 1] < elev_arr[curr_i, curr_j] and elev_arr[curr_i - 1, curr_j + 1] < min_elev:
elevrm1cp1 = elev_arr[curr_i - 1, curr_j + 1]
min_elev = elevrm1cp1
direc = 6
# Look straight down
if curr_i < nrow - 1:
if not sfrlayout[curr_i + 1, curr_j] == 0 and not ibnd[curr_i + 1, curr_j] == 0: # Step in if neighbor is a stream cell
if elev_arr[curr_i + 1, curr_j] > 0 and (elev_arr[curr_i + 1, curr_j] < elev_arr[curr_i, curr_j] and
elev_arr[curr_i + 1, curr_j] < sfrlayout_conn_candidate_elev):
sfrlayout_conn_candidate = sfrlayout[curr_i + 1, curr_j]
sfrlayout_conn_candidate_elev = elev_arr[curr_i + 1, curr_j]
stop_candidate = True
elif not elev_arr[curr_i + 1, curr_j] == 0 and not ibnd[curr_i + 1, curr_j] == 0: # Step here if neighbor is not an sfr cell
if elev_arr[curr_i + 1, curr_j] < elev_arr[curr_i, curr_j] and elev_arr[curr_i + 1, curr_j] < min_elev:
elevrp1 = elev_arr[curr_i + 1, curr_j]
min_elev = elevrp1
direc = 1
# Look down and left
if curr_i < nrow - 1 and curr_j > 0:
if not sfrlayout[curr_i + 1, curr_j - 1] == 0 and not ibnd[curr_i + 1, curr_j - 1] == 0: # Step in if neighbor is a stream cell
if elev_arr[curr_i + 1, curr_j - 1] > 0 and (elev_arr[curr_i + 1, curr_j - 1] < elev_arr[curr_i, curr_j] and
elev_arr[curr_i + 1, curr_j - 1] < sfrlayout_conn_candidate_elev):
sfrlayout_conn_candidate = sfrlayout[curr_i + 1, curr_j - 1]
sfrlayout_conn_candidate_elev = elev_arr[curr_i + 1, curr_j - 1]
stop_candidate = True
elif not elev_arr[curr_i + 1, curr_j - 1] == 0 and not ibnd[curr_i + 1, curr_j - 1] == 0: # Step here if neighbor is not an sfr cell
if elev_arr[curr_i + 1, curr_j - 1] < elev_arr[curr_i, curr_j] and elev_arr[curr_i + 1, curr_j - 1] < min_elev:
elevrp1cm1 = elev_arr[curr_i + 1, curr_j - 1]
min_elev = elevrp1cm1
direc = 8
# if stop candidate found, don't move the cell indices
if not stop_candidate:
# Direc corresponds to:
# |----------------------
# | 5 | 3 | 6 |
# |----------------------
# | 2 | cur_cel | 4 |
# |----------------------
# | 8 | 1 | 7 |
# |----------------------
if direc == 0:
break
elif direc == 1:
curr_i += 1
elif direc == 2:
curr_j -= 1
elif direc == 3:
curr_i -= 1
elif direc == 4:
curr_j += 1
elif direc == 5:
curr_i -= 1
curr_j -= 1
elif direc == 6:
curr_i -= 1
curr_j += 1
elif direc == 7:
curr_i += 1
curr_j += 1
elif direc == 8:
curr_i += 1
curr_j -= 1
if stop_candidate:
sfrlayout_new[i, j] = sfrlayout_conn_candidate
stop_candidate = False
break # Bust out of while loop
elif not stop_candidate:
# Check if encountered ibnd == 0, which may be a lake or boundary that drains out of model
if ibnd[curr_i, curr_j] == 0:
# This condition is dealt with after looping through all cells,
# see comment that starts, "Last step is set..."
break
pass # Commence next downstream cell search
# Last step is set the 0's in the vicinity of the lake equal to the negative of the lake connection
for i in np.arange(0, nrow):
for j in np.arange(0, ncol):
if sfrlayout_new[i, j] == 0 and ibnd[i, j] > 0:
sfrlayout_new[i, j] = -1
# Once all cells are filled, save to array
np.savetxt(os.path.join(pth, 'uzf_support','irunbnd_mf6.txt'), sfrlayout_new, fmt='%5d')
return sfrlayout_new

Related

Recover solution from dynamic programming memo table

My goal is to find the longest sub-list of a list of numbers such that each element is at most 1 away from each other, e.g., a list of [0,1,2,2,3,3] from the list [0,4,1,2,2,3,3,1]. I create the memo table as follows:
def memoizeLSS(a):
T = {}
n = len(a)
for j in range(-1, n):
T[(n, j)] = 0 # i = n and j
for i in range(0, n+1):
for j in range(-1, n+1):
T[(i, j)] = 0
for i in range(n-1, -1, -1):
for j in range(n-1, -1, -1):
aj = a[j] if 0 <= j < len(a) else None
if aj != None and abs(a[i] - a[j]) > 1:
T[(i, j)] = T[(i + 1, j)]
elif aj == None or abs(a[i] - a[j]) <= 1:
T[(i, j)] = max(T[(i + 1, i)] + 1, T[(i + 1, j)])
for i in range(n-2, -1, -1):
T[(i, -1)] = max(T[(i+1, -1)], T[(i+1, 0)], T[(i, 0)], 0)
return T
I can figure out the maximum length, however I'm having trouble reconstructing the subsequence from the memo table. I tried creating a list of paired indices where the numbers are <= 1 away from and building it up from there, but there are pairs of indices which are not part of the sub-sequence and I'm stumped on what to do from here or even if creating this list is useful:
def computeLSS(a):
T = {}
Y_list = []
# Now populate the entries for the base case
n = len(a)
for j in range(-1, n):
T[(n, j)] = 0 # i = n and j
for i in range(0, n+1):
for j in range(-1, n+1):
T[(i, j)] = 0
for i in range(n-1, -1, -1):
for j in range(n-1, -1, -1):
aj = a[j] if 0 <= j < len(a) else None
if aj != None and abs(a[i] - a[j]) > 1:
T[(i, j)] = T[(i + 1, j)]
elif aj == None or abs(a[i] - a[j]) <= 1:
T[(i, j)] = max(T[(i + 1, i)] + 1, T[(i + 1, j)])
if T[(i, j)] == T[(i + 1, i)] + 1 and a[i] != a[j]:
Y_list.append((i, j))
for i in range(n-2, -1, -1):
T[(i, -1)] = max(T[(i+1, -1)], T[(i+1, 0)], T[(i, 0)], 0)
Y_list_new = []
for x,y in Y_list:
if x==y:
pass
if (y,x) in Y_list_new:
pass
else:
Y_list_new.append((x,y))
print(Y_list_new)
#print(T)
return
Any help is appreciated. Thank you!

Dynamic Programming, create a memo table longest stable subsequence

I have worked on a dynamic programming problem for quite some time now and am stuck, so any help is much appreciated.
Here is the first part of the problem which I was able to get the tests to pass.
def lssLength(a, i, j):
aj = a[j] if 0 <= j < len(a) else None
# Implement the recurrence below. Use recursive calls back to lssLength
assert 0 <= i <= len(a)
if i >= len(a) or j >= len(a):
return 0
if aj and abs(a[i] - a[j]) > 1:
return lssLength(a, i+1, j)
if aj is None or (abs(a[i] - a[j]) <= 1 and i != j):
return max(lssLength(a, i+1, j), lssLength(a, i+1, i) + 1)
else:
return lssLength(a, i+1, j)
Here are my test cases for the first problem:
def test_lss_length(self):
# test 1
n1 = lssLength([1, 4, 2, -2, 0, -1, 2, 3], 0, -1)
print(n1)
self.assertEqual(4, n1)
# test 2
n2 = lssLength([1, 2, 3, 4, 0, 1, -1, -2, -3, -4, 5, -5, -6], 0, -1)
print(n2)
self.assertEqual(8, n2)
# test 3
n3 = lssLength([0, 2, 4, 6, 8, 10, 12], 0, -1)
print(n3)
self.assertEqual(1, n3)
# test 4
n4 = lssLength(
[4, 8, 7, 5, 3, 2, 5, 6, 7, 1, 3, -1, 0, -2, -3, 0, 1, 2, 1, 3, 1, 0, -1, 2, 4, 5, 0, 2, -3, -9, -4, -2, -3,
-1], 0, -1)
print(n4)
self.assertEqual(14, n4)
Now I need to take the recursive solution and convert it to dynamic programming, and this is where I am stuck. I am using the same tests as before, but the tests are failing.
def memoizeLSS(a):
T = {} # Initialize the memo table to empty dictionary
# Now populate the entries for the base case
# Now fill out the table : figure out the two nested for loops
# It is important to also figure out the order in which you iterate the indices i and j
# Use the recurrence structure itself as a guide: see for instance that T[(i,j)] will depend on T[(i+1, j)]
n = len(a)
for i in range(0, n+1):
for j in range(-1, n+1):
T[(i, j)] = 0
for i in range(n-1, -1, -1):
for j in range(n-1, -1, -1):
if abs(a[i] - a[j]) > 1:
try:
T[(i, j)] = max(0, T[(i, j+1)], T[(i+1, j)])
except Exception:
T[(i, j)] = 0
elif abs(a[i] - a[j]) <= 1 and i != j:
T[(i, j)] = T[(i+1, j+1)] + 1
else:
T[(i, j)] = max(0, T[(i+1, j+1)])
for i in range(n-2, -1, -1):
T[(i, -1)] = max(T[(i+1, -1)], T[(i+1, 0)], T[(i, 0)], 0)
return T
If you've read all of this, thank you so much. I know it is a lot and really appreciate your time. Any pointers to reading materials, etc. is much appreciated.
If there are more details required, please let me know. Thanks.
Your solution only worked for the first test case. Below is a corrected version:
def memoizeLSS(a):
T = {} # Initialize the memo table to empty dictionary
n = len(a)
for j in range(-1, n):
T[(n, j)] = 0 # i = n and j
# Now populate the entries for the base case
# Now fill out the table : figure out the two nested for loops
# It is important to also figure out the order in which you iterate the indices i and j
# Use the recurrence structure itself as a guide: see for instance that T[(i,j)] will depend on T[(i+1, j)]
n = len(a)
for i in range(0, n + 1):
for j in range(-1, n + 1):
T[(i, j)] = 0
for i in range(n-1, -1, -1):
for j in range(n-1, -1, -1):
aj = a[j] if 0 <= j < len(a) else None
if aj != None and abs(a[i] - a[j]) > 1:
T[(i, j)] = T[(i+1, j)]
elif aj == None or abs(a[i] - a[j]) <= 1:
T[(i, j)] = max(T[(i+1, i)] + 1, T[(i + 1, j)])
for i in range(n-2, -1, -1):
T[(i, -1)] = max(T[(i+1, -1)], T[(i+1, 0)], T[(i, 0)], 0)
return T

Finding maximal submatrix of all 1's - missing argument error

Program that finds the maximal rectangle containing only 1's of a binary matrix with the maximal histogram problem.
I am trying to do some tests on a code
def maximalRectangle(self, matrix):
if not matrix or not matrix[0]:
return 0
n = len(matrix[0])
height = [0] * (n + 1)
ans = 0
for row in matrix:
for i in range(n):
height[i] = height[i] + 1 if row[i] == '1' else 0
stack = [-1]
for i in range(n + 1):
while height[i] < height[stack[-1]]:
h = height[stack.pop()]
w = i - 1 - stack[-1]
ans = max(ans, h * w)
stack.append(i)
return ans
# Driver Code
if __name__ == '__main__':
matrix = [[0, 1, 0, 1],
[0, 1, 0, 1],
[0, 1, 1, 1],
[1, 1, 1, 1]]
print(maximalRectangle(matrix))
I get TypeError: maximalRectangle() missing 1 required positional argument: 'matrix' error
Solved by removing self and changing the print statement to:
print(maximalRectangle([
["1","0","1","0","0"],
["1","1","1","1","1"],
["1","1","1","1","1"],
["1","0","0","1","0"]]))

primitive calculator Second step,

I try to get the code right for the minimum required steps to get to n and the subsequent list, steps are multiply by 2 or 3, or add 1. It should be implemented through dynamic programming since using greedy choices for this one is unsafe. First I got the minimum steps required using the following code, it works just fine .
What I can't get is how do I go about unpacking that list, please I don't need answers, this is an assignment for an online class, hints or Help is Ok, so I try to maintain my moral integrity here.
def optimal_sequence(n):
sequence = [0]*(n+1)
for i in range(2, n+1):
if i % 3 == 0:
sequence[i] = sequence[(i // 3)]+1
if sequence[i] - sequence[i-1] <= 1:
sequence[i] = sequence[i]
else:
sequence[i] = sequence[i-1] + 1
elif i % 2 == 0:
sequence[i] = sequence[(i // 2)]+1
if sequence[i] - sequence[i-1] <= 1:
sequence[i] = sequence[i]
else:
sequence[i] = sequence[i-1] + 1
else:
sequence[i] = sequence[i-1] + 1
return sequence
while n >= 1:
seq.append(n)
if n % 3 == 0 and sequence[n] != sequence[n//3]: n = n // 3
elif n % 2 == 0 and sequence[n] != sequence[n//2]: n = n // 2
else: n = n-1
seq.reverse(); return seq
Here is how it maps the minimum number for let's say n = 28,
n = 28
print(optimal_sequence(n))
>>> [0, 0, 1, 1, 2, 3, 2, 3, 3, 2, 3, 4, 3, 4, 4, 4, 4, 5, 3, 4, 4, 4, 5, 6, 4, 5, 5, 3, 4]
Now, if you can help me see if the code is right for the first part, if it is, then what is wrong with the second part of it beginning with while.
Thanks

Dynamic Programming: Tabulation of a Recursive Relation

The following recursive relation solves a variation of the coin exchange problem. Count the number of ways in which we can sum to a required value, while keeping the number of summands even:
def count_even(coins, num_coins, req_sum, parity):
if req_sum < 0:
return 0
if req_sum == 0 and not parity:
return 1
if req_sum == 0 and parity:
return 0
if num_coins == 0:
return 0
count_wout_high_coin = count_even(coins, num_coins - 1, req_sum, parity)
count_with_high_coin = count_even(coins, num_coins, req_sum - coins[num_coins - 1], not parity)
return count_wout_high_coin + count_with_high_coin
This code would yield the required solution if called with parity = False.
I am having issues implementing a tabulation technique to optimize this algorithm. On a first attempt I tried to follow the same pattern as for other DP problems, and took the parity as another parameter to the problem, so I coded this triple loop:
def count_even_tabulation(S, m, n):
if m <= 0 or n < 0:
return 0
if n == 0:
return 1
table = [[[0 for x in range(m)] for x in range(n + 1)] for x in range(2)]
for j in range(m):
table[0][0][j] = 1
table[1][0][j] = 0
for p in range(2):
for i in range(1, n + 1):
for j in range(m):
y = table[p][i][j - 1] if j >= 1 else 0
x = table[1 - p][i - S[j]][j] if i - S[j] >= 0 else 0
table[p][i][j] = x + y
return table[0][n][m - 1]
However, this approach is not creating the right tables for parity equal to 0 and equal to 1:
[1, 1, 1]
[0, 0, 0]
[0, 0, 0]
[0, 0, 0]
[0, 0, 0]
[0, 0, 0]
[1, 1, 1]
[0, 1, 1]
[0, 0, 1]
[0, 0, 0]
How can I adequately implement a tabulation approach for the given recursion relation?

Resources