Cookie Notice

As far as I know, and as far as I remember, nothing in this page does anything with Cookies.

2015/10/17

Long, Boring To-Do Post

I'm considering stepping up my web presence, and as a precursor to that, I've created a twitter account specifically connected to this blog, @varlogrant. So, I need to do things to make it look more like I'm using it and less like it's an egg. (If I made the account picture the cover of that one Wilco album, would people get the joke?)

I certainly can automate a lot of stuff, going through the back catalog and retweeting old posts, but the question is, how much of that is just spammy? And, to what extent should I move my opinionated tech tweeting from @jacobydave to @varlogrant?

Beyond that, it strikes me that blogs where the blogger is more-or-less talking to himself are self-limiting, so I should start blogging more about certain subjects and less about things that are annoying me right this minute. 

That being said:
  • I am involved in a group creating an annual event. Specifically, I'm the web guy. There are some administrivia things going on, creating the pages for the team. This is a small matter of Wordpress time, so not hard. 
  • A harder thing is this: We have photos of previous presenters, which were existing head-shots of them, from before their presentations. We also have a large library of photos from the events. I've decided that the smart move is to use Flickr's API and WebService::Simple to grab all the old photos, use smartcrop.js to crop them to the appropriate size, and either personally chose a good one or make a web tool to crowdsource that amongst the group. This process seems more fun to me than the other thing.
  • I promised a while ago to contribute some R-specific stuff to Bobby Tables, and have done jack since. I made some progress on it recently, but need to install a more modern version of R to do appropriate testing before I make a PR. When I first looked into it, I saw no SQL escaping and no placeholders, but now I'm seeing some progress. Nothing's quite up to snuff, in my opinion, but it's better. 
  • A side project I'm involved in has need of Bluetooth Low Energy support, and I've done the slightest poking with it. I need to do more. It seems that a few necessary tools for debugging are Unix/Linux/Mac only, and my dev laptop is Windows, so I need to either get going with VirtualBox, figure things out in Visual Studio or let it go.
  • There's also need for a smartphone app, and my experiences with Eclipse and Android Studio haven't been pleasant. I know there's Cordova integration with Visual Studio, so that seems to be the quick way in. I don't know if I can do any BLE stuff within a Cordova app, but we'll get there when we get there.
  • There's another side project I'm involved in, called Lafayettech. Specifically, I'm in the proto-makerspace corner, Lafayettech Labs. And it seems like I'm the only one involved in it. So, I am thinking of stopping. Right now, there's a few self-perpetuating scripts in a crontab file that do much of the work. I need to decide something about this.
There's a few more things that should be here, but I don't have together enough to even make a lame bullet point for.

2015/10/11

Thinking Aloud: Power Issues for a Raspberry Pi as a Car Computer

We could switch from a Raspberry Pi to an oDroid or another sort of low-power computer-on-a-board. My Pi has a task right now, so if I was to go forward with this, I'll have to get something new anyway, but for sake of this discussion, we'll assume this is it.

I own a USB GPS unit. I own a OBDII-to-USB unit. I own a small VGA monitor for Pi use. A thing that would be useful is a thing that does some networking over the cellphone network, but if it just dumps to my home network when I get home, that'd be good enough.

Here's a niggly bit or me: I start the vehicle and the Pi gets power. I stop the vehicle and the power cuts, leading the computer shutting down suddenly. This is not a happy thing with computers. In fact, I think I can say they hate that, and eventually, the SD card will say enough with this and not boot.

So, the proper solution is to have a power circuit with a battery, that allows it to boot when the car starts and sends the shutdown signal when it stops, but providing enough juice in the battery for the Pi to shut down nicely.

Google told me how to trigger the shutdown when wanted. Just need to figure out how to know what's going on with power.

Overkill II: The Quickening

Previously on /var/log/rant, I talked about using recursion to brute-force a middle-school math problem. Because I learned a little bit about using Xeon Phi co-processor (the part formerly called video cards), I thought I'd try C++. And found that, while the Perl version ran for about a minute and a half, the C++ version took about a second and a half.

I then tried a Python version, using the same workflow as with the C++. I backed off on the clever for the testing because I am not as sure about using multidimensional arrays in C++ and Python as I am in Perl. When you only code in a language about once every 15 years, you begin to forget the finer points.

Anyway. the code follows. I don't believe I'm doing a particularly stupid thing with my Perl here, but it's hard to ID particularly stupid things in languages sometimes. Here's the code, now with your USDA requirement of Node.js.

