24 March 2009
En dash
Today, having noticed the behavior in my literature review, I learned that en dashes are the appropriate punctuation to use between the names of joint authors. For example, "Newton-Krylov methods" should be rewritten as "Newton–Krylov methods."
See this google books result.
See this google books result.
16 March 2009
Overwriting lines in terminal output
For weeks I've been wondering, off and on, if there existed an easy way to write information to the terminal output and be able to change it later, to overwrite or overtype or erase or something. I'd seen how curl will update the fraction downloaded and download rate at the end of the line rather than print a new line for every status change; such a feature would be very nice my code, where I could just use one line of output to write information about the time step. I'd seen the "curses" library, but that looked ridiculously complex for what I was asking. (It creates a whole GUI in the terminal rather than allowing simple operations.)
Well, after finally hitting the right keywords in a google search, I came across Python with ANSI escape codes (more ANSI escape sequences here). This is just what I want. All you have to do is to send the '\r' carriage return sequence to move to the beginning of the line, and then another ANSI sequence can erase the line. That behavior is actually just what I would expect based on the descriptions of the escape sequences: '\n', the "new line" character, should create a new line; '\r', which is called the 'carriage return', actually *does* in this contact emulate the behavior of a typewriter carriage returning to the rightmost position. Mostly due to the cross-platform confusion of the "end-of-line" character business, I'd never really thought this was the way it would work. The long and short of it, in a few lines of python code:
The
Well, after finally hitting the right keywords in a google search, I came across Python with ANSI escape codes (more ANSI escape sequences here). This is just what I want. All you have to do is to send the '\r' carriage return sequence to move to the beginning of the line, and then another ANSI sequence can erase the line. That behavior is actually just what I would expect based on the descriptions of the escape sequences: '\n', the "new line" character, should create a new line; '\r', which is called the 'carriage return', actually *does* in this contact emulate the behavior of a typewriter carriage returning to the rightmost position. Mostly due to the cross-platform confusion of the "end-of-line" character business, I'd never really thought this was the way it would work. The long and short of it, in a few lines of python code:
from time import sleep
from sys import stdout
for i in range(10):
stdout.write('\r\x1b[K')
stdout.write('Time step %03d/%03d ' % (i+1, 10))
stdout.flush()
The
'\r\x1b[K' moves the cursor to the beginning of the line the following ANSI escape sequence clears the line completely. The next line actually writes the code. The trailing spaces are in case some sort of output gets print during the time step: it will go at the end of the line, and assuming it has a newline of its own, the time step at which the output occurs will be preserved on the screen, and the next line will have the actual updating time step information.
10 March 2009
Lessons learned of the evening
To make a long story short, or more precisely, to summarize an hour of frustration: when using SWIG with Python, watch that you actually instantiate an object by calling its constructor, because apparently you can change the values of the class itself without creating an object from it. Then, when you later want to pass an instantiated object to another C++ method, it won't fail with an inscrutable error. You probably don't want to read the rest of this post, but it's preserved for posterity.
I have a struct of data, SourceDataUniform, that I pass to a class called RadiationController. My original code was:
but this failed with
I knew I'd gotten the exact same thing to work with a different class, so I wasn't sure if the problem was that I was using a struct, or what.
I spent a good while looking through the SWIG documentation on proxy classes, structs, the ".this" method. Eventually, noting that the similar case that actually worked gave a
I have a struct of data, SourceDataUniform, that I pass to a class called RadiationController. My original code was:
newSource = ImcTransport.SourceDataUniform
newSource.emissionRate = 2.0
newSource.cellIndex = 1
self.__radController.addUniformSource(src)
but this failed with
TypeError: in method 'RadiationControllerT_addUniformSource', argument 2 of type 'iMc::SourceDataUniform'. Yet I could print the data in the object, and it said it was of type <class 'ImcTransport.SourceDataUniform'>.I knew I'd gotten the exact same thing to work with a different class, so I wasn't sure if the problem was that I was using a struct, or what.
I spent a good while looking through the SWIG documentation on proxy classes, structs, the ".this" method. Eventually, noting that the similar case that actually worked gave a
repr of <ImcPhysics.OpacityModelConstant; proxy of <Swig Object of type 'iMc::OpacityModelConstant *' at 0x305670> >, and realizing that the "this" object was only set in the constructor for the SourceDataUniform Python wrapper, I discovered that I wasn't instantiating an object. Adding parenthesesnewSource = ImcTransport.SourceDataUniform()solved the problem.
09 March 2009
Unit tests again
Life is funny sometimes. It's occasionally the case that one thinks some almost-trivial task is totally unnecessary, yet the "best practice" is to do it anyway&emdash;and the task turns out to catch or prevent a subtle but insidious error.
This evening I started writing unit tests for my code, and the first one on the list was the (almost) dead-simple "check direction vector" routine, which is overloaded on Blitz tinyvector length. The one-D case has to ensure that the cosine is bounded by one. Simple enough, right?
Well, in addition to testing that it called a value of 1.0 and -0.5 allowed, I tested whether -1.1 was disallowed. I was flabbergasted when I got the message
which corresponded to the code
What the heck? Then I realized the mistake. My compiler (gcc 4.0) was silently downcasting a double to an integer, truncating -1.1 to -1, and then upcasting the result to the double -1.0, which satisfies the condition.
The solution is simple, to just use
This evening I started writing unit tests for my code, and the first one on the list was the (almost) dead-simple "check direction vector" routine, which is overloaded on Blitz tinyvector length. The one-D case has to ensure that the cosine is bounded by one. Simple enough, right?
inline bool checkDirectionVector(
const blitz::TinyVector<double, 1>& omega)
{
return (abs(omega[0]) <= 1.0);
}
Well, in addition to testing that it called a value of 1.0 and -0.5 allowed, I tested whether -1.1 was disallowed. I was flabbergasted when I got the message
/---- Unit test tBlitzStuff failed
| in <build/imclib/tests/tBlitzStuff.cpp> on line 32
| !checkDirectionVector(mu)
+-------------------------------
which corresponded to the code
mu = -1.1;
TESTER_CHECKFORPASS(!checkDirectionVector(mu));
What the heck? Then I realized the mistake. My compiler (gcc 4.0) was silently downcasting a double to an integer, truncating -1.1 to -1, and then upcasting the result to the double -1.0, which satisfies the condition.
The solution is simple, to just use
std::fabs(omega[0]) instead. But seriously? I never would have expected a failure on that unit test of all places. These things aren't as worthless as one might think.
02 March 2009
Zoidberg, on the economy
Once again, the conservative, sandwich-heavy portfolio pays off for the hungry investor!
01 March 2009
Ok, I like Python now
Whoever said that Perl had to be the language in which to write super-complicated commands all on one line? This Python command will turn a list of lists into a string amenable to writing to a file as MATLAB input:
EDIT: using generator comprehensions rather than list comprehensions for greater efficiency (thanks, Mike):
result = '[' + "\n ".join([" ".join(["%6g" % val for val in line]) for line in array]) + ']'EDIT: using generator comprehensions rather than list comprehensions for greater efficiency (thanks, Mike):
result = '[' + "\n ".join(" ".join("%6g" % val for val in line) for line in array) + ']'
27 February 2009
More frustration (Vim) resolved
Ugh, I spent the entire morning trying to fix a problem with Vim. I remember at one point getting frustrated that it refused to handle indentations of comments (which start with the hash or pound sign, #) correctly. The solution I got was to use someone else's indent file. Well, that indent file doesn't handle formatting lists extended over more than one line. But when I went back to the original, which worked for that, it couldn't handle the comments. I spent probably three hours searching for a solution, looking through $VIM/runtime/ trying to find out what the differences were between the different indent files. Furthermore, although the 'sh' file type displayed this behavior, the 'perl' file type did not!
Well, the long story was made short when I realized that the reason it forced all lines with a '#' to the beginning: it thought they were C preprocessor directives, which belong in column 1. I had unknowingly set an option, smartindent, which caused this behavior. Somehow, and I still haven't figured this out, the options in the Perl file mitigated that behavior.
Moral of this story: avoid setting options in vim that you aren't REALLY sure you understand. And with vim, this probably means you won't be setting many.
Well, the long story was made short when I realized that the reason it forced all lines with a '#' to the beginning: it thought they were C preprocessor directives, which belong in column 1. I had unknowingly set an option, smartindent, which caused this behavior. Somehow, and I still haven't figured this out, the options in the Perl file mitigated that behavior.
Moral of this story: avoid setting options in vim that you aren't REALLY sure you understand. And with vim, this probably means you won't be setting many.
Template specialization for std::swap
One of the algorithms in C++'s STL is swap, a templated function which takes two arguments of the same class and switches them. By default, it creates a new object and performs two copies, but for STL containers (such as std::list, which I was using) it has its own template specialization to only copy their internal pointers and not any actual data. This makes, by default, std::swap way more efficient on an STL container than everything else.
I have a class Census inside a namespace iMc, and it has-a std::list to store a bunch of particles. I'd like to call std::swap(iMc::Census& a, iMc::Census& b) but not copy all the particles inside the list. The solution was obvious and allowed: create a new specialization for my own class that calls std::swap on the std::list :
Well, because the _particles list was private, I had to make this function a friend of iMc::Census. Easy, right? Wrong. It turns out everything on the internet; that talks about templated friend functions is a lie! No matter what I did, I received a bunch of weird errors.
and
Well, it turns out that the correct answer is to have
I have a class Census inside a namespace iMc, and it has-a std::list to store a bunch of particles. I'd like to call std::swap(iMc::Census& a, iMc::Census& b) but not copy all the particles inside the list. The solution was obvious and allowed: create a new specialization for my own class that calls std::swap on the std::list :
namespace std {
template<>
inline void swap<iMc::Census>(iMc::Census& a, iMc::Census& b)
{
std::swap(a._particles, b._particles);
}
} // end namespace stdWell, because the _particles list was private, I had to make this function a friend of iMc::Census. Easy, right? Wrong. It turns out everything on the internet; that talks about templated friend functions is a lie! No matter what I did, I received a bunch of weird errors.
namespace iMc {
class Census {
private:
template<typename T> friend void std::swap(T& a, T& b);
...
};
}givesbuild/imclib/Census.hpp:64: error: 'void std::swap(iMc::Census&, iMc::Census&)' should have been declared inside 'std'
and
friend template<> void std::swap<iMc::Census>(iMc::Census& a, iMc::Census& b);gives
build/imclib/Census.hpp:64: error: expected unqualified-id before 'template'
Well, it turns out that the correct answer is to have
namespace iMc {
class Census {
private:
template<typename T> friend void std::swap(T& a, T& b);
...
};
}Who would have guessed? I even checked Stroustroup's reference book, and it didn't look like it had syntax for templated friend functions in there. Hopefully no one else has to fool around and waste an hour of their time trying to do this.
18 February 2009
CC license
I'm LaTeXing my class notes, and I plan on distributing them in some sense. Here's the Creative Commons license in LaTeX that I came up with (which puts CC in a circle and uses the hyperref package to hyperlink it):
\newcommand{\cclicense}{%
\smash{\raisebox{-0.45ex}{%
\setlength{\unitlength}{1em}%
\begin{picture}(1,1)%
\put(0.5,0.5){\circle{1}}
\put(0.5,0.5){\hbox to 0pt{%
\hss\raisebox{-.45ex}{\tiny\textsf{CC}}\hss}}%
\end{picture}%
}}%
\hskip -1em%
\href{http://creativecommons.org/licenses/by-sa/3.0/}%
{\ \hskip 1em \textsf{BY-SA}}%
}Update: thanks are due to Mike for pointing out my use of an externally defined term, which I thought was in base/latex.ltx but was actually defined elsewhere.
05 February 2009
MCNP syntax highlighting in vim
This syntax highlighter for MCNP in VIM is due to Giacomo Grasso. The file on his page is inaccessible other than through the white paper, so I have taken the liberty of extracting it and putting into a file available for download. Put it inside the ~/.vim/syntax folder.
There's no easy sure-fire way of detecting an MCNP input file, but if you create a file at ~/.vim/scripts.vim with the contents
if did_filetype() " filetype already set.. finish " ..don't do these checks endif if getline(2) =~ '^C.*\<mcnp\>\c' setfiletype imcnp endif
it will load the MCNP syntax coloring if the second line of your input deck is a comment (the first letter of the line is a 'c') with the word MCNP in it somewhere.
Subscribe to:
Posts (Atom)