* i need inspiration as well, and some clever coding

For users to report plugin bugs and request plugin enhancements; and for authors to test new/new versions of plugins, and to discuss plugin development (in the Programming Technicalities sub-forum). If you want advice on choosing or using a plugin, please ask in General Usage or an appropriate sub-forum.
User avatar
Ron Melby
Megastar
Posts: 928
Joined: 15 Nov 2016 15:40
Family Historian: V6.2

i need inspiration as well, and some clever coding

Post by Ron Melby »

being massively dissatisfied with birth and death date estimations, I am trying to write a fairly lightweight chunk that will do some cooking on dates. what I hope is that there is a way to glean several dates that will sort of coalesce around a reasonable range:

for instance:
gen 0: I have me, no birth date
gen1: my father no birth date
gen2: my grand father born 1887
ok, so one can see for estimation I need a multiplier (generation!)
simply illustrated:
assume a man is a father on average at 25. assume it takes 1 year to have a baby.
(already wrong I know..but)
so 1887+ 25 * 2gen) + 2gen years babymaking results in births:
gen 2: gf 1887
gen 1: f 1913
gen 0: me 1939
actual are
2.gf 1887
1.f 1918 (2nd son so add 1 there and 1914, but we aint there yet)
0.me 1954 so 15 years lite, but my father was married late (after the war, and my mothers 2nd marriage so that has to factor in, she was born 1922 but let us leave the complexities for a moment)
where can I get dates to help with estimation, wife born, marr, ancestor births, marr, and so on, children born...
so I found a fairly light frame for ancestors and descendants when I went shopping in the code snippets.
it is fundamentally the exact program in snippets decorated, and while it was easy to decide where the generations were on ancestors, on descendants not so easy.

to demonstrate:

geo and ruth ( my ggf 1869 my ggm 1871)
geo jr 1890
flossy 1897 not handy
beatrice 1902
lester 1907
leslie 1907

their children
geo jr 0
flossy 4
beatrice 1
lester and leslie (twins) 0

