Skip to content
Back to formatted view

Raw Message

Message-ID: <dfb68d74-a7ed-cd8d-d69d-10aaf565f8a7@comcast.net>
Date: 2019-02-02T18:29:29Z
From: Alan Feuerbacher
Subject: [FORGED] Newbie Question on R versus Matlab/Octave versus C
In-Reply-To: <alpine.BSF.2.00.1901292221200.83151@pedal.dcn.davis.ca.us>

On 1/29/2019 11:50 PM, Jeff Newmiller wrote:
> On Tue, 29 Jan 2019, Alan Feuerbacher wrote:
> 
>> After my failed attempt at using Octave, I realized that most likely 
>> the main contributing factor was that I was not able to figure out an 
>> efficient data structure to model one person. But C lent itself 
>> perfectly to my idea of how to go about programming my simulation. So 
>> here's a simplified pseudocode sort of example of what I did:
> 
> Don't model one person... model an array of people.
> 
>> To model a single reproducing woman I used this C construct:
>>
>> typedef struct woman {
>> ?int isAlive;
>> ?int isPregnant;
>> ?double age;
>> ?. . .
>> } WOMAN;
> 
> # e.g.
> Nwomen <- 100
> women <- data.frame( isAlive = rep( TRUE, Nwomen )
>  ?????????????????? , isPregnant = rep( FALSE, Nwomen )
>  ?????????????????? , age = rep( 20, Nwomen )
>  ?????????????????? )
> 
>> Then I allocated memory for a big array of these things, using the C 
>> malloc() function, which gave me the equivalent of this statement:
>>
>> WOMAN women[NWOMEN];? /* An array of NWOMEN woman-structs */
>>
>> After some initialization I set up two loops:
>>
>> for( j=0; j<numberOfYears; j++) {
>> ?for(i=1; i< numberOfWomen; i++) {
>> ?? updateWomen();
>> ?}
>> }
> 
> for ( j in seq.int( numberOfYears ) {
>  ? # let vectorized data storage automatically handle the other for loop
>  ? women <- updateWomen( women )
> }
> 
>> The function updateWomen() figures out things like whether the woman 
>> becomes pregnant or gives birth on a given day, dies, etc.
> 
> You can use your "fixed size" allocation strategy with flags indicating 
> whether specific rows are in use, or you can only work with valid rows 
> and add rows as needed for children... best to compute a logical vector 
> that identifies all of the birthing mothers as a subset of the data 
> frame, and build a set of children rows using the birthing mothers data 
> frame as input, and then rbind the new rows to the updated women 
> dataframe as appropriate. The most clear approach for individual 
> decision calculations is the use of the vectorized "ifelse" function, 
> though under certain circumstances putting an indexed subset on the left 
> side of an assignment can modify memory "in place" (the 
> functional-programming restriction against this is probably a foreign 
> idea to a dyed-in-the-wool C programmer, but R usually prevents you from 
> modifying the variable that was input to a function, automatically 
> making a local copy of the input as needed in order to prevent such 
> backwash into the caller's context).

Hi Jeff,

I'm well along in implementing your suggestions, but I don't understand 
the last paragraph. Here is part of the experimenting I've done so far:

*=======*=======*=======*=======*=======*=======*
updatePerson <- function() {
   ifelse( women$isAlive,
     {
# Check whether to kill off this person, if she's pregnant whether
# to give birth, whether to make her pregnant again.
       women$age = women$age + timeStep
# Check if the person has reached maxAge
     }
   )
}

calculatePopulation <- function() {
   lastDate = 0
   jd = 0
   while( jd < maxDate ) {
     for( i in seq_len( nWomen ) ) {
       updatePerson();
     }
     todaysDateInt = floor(jd/dpy)
     NAlive[todaysDateInt] = nWomen - nDead
# Do various other things
     todaysDate = todaysDate + timeStep
     jd = jd + timeStep
   }
}

nWomen <- 5
numberOfYears <- 30
women <- data.frame( isAlive = rep_len( TRUE, nWomen )
                    , isPregnant = rep_len( FALSE, nWomen )
                    , nChildren = rep_len( 0L, nWomen )
                    , ageInt = rep_len( 0L, nWomen )
                    , age = rep_len( 0, nWomen )
                    , dateOfPregnancy = rep_len( 0, nWomen )
                    , endDateLastPregnancy = rep_len( 0.0, nWomen )
                    , minBirthAge = rep_len( 0, nWomen )
                    , maxBirthAge = rep_len( 0, nWomen )
                    )

# . . .

   calculatePopulation()

*=======*=======*=======*=======*=======*=======*

The above code (in its complete form) executes without errors. I don't 
understand at least two things:

In the updatePerson function, in the ifelse statement, how do I change 
the appropriate values in the women dataframe?

I don't understand most of your last paragraph at all.

Thanks so much for your help in learning R!

Alan

---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus