Monthly Archives: October 2017

Erlang: Naive Matrix Multiplication

Someone asked what was surely a homework question today on StackOverflow about matrix multiplication in Erlang. I set out to answer him in as simple a way as possible, but wound up writing a naive matrix generation and multiplication module.

The code to the module might be of interest to new Erlangers, as it adheres both to the style of zuuid and includes many examples of using a combination of list operations and explicit recursion to cut clutter and make the meaning of otherwise complex operations clear.

Here is the code:

%%% @doc
%%% A naive matrix generation, rotation and multiplication module.
%%% It doesn't concern itself with much checking, so input dimensions must be known
%%% prior to calling any of these functions lest you receive some weird results back,
%%% as most of these functions do not crash on input that go against the rules of
%%% matrix multiplication.
%%%
%%% All functions crash on obviously bad values.
%%% @end 

-module(naive_matrix).
-export([random/2, random/3, rotate/1, multiply/2]).

-type matrix() :: [[number()]].


-spec random(Size, MaxValue) -> Matrix
    when Size     :: pos_integer(),
         MaxValue :: pos_integer(),
         Matrix   :: matrix().
%% @doc
%% Generate a square matrix of dimensions {Size, Size} populated with random
%% integer values inclusive of 1..MaxValue.

random(Size, MaxValue) when Size > 0, MaxValue > 0 ->
    random(Size, Size, MaxValue).


-spec random(X, Y, MaxValue) -> Matrix
    when X        :: pos_integer(),
         Y        :: pos_integer(),
         MaxValue :: pos_integer(),
         Matrix   :: matrix().
%% @doc
%% Generate a matrix of dimensions {X, Y} populated with random integer values
%% inclusive 1..MaxValue.

random(X, Y, MaxValue) when X > 0, Y > 0, MaxValue > 0 ->
    Columns = lists:duplicate(X, []),
    Populate = fun(Col) -> row(Y, MaxValue, Col) end,
    lists:map(Populate, Columns).


-spec row(Size, MaxValue, Acc) -> NewAcc
    when Size     :: non_neg_integer(),
         MaxValue :: pos_integer(),
         Acc      :: [pos_integer()],
         NewAcc   :: [pos_integer()].
%% @private
%% Generate a single row of random integers.

row(0, _, Acc) ->
    Acc;
row(Size, MaxValue, Acc) ->
    row(Size - 1, MaxValue, [rand:uniform(MaxValue) | Acc]).


-spec rotate(matrix()) -> matrix().
%% @doc
%% Takes a matrix of {X, Y} size and rotates it left, returning a matrix of {Y, X} size.

rotate(Matrix) ->
    rotate(Matrix, [], [], []).


-spec rotate(Matrix, Rem, Current, Acc) -> Rotated
    when Matrix  :: matrix(),
         Rem     :: [[number()]],
         Current :: [number()],
         Acc     :: matrix(),
         Rotated :: matrix().
%% @private
%% Iterates doubly over a matrix, packing the diminished remainder into Rem and
%% packing the current row into Current. This is naive, in that it assumes an
%% even matrix of dimentions {X, Y}, and will return one of dimentions {Y, X}
%% based on the length of the first row, regardless whether the input was actually
%% even.

rotate([[] | _], [], [], Acc) ->
    Acc;
rotate([], Rem, Current, Acc) ->
    NewRem = lists:reverse(Rem),
    NewCurrent = lists:reverse(Current),
    rotate(NewRem, [], [], [NewCurrent | Acc]);
rotate([[V | Vs] | Rows], Rem, Current, Acc) ->
    rotate(Rows, [Vs | Rem], [V | Current], Acc).


-spec multiply(ValueA, ValueB) -> Product
    when ValueA  :: number() | matrix(),
         ValueB  :: number() | matrix(),
         Product :: number() | matrix().
%% @doc
%% Accept any legal combination of scalar and matrix values to be multiplied.
%% The correct operation will be chosen based on input values.

