put binary derived state into the mutation table metadata - #665
Conversation
|
And again GitHub Desktop has based this PR on |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## multitrait #665 +/- ##
==============================================
+ Coverage 76.86% 76.90% +0.04%
==============================================
Files 117 117
Lines 78747 83275 +4528
Branches 14299 16165 +1866
==============================================
+ Hits 60528 64044 +3516
- Misses 18219 19231 +1012
🚀 New features to boost your workflow:
|
|
Hmm. The branch that this PR is based on, |
|
OK, clearly I'm (yet again) fundamentally confused by Git's conceptual model. I just made a new branch, |
|
The github-ness of this PR looks good - it's based on |
petrelharp
left a comment
There was a problem hiding this comment.
I haven't got into the weeds on the main work here yet because I think there's a much simpler way to do this. The derived_state and metadata columns are stored in exactly the same way by tskit. So, why not just move around the pointers instead of looping over entries? So we want to move the pointers metadata and metadata_length over to derived_state and derived_state_length, and then set metadata to NULL and metadata_length to 0?
(Tangentially, this made me think "why not just go through the code and (more or less) change over the references to derived_state to metadata?" But this is no good because we make heavy use of the tsk_variant object, which is very useful and relies on ancestral/derived states.)
|
Ah also I think we want "we don't actually use |
That's pretty much what the code does. That's the purpose of the
Yes, the derived state column needs to be functional, I think? Maybe for simplify as well? |
Huh, how strange. When you make a branch, you make it based on another branch; and |
Ah, good.
Oh, you're probably right.
Have you read the C API docs? It's kinda minimal but it is SOME documentation. |
|
Also: I think the reason that the sort of documentation you're looking for here doesn't exist is because we haven't settled on a public and stable API for it. We want to have the freedom to change how some of this works under the hood. |
I've skimmed it and found it pretty useless for my purposes. For example, on the salient question of whether you're allowed to free a column and put Is that allowed? I have no idea. What are the rules and requirements for how columns are managed? I don't see any guidance on that at all. (If I have missed it somewhere, then of course I'll eat my words; but I've mentioned this before and have gotten nowhere.) |
I don't think that's a valid reason not to document code. You can document it and write "This is internal and subject to change." I've had that debate with Jerome and Ben. :-> |
Co-authored-by: Peter Ralph <petrel.harp@gmail.com>
|
OK, accepted/replied/resolved review stuff. I'll now work on improving the code with |
|
OK, updated with |
| mutation_table.derived_state, | ||
| mutation_table.derived_state_offset, |
There was a problem hiding this comment.
Why do you need those swaps above? Why not just
| mutation_table.derived_state, | |
| mutation_table.derived_state_offset, | |
| mutation_table.metadata, | |
| mutation_table.metadata_offset, |
There was a problem hiding this comment.
oh wait reading the comment now
There was a problem hiding this comment.
Wait, no, I don't get it - why is all this swapping necessary? Why can't you do:
- takeset to the temporary table, with the
metadatain thederived_stateslot - set
p_tables->mutationsto the (pointer to the) temporary table - free the original table's metadata schema?
There was a problem hiding this comment.
I don't like changing p_tables->mutations to the temporary table, for a couple of reasons. (1) It requires that the temporary table be malloced, so it adds an allocation call (which is slow) and a free. (2) Changing over to a new pointer adds a risk of bugs where someone has a pointer to the table and now their pointer is invalid. So I prefer the way I've written it. I want the temporary table to remain the temporary table, and to fix up the original table to be the way it ought to be.
There was a problem hiding this comment.
FYI, and probably you know this, but the current code does a malloc, since takeset calls takeset_ragged_column which calls alloc_empty_ragged_column for the empty columns.
There was a problem hiding this comment.
Yeah; no way I can prevent that, with tskit's APIs. (It surprises me that they chose to make empty columns still be malloced rather than nullptr; that's not the choice I would've made.)
| mutation_table.derived_state_offset, | ||
| /* metadata */ new_metadata_buffer, | ||
| /* metadata_offset */ text_derived_state_offset); | ||
|
|
There was a problem hiding this comment.
okay, and this is more confusing here: why swap -> free schema -> swap back? what are the swaps doing?
There was a problem hiding this comment.
The second set of swaps is not a "swap back"; it is swapping the derived state and metadata columns within the single mutation table. That is necessary to put things where they belong, since the binary derived state information was being kept in the derived state column, and now needs to be in the metadata column (and vice versa). I think the code is correct and necessary as it stands (given that I don't want to change the pointer to the mutation table in the table collection); have another look.
|
BTW: are you sure that |
Yep, I'm quite sure of that. |
|
Merging after code review and Slack discussion. |
This PR fixes #664 (I hope). Review requested from @petrelharp. Right now I've tested that it round-trips a tree sequence out to disk and back, and that seems to work AFAICT. Let me know if it does what you need it to do.
Also, note: it does what it does in an unorthodox way, by munging around inside the tskit data structures, because I didn't want to be making copies of this stuff – the derived state column could potentially be a pretty big buffer, so I didn't want to push the high-water memory usage mark higher if possible. If there is a cleaner and more orthodox way to do what I'm doing, that would be great of course. In any case, please make sure that the way that I'm munging tskit's data structures is completely correct and safe (given the current tskit implementation). This code ought to be bulletproof, of course, but I'm not sure that it is since I don't feel 100% confident in my understanding of how tskit does things under the hood (and AFAIK that is not documented anywhere, even in comments, right?).