#include <stdio.h>
void recursive_magic_box ( int numbers[9] , int arrayc , int array[9] ) ;
int check_magic_box ( int arrayc , int array[9] ) ;
int contains_duplicates ( int arrayc , int array[9] ) ;
int main () {
int numbers[9] = {3,4,5,6,7,8,9,10,11} ;
int array[9] ;
recursive_magic_box( numbers , 0 , array ) ;
}
void recursive_magic_box ( int numbers[9] , int arrayc , int array[9] ) {
for ( int i = 0 ; i < 9 ; i++ ) {
int n = numbers[i] ;
int new_arrayc = arrayc + 1 ;
array[arrayc] = n ;
if ( check_magic_box( new_arrayc , array ) ){
recursive_magic_box( numbers , new_arrayc , array ) ;
}
}
}
int check_magic_box ( int arrayc , int array[9] ) {
if ( arrayc > 9 ) { return 0 ; }
if ( contains_duplicates( arrayc , array ) ) { return 0 ; }
if ( arrayc == 9 ) {
int sum = 21 ;
if ( sum != array[0] + array[1] + array[2] ) { return 0 ; }
if ( sum != array[3] + array[4] + array[5] ) { return 0 ; }
if ( sum != array[6] + array[7] + array[8] ) { return 0 ; }
if ( sum != array[0] + array[3] + array[6] ) { return 0 ; }
if ( sum != array[1] + array[4] + array[7] ) { return 0 ; }
if ( sum != array[2] + array[5] + array[8] ) { return 0 ; }
if ( sum != array[0] + array[4] + array[8] ) { return 0 ; }
if ( sum != array[6] + array[4] + array[2] ) { return 0 ; }
printf( "%4d%4d%4d\n" , array[0] , array[1] , array[2]) ;
printf( "%4d%4d%4d\n" , array[3] , array[4] , array[5]) ;
printf( "%4d%4d%4d\n" , array[6] , array[7] , array[8]) ;
printf ("\n");
}
return 1 ;
}
int contains_duplicates ( int arrayc , int array[9] ) {
int check[20] ;
for (int i=0;i<20;i++) {check[i]=0;}
for ( int i = 0 ; i < arrayc ; i++ ) {
int n = array[i] ;
if ( check[n] == 1 ) { return 1 ; }
check[n] = 1 ;
}
return 0 ;
}
view raw magicbox.cc hosted with ❤ by GitHub
package main
import "fmt"
// import "time"
func main() {
myarray := []int{}
numbers := []int{3,4,5,6,7,8,9,10,11}
recurse_magic_box( numbers , myarray )
}
func recurse_magic_box( numbers []int , myarray []int ) {
for i := 0 ; i < len(numbers);i++ {
// fmt.Println("----------------")
n := numbers[i]
// push
myarray = append( myarray , n )
// fmt.Println(myarray)
check := check_magic_box( myarray )
if check == 1 {
recurse_magic_box( numbers , myarray )
// fmt.Println(myarray)
}
// pop
x, newarray := myarray[len(myarray)-1], myarray[:len(myarray)-1]
myarray = newarray
x = x
}
}
func check_magic_box( myarray []int ) int {
if ( len(myarray) > 9 ) {
return 0
}
nodup := removeDuplicates( myarray )
if ( len(myarray) != len(nodup) ) {
return 0
}
if ( len(myarray) == 9 ) {
sum := 21
// rows
if ( sum != myarray[0] + myarray[1] + myarray[2] ) { return 0 }
if ( sum != myarray[3] + myarray[4] + myarray[5] ) { return 0 }
if ( sum != myarray[6] + myarray[7] + myarray[8] ) { return 0 }
// columns
if ( sum != myarray[0] + myarray[3] + myarray[6] ) { return 0 }
if ( sum != myarray[1] + myarray[4] + myarray[7] ) { return 0 }
if ( sum != myarray[2] + myarray[5] + myarray[8] ) { return 0 }
// diagonals
if ( sum != myarray[0] + myarray[4] + myarray[8] ) { return 0 }
if ( sum != myarray[6] + myarray[4] + myarray[2] ) { return 0 }
fmt.Println( myarray[0:3] )
fmt.Println( myarray[3:6] )
fmt.Println( myarray[6:9] )
fmt.Println( "" )
}
return 1
}
func removeDuplicates(elements []int) []int {
// Use map to record duplicates as we find them.
encountered := map[int]bool{}
result := []int{}
for v := range elements {
if encountered[elements[v]] == true {
// Do not add duplicate.
} else {
// Record this element as an encountered element.
encountered[elements[v]] = true
// Append to result slice.
result = append(result, elements[v])
}
}
// Return the new slice.
return result
}
// run
//
// real 1m41.756s
// user 1m5.212s
// sys 0m0.264s
// built
//
// real 1m44.859s
// user 1m4.772s
// sys 0m0.112s
view raw magicbox.go hosted with ❤ by GitHub
#!/usr/bin/env node
// real 0m24.494s
// user 0m22.725s
// sys 0m0.200s
function main () {
var numbers = range(3,11) ;
var array = [] ;
recurse_magic_box( numbers , array ) ;
}
function recurse_magic_box( numbers , array ) {
for (var n in numbers ) {
var num = numbers[n] ;
array.push(num);
if ( check_magic_box( array ) ) {
recurse_magic_box( numbers , array ) ;
}
array.pop() ;
}
}
function check_magic_box( array ){
if ( contains_duplicates( array ) ) { return 0 }
if ( array.length > 9 ) { return 0 }
if ( array.length == 9 ) {
var sum = 21 ;
if ( sum != array[0] + array[1] + array[2] ) { return 0 }
if ( sum != array[3] + array[4] + array[5] ) { return 0 }
if ( sum != array[6] + array[7] + array[8] ) { return 0 }
if ( sum != array[0] + array[3] + array[6] ) { return 0 }
if ( sum != array[1] + array[4] + array[7] ) { return 0 }
if ( sum != array[2] + array[5] + array[8] ) { return 0 }
if ( sum != array[0] + array[4] + array[8] ) { return 0 }
if ( sum != array[6] + array[4] + array[2] ) { return 0 }
console.log( [ '[' , array[0] , array[1] , array[2] , ']' ].join(" ") ) ;
console.log( [ '[' , array[3] , array[4] , array[5] , ']' ].join(" ") ) ;
console.log( [ '[' , array[6] , array[7] , array[8] , ']' ].join(" ") ) ;
console.log("");
}
return 1 ;
}
function contains_duplicates ( array ) {
var check = [] ;
for ( var i = 0 ; i < array.length ; i++ ) {
var n = array[i] ;
if ( check[n] == 1 ) { return 1 ; }
check[n] = 1 ;
}
return 0 ;
}
function range (start, end) {
return Array(++end-start).join(0).split(0).map(function(n, i) {
return i+start
});
}
main() ;
view raw magicbox.js hosted with ❤ by GitHub
#!/usr/bin/env perl6
my @numbers = 3 .. 11 ;
my @array ;
recurse_magic_box( @numbers, @array ) ;
sub recurse_magic_box ( @numbers , @array ) {
for @numbers -> $n {
@array.push($n) ;
if ( check_magic_box( @array ) ) {
recurse_magic_box( @numbers, @array ) ;
}
@array.pop ;
}
}
sub check_magic_box ( @array ) {
return 0 if @array.elems > 9 ;
my %done;
for @array -> $n {
return 0 if %done{$n}++ ;
}
if ( @array.elems == 9 ) {
# say @array ;
my $sum = 21 ;
return 0 if $sum != @array[0] + @array[1] + @array[2] ;
return 0 if $sum != @array[3] + @array[4] + @array[5] ;
return 0 if $sum != @array[6] + @array[7] + @array[8] ;
return 0 if $sum != @array[0] + @array[3] + @array[6] ;
return 0 if $sum != @array[1] + @array[4] + @array[7] ;
return 0 if $sum != @array[2] + @array[5] + @array[8] ;
return 0 if $sum != @array[0] + @array[4] + @array[8] ;
return 0 if $sum != @array[6] + @array[4] + @array[2] ;
say @array[ 0 .. 2 ] ;
say @array[ 3 .. 5 ] ;
say @array[ 6 .. 8 ] ;
say '' ;
}
return 1 ;
}
# real 104m3.203s
# user 93m25.498s
# sys 0m10.577s
# I think I'm doing something wrong, because this shouldn't take that long, but I don't know what.
view raw magicbox.p6 hosted with ❤ by GitHub
#!/usr/bin/env perl
use feature qw{ say signatures } ;
no warnings "experimental::signatures";
my $numbers = [ 3 .. 11 ] ;
my $array ;
recurse_magic_box( $numbers, $array ) ;
sub recurse_magic_box ( $numbers , $array ) {
# numbers is the list of allowable numbers
for my $n (@$numbers) {
push @$array, $n ;
if ( check_magic_box($array) ) {
recurse_magic_box( $numbers, $array ) ;
}
pop @$array ;
}
}
sub check_magic_box ( $array ) {
return 0 if scalar @$array > 9 ;
my %done ;
for my $n (@$array) {
return 0 if $done{$n}++ ;
}
do {
my $sum = 21 ;
return 0 if $sum != $array->[0] + $array->[1] + $array->[2] ;
return 0 if $sum != $array->[3] + $array->[4] + $array->[5] ;
return 0 if $sum != $array->[6] + $array->[7] + $array->[8] ;
return 0 if $sum != $array->[0] + $array->[3] + $array->[6] ;
return 0 if $sum != $array->[1] + $array->[4] + $array->[7] ;
return 0 if $sum != $array->[2] + $array->[5] + $array->[8] ;
return 0 if $sum != $array->[0] + $array->[4] + $array->[8] ;
return 0 if $sum != $array->[6] + $array->[4] + $array->[2] ;
say join "", map { sprintf '%4d', $_ } @$array[ 0 .. 2 ] ;
say join "", map { sprintf '%4d', $_ } @$array[ 3 .. 5 ] ;
say join "", map { sprintf '%4d', $_ } @$array[ 6 .. 8 ] ;
say '' ;
} if scalar @$array == 9 ;
return 1 ;
}
__DATA__
TIME:
magicbox
real 0m1.713s
user 0m1.520s
sys 0m0.008s
magicbox.py
real 0m45.771s
user 0m34.382s
sys 0m0.620s
magicbox.pl
real 1m39.328s
user 1m20.685s
sys 0m0.344s
view raw magicbox.pl hosted with ❤ by GitHub
#!/usr/bin/env python
def main ():
numbers = range(3,12)
array = []
recurse_magic_box( numbers , array )
def recurse_magic_box ( numbers , array ):
for i in numbers:
array.append(i)
if check_magic_box( array ):
recurse_magic_box( numbers , array )
array.pop()
def check_magic_box( array ):
if len(array) > 9:
return 0
for n in array:
if array.count(n) > 1 :
return 0
if len(array) == 9:
sum = 21
if sum != array[0] + array[1] + array[2]:
return 0
if sum != array[3] + array[4] + array[5]:
return 0
if sum != array[6] + array[7] + array[8]:
return 0
if sum != array[0] + array[3] + array[6]:
return 0
if sum != array[1] + array[4] + array[7]:
return 0
if sum != array[2] + array[5] + array[8]:
return 0
if sum != array[0] + array[4] + array[8]:
return 0
if sum != array[6] + array[4] + array[2]:
return 0
print( array[0:3] )
print( array[3:6] )
print( array[6:9] )
print( "" )
return 1
if __name__ == '__main__':
main()
view raw magicbox.py hosted with ❤ by GitHub
#!/usr/bin/env ruby
numbers=*(3..11)
array = Array.new
checks = 1
def recurse_magic_box( numbers, array )
for n in numbers
array.push(n)
if 1 == check_magic_box(array)
recurse_magic_box( numbers , array )
end
array.pop
end
end
def check_magic_box ( array )
if array.length > 9
return 0
end
if array.uniq.length != array.length
return 0
end
if 9 == array.length
sum = 21
# rows
if sum != array[0] + array[1] + array[2]
return 0
end
if sum != array[3] + array[4] + array[5]
return 0
end
if sum != array[6] + array[7] + array[8]
return 0
end
# columns
if sum != array[0] + array[3] + array[6]
return 0
end
if sum != array[1] + array[4] + array[7]
return 0
end
if sum != array[2] + array[5] + array[8]
return 0
end
# diagonal
if sum != array[0] + array[4] + array[8]
return 0
end
if sum != array[6] + array[4] + array[2]
return 0
end
puts array[0..2].join(' ')
puts array[3..5].join(' ')
puts array[6..8].join(' ')
puts ''
end
return 1
end
recurse_magic_box( numbers , array )
# real 1m2.287s
# user 0m59.544s
# sys 0m0.052s
view raw magicbox.rb hosted with ❤ by GitHub