multiply(A, B) when is_number(A), is_number(B) ->
    A * B;
multiply(A, B) when is_number(A), is_list(B) ->
    multiply_scalar(A, B);
multiply(A, B) when is_list(A), is_list(B) ->
    multiply_matrix(A, B).


-spec multiply_scalar(A, B) -> Product
    when A       :: number(),
         B       :: matrix(),
         Product :: matrix().
%% @private
%% Simple scalar multiplication of a matrix.

multiply_scalar(A, B) ->
    multiply_scalar(A, B, []).


-spec multiply_scalar(A, B, Acc) -> Product
    when A       :: number(),
         B       :: matrix(),
         Acc     :: matrix(),
         Product :: matrix().
%% @private
%% Scalar multiplication is implemented here as an explicit recursion over
%% a list of lists, each element of which is subjected to a map operation.

multiply_scalar(A, [B | Bs], Acc) ->
    Row = lists:map(fun(N) -> A * N end, B),
    multiply_scalar(A, Bs, [Row | Acc]);
multiply_scalar(_, [], Acc) ->
    lists:reverse(Acc).


-spec multiply_matrix(A, B) -> Product
    when A       :: matrix(),
         B       :: matrix(),
         Product :: matrix().
%% @doc
%% Multiply two matrices together according to the matrix multiplication rules.
%% This function does not check that the inputs are actually proper (regular)
%% matrices, but does check that the input row/column lengths are compatible.

multiply_matrix(A = [R | _], B) when length(R) == length(B) ->
    multiply_matrix(A, rotate(B), []).


-spec multiply_matrix(A, B, Acc) -> Product
    when A       :: matrix(),
         B       :: matrix(),
         Acc     :: matrix(),
         Product :: matrix().
%% @private
%% Iterate a row multiplication operation of each row of A over matrix B until
%% A is exhausted.

multiply_matrix([A | As], B, Acc) ->
    Prod = multiply_row(A, B, []),
    multiply_matrix(As, B, [Prod | Acc]);
multiply_matrix([], _, Acc) ->
    lists:reverse(Acc).


-spec multiply_row(Row, B, Acc) -> Product
    when Row     :: [number()],
         B       :: matrix(),
         Acc     :: [number()],
         Product :: [number()].
%% @private
%% Multiply each row of matrix B by the input Row, returning the list of resulting sums.

multiply_row(Row, [B | Bs], Acc) ->
    ZipProd = lists:zipwith(fun(X, Y) -> X * Y end, Row, B),
    Sum = lists:sum(ZipProd),
    multiply_row(Row, Bs, [Sum | Acc]);
multiply_row(_, [], Acc) ->
    Acc.

Hopefully reading that on a blog won’t drive anyone too nuts. I’ll probably include an expanded version of that (or something related) in a convenience library eventually. Unless I forget. Meh.

Web Designers: Stop making SPAs for inherently web 1.0 style sites

It is 2017. What’s with the drive to make everything an SPA whether it needs to be or not? This is getting a little ridiculous. I’m going to ramble on below a bit because I’ve got a hankering to do so — pay this no mind.

All around the web I see sites that are best represented as a collection of inter-linked documents, and all around the web I see many of those being changed into single-page application (SPAs). Even more stupid is when the SPA in question was built by some naive dope who included a little bit of almost every JS framework in existence — including a random selection from the thousands of obsolete and dead ones.

What is the goal? What’s the deal? Do web authors today not know how the web was actually intended to work originally? That document publication is actually its reason for existence in the first place and that “web applications” are a new thing that is a backhack to an incomplete standard that only sorta-kinda-works?

Granted, the reason it only sorta-kinda-works is due mostly to the problems inherent in the fact that only a single language is allowed in scripts… which is ridiculous. Was nobody paying attention to the Guile2 approach all those years? The only lesson learned from the Java applet and Flash experience seems to have been that “it sucks to force users to install runtimes as plugins”. Ugh.

Anyway, back to web applications…