it is trivial to get the generation in ascendency **and know it before I make the table entry** which generation I am on (my multiplier) when hunting for dates.
at some point, I would expect the not so random dates I collect to coalesce in a reasonable time frame. I will have to do a sideways (his wife ) and a 1 up, his brothers and sisters, but otherwise it is parents by generation, and downwards by generation and work back with negatives that is
born 1954 - 2 gen * 25 = 1900 (for my 1887 grandfather. again, much more complex calcs than are explained here, but I have around 60% of my file with no birth and or death, and would like to estimate it better.

anyway, can someone figure out a clever way to straightforwardly count generations without going to gen=fhCallBuiltinFunction("RelationCode") every time?

Code: Select all

--[[
@function: IsInList
@description: Adds rcdid as value and index to table if it does not already exist
@parameters: Item Pointer - Must be at Record Level
@returns: true if pointer is a duplicate
@requires: none
]] 
function IsInList(table, iptr)
  local rcdid = fhGetRecordId(iptr)
  if table[rcdid] == nil then
    table[rcdid] = rcdid
    return false
  else
    return true
  end
end --fn IsInList

--[[
@function: rtvAncestors
@description: Returns a list of Ancestors
@parameters: Item Pointer - Must be at Record Level
@returns: table of record Item Pointers
@requires: IsInList
]] 
function rtvAncestors(iptr)
  local ancestors  = {}
  local inlist     = {}
  local ent        =  0
  local gen        =  0  

  local ptrBAS  = fhNewItemPtr()
  local ptrFAMC = fhNewItemPtr()
  local ptrHUSB = fhNewItemPtr()
  local ptrWIFE = fhNewItemPtr()

  table.insert(ancestors, iptr:Clone())
  IsInList(inlist, iptr)

  ent = 1
  while ent <= #ancestors do
    ptrBAS = ancestors[ent]
    -- Loop Family as Child
    ptrFAMC:MoveTo(ptrBAS,'~.FAMC')
    while ptrFAMC:IsNotNull() do
      gen = gen + 1
      ptrHUSB:MoveTo(fhGetValueAsLink(ptrFAMC), '~.HUSB>')
      if ptrHUSB:IsNotNull() 
      and (not IsInList(inlist, ptrHUSB)) then
        table.insert(ancestors, ptrHUSB:Clone())
      end
      ptrWIFE:MoveTo(fhGetValueAsLink(ptrFAMC), '~.WIFE>')
      if ptrWIFE:IsNotNull() 
      and (not IsInList(inlist, ptrWIFE)) then
        table.insert(ancestors, ptrWIFE:Clone())
      end
      ptrFAMC:MoveNext('SAME_TAG')
    end
    ent = ent + 1
  end
  return ancestors
end --fn rtvAncestors 

--[[
@function: rtvDescendants
@description: Returns a list of decendants
@parameters: Item Pointer - Must be at Record Level
@returns: table of record Item Pointers
@requires: IsInList
]] 
function rtvDescendants(iptr)
  local decendants = {}
  local inlist     = {}
  local ent        =  0
  local gen        =  0 

  local ptrBAS   = fhNewItemPtr()
  local cptrFAMS = fhNewItemPtr()
  local ptrFAMS  = fhNewItemPtr()
  local cptrCHIL = fhNewItemPtr()
  local ptrCHIL  = fhNewItemPtr()

  table.insert(decendants, iptr:Clone())
  IsInList(inlist, iptr)
  ent = 1
  while ent <= #decendants do
     ptrBAS = decendants[ent]
    -- Loop Family as Spouse
    cptrFAMS:MoveTo(ptrBAS, '~.FAMS')
    while cptrFAMS:IsNotNull() do
      ptrFAMS = fhGetValueAsLink(cptrFAMS)
      -- Loop Children
     cptrCHIL:MoveTo(ptrFAMS, '~.CHIL')
      while cptrCHIL:IsNotNull() do 
        ptrCHIL = fhGetValueAsLink(cptrCHIL)
        if ptrCHIL:IsNotNull() 
        and not IsInList(inlist, ptrCHIL) then
          table.insert(decendants, ptrCHIL:Clone())
        end
        cptrCHIL:MoveNext('SAME_TAG')
     end
      cptrFAMS:MoveNext('SAME_TAG')
    end
    ent = ent + 1
  end
  return decendants
end --fn GetDecendantList


-- USAGE:
tblROOT = fhPromptUserForRecordSel('INDI', 1)
if #tblROOT == 0 then
  return
--  table.insert(decendants, fhGetValueAsLink(cptrCHIL))
end

local ptrINDI = tblROOT[1]
local tblAncs = rtvAncestors(ptrINDI)
local tblDesc = rtvDescendants(ptrINDI)
return
FH V.6.2.7 Win 10 64 bit
User avatar
tatewise
Megastar
Posts: 28410
Joined: 25 May 2010 11:00
Family Historian: V7
Location: Torbay, Devon, UK
Contact:

Re: i need inspiration as well, and some clever coding

Post by tatewise »

I contemplated something along those lines when I found some anomalies in the FH estimates.
However, apart from those few anomalies, I find the FH estimates are about as good as one could expect.
So, I decided it was much easier to write workarounds for the more glaring anomalies.
Those workarounds are published as code snippet functions:
plugins:code_snippets:estimated_birth_dates|> Estimated Birth Dates (code snippet)
plugins:code_snippets:estimated_death_dates|> Estimated Death Dates (code snippet)
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
User avatar
Ron Melby
Megastar
Posts: 928
Joined: 15 Nov 2016 15:40
Family Historian: V6.2

Re: i need inspiration as well, and some clever coding

Post by Ron Melby »

I use those to no avail. the bulk of my INDIs have no events other than the birth death marriage of 5500 +, 3 christenings, for instance
FH V.6.2.7 Win 10 64 bit
User avatar
tatewise
Megastar
Posts: 28410
Joined: 25 May 2010 11:00
Family Historian: V7
Location: Torbay, Devon, UK
Contact:

Re: i need inspiration as well, and some clever coding

Post by tatewise »

The anomalies are not to do with the types of events, but where there are Date Ranges instead of simple Dates.
If your data only has dated BMD events, then I am doubtful if a Plugin could do much better than FH.
However, as always, that is your choice.
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
User avatar
Ron Melby
Megastar
Posts: 928
Joined: 15 Nov 2016 15:40
Family Historian: V6.2

Re: i need inspiration as well, and some clever coding

Post by Ron Melby »

I believe we both understand that. Were I so lucky that I had relatives who were forthcoming with actual squirreled away photos, documents and whatnot, I would have much of that. Instead of them actually looking I am presented with either indifference or LORE (in fact I have made such an event) and memories (dimly, thru a dark mirror) MEM in my file. In the case of my great grandfather, whom I knew, and all his offspring:

they came over to the US from Wittersham Kent where they were leaving Bethersden, Kent to prepare. In a sailboat, a child of theirs died along the way. they arrived NY 24 Apr 1871. I have that 1871 census in Wittersham, Finally, 5 years later, having searched and searched high and low for the sailboat and etc, I find that they left (99% sure, from Liverpool) and I dont need to tell you your countries geography, Bethersden>Wittersham>Liverpool is the long way around the barn, there was something else afoot in the move.

They either sailed from Liverpool or a bit up the coast Ireland, I chose to believe the closer, on general principle. They sailed on the "City of London" which indeed had sails, and a stack...they arrived in NY 1 Jan 1871 cannot find when that ship left Liverpool (they also made norwegian trips and that is well documented) and as the ship roll was being taken there were two families listed in line with one exception, the little girl from the other family was registered in the middle of mine, I expect kids playing...and she might have died, but no relation to me or my family. So, just figuring families I know and grew up with is like cutting tarpstraps all day. So, I feel I need extraordinary good estimates to hunt people. Half my husbands and wives and children are Husband [Sibley] (from the wifes name) or Wife Laron (know her last) or Female Sibley. every so often in a census I hit a goldmine of 20 or so, and get them caught up, but a great number I dont even have places for. I know most of them are between NY and the northern route in the US. PA, IN. IL, MI, WI, MN, ND, MT. well, thats me. thats why. PS, for the first go round, I have caved and went RelationCode what would be nice is to have access to the tree and to set pointer root from code, because my bets is the tree is a network type graph and the relations as well, because if you set file root from the menu, the root, relations and generations are immediately changed. for this reason, I do not believe it is a simple tree behind it, but it would be nice to change the root (not play change it) in software. trivial to save/restore the original root after machinations are complete.
FH V.6.2.7 Win 10 64 bit
User avatar
Jane
Site Admin
Posts: 8514
Joined: 01 Nov 2002 15:00
Family Historian: V7
Location: Somerset, England
Contact:

Re: i need inspiration as well, and some clever coding

Post by Jane »

Just to echo what Mike said estimates will never be "right", in a murder I am researching at the moment the victim was accompanied by his son and grandson.

The son was 19, his youngest son and the grandson 15, the son of the victims oldest child.

So even in a single generation the gaps can vary a great deal.

Liverpool was the main port of exit for North America, remember it's only a few hours by train from London. There were also some sailings from Southampton.
Jane
My Family History : My Photography "Knowledge is knowing that a tomato is a fruit. Wisdom is not putting it in a fruit salad."
User avatar
Ron Melby
Megastar
Posts: 928
Joined: 15 Nov 2016 15:40
Family Historian: V6.2

Re: i need inspiration as well, and some clever coding

Post by Ron Melby »

Yes, I am aware of the fraught with dispair situations. Insofar as my limited information goes, in 1870-1871 The City of London never sailed from other than Liverpool or the Irish port just above it (whose name I cannot recall) on UK to US voyages. As I have said, I saw a manifest for Ellis Island but no start date and ports. To find the complete voyage logs for those years would be brilliant.
FH V.6.2.7 Win 10 64 bit
User avatar
tatewise
Megastar
Posts: 28410
Joined: 25 May 2010 11:00
Family Historian: V7
Location: Torbay, Devon, UK
Contact:

Re: i need inspiration as well, and some clever coding

Post by tatewise »

I cannot imagine what you mean by the Irish port just above Liverpool.
Liverpool is in England and Ireland is to the West of England separated by the Irish Sea.
Look at a map of UK & Ireland to see what I mean.
There is no possibility of an Irish port above (i.e. North of) Liverpool.
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
User avatar
LornaCraig
Megastar
Posts: 3201
Joined: 11 Jan 2005 17:36
Family Historian: V7
Location: Oxfordshire, UK

Re: i need inspiration as well, and some clever coding

Post by LornaCraig »

Most ships which left Liverpool for a transatlantic journey called at Queenstown, Ireland. Between 1849 and 1920 'Queenstown' was the name of the port now known as Cobh (pronounced 'Cove') in County Cork. It is on the south coast of Ireland and certainly not 'above Liverpool'.

According to Wikipedia SS City of London "completed her maiden voyage from Liverpool, to Queenstown, and then to New York on September the 29th 1870. She carried immigrants from Liverpool to New York for many years. "
Lorna
User avatar
tatewise
Megastar
Posts: 28410
Joined: 25 May 2010 11:00
Family Historian: V7
Location: Torbay, Devon, UK
Contact:

Re: i need inspiration as well, and some clever coding

Post by tatewise »

The research aspects of this thread need to be continued in the Research Forum and not this Plugin Discussion Forum.
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
User avatar
Ron Melby
Megastar
Posts: 928
Joined: 15 Nov 2016 15:40
Family Historian: V6.2

Re: i need inspiration as well, and some clever coding

Post by Ron Melby »

ok, back to subject at hand.

simple deal, I have a table of record ids, and a table of indi pointers

ancestors = {} --indi pointers
alist = () record ids for those indis

now, I want to print out:

tblkey = {}
tblNAME = {}
tblINDI = {}

for key, val in pairs (alist) do
table.insert(tblkey, val)

PTR = fhGetItemAsPtr( ancestors[val] ) <<<<< the actual statements for that, I have a table of pointers and I want to "materialize them" so I can:


Name = fhGetItemText(PTR, '~.NAME:SURNAME_FIRST')
NameSuffix = fhGetItemText(PTR,'~.NAME.NSFX')
Name = (Name .. NameSuffix)
table.insert(tblName, Name)
table.insert(tblINDI, PTR:Clone())

end

I am having no luck thru the fhPtr functions
FH V.6.2.7 Win 10 64 bit
User avatar
tatewise
Megastar
Posts: 28410
Joined: 25 May 2010 11:00
Family Historian: V7
Location: Torbay, Devon, UK
Contact:

Re: i need inspiration as well, and some clever coding

Post by tatewise »

Assuming ancestors and alist are in the same order then
PTR = fhGetItemAsPtr( ancestors[val] )
should be
PTR = ancestors[key]:Clone()
I.e. For the nth alist Record Id you are grabbing the nth ancestors pointer.

However, you don't need the alist of Record Id as the following will work and does not rely on the order of entries :

for _, PTR in pairs (ancestors) do
table.insert(tblkey, fhGetRecirdId(PTR))

and then the NAME... statements.
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
User avatar
Ron Melby
Megastar
Posts: 928
Joined: 15 Nov 2016 15:40
Family Historian: V6.2

Re: i need inspiration as well, and some clever coding

Post by Ron Melby »

yes that is what I want. a slight change perhaps I wasn't clear:
if I can code this clearer or faster, I am open to instruction.
(my main takeaway here is that I can now build and use a pointer table.)
first few rows of the tables so you can see whats going on as well:

alist => (table .204)
[3721] => 3721
[139] => 139
[2703] => 2703
[2705] => 2705
[53] => 53
[453] => 453
[78] => 78
[4897] => 4897
[4898] => 4898
[4899] => 4899
[4900] => 4900
[4646] => 4646
[4647] => 4647
[4648] => 4648
[4649] => 4649
[4650] => 4650
[118] => 118

ancestors => (table #204)
[1] (item) => Individual: Emelia Darlene STEWARD
[2] (item) => Individual: DeWayne Michael STEWARD
[3] (item) => Individual: Margaret Nolan MAHLING
[4] (item) => Individual: Todd STEWARD
[5] (item) => Individual: Cathy [STEWARD]
[6] (item) => Individual: Ronald Nolan MELBY
[7] (item) => Individual: Pamela Jean MAHLING
[8] (item) => Individual: Morris Carl MELBY
[9] (item) => Individual: Ruth Jeanette HOOK
[10] (item) => Individual: John Francis MAHLING
[11] (item) => Individual: Kathleen Josephine PROZINSKI
[12] (item) => Individual: Knute MELBY
[13] (item) => Individual: Nora Valmina RISAN
[14] (item) => Individual: Beatrice Mabel HOOK
[15] (item) => Individual: Knud KNUDSEN
[16] (item) => Individual: Ingebjorg THONSBRAATEN
[17] (item) => Individual: John Andreas RISAN

Code: Select all

tblkey  = {}
tblName = {}
tblINDI = {}
ix = 0

for key, val in pairs(alist) do
  table.insert(tblkey, val)
  
  ix = ix + 1
  ancPTR = ancestors[ix]:Clone()
  Name  = fhGetItemText(ancPTR, '~.NAME:SURNAME_FIRST')
  NameSuffix = fhGetItemText(ancPTR,'~.NAME.NSFX')
  Name  = (Name ..  NameSuffix)
  table.insert(tblName, Name)        
  table.insert(tblINDI, ancPTR:Clone())
end  

fhOutputResultSetTitles('1234567')  -- 7 char show in tab 
fhOutputResultSetColumn('rcdid',   'integer', tblkey,  #tblkey,       24, 'align_right')
fhOutputResultSetColumn('Name',    'text',    tblName, #tblName,   cwnam, 'align_left' )
fhOutputResultSetColumn('',        'item',    tblINDI, #tblINDI,   cwptr, 'align_mid',  0, true, 'default', 'buddy')
return
FH V.6.2.7 Win 10 64 bit
User avatar
Ron Melby
Megastar
Posts: 928
Joined: 15 Nov 2016 15:40
Family Historian: V6.2

Re: i need inspiration as well, and some clever coding

Post by Ron Melby »

well, that is very distressing, having just penned a gigagigagiga (x12) gabillion pixel monograph on 3 problems I have I will advance one of them further and really auger in on my own for a bit, until i have fixed it so nobody else can fix it, its gravamen being this. given a child whos pointer I already possess, knowing one parent of the two, how do I derive which FAMS the FAMC of hers is a member of?

also, given the following
1 FAMC @F120@
1 ADOP
2 FAMC @F210@

I can in code tell that FAMC @F120@ has no parent and FAMC @F210@ does: IS THAT A TRUE STATEMENT?

and three, given an algorithmic layout of a pointer table:
POINTERS
pgm root
father
mother

<repeat >
fathers father
fathers mother
mothers father
mothers mother
</end repeat>

if I empty string placeholders not found so I can do:
if ptrtbl[ptr] == ''
break
else
ptrmyptr = ptrtbl[ptr]
do some magic ...
end
end
my understanding is that I can use pairs and ipairs upon such a table with no unexpected things popping up. <<Is my understanding correct?
FH V.6.2.7 Win 10 64 bit
User avatar
tatewise
Megastar
Posts: 28410
Joined: 25 May 2010 11:00
Family Historian: V7
Location: Torbay, Devon, UK
Contact:

Re: i need inspiration as well, and some clever coding

Post by tatewise »

Sorry Ron, but you are talking in riddles!
I have no idea what problems you are trying to solve.
I do not understand your questions.

Try dealing with just one problem at a time.
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
User avatar
Ron Melby
Megastar
Posts: 928
Joined: 15 Nov 2016 15:40
Family Historian: V6.2

Re: i need inspiration as well, and some clever coding

Post by Ron Melby »

and three, given an algorithmic layout of a pointer table:
POINTERS
pgm root
father
mother

<repeat >
fathers father
fathers mother
mothers father
mothers mother
</end repeat>

if I use an empty string as a placeholder, ie: I have a record for the 9th Generation Fathers Father but no record for the mother...
and use code like this:

if ptrtbl[ptr] == ''
break
else
ptrmyptr = ptrtbl[ptr]
do some magic ...
end
end

my understanding is that I can use pairs and ipairs upon such a table containing empty strings, with no unexpected things popping up, the empty string will be (not nil) and it will not affect ipairs or pairs processing of the table.


Is my statement of understanding correct?
FH V.6.2.7 Win 10 64 bit
User avatar
tatewise
Megastar
Posts: 28410
Joined: 25 May 2010 11:00
Family Historian: V7
Location: Torbay, Devon, UK
Contact:

Re: i need inspiration as well, and some clever coding

Post by tatewise »

I still have no idea.
Use snippets of Lua to define your pointer table structure and it might be clearer.

You don't appear to understand how the ipairs and pairs iterator functions work.
Table values can be any type of data such as a pointer, number, empty string, or nil and those iterators don't care.
The iteration is only governed by the table keys.

ipairs will loop through a table starting at key [1], then [2], then [3] et seq, so the order is known.
So if there is no key [1] the loop terminates immediately.
Otherwise, it terminates when there is no key with the next consecutive integer.

pairs will loop through a table regardless of the keys, returning every key & value, but in no particular order.
However, the keys can be any type of data, and don't have to be integers.

So let's revisit your alist and ancestors table scenario.
It seems you're assuming alist[3721] => 3721 is the Record Id of ancestors[1] => Individual: Emelia Darlene STEWARD
BUT for key, val in pairs(alist) do does NOT necessarily start with key = 3721 and then key = 139
It will loop through alist in an indeterminate order.
So the Result Set table tblkey will probably NOT hold the rcdid of the associated Individual name & ptr.

I assume you want a Result Set in ancestors table key order with associated Rec Id and Name with ptr.
The following code will do that and needs no alist table:

Code: Select all

local tblkey  = {}
local tblName = {}
local tblINDI = {}
for _, ancPTR in ipairs ( ancestors ) do
  table.insert( tblkey, fhGetRecordId(ancPTR) )
  Name  = fhGetItemText( ancPTR, '~.NAME:SURNAME_FIRST' )
  NameSuffix = fhGetItemText (ancPTR,'~.NAME.NSFX' )
  Name  = ( Name ..  NameSuffix )
  table.insert( tblName, Name )       
  table.insert( tblINDI, ancPTR:Clone() )
end  
fhOutputResultSetTitles('1234567')  -- 7 char show in tab
fhOutputResultSetColumn('rcdid',   'integer', tblkey,  #tblkey,       24, 'align_right' )
fhOutputResultSetColumn('Name',    'text',    tblName, #tblName,   cwnam, 'align_left' )
fhOutputResultSetColumn('',        'item',    tblINDI, #tblINDI,   cwptr, 'align_mid',  0, true, 'default', 'buddy' )
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
User avatar
Ron Melby
Megastar
Posts: 928
Joined: 15 Nov 2016 15:40
Family Historian: V6.2

Re: i need inspiration as well, and some clever coding

Post by Ron Melby »

and I have no idea what you are talking about either.

Steward, Emilia Darleen --pgm root

Steward, DeWayne -- father
Mahling, Margaret -- mother

Steward, Todd -- fathers father
[Steward], Kathy -- fathers mother

Melby, Ronald -- mothers father
Mahling, Pamela -- mothers mother

nil -- fathers father (1G) Todd Stewards father
nil -- fathers mother(1G) Todd Stewards Mother
nil -- mothers father(1G) Cathy [Stewards] father
nil -- mothers mother(1G) Cathy [Stewards] mother

Melby, Morris Carl -- fathers father (1G) Ron Melbys father
Hook, Ruth Jeanette -- fathers mother(1G) Ron Melbys mother
Mahling, John -- mothers father(1G) Pamela Mahlings father
Prozinski, Kathleen -- mothers mother(1G) Pamela Mahlings mother

... ^^ << *NB: spaces above and all that follows are not part of table, formatted and explained to aid clarity
<repeat for the next generations> until
you run out of records
then <end repeat>

So, let us consider placeholder records-- that is: an element that is required by syntactic constraints but carries little or no semantic information. In our vignette, they will be the records whose value, or key (depending on programming) is nil.

I know pairs will cycle thru this, but I may want to use ipairs, so the table would have to be modified thus:

[0] Steward, Emilia Darleen --pgm root

[1] Steward, DeWayne -- father
[2] Mahling, Margaret -- mother

[3] Steward, Todd -- fathers father
[4] [Steward], Kathy -- fathers mother

[5] Melby, Ronald -- mothers father
[6] Mahling, Pamela -- mothers mother

[7] nil -- fathers father (1G) Todd Stewards father
[8] nil -- fathers mother(1G) Todd Stewards Mother
[9] nil -- mothers father(1G) Cathy [Stewards] father
[10] nil -- mothers mother(1G) Cathy [Stewards] mother

[11] Melby, Morris Carl -- fathers father (1G) Ron Melbys father
[12] Hook, Ruth Jeanette -- fathers mother(1G) Ron Melbys mother
[13] Mahling, John -- mothers father(1G) Pamela Mahlings father
[14] Prozinski, Kathleen -- mothers mother(1G) Pamela Mahlings mother

... ^^ << *NB: spaces above and all that follows are not part of table, formatted and explained to aid clarity
<repeat for the next generations> until
you run out of records
then <end repeat>

well, I may have that slightly messed up, but it looks exactly like an ahnentafel key (trivial to make), and I probably have to go 1...n on the key instead of 0..n on the key. Since I am making in fact, a table where I programmatically set a logical temporary root, ahnentafel number is a valid construct relative to that root in the problem domain, and I understand it is not valid file wide domain.

so, questions I have:

is ptr:SetNull() = nil or some other value?
having put either value nill or :SetNull
will in both cases pairs (for the first table config)
and ipairs (for the second table config)

and yeah, I think I understand the pairs and ipairs thing, having wasted my time on the other, and now trying to consolidate and simplify code and tables for the next problem I face, contained in the original codesegment:

--[[
@function: IsInList
@description: Adds rcdid as value and index to table if it does not already exist
@parameters: Item Pointer - Must be at Record Level
@returns: true if pointer is a duplicate
@requires: none
]]
function IsInList(table, iptr)
local rcdid = fhGetRecordId(iptr)
if table[rcdid] == nil then
table[rcdid] = rcdid
return false
else
return true
end
end --fn IsInList

--[[
@function: rtvAncestors
@description: Returns a list of Ancestors
@parameters: Item Pointer - Must be at Record Level
@returns: table of record Item Pointers
@requires: IsInList
]]
function rtvAncestors(iptr)
local ancestors = {}
local inlist = {}
local ent = 0
local gen = 0

local ptrBAS = fhNewItemPtr()
local ptrFAMC = fhNewItemPtr()
local ptrHUSB = fhNewItemPtr()
local ptrWIFE = fhNewItemPtr()

table.insert(ancestors, iptr:Clone())
IsInList(inlist, iptr)

ent = 1
while ent <= #ancestors do
ptrBAS = ancestors[ent]
-- Loop Family as Child
ptrFAMC:MoveTo(ptrBAS,'~.FAMC')
******
-- nora valmina risan has 2 FAMC, only want one.
-- her father john andreas risan has 3 FAMS, I only want
-- the one nora valmina risan belongs to
******
while ptrFAMC:IsNotNull() do
gen = gen + 1
ptrHUSB:MoveTo(fhGetValueAsLink(ptrFAMC), '~.HUSB>')
if ptrHUSB:IsNotNull()
and (not IsInList(inlist, ptrHUSB)) then
table.insert(ancestors, ptrHUSB:Clone())
end
ptrWIFE:MoveTo(fhGetValueAsLink(ptrFAMC), '~.WIFE>')
if ptrWIFE:IsNotNull()
and (not IsInList(inlist, ptrWIFE)) then
table.insert(ancestors, ptrWIFE:Clone())
end
ptrFAMC:MoveNext('SAME_TAG')
end
ent = ent + 1
end
return ancestors
end --fn rtvAncestors
FH V.6.2.7 Win 10 64 bit
User avatar
tatewise
Megastar
Posts: 28410
Joined: 25 May 2010 11:00
Family Historian: V7
Location: Torbay, Devon, UK
Contact:

Re: i need inspiration as well, and some clever coding

Post by tatewise »

ptr:SetNull() assigns a special value to ptr such that ptr:IsNull() is true and ptr:IsNotNull() is false.

It is the same special value as is assigned by ptr = fhNewItemPtr()

nil is a unique Lua value that is nothing to do with FH pointers which are only understood by the FH API.

You can assign ptr = nil but then ptr no longer holds an FH pointer value and FH API functions such as ptr:IsNull() or ptr:SetNull() will fail with an error message.
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
User avatar
Ron Melby
Megastar
Posts: 928
Joined: 15 Nov 2016 15:40
Family Historian: V6.2

Re: i need inspiration as well, and some clever coding

Post by Ron Melby »

SetNull is what I have decided to do, since it will always be a pointer table of some type of pointers. I understand in the real ahnentafel world that people who are not in the gedcom are simply skipped, but programatically it makes a great deal more sense to put their null placeholders and ahentafel position in place. Less code around worries, and the "key" not being one-up causing problems in coding all of its own. so for program reasons and down the line coding reasons it seems like a standard interface with no need to workaround its either there (valid pointer) or not(null pointer) is the simplest and cleanest way to handle this.

next question follows.
FH V.6.2.7 Win 10 64 bit
User avatar
Ron Melby
Megastar
Posts: 928
Joined: 15 Nov 2016 15:40
Family Historian: V6.2

Re: i need inspiration as well, and some clever coding

Post by Ron Melby »

I have most of the logic worked out in my ahentafel style pointer table.
first some remarks before the problem statement, so you can follow the FAMC logic I have.
rtvFAMPtr(*indi ptr)
if there is only one famc record in the indi, it doesnt matter if it is an adopt, or foster or anything else, that is all we know at present for that persons ancestors, and that indi is in the "bloodline" .
if there are multiple FAMCs, we must assume that one is their actual ancestry. and so we load up all the FAMCs in ftbl and then remove adoption FAMCs and those with certain types of PEDIs (I have not done the additional logic to leave in PEDIs where the particularly pedantic have used birth PEDIs but I have none in my file of some 5400+ i will have to consider Step, since i have those, and dont know which way they are step in every case, Those issues are simple and or things at some point. However in the case it is a single FAMC record, they are ignored and processed as if they are normal mother father FAMCs. I do have a couple De Facto, and have no idea what that means.

So, I have a working model to get me to a single line FAMC.... but

On to rtvAncestors(root)

My single FAMC is going to be difficult to use in that SAME_TAG will not work as a looping mechanism. it ignores my beautiful work.
and I am uncertain of how to run a loop, perhaps I dont need to loop on that. The next problem is placeholders logic, here I am at a whole loss and looking for clever coding:

I will place a small bit of the resulting file here to show the issues:

rcdid Name
2471 STEWARD, Emelia Darlene
2470 STEWARD, DeWayne Michael
172 MAHLING, Margaret Nolan
5524 STEWARD, Todd
5525 [STEWARD], Cathy -- Dewaynes (2470) mom and dad (5524, 5525)
78 MELBY, Ronald Nolan -- me, Margarets dad
2469 MAHLING, Pamela Jean -- Margarets (172) mom
**here should be 4 null entries (and repeat in their ahentafel cycle for anc of 5524, and 5525.
75 MELBY, Morris Carl
53 HOOK, Ruth Jeanette
5512 MAHLING, John Francis
5513 PROZINSKI, Kathleen Josephine
2592 MELBY, Knute
2593 RISAN, Nora Valmina --this is my first 2 famc record my fathers mother
0 -- my grandfather unknown mothers side (correct)
39 HOOK, Beatrice Mabel --
2598 KNUDSEN, Knud
2599 THONSBRAATEN, Ingebjorg
2703 RISAN, John Andreas --2593 father FAMC[1]
2705 GILBERTSON, Anna Marie --2593 mother FAMC[1]
4898 THORSON, Lars --2593 father FAMC[2] PEDI Foster
4897 SAGEN, Mary Caspara --2593 mother FAMC[2] PEDI Foster records should not go in table, but SAME_TAG - loop prob
46 HOOK, George Clarence Sr.
18 SIBLEY, Ruth

**and throughout though it doesnt show, I need to write 0 Null placeholders where an ancestry line runs out, until the last real entry is placed in the table (it ends correctly now) >>> just the placeholder logic and constructing the advance loop on a single famc record is the 2 problems I am trying to solve. then the table can include ahnentafel number and generation. Anyone with a brilliant little algorithm to solve those problems? I havent got anything...

I appear to be handling FAMC correctly and writing a placeholder record rcdid 0 and null where there is no known spouse.

Code: Select all

function rtvElemCount(eptr)   -- Count instances of TAG
  local thisPTR = eptr:Clone()
  local elem = 0
  while thisPTR:IsNotNull() do
    elem     = elem + 1
    thisPTR:MoveNext('SAME_TAG')
  end
  return elem
end -- fn rtvElemCount

function rtvFAMPtr(iptr)
  local thisPTR = thisPTR or fhNewItemPtr()
  local fptr    = fhNewItemPtr()
  local aptr    = fhNewItemPtr()
  local pptr    = fhNewItemPtr()
  local ftbl    = {}
  local trmv    = {}

  if iptr:IsNull() then
    fptr:SetNull()
    return fptr
  end

  if iptr:IsSame(thisPTR) then
    fptr:SetNull()
    return fptr
  end

  thisPTR = iptr

  fptr = fhGetItemPtr(iptr,'~.FAMC')
  if not fptr then
    fptr:SetNull()
    return fptr
  end

  local fc = rtvElemCount(fptr) 
  if fc > 1 then

    while fptr:IsNotNull() do 
      table.insert(ftbl, fptr:Clone())
      fptr:MoveNext('SAME_TAG') 
    end

    local aofs    = '~.ADOP.FAMC'  --adop
    for key, val in pairs(ftbl) do 
      aptr = fhGetItemPtr(ftbl[key], aofs)
      if aptr:IsNotNull() then 
        ftbl[key] = nil
      end  
    end

    local pofs    = '~.PEDI'  --pedi
    for key, val in pairs(ftbl) do 
      pptr = fhGetItemPtr(ftbl[key], pofs)
      if pptr:IsNotNull() then 
        ftbl[key] = nil
      end  
    end
    assert(#ftbl == 1, fhGetRecordId(iptr))
    fptr = ftbl[1]
    return fptr
  end
  return fptr
end

--[[
@function: rtvAncestors
@description: Returns a list of Ancestors
@parameters: Item Pointer - Must be at Record Level
@returns: table of record Item Pointers
@requires: IsInList
]] 
function rtvAncestors(iptr)
  local thisPTR = iptr:Clone()
  local alist   = {}
  local igens   =  igens or 32767 

  local ent        =  1
  local at         =  1 
  local gen        =  0  
--[[
Ahnentafel numbering begins with the starting individual, who is given a number of 1. From then on, an individual's father is assigned a number that is two times the number of the individual. The mother is assigned a number that is twice the individual's, plus 1.  If you are number one, your father is 2, your mother is 3, your father's father and mother are 4 and 5 and your mother's father and mother are 6 and 7 and so on. If a person is missing, their number is skipped. The child of any person always has a number that is one half the number of the father. So Ahnentafel numbers will be skipped for great-grandparents, etc. for who you have not entered information.

Because Ahnentafel number increase exponentially, they quickly become very large.  For example by the 20th generation, the Ahnentafel number in the direct male line would be 524,288 and by the 25th generation the Ahnentafel number in the direct male line would be 16,777,216.
]]  
  local ptrBAS  = fhNewItemPtr()
  local ptrFAMC = fhNewItemPtr()
  local ptrHUSB = fhNewItemPtr()
  local ptrWIFE = fhNewItemPtr()

  table.insert(ancestors, iptr:Clone())
--  IsInList(alist, iptr)

  while ent <= #ancestors do
    ptrBAS = ancestors[ent]

    -- Loop Family as Child
    ptrFAMC = rtvFAMPtr(ptrBAS)
    while ptrFAMC:IsNotNull() do
      gen = gen + 1
      ptrHUSB:MoveTo(fhGetValueAsLink(ptrFAMC), '~.HUSB>')
      --     if ptrHUSB:IsNotNull() 
      --     and (not IsInList(alist, ptrHUSB)) then
      table.insert(ancestors, ptrHUSB:Clone())
      --     end
      ptrWIFE:MoveTo(fhGetValueAsLink(ptrFAMC), '~.WIFE>')
      --     if ptrWIFE:IsNotNull() 
      --     and (not IsInList(alist, ptrWIFE)) then
      table.insert(ancestors, ptrWIFE:Clone())
      --     end
      ptrFAMC:MoveNext('SAME_TAG')
    end
    ent = ent + 1
  end
  return ancestors
end --fn rtvAncestors 

-- USAGE:
tblROOT = fhPromptUserForRecordSel('INDI', 1)
if #tblROOT == 0 then
  return
--  table.insert(descendants, fhGetValueAsLink(cptrCHIL))
end

ptrINDI = tblROOT[1]
rtvAncestors(ptrINDI)
-- rtvDescendants(ptrINDI)

for key, _ in pairs (ancestors) do
  ancPTR = ancestors[key]:Clone()
  table.insert(tblrcd, fhGetRecordId(ancPTR))
  Name  = fhGetItemText(ancPTR, '~.NAME:SURNAME_FIRST')
  NameSuffix = fhGetItemText(ancPTR,'~.NAME.NSFX')
  Name  = (Name ..  NameSuffix)
  table.insert(tblName, Name)        
  table.insert(tblINDI, ancPTR)
end  

fhOutputResultSetTitles('1234567')  -- 7 char show in tab 
fhOutputResultSetColumn('rcdid',   'integer', tblrcd,  #tblrcd,       48, 'align_right')
fhOutputResultSetColumn('Name',    'text',    tblName, #tblName,     124, 'align_left' )
fhOutputResultSetColumn('',        'item',    tblINDI, #tblINDI,       0, 'align_mid',  0, true, 'default', 'buddy')

return
FH V.6.2.7 Win 10 64 bit
User avatar
tatewise
Megastar
Posts: 28410
Joined: 25 May 2010 11:00
Family Historian: V7
Location: Torbay, Devon, UK
Contact:

Re: i need inspiration as well, and some clever coding

Post by tatewise »

The meaning of De Facto is explained via the FH Help > Search Help in the Select Relationship Type page.

I would ignore multiple FAMC instances and only ever investigate the first instance.
Only the first FAMC instance can link to the actual birth blood line parents.
All subsequent FAMC links can only be to adoptive/foster/step non-birth parents, so are useless as DNA research ancestors, and estimating dates will be very unreliable.

If you still feel the ned to loop on FAMC then "SAME_TAG" method should work fine.

Code: Select all

	local ptrFAMC = fhGetItemPtr(ptrINDI,"~.FAMC")
	while ptrFAMC:IsNotNull() do
		-- process each FAMC here
		ptrFAMC:MoveNext("SAME_TAG")
	end
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
User avatar
ColeValleyGirl
Megastar
Posts: 5499
Joined: 28 Dec 2005 22:02
Family Historian: V7
Location: Cirencester, Gloucestershire
Contact:

Re: i need inspiration as well, and some clever coding

Post by ColeValleyGirl »

Only the first FAMC instance can link to the actual birth blood line parents.
Mike, out of curiosity -- why do you say this? I have records where the first FAMC is an adoptive family and a subsequent one is the birth family because that's how the individual (Still living) wants it to be shown. Perhaps Ron has been stringent and gone through reordering data so that the birth family is always first -- or perhaps he hasn't.
User avatar
tatewise
Megastar
Posts: 28410
Joined: 25 May 2010 11:00
Family Historian: V7
Location: Torbay, Devon, UK
Contact:

Re: i need inspiration as well, and some clever coding

Post by tatewise »

You are of course correct, and I should have qualified it by saying if the data is in chronological order.
Otherwise, as you imply, Ron will have to search and filter every FAMC.
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
User avatar
Ron Melby
Megastar
Posts: 928
Joined: 15 Nov 2016 15:40
Family Historian: V6.2

Re: i need inspiration as well, and some clever coding

Post by Ron Melby »

This one requires maths.

I have abandoned the table entry per ancestor, the table is huge. So, I am going the ahnentafel number skipping and incrementing route, from which one should be able to derive the needed information simply and algorithmically. yet, in the direct line, I will keep unknown husband or wife partnerships in the table directly.
It aint there, or I have some subtle mistake in my calcs or...

here is a snip of the table:


at math.log10(at) math.log10(2) log10(at)/bin floor Name
1 0.30102999566398 0.30102999566398 1 (constant) 0 STEWARD, Emelia Darlene
2 0.30102999566398 0.30102999566398 1 1 STEWARD, DeWayne Michael
3 0.60205999132796 0.30102999566398 2 1 MAHLING, Margaret Nolan
4 0.60205999132796 0.30102999566398 2 2 STEWARD, Todd
5 0.77815125038364 0.30102999566398 2.5849625007212 2 [STEWARD], Cathy
6 0.77815125038364 0.30102999566398 2.5849625007212 2 MELBY, Ronald Nolan
7 1.0791812460476 0.30102999566398 3.5849625007212 2 MAHLING, Pamela Jean
12 1.0791812460476 0.30102999566398 3.5849625007212 3 MELBY, Morris Carl
13 1.1461280356782 0.30102999566398 3.8073549220576 3 HOOK, Ruth Jeanette
14 1.1461280356782 0.30102999566398 3.8073549220576 3 MAHLING, John Francis
15 1.2041199826559 0.30102999566398 4 3 PROZINSKI, Kathleen Josephine
16 1.2041199826559 0.30102999566398 4 4 MELBY, Knute
17 1.2552725051033 0.30102999566398 4.1699250014423 4 RISAN, Nora Valmina
18 1.2552725051033 0.30102999566398 4.1699250014423 4 ********
19 1.3802112417116 0.30102999566398 4.5849625007212 4 HOOK, Beatrice Mabel
24 1.3802112417116 0.30102999566398 4.5849625007212 4(5) KNUDSEN, Knud (12s GF)
25 1.4149733479708 0.30102999566398 4.7004397181411 4(5) THONSBRAATEN, Ingebjorg
26 1.4149733479708 0.30102999566398 4.7004397181411 4(5) RISAN, John Andreas
27 1.4771212547197 0.30102999566398 4.9068905956085 4(5) GILBERTSON, Anna Marie
30 1.4771212547197 0.30102999566398 4.9068905956085 4(5) HOOK, George Clarence Sr.
31 1.5051499783199 0.30102999566398 5 4(5) SIBLEY, Ruth
32 1.5051499783199 0.30102999566398 5 5(6) KNUDSEN, Knud
33 1.5314789170423 0.30102999566398 5.0874628412503 5(6) CHRISTENSDATTER, Kari
34 1.5314789170423 0.30102999566398 5.0874628412503 5(6) THONSBRAATEN, Ola (Guttormsen)
35 1.5563025007673 0.30102999566398 5.1699250014423 5(6) LARSDATTER, Anne


here is the code involved in the calculations:

Code: Select all

  local at         =  1            -- ahnentafel nbr
  local gen        =  0            -- generation
  local bin        =  math.log10(2)-- log base  

  gen = gen + 1
  while ent <= #ancestors do
    ptrBAS = ancestors[ent]

    -- Loop Family as Child to derive parents and next gen
    ptrFAMC = rtvFAMPtr(ptrBAS)
    if ptrFAMC:IsNull() then
      at = at + 2
    else
      ptrHUSB:MoveTo(fhGetValueAsLink(ptrFAMC), '~.HUSB>')
      at = at + 1
      table.insert(ahnentafel, at) 
      d = math.log10(at)
      r = bin
      f = (math.log10(at)/bin)
      table.insert(raw, f) 
      table.insert(dvdd, d) 
      table.insert(dvsr, r) 
      gen = math.floor((math.log10(at)/bin))
      table.insert(generation, gen) 
      table.insert(ancestors, ptrHUSB:Clone())

      ptrWIFE:MoveTo(fhGetValueAsLink(ptrFAMC), '~.WIFE>')
      at = at + 1
      table.insert(ahnentafel, at) 
      table.insert(raw, f) 
      table.insert(dvdd, d) 
      table.insert(dvsr, r) 
      table.insert(generation, gen) 
      table.insert(ancestors, ptrWIFE:Clone())
    end

    ent = ent + 1
  end
this is how I arrived at calculations for generation from ahnentafel nbr:
1) https://en.wikipedia.org/wiki/Ahnentafel > Calculation of the generation number
2) https://en.wikipedia.org/wiki/Ahnentafe ... ion_number
3) we are on 5.1 so log(e) and log(10) are our only resource without a heavy math guy or gal...
so, log change base formula:= https://www.purplemath.com/modules/logrules5.htm

calculating generations says throw away decimal part, not important
math.floor will do that.

**CONCLUSION: either my maths is incorrect or I have a coding error.
does anyone with fresh eyes have the solution?
FH V.6.2.7 Win 10 64 bit
Post Reply