2015/10/09

Overkill: Using the Awesome Power of Modern Computing to Solve Middle School Math Problems

I was helping my son with his math the other night and we hit a question called The Magic Box. You are given a 3x3 square and the digits 3,4,5,6,7,8,9,10,11, and are expected to find a way of placing them such that each row, each column, and each diagonal adds up to 21.

I'm a programmer, so my first thought was, hey, I'll make a recursive algorithm to do this. The previous question, measuring 4 quarts when you have a 3 quart measure and a 5 quart measure, was solved due to insights remembered from Die Hard With A Vengeance, so clearly, I'm not coming at these questions from the textbook.

With a little more insight, I solved it. 7 is a third of 21, and it the center of an odd-numbered sequence of numbers, so clearly, it is meant to be the center. There is only one way you can use 11 on a side, with 4 and 6, so that a center column or row will be 3 7 11. If you know that column and the 4 11 6 row, you know at least this:

.  3  .
.  7  .
4 11  6

And because you know the diagonals, you know that it'll be

8  3 10 
.  7  .
4 11  6

And you only have 5 and 9 left, and they're easy to just plug in

8  3 10
9  7  5
4 11  6

So, that's the logical way to to solve it. Clearly, order isn't important; it could be reversed on the x and y axis and still be a solution. But, once the thought of solving with a recursive algorithm came into my head, I could not leave well enough alone. So, here's a recursive program that finds all possible solutions for this problem.


