11 ms·
There's a clear-cut "scissor statement" that you can use to divide programmers into two opposite sides. You ask the following question: "--If you need to inver
by enriquto 7y ago
There's a clear-cut "scissor statement" that you can use to divide programmers into two opposite sides. You ask the following question:
"--If you need to invert a 2x2 matrix in your program, do you write down the algebraic formula for the solution by hand or do you call a linear algebra library? (that you would not need otherwise)"
The answer to this question is obvious to most programmers. Also, it is obvious to them that the opposite answer is clearly wrong and absurd. Unfortunately, not everybody gives the same answer!
- deleted 7y ago[deleted]
- seisvelas 7y agoOkay, you got me. I am in the camp that says calling the library is (in the general case) obviously the better choice. My (camp's) reasoning: 1. Your handrolled solution is likely worse than the library anyway 2. You're wasting effort reinventing the wheel 3. You risk adding unnecessary opacity by littering the program with dense math 4. Other programmers will assume there is a pertinent reason you handrolled the algorithm instead of using the library. Now everytime someone touches that code they have to reverse engineer your approach to see what it does different from the library such that you had to roll it yourself (surprise: nothing!). The two exceptions I imagine are 1) if you really do absolutely need some slightly modified microoptimization of what the library does or 2) if you are working for a platform where there is good reason to avoid even slight bloat (embedded). For the people who read OP's comment and believe I am (obviously) wrong, what is your camp's way of looking at this?
- enriquto 7y ago> I am in the camp that says calling the library is (in the general case) You misunderstood the question. The question is not about the general case. It is about solving a linear system of two equations and two variables. The solution is not found by "an algorithm", it is a simple formula that fits in one line.
- heisenbit 7y agoI was tending to go in your direction, but then the formula contains a division and we could be faced with a division by zero error. Which makes me a bit uncertain whether it is so simple. If we are guaranteed the matrix is invertible then doing it by hand is something I would prefer. And likely if it is not then as well since... The invertibility issue also plagues any library and while it may not blow up by a division by zero we likely still would need to handle that case. This requires to understand the libraries handling of corner cases and how it affects the results.
- crispyambulance 7y agoSure, if you're solving a 2x2 in ONE place in a piece of software, it makes sense to just perform the computation directly without using a library. Realistically speaking, though, if you're doing one 2x2 computation, you're probably going to end up doing a bunch of other linear algebra as well. If you don't do linear algebra in your everyday work, the threshold from rolling-your-own solution to grabbing a library is going to come up very quickly. The Armstrong example is perhaps a bit mis-titled. He's talking about "implementing from scratch" only insofar as he can use the facilities of his platform to perform exactly the task he needs to do rather than bringing in a huge dependency, in this case, an FTP server that does a lot more than the one task at hand.
- NohatCoder 7y agoIf you don't know how to do linear algebra, a library is unlikely to help you. Rote stuff like matrix inversion is the easy part, figuring that that is what you need is where things tend to get hairy.
- crispyambulance 7y agoI think also that people can "know" linear algebra but not be skilled it's practical implementation and usage in software. That's partly why computation libraries are among the longest-lived pieces of software in existence.
- 7y ago
- throwsprtsdy 7y ago> Your handrolled solution is likely worse than the library anyway This assumption led to a lot of O(n^2) left-padding happening over the years, via left-pad from node.js. Ideally libraries would be well-tested and of high quality, but at this point there may be too many of them to vet. My own 2 cents is that if it's easier to implement the code from scratch than to evaluate and choose a library, perhaps the invent-it-here choice works best.
- jolux 7y agoIf you're better at this than LAPACK to the extent that you do not even trust it to function correctly, more power to you.
- BubRoss 7y agoI'm not going to integrate LAPACK for a single line expression.
- jolux 7y agoLAPACK is the underlying library behind most linear algebra packages in other languages and furthermore it was just an example. My guess is that you probably don’t have just one line of matrix manipulation ever, in which case using a well established library is a good idea. If not, then sure. Do it yourself. But that’s still more code that you have to maintain now.
- username90 7y ago> But that’s still more code that you have to maintain now. 10 lines of code is easier to maintain than a whole dependency.
- jolux 7y agoThat's arguable, because 10 lines of code almost never just stays 10 lines of code, and my point in the first place was more contesting that the dependency is hard to choose, or that there aren't solid proven libraries for this.
- bryanrasmussen 7y ago1. If you were Joe Armstrong or at his level, probably not. 2. If you're Joe Armstrong the amount of time you're wasting is negligible, and you don't need to worry about working with an unneeded dependency. I mean I would be wasting a significant amount of time because I'm not Joe Armstrong but there are things I get asked to do that other people would use a library for and I think what, why? 3. Opacity is in the eye of the beholder. If you're working on a project only you and a few people you know can handle it will ever look at, then you are that beholder. If you're working for a big organization as a consultant and your contract runs down in a month, think of the worst guy you have ever worked with that was still a programmer - that guy is the beholder. 4. If you write a comment then they won't make the assumption. Later: Why the downvote? Even Later: Upvoted, so I guess someone didn't like or maybe just clicked wrong.
- zimpenfish 7y ago> 1. If you were Joe Armstrong or at his level, probably not. But 99% of us are not at his level. And more importantly, 99% of the people who come after to maintain this code are not either.
- bryanrasmussen 7y agoI'm not sure if the people who come after Joe Armstrong to maintain his code are not at his level. Or at least close enough that this particular decision wouldn't be a problem
- NohatCoder 7y ago1. The computation is a handful of simple arithmetic statements, there is almost nothing one can do to optimize those. The library is likely written to handle inversion of any size matrix, that means it adds a bunch of control code to be more general, but also slower for this case. 2. You are wasting effort evaluating libraries. And I wonder what you lose in compile time? 3. You are calling into a black box, and you talk about opacity, a simple comment: /* this inverses the matrix */ will deal with your perceived issue. 4. Other programmers will assume there is a pertinent reason you included yet another dependency. Wonder what it does that 5 lines of code couldn't have done (surprise: nothing!).
- SilasX 7y ago>The computation is a handful of simple arithmetic statements, there is almost nothing one can do to optimize those. I'm not sure that's right in this case. For inverting a matrix, it makes a huge difference whether the determinant is exactly zero or just very close, and (IIRC) floating point math may give the wrong answer. A library will have worked through this issue.
- rzwitserloot 7y agoThe history of various bugs in various very commonly used libraries, with them being extremely obvious after being discovered, strongly suggests this: If there is some situation that is somewhat likely to come up and needs special code, but it is not immediately obvious (and, going by OP's evident lack of realizing it, that's some proof to say it is not immediately obvious)? It may not be there. And even if it is the common path, it can still be buggy. Is is less likely that a library with some actual use out there has these bugs vs. handrolling it, but, if you handroll it, you're writing it for _your_ case, specifically with what you have in mind, whereas the library is more general than that. That's usually upside, but there's also downside, in what may be obvious to your usecase may not be obvious to the library. The central point of the top comment here, that opinions differ and that there isn't actually an obvious answer even if you think there is one, holds true here.
- NohatCoder 7y ago
- rubyn00bie 7y ago> 1. Your handrolled solution is likely worse than the library anyway I quite doubt that, though I used to feel the same. The one feature I need in the library is probably implemented for a specific use case which is undocumented or misrepresented; and use cases outside of that are likely to be egregiously unsupported. Fixing the issues is almost always more work than just implementing X directly and looking up gotchas. (aside: to understand this first-hand, go pick any JavaScript[0] animation library, and then go add a library that integrates it the core framework you're using (or not)... et voila, enjoy the descent into hell.) A simple implementation of X that doesn't lock you into patterns you don't need or will one day harm you is worth its wait in gold. Seriously, I'd rather sacrifice DRY code than fuck myself eight months down the road by using a shitty over-engineered pattern that doesn't actually fit my needs. > 2. You're wasting effort reinventing the wheel Probably not; it turns out most of the wheel was invented and given to you in the language and runtime. For the article, it's 100% true, BEAM is pretty much an operating system and a great one at that. We often abstract for the sake of abstraction; I honestly think Elixir/Erlang has helped break me of quite a bit of that. Rust is also nice because it'll make things so very painful for you when you abstract for no reason. > 3. You risk adding unnecessary opacity by littering the program with dense math Opaque libraries are the exact same thing but are even harder to understand since the source code doesn't comply with your same coding standards, methodologies, or test suite. > 4. Other programmers will assume there is a pertinent reason you hand-rolled the algorithm instead of using the library. Now everytime someone touches that code they have to reverse engineer your approach to see what it does different from the library such that you had to roll it yourself (surprise: nothing!). Documentation is the answer here, it doesn't have much to do with library or DIY. Why go through the trouble to properly evaluate a solution, decide the best solution was to implement your specific use case (or otherwise), and then not document it? You're just asking to repeat yourself or forget. On the flip-side, its really easy to assume that library authors did something brilliant when in fact they've done the opposite. Or someone will assume you've chosen this library because you took the time to properly evaluate it and never question it... Ex. After eight months of having the library run slow and leak memory some junior engineer pulls you aside and softly says "I have a minor in mathematics, I noticed that library Y is only doing simple matrix multiplication... I can do the same thing with this [shows you four lines of code] and its a lot faster... I just assumed we had to use that library since its in our code base." Adding libraries before you need them causes more headaches than not because now you've littered a dependency throughout your code which may not be sufficient for future use cases. This goes back to I'd rather have less DRY code than be bound to a shitty inflexible pattern. > The two exceptions I imagine are 1) if you really do absolutely need some slightly modified microoptimization of what the library does or 2) if you are working for a platform where there is good reason to avoid even slight bloat (embedded). I don't totally agree with either of those statements fully but I don't strongly disagree with them either. I'd like to add for me these would be of much high significance: 1. Your future use case are unknown. 2. You do not know if the library will be maintained; so, by using it, you're going to own it anyway. There are no free lunches. 3. You're using only a small, defined subset of some standard (i.e. RFC or specification). The existing solutions provide too much cruft for your specific use case. 4. The solution is obvious and has one correct answer. In some languages this is easier because of strong conventions and standard libraries. In others, this is probably a pipe dream. 5. The libraries are not tested adequately or are not easily testable. I dunno, over the past few years especially, I've just started doing more things myself and yeah things do take slightly longer to start (sometimes...) they almost never take more time to maintain, expand on, or use. Each line of code used by your project is a liability (debt), not an asset, on your balance sheet... Less code, less liability, less debt. [0] No offense to JavaScript <3, I only choose it, because it's so ubiquitous.
- mrighele 7y agoI used to be in the "implement from scratch" side, but these days my position is a lot more "it depends". My approach to deciding if using an external library or write the code goes more or less as follows: a) Limit yourself to a few big libraries that are widely used and well supported. Especially if you work with a language where it is trivially easy to publish a new library, let's say javascript, you will find that even if you are just an average programmer half of the libraries you have access to have worse code that you would have written (so your point 1. is not necessarily correct) Also using a library has a number of costs with it: increase in code size, time wasted updating it when needed, learning how to use it, understanding its documentation (if there is any at all), understanding why it doesn't behave how it is supposed to, checking github for bugs not yet fixed, etc. (so the effort spent in your 2. point is not necessarily bigger) This cost is reduced is the library is a quality one, and also if you use a good amount of it, so my second point is b) try to avoid a library if you just you need to use little of its functionality Not only it may be cheaper to re-implement the part that you need, but adding a whole library means that you give charte blanc to other developers to use all the other parts of that library. This may be something that you want to avoid, expecially if the library has varying quality and not all parts are well-written. On the other side, if you know that you will probably need other parts in the future, it may be better to use the library instead. My third rule is c) keep in mind your team If most people in your team already know a library, the cost of using it is greatly reduced. On the other side, if it new for most of them, it may be easier for them to maintain custom code (relates to your point 3.).
- ci5er 7y ago2x2? Do it by hand. No dense math involved. One line of code (or so, depending on coding style). If you want to implement or call LINPACK to do a 2x2, you've got other problems.
- henriquez 7y agoEvery time I npm install my projects and get the "you have 10 new critical vulnerabilities!" message it makes me a little more cautious about relying on third party code. I think there's a balance between rolling your own and using a lib, and it boils down to the domain of the problem being solved. If you're really just flipping a 2x2 matrix, the linear algebra lib will have way too much junk you don't need, and learning to use it would be more work than just solving a math problem. On the other hand, if you need a lot of common functionality (like multitouch events on the frontend), then why reinvent the wheel when there are a handful of great libraries for it.
- smichel17 7y agoHey, you're me!'I would do this: 1. Add an "invert2x2Matrix(theMatrix)" function. 2. Implement the function myself (no library). 3. Add a comment at the top of the function to the effect of "if this ever ends up doing much more than what the name says, consider replacing it with a library."
- Scarblac 7y agoDo you know that we are talking about applying 1 well-known formula? And that he mentioned that the library wasn't otherwise used in the project?
- caymanjim 7y agoYou first need to divide the programmers into two bins based on whether or not they even understand the question and could reason out the answer on their own. What world do you live in where programmers know linear algebra and understand what inverting a matrix is?
- enriquto 7y agoI work in a department of applied math. Hard to conceive anybody around here who does not know how to solve a 2x2 linear system.
- zamadatix 7y agoSure in your individual case that may be but the scissor statement was presented generally as if one could walk up to any programmer. It only being immediately understood by a smaller subset makes it not very helpful. I can't think of a similar scissor the majority of programmers both already have a solid understanding of and would be likely to be divided on - but I'd love to be out thought!
- cle 7y agoI didn’t see it as trying I be helpful in the way you’re thinking, just illustrative. IMO, the best way to write the code (pulling in a lib vs doing it yourself) is to consider the context in which it’s going to be read, maintained, and used. If that’s by a bunch of applied scientists or linalg experts who can read a formula more easily than debugging and maintaining integrated libraries, then roll it yourself.
- zamadatix 7y agoIn the actual case of just needing to invert a single 2x2 matrix in one spot of the program it takes more to understand what the library is being asked to do, how to format the ask, and what it should be giving back than it does to understand the 3 commented steps to do it. Maybe put a comment that if the needs change in the future it might be worth pulling in <linear algebra library of choice>. On the flipside if you expect the needs to increase in the future might as well do it now. In the general case look at complexity of the options and then look at context of who has to maintain that complexity don't just assume 3rd party means it'll be easier for others to grok while bug hunting.
- _bxg1 7y agoI'd feel conflicted about it. Maybe that's secretly the "best" answer? ;)
- p0nce 7y agoIt's a debt decision, the difficulty of creating the code is relatively small compared to the everlasting cost of maintaining it afterwards. Also, managing the dependencies whims also is debt.
- jschwartzi 7y agoOn the other hand, it's not necessarily about LAPACK specifically or the 2x2 matrix. On embedded systems image size actually matters because you have to distribute the image to the embedded system and in many cases your systems have like 4k of flash. So if LAPACK costs you 2k of flash just to invert a 2x2 matrix and you can come up with a solution for inverting 2x2 matrices easily with 200 bytes of code because you have your Linear Algebra textbook handy, why would you include LAPACK? In fact even if LAPACK does all linear algebra operations correctly 100% of the time, it also introduces a new paradigm, meaning I have to learn how to do things the LAPACK way which may not be intuitive for the class of problem I have. Or LAPACK may do things correctly for the general case at the cost of CPU time whereas my problem needs to be calculated in real-time, in which case including LAPACK is a net-negative for me. I think the two schools of programmer divide pretty cleanly into people who assume infinite resources and no CPU time constraints and people who have to make trade-offs between resources and time constraints. Serious embedded programmers will almost never want to just include LAPACK and be done with it unless their problem domain involves a ton of linear algebra. Whereas I've yet to meet a web developer who wouldn't just pull in 400 megabytes of libraries doing god knows what to invert a 2x2 matrix with a function call. There are web developers out there who have to optimize pretty close to what the system is capable of, but most web developers don't really care that much about that because they have infinite computing resources(just spin up more instances!) but they need to release their website "like, yesterday." So it's not about camps per se. As is everything in engineering, it's about trading a resource you have in abundance for a resource that is scarce. For embedded programmers, the real-time requirements and storage capabilities of the MCU are king and they'll gladly spend all the time in the world rolling their own 2x2 matrix inverter. And for web developers, their development time is king so it's better to just cobble together something working using LAPACK and move on because they can just reserve a bigger, faster server.
- hinkley 7y agoWhat’s the old line about experts answering “it depends” for everything? I’d give good odds that the person doing a 2x2 matrix didn’t even notice it was linear algebra. I wrote a trivial image rotation, zoom and crop feature a number of years ago and I bet if you looked at that code you’d tell me I fucked up by not using linear algebra. Instead I had a series of geometry diagrams on my whiteboard trying to figure out unit tests for my hand written code. Which the next guy promptly broke but that’s another story for a different day. If I know it’s linear algebra, it will probably come up again. Now my decision is somewhat informed and also more difficult.
- username90 7y agoUltimately the kind which imports a library becomes react developers or django developers or other framework developers, while the kind who learns how to implement things on their own become generic software engineers. So you can see which kind a company hires based on their job ads, if it lists a lot of frameworks and libraries then they expect you to have spent most of your time importing and using libraries. While if the ad just lists domain specific knowledge and some generic coding bits they will mostly have people who likes doing things on their own.
- ohazi 7y agoGood Lord, you guys are all crazy... It's a TWO BY TWO matrix!
- zzo38computer 7y agoMy own choice is normally the first one (doing it by hand). But things can depend on stuff not mentioned in your questions.
- d0mine 7y agoMy answer: it depends (how long the project might live? (a one of script vs. 10 years project that has to be maintained) What is the cost of adding a dependency? (deployment, security risks, onboarding curve) Do ai need to care about numeric stability and such? etc. For example, for a one of script deployed in Pythonista on iOS, I would probably use a library if It is available/installable via pip with a single command, rolling out my own otherwise for 2x2 cases with a single google search unless I need to handle special cases.
- hyperpape 7y agoThe levels of stereotyping in this thread prove that you’re good at creating scissor statements.
- jancsika 7y agoThat's simple-- I read the docs and peruse the implementation for the linear algebra library. If it fits the use case I use it. If not I roll my own. Don't most people do this?
- pgcj_poster 7y agoIsn't this just going to be `lambda M: [[M[1][1],-M[0][1]], [-M[1][0], M[0][0]]]`? You guys are going to add a library just for that?
- dimtion 7y agoI don't want to sound mean, but the simple fact that you forgot to divide by the matrix determinant for me is a great illustration of why using a library might be a good option. I think for most of us can make this mistake, and reasoning in higher order (i.e. using a function from a tested library) helps avoiding this kind of error.
- cochne 7y agoIt might be helpful to have some actual example code of what this looks like. In Python it would be def invert_2_by_2_matrix(matrix): # matrix is of form, for example ((1,2), (3,4)) ((a, b), (c, d)) = matrix det = (a*d - b*c) return ((d/det, -b/det), (-c/det, a/det)) (This doesn't do any input checking including if the determinant is 0)
- SilasX 7y ago>This doesn't do any input checking including if the determinant is 0 Which seems to me like it assumes away a big part of the difficulty -- you'd need to follow up with: for this problem domain, what am I doing with the answer? How do I need to handle a singular matrix? Should do I throw an exception, and how should the caller handle it?
- PureParadigm 7y agoCompared to the library version: import numpy as np np.linalg.inv([[1,2],[3,4]]) and this does handle the case where the determinant is 0 (by throwing an error about it being a singular matrix).
- xaedes 7y agoAvoid np.linalg.inv if you can do it in another way.. It slows the already slow python even more. Recently replaced np.linalg.inv by an affine transformation inverse (what was really needed) in one of our codebases to get a speedup of 100x.
- eikenberry 7y agoWhat about the group that would do one or the other based on their mood? If I felt curious that day I'd definitely do it the first way as it has been forever since I've needed to do any sort of matrix math and it would be interesting to re-visit it. On the other hand if I was tired or in a more down mood I'd probably just use the library as I wouldn't care.
- bobbiechen 7y agoThe origin of the term "scissor statement", for anyone interested - Scott Alexander writes some entertaining fiction: https://slatestarcodex.com/2018/10/30/sort-by-controversial/ https://slatestarcodex.com/2018/10/30/sort-by-controversial/
- enriquto 7y agoI love this story! The thing is that these statements are easier to come by than the story assumes. You do not need deep learning for natural language processing. It is actually very easy: You just think about something which is clearly obvious, start saying it around, and find that many people think you are completely nuts or you are trolling them. When the percentage of people who think you are nuts approaches 50%, it means that you found a good scissor statement.
- bsder 7y ago> "--If you need to invert a 2x2 matrix in your program, do you write down the algebraic formula for the solution by hand or do you call a linear algebra library? (that you would not need otherwise)" If you wanted to use equations in your code and I was reviewing it, you're going to have a LONG session explaining the finer points of floating point and how you avoided all the problems that can cause. I can quote sections of IEEE-754 from memory, and I would use a library. I simply have zero confidence that my algebraic equations would handle massive cancellation and roundoff correctly in all cases. And these are the WORST class of bugs to introduce into your program--a function that works right 99.9% of the time but fails catastrophically at random times.
- dogcomplex 7y agoI love this. I think the show Silicon Valley made two perfect archetypes of this divide: Gilfoyle: the proudly independent coder who prefers to build everything himself rather than be subject to trusting other's code. Documentation is minimal. Code is intense, efficient, and requires a (too) high level of intelligence and effort just to make sense of. Gravitates towards back-end bare-metal systems code and hardware. Background is self-taught pragmatic hacker. Refuses management roles, preferring to do a department's work himself rather than trust underlings. "Why would I use a library to perform elliptic curve cryptographic functions I am fully capable of writing myself? Do you think I'm a fucking moron?" Dinesh: the extremely needy but clever programmer whose code is a massive pile of dependencies and abstractions. Unhindered by pride and happy to trust any workaround or outside source if it means him doing less "work" (he does not view learning about new libraries/codebases as work). Documentation is conversational and verbose, with huge doc blocks above the simplest functions. Code is highly abstracted and spread across many files but with an overall working logic to it - often following various (obscure) engineering standards rather than using personal pragmatism. Loves to communicate, and so has a flair for front-end-facing code and making things pretty and understandable rather than completely efficient. Background is more academic and group project based, with a deep understanding of standards and love of new technologies. In a management role, tries to befriend, integrate, and understand all his employees programming styles - and sends many memos with emoticons. "Oooh, look, I found this neat library that animates my system font whenever I press the 'r' key! Arrrrrr! Hah. Pirates..."
- dogcomplex 7y agoI think, reading this again, most people would want to be Gilfoyle. However, undoubtedly the one who would most happily and realistically fit into real software teams is Dinesh. Real life Gilfoyle is basically confined to reinventing the wheel in small-scale obscure projects that don't interconnect well with the rest of the app-o-sphere, incapable of scaling beyond a single programmer. Worse: he's incapable of delivering sub-par work in a timely manner using heaps of thrown-together trash dependencies, which is pretty much essential to modern programming. The ability to happily navigate the garbage dump, jump through all the standardization hoops, and communicate well is arguably far more of the modern programming job than real deep understanding, efficiency, and sole dedication to the craft ever will be. (May our industry RIP)
- sriram_malhar 7y agoI wonder if am in a third camp. I like to implement everything from scratch (compilers, TCP/IP/arp/rarp stack, databases). But I like to use recommended libraries, not my own code. By implementing everything myself, I have a ready list of questions about how certain problems were handled, and a firmer understanding of where to look when the software misbehaves.
- alfiedotwtf 7y agoHa! Given the huge and varied responses to your simple question, I’m stealing it for interviews!