把有界凸空間中所有點輸出的演算法討論

2021-07-03 18:07:44 字數 3977 閱讀 3848

華電北風吹

最後修改日期:2015/8/6

如果只有一些線性約束,想把所有的可行解都輸出出來怎麼辦?

例如下面的小例子:

約束條件為|a

1x1+

a2x2

+a3x

3+..

.+an

xn−b|m1

=<=m1m2=

<=m2

… mn

=<=mn

最簡單的方法肯定是把所有的點根據超矩形約束條件遍歷一遍,然後把與到超平面距離滿足約數的點輸出。

我寫了個小例子,如下,迴圈把所有的可行解個數輸出。

__author__ = 'zhengyi'
defmainfunc

(m0,m,x):

if len(m)>0:

k1=m0[0]

k2=m[0]

for i in range(k1,k2+1):

t=x.copy()

mainfunc(m0[1::],m[1::],t)

else:

if distance(x)<=e:

print(x)

defdistance

(x):

result=map(lambda x,y:x*y,a,x)

return abs(sum(result)-b)

a=[20,30]

b=90

m=[5,5]

m0=[2,0]

e=20

x=mainfunc(m0,m,x)**執行結果為:

[2, 1]

[2, 2]

[3, 1]

[4, 0]

[4, 1]

[5, 0]

但是當特徵個數增大的時候,這個計算時間會特別大。因為,計算時間複雜度是theta(mn

)。其中m為每個特徵的取值範圍,n為特徵維數。

考慮到即使你知道那個解是可行解,把所有的解輸出也需要迴圈n次。因此如果想要減少計算量,貌似只能減少在無用解上的計算次數。這時候我們可以考慮先在可行解內部獲取乙個初始點,然後以這個初始點為中心,在可行解空間中向外圍搜尋,直到到達可行解邊界。

這樣做需要考慮搜尋方向問題。比較好的一點是,由線性約束的可行解構成的空間肯定是乙個凸空間。因此可以想到以下兩種搜尋策略:

1、根據特徵遞迴迴圈(這裡有缺陷,就是如果不讓下層特徵對上層特徵進行搜尋的話,需要保證當前特徵搜尋路徑是最寬的,這個就很麻煩了)

2、根據空間的外方向,逐層外擴(這也是下面**採用的思想)

__author__ = 'zhengyi'
defmainfunc

(x,d):

flag=true

for i in range(0,len(d)):

x[i]+=d[i]

if x[i]or x[i]>m[i]:

return

if d[i]!=0

and flag:

flag=false

if flag:

return

if distance(x)>e:

return

print(x)

mainfunc(x.copy(),d.copy())

for i in range(0,len(d)):

if d[i]!=0:

td=d.copy()

td[i]=0

mainfunc(x.copy(),td)

defdistance

(x):

result=map(lambda x,y:x*y,a,x)

return abs(sum(result)-b)

a=[20,30]

b=90

m=[5,5]

m0=[2,0]

e=20

x=[2,2]

print(x)

d=[-1

for i in range(0,len(a))]

k=pow(3,len(a))

for i in range(1,k):

td=d.copy()

j=0while i>0:

td[j]+=i%3

i//=3

j+=1

mainfunc(x.copy(),td)**輸出結果:

[2, 2]

[2, 1]

[3, 1]

[4, 0]

[5, 0]

[4, 1]

但是這個演算法的複雜度仍舊是theta(3^n),因為每一維都有3中選擇,共同構成的空間外方向數目就是3n

−1種。這樣的搜尋策略能夠保證搜尋一直在可行解內部搜尋,**計算效率比較高,這是我目前想到的最好的方法,歡迎對這個問題感興趣的有想法的朋友一起討論。

補充:

第二種方法需要在可行解內找乙個初始點,由於這個問題不是主要問題,可以由隨便指定乙個優化函式,然後利用單純形法得到乙個初始解。在這裡我為了方便,使用lingo得到乙個初始解。

lingo**如下:

model:
sets:

s/1.

.20/:a,x,m0,m;

endsets

data:

a=20,30,15,17,20,20,20,20,30,15,17,20,20,20,20,30,15,17,20,20;

m=5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5;

m0=2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0;

enddata

@abs(@sum(s(i):a(i)*x(i))-1000)<100;

@for(s(i):m0(i)i));

@for(s(i):x(i)i));

@for(s(i):@gin(x(i)));

end**1的非遞迴形式:

__author__ = 'zhengyi'
defdistance

(x):

result=map(lambda x,y:x*y,a,x)

return abs(sum(result)-b)

a=[20,30]

b=90

m=[5,5]

m0=[2,0]

e=20

k=len(a)

totalnum=1

original=m0.copy()

rangelist=[0

for i in range(0,k)]

for i in range(0,k):

rangelist[i]=m[i]-m0[i]+1

totalnum*=rangelist[i]

for i in range(0,totalnum):

s=original.copy()

p=0while i>0:

s[p]=original[p]+i%(rangelist[p])

i=i//(rangelist[p])

p+=1

if distance(s)<=e:

print(s)作為對比,放乙個相似問題的解法

參考**:

#include 

#include

using

namespace

std;

int main(int argc, char* argv)

else}}

}}}}

cout

<< count << endl;

getchar();

return

0;}

Scipy空間 計算凸包(convexHull

凸包 數學上指,在實向量空間v中的一組點x的凸包或凸包絡是包含x的最小凸集。通俗的來說就是包圍一組散點的最小凸邊形。在scipy.spatial 中計算凸包的函式,scipy中convexhull輸入的引數可以是m2的點座標。其返回值的屬性.verticess是所有凸輪廓點在散點 m2 中的索引值。...

把Gmail空間當磁碟使用

把gmail空間當磁碟使用 by webleon 今天早上 zheng 那裡看到了這個神奇的軟體,可以把gmail的1000m空間作為乙個虛擬磁碟來使用。當然,你可以像操作硬碟一樣,在這個磁碟中進行複製貼上等工作,非常方便。乙個多月前,richard jones就提出了 gmailfs 的概念,並開...

如何把資料匯入不同的表空間

使用者unlimited tablespace許可權 這樣就可以匯入到使用者預設表空間 sql create user bjbbs identified by passwd 2 default tablespace bjbbs 3 temporary tablespace temp 4 user c...