Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Theory Help 4

Status
Not open for further replies.

Scott24x7

Programmer
Jul 12, 2001
2,826
JP
Hi All,
I'm having some difficulty getting my head around an "experiment" I'm trying to run. (This is just for some idea I have related to a thought experiment I'm working on and thought that I could generate a data set based on it, but I'm stuck on how to actually make it work).
The idea is based on Duffey & Saull's "Jar of Life" experiment, which has 25 white balls, and 5 black balls which are in a jar. Each of the 30 balls is drawn in succession. At the end you have a result that would look something like:


Where W = W=white and B = black.
SO this sequence is a random sequence every time, but there will always be exactly 25 White and 5 Black (this is the part that is doing my head in).

I created a routine to randomize 0 and 1 (Where 0 represents white, and 1 represents black) This I will actually store in a text field in a table, C30 in length, so later I can just use SQL commands to pluck out the patterns that I want after I run about 1,000,000 iterations of the test.

So I can do something like:
Code:
White = 0
Black = 1
APPEND BLANK
FOR X = 1 to 30
   REPLACE SEQUENCE WITH ALLTRIM(SEQUENCE)+ALLTRIM(STR((INT((White - BLACK + 1) * RAND( ) + Black))
ENDFOR

I'll of course bury that into a loop that runs 1,000,000 iterations, but this is the idea.

The problem is, HOW do I get it to produce only 25 White outcomes and 5 black outcomes in an iteration???


Best Regards,
Scott
MSc ISM, MIET, MASHRAE, CDCP, CDCS, CDCE, CTDC, CTIA, ATS

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Hi,

You may additionally want to check the occurrences of "W" and "B" in your sequence

Code:
pseudo code
for i = 1 to 30
...
if OCCURS("W", Sequence) = 25 or OCCURS("B", Sequence) = 5
[indent]if OCCURS("W", Sequence) = 25 - replace rest 5 with "B" - end loop [/indent]
[indent]if OCCURS("B", Sequence) = 5 - replace rest 25 with "W" - end loop [/indent]
endif
...
endfor

hth
MK
 
Hi mjmksksr,
I explained the W and B for simplicty as that's the terms used by creator, but I just want to use 0 and 1 as it will be much simpler to deal with. This way I just have one value, and I don't have to do any converting. So a 0 will represent White and a 1 will represent Black.
If I REALLY wanted to after all the sequences were run, I could always do an STRTRAN to convert 0 to W and 1 to B, but really not necessary.

So the issue I still have is, how do I do the draw but ensure that only 25 0 and 5 1 are always produced?


Best Regards,
Scott
MSc ISM, MIET, MASHRAE, CDCP, CDCS, CDCE, CTDC, CTIA, ATS

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Interesting question, Scott. It merits some deep thought.

But just off the top of my head, how about something like this:

1. Create a 2 col. x 30 row array.

2. Populate the first column with your 25 zeroes and 5 ones.

3. Populate the second column with a random number.

4. ASORT the array on the second column.

5. Concatenate the values in the first column - in the new sequence - into your string.

6. Repeat one million time.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Hi,

Please have a look at the code below

Code:
LOCAL Sequ
LOCAL ARRAY laSequ[1]

sequ = ""

FOR J = 1 TO 5
	FOR X = 1 to 30
	   SEQU = ALLTRIM(SEQU) + ALLTRIM(STR((INT((1 - 0 + 1) * RAND( )) + 0)))
	   
*!*		   WAIT WINDOW + sequ TIMEOUT .1
	   
			IF OCCURS("1", Sequ) >= 25 
				sequ = SEQU + REPLICATE("0", 30 - LEN(SEQU))
				X = 30
			ENDIF
			
			IF OCCURS("0", Sequ) >= 5
				sequ = SEQU + REPLICATE("1", 30 - LEN(SEQU))
				X = 30
			ENDIF
		

	ENDFOR 
	
	DIMENSION laSequ[j]
	laSequ[j] = sequ
	sequ = ""
ENDFOR

DISPLAY MEMORY LIKE laS*

hth

MK
 
Scott

A quick code on this, by stuffing blues into whites:
Code:
LOCAL Result AS String
LOCAL Whites AS Integer
LOCAL Blues AS Integer
LOCAL White AS Character
LOCAL Blue AS Character
LOCAL StoreBlue AS Integer

m.Blues = 5
m.Whites = 25

m.White = "0"
m.Blue = "1"

m.Result = REPLICATE(m.White, m.Blues + m.Whites)

FOR m.StoreBlue = 1 TO m.Blues
	m.Result = STUFF(m.Result, AT(m.White, m.Result, 1 + RAND() * FLOOR((m.Blues + m.Whites) - m.StoreBlue)), 1, m.Blue)
ENDFOR

? TEXTMERGE("<<m.Result>> / Whites: <<OCCURS(m.White, m.Result)>> Blues: <<OCCURS(m.Blue, m.Result)>>")
 
Instead of randomly generating 0 and 1 and hoping you get 25 of one and 5 of the other, why not compute 5 distinct(!) positions where the 1 should go?

You can also fill 25 collection elements´, 20 with "0" and five with "1" and then draw from that like from a hat. That guarantees the amount you need.
Code:
Local lnI, lnItem

=Rand(-1) && randomize random number generator
loBitcollection = CreateObject("collection")

For lnI = 1 to 20
   loBitcollection.Add("0")
Endfor 

For lnI = 1 to 5
   loBitcollection.Add("1")
Endfor 

lcCombination = ""
For lnI = 1 to 30
   lnItem = 1+Int(Rand()*loBitcollection.Count)
   lcCombination = lcCombination + loBitcollection.Item(lnItem)
   loBitcollection.Remove(lnItem)
EndFor

?lcCombination

Notice, if you generate these combinations randomly, there is a likelyhood you generate the same sequence twice. 5 bits set in 30 bits has about 17 million possible combinations. (30 over 5)

Bye, Olaf.

Olaf Doschke Software Engineering
 
Computing the 5 positions is cheaper, as you only need to draw 5 positions of set bits:

Code:
Local lnI, lnItem, lnPos

=Rand(-1) && randomize random number generator
loBitcollection = CreateObject("collection")

For lnI = 1 to 30
   loBitcollection.Add(lnI)
Endfor 


lcCombination = Replicate("0",30)
For lnI = 1 to 5
   lnItem = 1+Int(Rand()*loBitcollection.Count)
   lnPos = loBitcollection.item(lnItem)
   loBitcollection.Remove(lnItem)
   lcCombination = Stuff(lcCombination,lnPos,1,"1")
EndFor

?lcCombination

Bye, Olaf.

Olaf Doschke Software Engineering
 
Even cheaper to pick 5 positions from a cursor with random order, since only a reindex is necessary to compute a new combination, once the cursor is created with 30 rows.
Code:
Local lnI
=Rand(-1)
Create Cursor crsBits (cBit C(1))
For lnI = 1 To 30
   Insert Into crsBits Values (Iif(lnI<=25,"0","1"))
Endfor
Index On Rand() Tag xrandom

For lnI = 1 To 10 && compute 10 combinations
   lcCombination = ""
   Reindex
   Scan
      lcCombination = lcCombination + cBit
   Endscan
   ? lcCombination
Endfor

Bye, Olaf.

Olaf Doschke Software Engineering
 
Hi Scott,
I did it just based on a simple string not with 25 columns though.

Code:
LOCAL lcString as Character
lcString = REPLICATE( [0] , 25 )
DO WHILE OCCURS( [1] , lcString ) < 5
	lcString = STUFF( lcString , INT( RAND() * 25 ) , 1 , [1] )
ENDDO 
?lcString

It's based on the fact, that in the first lane there are 25 Ws and then we place random Bs until there are 5 Bs in the string.
As I just noticed, it is more or less the string based version of Olafs code :)

-Tom
 
Tom, in your case you don't need to replace, you need to use stuff to add a character without removing a 0.

And since the string length then grows from 25 to 30 you also need to compute int(rand()*len(lcString)+1, don't forget the +1. stuff works with start position =0, but then does the same as with start position 1. You are allowed to go to position length+1 to add the new string at the end, so you actually need int(rand()*(len(lcString)+1))+1.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Sorry, yes, the Replicate() has to be 30 not 25, otherwise there are only 20 Ws left :)

So changing the code to

Code:
LOCAL lcString as Character
lcString = REPLICATE( [0] , 30 ) && 25 changed to 30
DO WHILE OCCURS( [1] , lcString ) < 5
	lcString = STUFF( lcString , INT( RAND() * 30 ) , 1 , [1] )
ENDDO 
?lcString

should be enough.

-Tom
 
[pre]#Define crlf Chr(12)+Chr(10)
Local lcReturn, lcX, lnX
m.lcReturn = []
Rand(-1)
For m.lnX = 1 To 10
Do While .T.
m.lcX = Num2bin30(2 ** 30 * Rand())
If Occurs([1], m.lcX ) = 5
m.lcReturn = m.lcReturn + m.lcX + crlf
Exit
Endif
Enddo
Endfor
Messagebox( m.lcReturn)

Function Num2bin30
Lparameters tnValue
Local lcValue, lnX
m.lcValue = []
For m.lnX = 0 To 29
m.lcValue = m.lcValue + Iif(Bittest(m.tnValue, m.lnX), [1], [0])
Endfor
Return m.lcValue[/pre]

Update: corrected a minor error. I forgot that Bittest() is 0-based.
 
I like Mike's suggestion, don't sort the numbers - shuffle the pigeon holes

Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.
 
Coming back for a correction to allow the last position to be chosen as a place to stuff some Blue:

Code:
	m.Result = STUFF(m.Result, AT(m.White, m.Result, 1 + RAND() * ((m.Blues + m.Whites + 1) - m.StoreBlue)), 1, m.Blue)
 
@Griff,

well, ASORT would also sort the "0" and "1", but just like a cursor sorted by INDEX ON Rand() you can use that universally no matter what characters or bits you want in which combination and the count will match.

Chances you create a 30 bit number with 5 bits set are about 17 million: 2^30 and that is quite bad, as high as 17 million sounds, 2^30 is ~1 billion. So it comes down to 2% only, so you'd generate 50 numbers in average before you get one matching the conditions. It's not that bad as the other solutions also generate 30 random numbers, but it gets far worse with other conditions, eg there only are 30 combinations with just 1 bit set in 2^30. Hit or miss is almost always a miss. Same as 29 bits set = 1 bit unset. But these cases are simple just computing 1 position.

Bye, Olaf.

Olaf Doschke Software Engineering
 
My thinking was just that the simplicity of his answer and the clarity with which the execution could be enabled was thus a truly elegant solution.

Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.
 
WOW
I wasn't expecting there to be SO many amazing answers to this! I posted this up about 12 hours ago, and then went off forgetting about it for a while, and just came back to Tek-Tips and found all these replies!
First, thanks to all, totally cool, and I love how there are so many approaches to this.
I will try several of them, and see what comes up from this.
Just to mention some context, I'm looking at simulating "failure" scenarios, and wanted to look at the stochastic distribution of failures. Some of you may know, I'm in the thesis phase of my doctorate, and I had this crazy idea last night, and tried to model it, just to get a glimpse of what the result would look like. My "thinking" is major catastrophe are represented by not the appearance of the black, but the appearance of all 5 black in a row. But I'm going to be testing this theory, so the number of white and number of black may change, until I can find a typical occurrence. I just wanted to start with a million iterations as a point to see how often this will occur.
When I win the Nobel Prize, I'll make sure to thank everyone here in the acceptance speech. ><


Best Regards,
Scott
MSc ISM, MIET, MASHRAE, CDCP, CDCS, CDCE, CTDC, CTIA, ATS

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Ok, Very interesting results here.
The 1,000,000 iterations only take about 20 seconds to run using Tom Borgamanns very elegant solution.
Thought you guys might like to know, of the first test set of 1,000,000 there were 187 were all 5 occur in a row.
But a quick look at the result set shows this may not be giving me the randomness I need. One interesting thing is the occurrence of 5 1's in a row at the start appeared 17 times, but the appearance of all 5 1's at the end occurs 0 times.
So that's the first test, but I can see this isn't giving me a stochastic distribution. So next, I think I'll give one of Olaf's solutions a try.


Best Regards,
Scott
MSc ISM, MIET, MASHRAE, CDCP, CDCS, CDCE, CTDC, CTIA, ATS

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top