2011-10-15 4 views
2

저는 Mathematica의 난수 생성기를 여러 가지 조건으로 억제했습니다. 지금 내 코드는 다음과 같습니다Mathematica에서 while 루프 : 복수 출력

list = RandomSample[Range[36], 7]; 
f := If[1 <= Count[Select[list, # <= 12 &], _Integer] <= 2, 
    If[Count[Select[list, # > 31 &], _Integer] >= 1, 
    If[Count[Select[list, Divisible[#, {2, 7}] &], _Integer] <= 3, 
    Sort[list], False], False], False] 
While[f == False, 
    list = RandomSample[Range[36], 7]; 
    If[list == f, f]]; 
f 

은 다음과 같이 구축이다

  1. F를 만들어 1-36 간격의 7 개 정수의 임의 목록은 몇 가지 조건을 정의하는 충족되어야한다 : 1-12 범위의 적어도 하나의 요소와 최대 두 개의 요소. 하나 이상의 요소가 31보다 큽니다. 최대 세 개의 요소는 2-7 범위의 정수로 나눌 수 있습니다.
  2. 조건이 충족되면 f가 목록과 같고 그렇지 않으면 False입니다.
  3. 다음 것은 "While"루프입니다. f가 False이면 새로운 목록이 생성되고이 루프는 f i가 False가 될 때까지 계속됩니다.
  4. f에 저장된 결과가 호출됩니다.

이제는 한 줄의 출력 만 생성됩니다. 다중 출력을 얻는 데 관심이 있습니다. 5-10. 내가 테이블 명령으로 어떤 식 으로든 그것을하려고 노력했지만, 것은 아무것도 함수 f와 while 루프를 동시에 정의하지 않는다. 그래서, f를 사용하여 테이블을 실행함으로써, 나는 많은 시간 동안 동일한 결과를 얻습니다.

여기 진행 방법에 대한 의견이 있으십니까?

+0

, 당신의 while 루프의 마지막 줄 while의 출력은';'로 인해 억제되므로 아무 것도하지 않습니다. 루프가 원하는 조건과 일치하는 목록을 선택하면 루프 뒤의'f'가 선택된 목록을 반환합니다. – rcollyer

답변

3

f 함수는 list을 매개 변수 대신 자유 변수로 참조합니다. 이것이 극복 할 수없는 장애물은 아니지만,이 기능을 패키지화하여 Table에서 사용할 수 있도록하는 것이 어렵습니다.이 정의를 재 작업하고 그 과정에서 단순화를 적용 해 봅시다.

먼저, 샘플이 수용 여부에 대한 테스트를 해결하자 : 원본

acceptableQ[sample_] := 
    MemberQ[sample, n_ /; n > 31] && 
    1 <= Count[sample, n_ /; n <= 12] <= 2 && 
    Count[sample, n_ /; divisible2to7[n]] <= 3 

divisible2to7[n_] := MemberQ[Range[2, 7], d_ /; Divisible[n, d]] 

주요 단순화는 중첩 된 If 문이 And 상태로 평평하게 된 것입니다. 새로운 정의는 또한 Count이 중첩 된 Select을 호출 할 필요없이 목록 값을 테스트 할 수 있다는 사실을 이용합니다. 또한 존재 확인은 MemberQ[...]을 사용하여 표시되었습니다. 헬퍼 함수는 주 테스트 표현의 시각적 복잡성을 줄이기 위해 나누기 검사를 수행하기 위해 도입되었습니다. 원래의 나눗셈 검사가 부울 값이 예상되는 목록을 잘못 반환하고있었습니다. _Integer 헤드 테스트가 제거되었지만 바람직하다고 생각되면 n_n_Integer으로 변경하여 다시 도입 할 수 있습니다. 허용 하나가 발견 될 때까지

이제 우리는 단지 루프에서 샘플을 생성하는 방법이 필요합니다 :

generateSample[] := 
    While[ 
    True 
    , RandomSample[Range[36], 7] /. 
     s_ :> If[acceptableQ[s], Return[Sort @ s]] 
    ] 

generateSample[] 필요에 따라 이제 많은 결과를 테이블을 생성하는 데 사용할 수 있습니다

In[113]:= Table[generateSample[], {5}] 

Out[113]= {{6, 13, 17, 19, 25, 29, 33}, {1, 11, 13, 15, 31, 35, 36}, 
      {1, 10, 17, 23, 25, 31, 32}, {1, 6, 17, 19, 22, 23, 33}, 
      {8, 17, 19, 23, 30, 31, 36}} 

패턴을 일반화하면

generateSample로 구현 패턴 ㄴ 수 즉, 각각의 루프를 통과에 새로이 평가 될 수 있도록

SetAttributes[generatorSelect, HoldFirst] 
generatorSelect[generator_, predicate_] := 
    While[True, generator /. s_ :> If[predicate[s], Return[s]]] 

generator 인자가 평가되지 않은 형태로 유지된다 : 임의 발생 및 필터링 기능을 수락 파라미터 E. 이 새로운 기능을 다음과 같이 사용할 수 있습니다.

In[114]:= Table[ 
      generatorSelect[RandomSample[Range[36], 7], acceptableQ] // Sort 
      , {5} 
      ] 

Out[114]= {{9, 17, 19, 23, 27, 29, 32}, {8, 13, 17, 19, 22, 23, 35}, 
      {4, 17, 19, 21, 23, 29, 36}, {1, 8, 15, 19, 23, 31, 33}, 
      {1, 10, 17, 19, 24, 29, 36}} 

새로운 기능의 장점은 모든 생성기 및 필터 기능과 함께 사용할 수 있다는 것입니다. 여기서 우리는 총 7 개의 합계 세 개의 튜플을 생성합니다. 스타일의 문제로

In[115]:= Table[ 
      generatorSelect[RandomInteger[7, 3], Total[#] == 7 &] 
      , {5} 
      ] 

Out[115]= {{2, 3, 2}, {0, 5, 2}, {5, 0, 2}, {2, 4, 1}, {2, 1, 4}} 

, 일부는 절대적으로 필요한 경우가 아니면 Hold 속성으로 함수를 정의하지 않도록하는 것을 선호합니다. generatorSelect2는 설계 선택을 반영

generatorSelect2[generator_, predicate_] := 
    While[True, generator[] /. s_ :> If[predicate[s], Return[s]]] 

이와 generatorSelect 사이의 유일한 차이는 첫 번째 인수는 이제 함수로 평가 것으로 예상된다는 점이다 : 서면으로

In[116]:= Table[ 
      generatorSelect2[RandomInteger[7, 3] &, Total[#] == 7 &] 
      , {5} 
      ] 

Out[116]= {{5, 1, 1}, {3, 0, 4}, {0, 1, 6}, {3, 2, 2}, {4, 1, 2}} 
+0

업데이트 : 나는 대신에'! FreeQ [...]'를 사용하여'MemberQ [...]'를 사용하는 것을 단순화했습니다. 처음으로 무엇을 생각하고 있었는지 확신 할 수 없습니다. 또한 부정확 한 나누기 테스트 ('divisible2To7' ->'divisible2to7', 오타가 아닌 언어의 위험)가 발생하는 오타를 수정했습니다. – WReach

2

이에 대한 ReapSow를 사용할 수 있습니다

n = 1; [email protected]@[email protected][n < 4, Sow[n++]] 

(*=> {1, 2, 3}*) 

은 내가 NestWhileList보고도 추천합니다 : 그것은 당신의 요구에 매우 적합한 찾을 수 있습니다.

2

괜찮습니다. 가능한 혼합 유형, 목록 및 불린 비교를 위해 SameQ (===)를 사용합니다. 예 : {4, 7, 17, 22, 25, 27, 34} == False은 평가되지 않습니다.

f := If[1 <= Count[Select[list, # <= 12 &], _Integer] <= 2, 
    If[Count[Select[list, # > 31 &], _Integer] >= 1, 
    If[Count[Select[list, Divisible[#, {2, 7}] &], _Integer] <= 3, 
    Sort[list], False], False], False] 

g := (list = RandomSample[Range[36], 7]; 
    While[f === False, list = RandomSample[Range[36], 7]; 
    If[list === f, f]]; 
    f) 

Table[g, {9}] 
4

나는 f의 당신의 정의에서 세 번째 줄은 당신이 그것을하고있어 무슨 생각을하고 있다고 생각하지 않습니다. 하지 중 하나 True 또는 False{True, False}을 반환 예를

Divisible[20, {2, 7}] 

에 대해 생각해 보자. 즉, Select[list, Divisible[#, {2, 7}] &]은 항상 빈 목록을 반환하고 Count[Select[list, Divisible[#, {2, 7}] &], _Integer] 은 항상 0을 반환합니다. 내가 제대로 목록에 대한 조건을 해석하는 경우

, 대신 SowReap를 사용하는

Count[Select[list, Or @@ Divisible[#, Range[2, 7]] &], _Integer] <= 3 
이와

와 알렉세이의 제안 같은 것을 사용할 수 있습니다, 당신처럼 뭔가를 할 수

f[list_] := And[ 
    1 <= Count[Select[list, # <= 12 &], _Integer] <= 2, 
    Count[Select[list, # > 31 &], _Integer] >= 1, 
    Count[Select[list, Or @@ Divisible[#, Range[2, 7]] &], _Integer] <= 3] 

Block[{n = 0, list}, 
    Reap[While[n < 5, list = [email protected][Range[36], 7]; 
    If[f[list], n++; Sow[list]]]]][[2, 1]] 
+0

나눌 수있는 명령을 고려해 볼 때 조건에 완전히 동의합니다. 나는 그것을 간과했습니다! Sow and Reap 사용에 대한 제안을 많이 해 주셔서 감사합니다. 이것에 대해 생각해 보았지만 결코 작동시키지 못했습니다! – thesixmax