如何构建策略来创建具有相同值对的元组数组?

How to build a strategy to create array of tuples with pairs of identical values?

我想为 NumPy 测试生成一个策略,输出如下:

array([[-2, -2],
       [-3, -3],
       [5,  5],
       [-1, -1]], dtype=int16)

我试过的是:

import numpy as np
from hypothesis.strategies import integers
from hypothesis.extra.numpy import arrays
arrays(np.int16, (4,2), elements=integers(-10, 10)).example()

不幸的是,我无法使元组内的值相同,所以上面的查询 returns:

array([[ 5,  5],
       [-7,  5],
       [ 5,  5],
       [ 5,  5]], dtype=int16)

无需过多研究 np 必须提供的内容,您可以使用生成器生成元组:

tuple_list = [tuple(a) for a in arrays(np.int16, (4,2), elements=integers(-10,10)).example()]

不确定这就是您想要的,但是 hypothesis.extra.numpy 中的 arrays 似乎没有重复值的选项。

你可以像这样构建你需要的数组:

import numpy as np
from hypothesis.strategies import integers
strat = integers(10, -10)
np.array([[x, x] for x in [strat.example() for _ in range(4)]], np.int16)

示例结果:

array([[-9, -9],
       [ 0,  0],
       [-2, -2],
       [ 0,  0]], dtype=int16)

如果您不喜欢内置 2 维度,您可以像这样设置两个参数:

def get_array(rows, cols, strat):
    np.array([[x]*cols for x in [strat.example() for _ in range(rows)]], np.int16)


get_array(4, 2, integers(-10, 10))

我发现,如果我需要在 现有策略的结构中控制内容(例如, 数组内的相同值对)对于较低级别的策略,我需要跳过该策略,我可以使用它来构建一个 "ready-made" 值,该值可以为我想要生成的类型提供种子。

让我们利用 numpy.array 接受列表的列表来创建数组。我们还假设您希望每一行都是唯一的,因为您的示例没有显示重复的行。如果不需要,请从 depth_strategy 定义

中删除 unique_by=str
  1. 生成一个整数并创建一个重复多次以满足宽度的值的列表。
  2. 生成我们在第一步中创建的那种列表的深度长度列表。
  3. 通过嵌套将两种策略结合起来。
  4. 将第三步的结果输入 numpy.array,确保 dtype 与第一步中用于生成值的策略相匹配。
# %%
"""Hypothesis strategy for array of tuples with pairs of identical values."""
from hypothesis import given, settings, strategies as st

import numpy as np

WIDTH = 2
DEPTH = 4
MIN_VALUE = -10
MAX_VALUE = 10

# Build the row - Here for clarification only
width_strategy = st.integers(MIN_VALUE, MAX_VALUE).map(
    lambda i: tuple(i for _ in range(WIDTH))
)

# Build the array of rows - Here for clarification only
depth_strategy = st.lists(
    width_strategy, min_size=DEPTH, max_size=DEPTH, unique_by=str
).map(lambda lot: np.array(lot, dtype=np.int64))

# All-in-One
complete_strategy = st.lists(
    st.integers(MIN_VALUE, MAX_VALUE).map(
        lambda i: tuple(i for _ in range(WIDTH))
    ),
    min_size=DEPTH,
    max_size=DEPTH,
    unique_by=str,
).map(lambda lot: np.array(lot, dtype=np.int64))


@settings(max_examples=10)
@given(an_array=complete_strategy)
def create_numpy_array(an_array):
    """Turn list of lists into numpy array."""
    print(f"A numpy array could be:\n{an_array}")


create_numpy_array()

这会生成如下内容:

A numpy array could be:
[[ 3  3]
 [ 9  9]
 [-5 -5]
 [ 0  0]]
A numpy array could be:
[[ 3  3]
 [-2 -2]
 [ 4  4]
 [-5 -5]]
A numpy array could be:
[[ 7  7]
 [ 0  0]
 [-2 -2]
 [-1 -1]]

请注意,我将 max_examples 设置为 10,因为假设给出了它认为 "troublesome" 的值更高的出现率,例如零、NaN、无穷大等。因此 example() 或更少数量的示例可能会生成大量全为零的 2x4 数组。幸运的是,unique_by 约束在这里帮助了我们。