I get it. For the moment we don’t have a solid distinction between “a document browser” and “an application browser” so we are stuck with this insufficient worst-of-both-worlds nether region of “applications that masquerade as documents”. And that drives anyone nuts who has given this much thought.

Not that a lot of people have considered the difference deeply. I imagine that is probably because very few new coders today have ever written more than a line or two of code intended to run natively on a user’s local system. Nearly everyone has written thousands of lines of code intended to run natively on server-side systems, but even that is getting wonky because many youngsters today don’t know how to deploy without using Docker yet lack the faintest inkling as to what problems Docker actually is intended to solve and wind up bypassing better solutions when they exist.

Tools shine when they are used in a focused way, performing they job for which they were intended. The web is the same way. Yes, it is a big jumble of crap. So let’s just leave that there. Networks are a big jumble of crap, too, and so are human societies — so we’ve adopted dirty ways of dealing with the dirt. The jumbly pile of shit that is the web is one of our ways of dealing with that. Everything times out. Everything is sent in text. Protocols are bloated and redundant. There isn’t even a proper definition of what “valid” HTML and XML and JSON and whatever else is in most cases. Its all racing toward a singularity where everything is uniformly stupid. But… whatever, it sort of kind of still works — and humans just barely work themselves, so that’s par for the course.

The original web was designed to function as an insecure document publication system where documents could be interlinked. We realized that we could include more interesting stuff by expanding the definition of “document” to include more than just text, and quite recently with HTML5 the way in which documents can be written is only a few orders of magnitude behind, say, LaTeX, in its ability to arrange things on the screen (that’s feature lag is not entirely the fault of the HTML5 authors).

This gives a lot of freedom to website authors — perhaps too much.

If a website is a set of news articles or academic papers (or even tweets) then you really don’t need a SPA, you need a more traditional sort of “web site”. It can be dressed up all pretty with shiny things sprinkled around, of course, but we don’t want a SPA that mysteriously changes state in ways that users cannot bookmark things, can’t easily send links to one another to specific resources (something Twitter got right despite some initial confusion over how to frame their content), etc.

If a website is actually just a delivery front end for a graphical RPG, well, obviously the game part of the site is probably best designed as a SPA, but the rest of the site — the forums, armory, character pages, beastiary, fan wiki, manual, guild rankings, lore pages, etc. — are absolutely best presented outside of that SPA as an actual website.

See the difference?

The game example is actually quite useful to contemplate for a variety of reasons. I’ll probably come back and cut this post down to just that part. Either that or eventually come back and rewrite the first bits to more accurately convey the humor with which I, as a graybeard resident in cyberspace for about 30 years now, view the state of the web today.

Whatever you do, dear reader, have fun coding, and remember: Don’t outsmart yourself!

Las Vegas shooting prediction: Most casualties were not due to gunshot wounds

Looking over the data for large stampedes and crowd crush events at concerts and sporting events, and comparing this to what I know personally from a career spent mostly handling various weapons in a tactical environment, I expect that we will discover fairly soon that the vast majority of casualties during the Las Vegas shooting — both injuries and fatalities — were actually due to stampede, and not anything to do with gunshot wounds at all.

Of course, in the confusion this issue has become politicized to an absolutely ridiculous degree by various anti-gun factions, and much of the US and European media is loathe to report anything other than anti-gun statistics for the moment, so we are seeing language tailored to evoke images of hundreds of people with actual gunshot wounds and zero people with stampede injuries.

For example: “Shooter in Las Vegas [blah blah blah] over 500 wounded.” This makes the reader or listener immediately envision 500 people actually wounded, as in due to violent trauma — and deliberate violent trauma at that. Which in this case would be exclusively due to gunshot wounds. But we have never seen a breakdown of causes of bodily harm by type, and this data will take a while to assemble.

By the time we do see these stats most people will not really be interested because immigration in Europe or stubborn people in Madrid/Barcelona or NFL SJW activity or whatever else will steal the spotlight and public attention before then. In other words, people will be distracted with another issue-of-the-day by then and forget that the new factoids they see relate to a previous event they felt very strongly about at the time it occurred.