#!/usr/bin/env perl
use feature qw{ say state signatures } ;
use strict ;
use warnings ;
use utf8 ;
use Data::Dumper ;
my $numbers = [ 3 .. 11 ] ;
my $array ;
recurse_magic_box( $numbers, $array ) ;
sub recurse_magic_box ( $numbers , $array ) {
# numbers is the list of allowable numbers
for my $n (@$numbers) {
push @$array, $n ;
if ( check_magic_box($array) ) {
recurse_magic_box( $numbers, $array ) ;
}
pop @$array ;
}
}
sub check_magic_box ( $array ) {
for my $n (@$array) {
my $c = scalar grep {m{$n}} @$array ;
return 0 if $c > 1 ;
}
do {
my $sum = 21 ;
my $checks = [
[ 0, 1, 2 ], # first row
[ 3, 4, 5 ], # second row
[ 6, 7, 8 ], # third row
[ 0, 3, 6 ], # first col
[ 1, 4, 7 ], # second col
[ 2, 5, 8 ], # third col
[ 0, 4, 8 ], # diagonal from top right
[ 6, 4, 2 ], # diagonal from bottom right
] ;
for my $check (@$checks) {
my $s = 0 ;
for my $p (@$check) {
$s += $array->[$p] ;
}
return 0 if $s != $sum ;
}
say join "\t", @$array[ 0 .. 2 ] ;
say join "\t", @$array[ 3 .. 5 ] ;
say join "\t", @$array[ 6 .. 8 ] ;
say '' ;
} if scalar @$array == 9 ;
return 1 ;
}
view raw magicbox.pl hosted with ❤ by GitHub

