CVXPY 是否有办法将变量约束为偶数?
Does CVXPY have a way to constrain a variable to be even?
我正在尝试编写对时钟频率和除数的搜索以生成目标频率。
但是,一个限制条件是除数必须是偶数(由于硬件限制),我找不到对此建模的方法。
我没有得到模运算符支持
"TypeError: unsupported operand type(s) for %: 'Variable' and 'int'"
以下使用除法和乘法的 hack 尝试无效:
wantipp = cp.Parameter(name = 'wantedipp') # Desired IPP
div = cp.Variable(integer = True, name = 'div') # Divisor must be integral
ipp = cp.Variable(pos = True, name = 'ipp') # nsec
constraints = [
ipp == 1e9 / 6e6 * div, # Constrain IPP to divisor
div >= 2, div <= 65536, # Divisor must be 2-65536
div / 2 * 2 == div, # Divisor must be even (doesn't actually work)
]
objective = cp.Minimize(cp.abs(ipp - wantipp)) # Find closest possible IPP
prob = cp.Problem(objective, constraints);
for i in (1e3, 2e3, 1e6, 2e6, 123123, 5412341, 1233, 12541):
wantipp.value = i
prob.solve()
print('IPP %.3f nsec (%.3f Hz) -> Divisor %d %.3f nsec (%.3f Hz)' % (
i, 1e9 / i, div.value, ipp.value, 1e9 / ipp.value
))
IPP 1000.000 nsec (1000000.000 Hz) -> Divisor 6 1000.000 nsec (1000000.000 Hz)
IPP 2000.000 nsec (500000.000 Hz) -> Divisor 12 2000.000 nsec (500000.000 Hz)
IPP 1000000.000 nsec (1000.000 Hz) -> Divisor 6000 1000000.000 nsec (1000.000 Hz)
IPP 2000000.000 nsec (500.000 Hz) -> Divisor 12000 2000000.000 nsec (500.000 Hz)
IPP 123123.000 nsec (8121.959 Hz) -> Divisor 739 123166.667 nsec (8119.080 Hz)
IPP 5412341.000 nsec (184.763 Hz) -> Divisor 32474 5412333.333 nsec (184.763 Hz)
IPP 1233.000 nsec (811030.008 Hz) -> Divisor 7 1166.667 nsec (857142.857 Hz)
IPP 12541.000 nsec (79738.458 Hz) -> Divisor 75 12500.000 nsec (80000.000 Hz)
即它最终得到一个除数 739 等等
(注意我开始时是固定时钟,以后会变)
我在 MacOSX 10.14.6
上使用 CVXPY 1.0.25
、Python 3.7.5
。
要回答您磁贴中的问题,没有办法在本地创建此类约束。如果你可以直接施加这样的约束,你将不再有凸包作为你的解决方案space。
这里的根本问题是您不能创建使范围采样不连续的约束。这在界面中以两种方式表现出来,如您所见:您也不能对依赖于包含该变量的表达式的变量进行约束,并且运算符 //
和 %
不是t 为表达式定义。
针对您的特定情况的解决方法是在您求解的变量和您希望从中获得的值之间创建一个一对一的映射。偶数只是整数乘以 2,因此您可以删除显式均匀性约束并执行
constraints = [
ipp == 1e9 / 3e6 * div, # Constrain IPP to divisor
div >= 1, div <= 32768, # Divisor must be 2-65536
]
objective = cp.Minimize(cp.abs(ipp - wantipp)) # Find closest possible IPP
打印解决方案时,显示两倍的解决值:
print('IPP %.3f nsec (%.3f Hz) -> Divisor %d %.3f nsec (%.3f Hz)' % (
i, 1e9 / i, 2 * div.value, ipp.value, 1e9 / ipp.value
))
更好的是,使用更现代的 f 弦代替旧式插值:
print(f'IPP {i:.3f} nsec ({1e9 / i:.3f} Hz) -> Divisor {2 * div.value} {ipp.value:.3f} nsec ({1e9 / ipp.value:.3f} Hz)')
创建约束为偶数的变量 x 的完全标准方法是添加整数变量 y 和约束 x=2y。
我正在尝试编写对时钟频率和除数的搜索以生成目标频率。 但是,一个限制条件是除数必须是偶数(由于硬件限制),我找不到对此建模的方法。
我没有得到模运算符支持
"TypeError: unsupported operand type(s) for %: 'Variable' and 'int'"
以下使用除法和乘法的 hack 尝试无效:
wantipp = cp.Parameter(name = 'wantedipp') # Desired IPP
div = cp.Variable(integer = True, name = 'div') # Divisor must be integral
ipp = cp.Variable(pos = True, name = 'ipp') # nsec
constraints = [
ipp == 1e9 / 6e6 * div, # Constrain IPP to divisor
div >= 2, div <= 65536, # Divisor must be 2-65536
div / 2 * 2 == div, # Divisor must be even (doesn't actually work)
]
objective = cp.Minimize(cp.abs(ipp - wantipp)) # Find closest possible IPP
prob = cp.Problem(objective, constraints);
for i in (1e3, 2e3, 1e6, 2e6, 123123, 5412341, 1233, 12541):
wantipp.value = i
prob.solve()
print('IPP %.3f nsec (%.3f Hz) -> Divisor %d %.3f nsec (%.3f Hz)' % (
i, 1e9 / i, div.value, ipp.value, 1e9 / ipp.value
))
IPP 1000.000 nsec (1000000.000 Hz) -> Divisor 6 1000.000 nsec (1000000.000 Hz)
IPP 2000.000 nsec (500000.000 Hz) -> Divisor 12 2000.000 nsec (500000.000 Hz)
IPP 1000000.000 nsec (1000.000 Hz) -> Divisor 6000 1000000.000 nsec (1000.000 Hz)
IPP 2000000.000 nsec (500.000 Hz) -> Divisor 12000 2000000.000 nsec (500.000 Hz)
IPP 123123.000 nsec (8121.959 Hz) -> Divisor 739 123166.667 nsec (8119.080 Hz)
IPP 5412341.000 nsec (184.763 Hz) -> Divisor 32474 5412333.333 nsec (184.763 Hz)
IPP 1233.000 nsec (811030.008 Hz) -> Divisor 7 1166.667 nsec (857142.857 Hz)
IPP 12541.000 nsec (79738.458 Hz) -> Divisor 75 12500.000 nsec (80000.000 Hz)
即它最终得到一个除数 739 等等
(注意我开始时是固定时钟,以后会变)
我在 MacOSX 10.14.6
上使用 CVXPY 1.0.25
、Python 3.7.5
。
要回答您磁贴中的问题,没有办法在本地创建此类约束。如果你可以直接施加这样的约束,你将不再有凸包作为你的解决方案space。
这里的根本问题是您不能创建使范围采样不连续的约束。这在界面中以两种方式表现出来,如您所见:您也不能对依赖于包含该变量的表达式的变量进行约束,并且运算符 //
和 %
不是t 为表达式定义。
针对您的特定情况的解决方法是在您求解的变量和您希望从中获得的值之间创建一个一对一的映射。偶数只是整数乘以 2,因此您可以删除显式均匀性约束并执行
constraints = [
ipp == 1e9 / 3e6 * div, # Constrain IPP to divisor
div >= 1, div <= 32768, # Divisor must be 2-65536
]
objective = cp.Minimize(cp.abs(ipp - wantipp)) # Find closest possible IPP
打印解决方案时,显示两倍的解决值:
print('IPP %.3f nsec (%.3f Hz) -> Divisor %d %.3f nsec (%.3f Hz)' % (
i, 1e9 / i, 2 * div.value, ipp.value, 1e9 / ipp.value
))
更好的是,使用更现代的 f 弦代替旧式插值:
print(f'IPP {i:.3f} nsec ({1e9 / i:.3f} Hz) -> Divisor {2 * div.value} {ipp.value:.3f} nsec ({1e9 / ipp.value:.3f} Hz)')
创建约束为偶数的变量 x 的完全标准方法是添加整数变量 y 和约束 x=2y。