Answer:
The tasks mentioned here need two Python functions - `main` and `get_corner`. These functions rely on the use of NumPy, a popular Python library for numerical computations.
The `main` function takes in two functions and a tuple representing the size of the array. It applies these functions to generate two arrays and then performs elementwise addition of these arrays. The `get_corner` function, on the other hand, extracts a subarray of specified size from the bottom-left corner of a given 2D array.
Here's how you can write these functions:
```
import numpy as np
def main(func1, func2, size):
arr1 = np.fromfunction(func1, size)
arr2 = np.fromfunction(func2, size)
return arr1 + arr2
def get_corner(arr, M, N):
if arr.shape[0] < M or arr.shape[1] < N:
return "The array is too small to retrieve {} x {} subarray from the lower left corner.".format(M, N)
else:
return arr[-M:, :N]
```
Here's how you can test these functions:
```
print(main(lambda x, y: x+y, lambda x, y: x+y,(3,3)))
A = np.array([[2, 3, 4, 5, 6, 7], [0, 8, 1, 5, 5, 2], [12, 5, 4, 9, 1, 5], [0, 8, 1, 5, 5, 2], [1, 3, 4, 8, 1, 7]])
print(get_corner(A,2,3))
A = np.array([[2, 13, 4, 5, 16, 7], [0, 8, 1, 5, 15, 2], [12, 5, 4, 19, 1, 5], [0, 8, 1, 15, 5, 2], [1, 3, 4, 18, 1, 17]])
print(get_corner(A,6,5))
```
Remember that the subarray size in `get_corner` function is determined by M (number of rows) and N (number of columns) parameters. The extraction starts from the bottom-left corner of the array. The `-M:` in the slicing is used to start from the bottom of the array and `:N` is used to limit the columns from the left.