Add a New Comment (Rich Markup)
( Jump to the original submission )
I've confirmed that the scenario I described is what is happening. That is, I'll write notes in the code below of what happens with the "x = A(rand(3,4)); whos" command:
octave_value varval (context_id context = xdefault_context) const { if (is_global ()) return symbol_table::global_varval (name); else if (is_persistent ()) return symbol_table::persistent_varval (name); else { if (context == xdefault_context) context = active_context (); if (context < value_stack.size ()) return value_stack[context]; // ALWAYS GOES THIS ROUTE else return octave_value (); // NEVER GOES THIS ROUTE } }
I see the the line ALWAYS GOES THIS ROUTE accessed maybe 50 or 60 times with the command. (I suppose there are many things in the symbol table beyond the user's variables.) Beyond that, I've not looked further, mainly because of the slowness of doing development when touching any sort of header file. Takes maybe 20 to 30 minutes to recompile in that case. These routines longer than a few lines should not be inline and inside the header file. Inline routines are for the case when the cost of jumping (i.e., setting up stack, making the jump, etc.) is large relative to the length of the routine.
I lost track of this bug... I no longer see a "elements += val.capacity ();" in variables.cc. Perhaps a change was made there to fix bug #43096 but didn't get to checking this one. Anyway, the line of code that computes number of elements and displays is now
for (const auto& syminfo : lst) { syminfo.display_line (os, params); octave_value val = syminfo.varval; elements += val.numel (); bytes += val.byte_size (); }
It appears here that after extracting the A class files to a subdirectory and generating x, y, z according to comment #5, numel(x) produces a proper result. The code that does this is (from data.cc):
if (nargin == 1) retval = args(0).numel (); else if (nargin > 1) { // Don't use numel (const octave_value_list&) here as that corresponds to // an overloaded call, not to builtin! retval = dims_to_numel (args(0).dims (), args.slice (1, nargin-1)); }
It seems to me that now both routes use the octave_value::numel() route. So why does one produce a correct result and not the other? The answer might be in the symbol_record::varval() routine, which is:
octave_value varval (context_id context = xdefault_context) const { if (is_global ()) return symbol_table::global_varval (name); else if (is_persistent ()) return symbol_table::persistent_varval (name); else { if (context == xdefault_context) context = active_context (); if (context < value_stack.size ()) return value_stack[context]; else return octave_value (); } }
That is, whereas the numel() function definition uses the octave_value "arg(0)" directly, this symbold_record::varval() routine might be returning something other than the symbol's octave_value depending on active_context(). Just a theory. I'll experiment after compiling finishes.
I think this behavior is still present in Octave 4.2.0. The result from the code in comment #5 is still the same. (Even though the mentioned bug #43096 is now marked as fixed.)
I would expect this is related to the kluge mentioned in https://savannah.gnu.org/bugs/?43096, so a proper fix there would likely resolve this.
OK, I understand it now. Yeah, I tried searching too and I see the "elements += val.capacity ();" line in variables.cc. And searching through octave_value indicates that capacity() is basically numel() in the base class and sometimes is nelem(). But I'm having trouble grepping for "class" definition because, well, "class" is used a thousand times in the code. I think "class" is something new. Is it this routine:
octave_idx_type octave_class::numel (const octave_value_list& idx) {
in libinterp/octave-value/ov-class.cc?
Let's start again so its all in this bug instead of cross-linked to the other one where @mtmiller pointed this out. See attached class.
octave:1> x = A(rand(3,4)) class is: A with data: 0.191086 0.658946 0.063937 0.394757 0.285017 0.690299 0.827248 0.889642 0.378245 0.180257 0.350445 0.330926 octave:2> y = A(42) class is: A with data: 42 octave:3> z = 42 z = 42 octave:4> whos Variables in the current scope: Attr Name Size Bytes Class ==== ==== ==== ===== ===== x 3x4 96 A y 1x1 8 A z 1x1 8 double Total is 3 elements using 112 bytes
Note each x and y counts as only one "element" even though x reports numel(x) -> 12 and size(x) -> [3 4]. I.e., the element calculation does not respect numel/size/etc for a user-defined class. From reading the code, the element count is done by adding up the ".capacity". That is as far as I've tracked it down.
I take it back, I think the current sparse behaviour looks correct to me. The count matches nnz() of the sparse matrix. That's what I expect.
yeah, sorry "symbolic". Any simple class will demonstrate it, see @A class in the linked bug report. As you note, apparently sparse shows it too.
What is 'sym'? Is it related to symmetric elimination tree? "symbolic"? Here's another example:
>> sparse(1,2,3) ans = Compressed Column Sparse (rows = 1, cols = 2, nnz = 1 [50%]) (1, 2) -> 3 >> whos Variables in the current scope: Attr Name Size Bytes Class ==== ==== ==== ===== ===== ans 1x2 24 double Total is 1 element using 24 bytes
Could it be that the sparse variables only count the defined, non-zero values? Filling in the zero value results in two elements:
>> ans(1,1) = 6 ans = Compressed Column Sparse (rows = 1, cols = 2, nnz = 2 [100%]) (1, 1) -> 6 (1, 2) -> 3 >> whos Variables in the current scope: Attr Name Size Bytes Class ==== ==== ==== ===== ===== ans 1x2 36 double Total is 2 elements using 36 bytes
This is a minor bug (I don't seem to be able to set that?)
In this example, the count should be 9 (from the doubles) + 7 (from the user-defined class sym). But instead each sym counts only as 1 and we see 11 displayed.
>> whos Variables in the current scope: Attr Name Size Bytes Class ==== ==== ==== ===== ===== A 3x2 240 sym d 3x3 72 double x 1x1 30 sym Total is 11 elements using 342 bytes
@mtmiller found this looking at a related bug: https://savannah.gnu.org/bugs/?43096 There is a minimal class that demonstrates this problem in that bug. In that other bug, I said:
> The number of elements thing is counted by adding up > the ".capacity" of each varval. So I guess "capacity" > is wrong for simple classes.
(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)
Attach Files: Comment:
Depends on the following items: None found
Items that depend on this one: None found
There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.
Only project members can vote.
Please enter the title of George Orwell's famous dystopian book (it's a date):
Follow 4 latest changes.
Copyright © 2023 Free Software Foundation, Inc. Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved. The Levitating, Meditating, Flute-playing Gnu logo is a GNU GPL'ed image provided by the Nevrax Design Team. Source Code
Powered by Savane 3.12