2015/10/03

You Know Where You Stand In Your Hellhole

Sawyer X tweeted this:
I said "Deep".

This can be a variation of "He says he has 5 years of experience, but he really has 1 year of experience 5 times." Except not really.

I've worked as a developer for years, and it took me years before I started writing modules. It took a while after before I started having those modules being more than bags of vaguely related functions. And it was just this year before I looked into and started contributing patches to open source projects..

So, one way of looking at this is "I have one year experience as a newbie which I repeated for five years, one year of being a coder which I repeated for five years, and I've just finished a year of being a developer making modern tools for other developers, which I haven't repeated." Or the like.

There isn't necessarily anything wrong with this. In the year where you've been coding, you're doing a thing. You aren't growing, you aren't taking it to the next level, but you are creating and maintaining code, and you are making something that provides value to someone.

Or, you can think of Sawyer's statement more like I've been coding, working at the a well-trod level, bit-twiddling and the like, but not doing anything interesting. This is the feeling I get when I get close to more computer-theoretical things. I have access to computers with massive amounts of cores, massive amounts of memory, but don't see where my problems map to those resources. Until I do interesting things with interesting data on interesting hardware, I'm a coder, not a programmer.

I'm interested in improving, in coding less and programming more. Or, perhaps, interested in aspects of improvement but less interested in doing the work. There's a certain safety in knowing that you're doing what you're experienced with, not reaching out. Perhaps David St. Hubbins and Nigel Tufnel say it best in the last chorus: "you know where you stand in a hell hole".


I'm trying to take steps to move forward. Maybe find myself a new, more interesting hell hole to program in.