Watch for this one.

Asian Governments Making Social Moves Together

I expect Asian governments to manifest a low-key but characteristically firm and absolute (and often official) position against Islam. Actually, I don’t expect it, I’m watching it happen and just now recognizing a fairly uniform trend. Something is going on in Asia with regard to this, and I don’t know quite what it is, but there is no doubt that doors are closing all across Asia for Muslims in general.

I think the timing is not a coincidence — the nature of Islamic threats are changing, becoming more diffuse, and taking on a different character just as a new generation of indoctrination is beginning across the West and Asia.

  • Myanmar has found something much more compelling than mere domestic political expediency to engage in its current operations (ISIS returners, as are turning up in Malaysia, Indonesia and the Philippines, is one possibility).
  • China has begun confiscating the Koran and categorized it as a book containing extremist political sentiment.
  • Thailand is readying a firm move against the southern Muslim rebels — and at the same time ISIS returners are very effectively influencing the young generation throughout the old Pattani region.
  • Saudis and other donors are standing up madrasas throughout Malaysia and Indonesia, and the Malaysian government is both unable to stop the trend while at the same time higher-ups in Putrajaya are strangely blind to the problem while also complaining about it.
  • The Philippines is obviously on a “you’re with us or against us” path politically and socially. And a certain of portion of the younger Muslim generation today is much more willing to take that as a challenge instead of an offer to pledge fealty (or at least negotiate terms).
  • Japanese are, at least anecdotally, becoming increasingly uneasy with the idea of accepting any Muslims, even as guest workers. The striking thing there is that ten years ago (well after 9/11) the topic of religion would never have been mentioned discussing this issue socially, but now it is brought up. This change over the last year or two coincides with the first mosque in Kyoto trying to promote itself via online ads and Japanese demonstrating an instant and strong aversion to the very concept of proselytization. They are now in “wait and see” mode socially — to watch and see how things turn out in Europe.
  • South Koreans seem to be on the same page as the Japanese — the attitude toward Islam having soured considerably over the last five years or so. Once again, this is anecdotal, but the subject has come up more than once, and many South Koreans keep up with news of attacks in France, Sweden and the UK.
  • Indonesia is seeing the rise of extra-judicial Islamic enforcement gangs.
  • Malaysia is seeing a similar rise in extra-judicial Islamic enforcement gangs, but the effect is somewhat muted by considerable repression by the special police and more active engagement with the group leaders.
  • Returners, returners, returners. ISIS veterans are flooding into various part of Asia, fresh off a tour in Syria, North Africa, Iraq or Afghanistan with ISIS and keeping in touch with one another. Of course, nobody feels comfortable with that. Unlike in Europe, though, well-known jihadis are not left to their own devices and most go missing somewhere in transit — but it is clear and evident that many are still returning and building new lines of communication and influence locally.

Any one of these issues, from official government actions to simple social reactions, would be grounds for certain groups to rally large responses — Islamic groups as well as Western-based political groups with strong anti-Asian nationalist agendas (something I’ve always found very odd). But the only thing making the news is Myanmar right now, and that’s a pretty hopeless fight to try to pick in terms of political pressure. Myanmar is about as pliable as North Korea as long as China is on their side, and China is indeed on their side with regard to this detail.

I do not see a future where Asian governments will feel compelled to do anything other than increase their resistance to an increased domestic Muslim presence. I fully expect that religious questions will be incorporated on visa applications to places like China eventually (not that repression of religion is anything new there).

I have no idea how any of this is going to turn out, but I find this trend notable and the timing troubling. I don’t know exactly what is triggering this much activity just now (why not a decade ago?), but something is clearly going on. It could be the outcome of some government assessments, or simply a change in the domestic social outlook, or both — but something is going on with this. And, of course, it is impossible to say “they are wrong”. It is just what they are doing and I’m just pointing it out.