Thursday, August 12, 2010

Eliza vs. Eliza

What happens when you sic Chatbot::Eliza on itself? Well, you've come to the right place to find out!

#!/bin/env perl -w
use warnings;
use strict;
use utf8;
use Chatbot::Eliza;

my ($bot1, $bot2) = (new Chatbot::Eliza, new Chatbot::Eliza);

my $text = "Hello.";
print "Me: $text\n";
for(1..100) {
if($_ % 2) {
$text = $bot1->transform($text);
print "Eliza #1: $text\n";
}
else {
$text = $bot1->transform($text);
print "Eliza #2: $text\n";
}
}
Me: Hello.
Eliza #1: Hi. What seems to be your problem?
Eliza #2: Does that question interest you?
Eliza #1: You're not really talking about me -- are you?
Eliza #2: What makes you think I am not really talking about you -- are me?
Eliza #1: What makes you think I -- are you?
Eliza #2: Oh, I?
Eliza #1: Why do you say you?
Eliza #2: We were discussing you -- not me.
Eliza #1: Do you wish to believe I -- not you?
Eliza #2: You're not really talking about me -- are you?
Eliza #1: What makes you think I am not really talking about you -- are me?
Eliza #2: Really, I -- are you?
Eliza #1: Oh, I?
Eliza #2: Can you elaborate on that?
Eliza #1: Oh, I elaborate on that?
Eliza #2: Do you say you elaborate on that for some special reason?
Eliza #1: We were discussing you -- not me.
Eliza #2: Do you wish to believe I -- not you?
Eliza #1: We were discussing you -- not me.
Eliza #2: Really, I -- not you?
Eliza #1: Oh, I?
Eliza #2: Why do you say you?
Eliza #1: You're not really talking about me -- are you?
Eliza #2: Does it please you to believe I am not really talking about you -- are me?
Eliza #1: Why do you think I -- are you?
Eliza #2: Oh, I?
Eliza #1: Why do you say you?
Eliza #2: What are your feelings now?
Eliza #1: Have you asked such questions before?
Eliza #2: We were discussing you -- not me.
Eliza #1: Really, I -- not you?
Eliza #2: You're not really talking about me -- are you?
Eliza #1: Do you sometimes wish you were not really talking about you -- are me?
Eliza #2: Really, I -- are you?
Eliza #1: We were discussing you -- not me.
Eliza #2: Suppose I did -- not you -- what would that mean?
Eliza #1: We were discussing you -- not me.
Eliza #2: Suppose I did -- not you -- what would that mean?
Eliza #1: You're not really talking about me -- are you?
Eliza #2: Do you sometimes wish you were not really talking about you -- are me?
Eliza #1: Does someone else believe I -- are you?
Eliza #2: Oh, I?
Eliza #1: That's quite interesting.
Eliza #2: Tell me more about that.
Eliza #1: Please go on.
Eliza #2: Does talking about this bother you?
Eliza #1: You're not really talking about me -- are you?
Eliza #2: Perhaps you would like to be not really talking about you -- are me.
Eliza #1: Do you wish to believe I -- are you?
Eliza #2: We were discussing you -- not me.
Eliza #1: Why do you think I -- not you?
Eliza #2: You're not really talking about me -- are you?
Eliza #1: Do you sometimes wish you were not really talking about you -- are me?
Eliza #2: Does someone else believe I -- are you?
Eliza #1: You're not really talking about me -- are you?
Eliza #2: Does it please you to believe I am not really talking about you -- are me?
Eliza #1: What makes you think I -- are you?
Eliza #2: You're not really talking about me -- are you?
Eliza #1: What makes you think I am not really talking about you -- are me?
Eliza #2: Really, I -- are you?
Eliza #1: What are your feelings now?
Eliza #2: What is it you really want to know?
Eliza #1: What are your feelings now?
Eliza #2: What do you think?
Eliza #1: You're not really talking about me -- are you?
Eliza #2: Perhaps you would like to be not really talking about you -- are me.
Eliza #1: What makes you think I -- are you?
Eliza #2: We were discussing you -- not me.
Eliza #1: Really, I -- not you?
Eliza #2: Oh, I?
Eliza #1: Why do you say you?
Eliza #2: You're not really talking about me -- are you?
Eliza #1: What makes you think I am not really talking about you -- are me?
Eliza #2: You like to think I -- are you -- don't you?
Eliza #1: We were discussing you -- not me.
Eliza #2: Suppose I did -- not you -- what would that mean?
Eliza #1: We were discussing you -- not me.
Eliza #2: Do you wish to believe I -- not you?
Eliza #1: You're not really talking about me -- are you?
Eliza #2: Perhaps you would like to be not really talking about you -- are me.
Eliza #1: Really, I -- are you?
Eliza #2: You're not really talking about me -- are you?
Eliza #1: Perhaps you would like to be not really talking about you -- are me.
Eliza #2: What makes you think I -- are you?
Eliza #1: Oh, I?
Eliza #2: That's quite interesting.
Eliza #1: Please go on.
Eliza #2: That is interesting. Please continue.
Eliza #1: Tell me more about that.
Eliza #2: Does talking about this bother you?
Eliza #1: What are your feelings now?
Eliza #2: Have you asked such questions before?
Eliza #1: We were discussing you -- not me.
Eliza #2: You like to think I -- not you -- don't you?
Eliza #1: Oh, I?
Eliza #2: Do you say you for some special reason?
Eliza #1: Oh, I for some special reason?
Eliza #2: Do you say you for some special reason for some special reason?
Eliza #1: We were discussing you -- not me.
Eliza #2: Does someone else believe I -- not you?

Yeah, it's not as interesting as one would think.

Friday, July 23, 2010

Converting Between Tabs and Spaces

If you want to use tabs in Python but everyone else uses spaces, here's something helpful you can do in git!

% echo '*.py filter=tabspace' >> .git/info/attributes
% git config --global filter.tabspace.smudge 'unexpand --tabs=4 --first-only'
% git config --global filter.tabspace.clean 'expand --tabs=4 --initial'

You can appear to comply with PEP-8 to others using your repository, but you don't need to change your habits!

Thursday, June 10, 2010

ALSA, dmix, and X-Fi

I was having all sort of issues getting my SoundBlaster X-Fi working properly using the snd-ctxfi module. First off, I got something about "invalid sw-parameters," and once I had fixed that by going through dmix I lost the ability to have multiple streams playing at once.

Eventually I found a middle ground that had everything working, with the bonus of pretty sweet upmixing, all by putting this in my asound.conf:

pcm.!default {
type plug
slave {
pcm "duplex"
channels 6
}
ttable {
0.0 1
1.1 1
0.2 1
1.3 1
0.4 0.5
1.4 0.5
0.5 0.5
1.5 0.5
}
}

pcm.snd_card {
type hw
card 0 # SoundBlaster X-Fi
}
pcm.s51 {
type plug
slave {
pcm "surround51"
rate 48000
channels 6
}
}



pcm.duplex {
type asym
playback.pcm "s51"
capture.pcm "snd_card"
}

It looks like pushing everything through surround51 (though not directly) works perfectly.

Monday, March 15, 2010

flatten2.py

After reading about OptiPNG, I decided to add it into the mix of flatten.py. Since it doesn't support reducing bit depths of grayscale images, I have the script run pngcrush first and then OptiPNG.

Since the last post about flatten, I've made a few other changes as well, such as passing -bit_depth to pngcrush when a bit depth is provided. Since I use this script to compress images for my webcomic, that's an important change.

flatten.py

#!/usr/bin/python
from sys import argv, stderr, exit
from subprocess import Popen
from optparse import OptionParser, OptionValueError
from copy import copy
from os import remove
from os import close as os_close
from re import compile as re_compile
from os.path import join, isfile
from tempfile import mkstemp


size = re_compile('^(.+)x(.+)$')

def check_size(option, opt_str, value, parser):
m = size.search(value)
if m:
parser.values.size = m.group(1), m.group(2)
else:
raise OptionValueError('Invalid size: %s' % value)

filext = re_compile('^(.+)\.(.+)$')
filext_png = re_compile('\.png$')

img_type = ['Bilevel', 'Grayscale', 'GrayscaleMatte', 'Palette', 'PaletteMatte', 'TrueColor', 'TrueColorMatte', 'ColorSeparate', 'ColorSeparationMatte', 'Optimize']
img_cspace = ['CMY', 'CMYK', 'Gray', 'HSB', 'HSL', 'HWB', 'Lab', 'Log', 'OHTA', 'Rec601Luma', 'Rec601YCbCr', 'Rec709Luma', 'Rec709YCbCr', 'RGB', 'sRGB', 'Transparent', 'XYZ', 'YCbCr', 'YCC', 'YIQ', 'YPbPr', 'YUV']
pngcrush = ['pngcrush', '-rem', 'gAMA', '-rem', 'cHRM', '-rem', 'iCCP', '-rem', 'sRGB']

parser = OptionParser(usage = 'Usage: %prog [ options ] input [ output ]')
parser.add_option('-s', '--size', dest = 'size', type = 'string', action = 'callback', callback = check_size, default = None, help = 'The output size: WIDTHxHEIGHT')
parser.add_option('-n', '--no-clobber', dest = 'clobber', default = True, action = 'store_false', help = 'The output size: WIDTHxHEIGHT')
parser.add_option('-f', '--filter', dest = 'filter', default = 'Catrom', help = 'The filter to resize with if necessary.')
parser.add_option('-b', '--background', dest = 'background', default = 'white', help = 'The background when flattening.')
parser.add_option('-F', '--no-flatten', dest = 'flatten', default = True, action = 'store_false', help = 'Don\'t flatten the output.')
parser.add_option('-t', '--type', dest = 'type', type = 'string', default = None, help = 'The type of the output image: analogous to both -type and -colorspace in ImageMagick')
parser.add_option('-d', '--depth', dest = 'depth', type = 'int', default = None, help = 'The depth of the output image.')

options, args = parser.parse_args()
if len(args):
input = args.pop(0)
if isfile(input):
output = None
pngout = False
if len(args):
output = args.pop(0)
if filext_png.search(output):
pngout = True
else:
m = filext.search(input)
if not m is None:
output = '%s_small.%s' % (m.group(1), m.group(2))
if m.group(2) == 'png':
pngout = True
else:
output = '%s_small.png' % input
pngout = True
if not options.clobber and isfile(output):
print >>stderr, 'Output file exists:', output
exit(2)
# ACTUAL PROCESSING
args = ['convert', input]

if not options.type is None:
if options.type in img_type:
args += ['-type', options.type]
if not options.depth is None:
args += ['-depth', str(options.depth)]
elif options.type in img_cspace:
args += ['-colorspace', options.type]
if not options.depth is None:
args += ['-depth', str(options.depth)]
if options.flatten:
args += ['-background', options.background, '-flatten', '+matte']
if not options.size is None:
args += ['-filter', options.filter, '-resize', '%sx%s' % options.size]


if pngout:
# Run convert
fd, tmpfile = mkstemp()
os_close(fd)
args.append('png:' + tmpfile)
Popen(args).communicate()
# Run pngcrush
args = copy(pngcrush)
if not options.depth is None:
args += ['-bit_depth', str(options.depth)]
args += [tmpfile, output]
Popen(args).communicate()
remove(tmpfile)
# Run optipng
Popen(['optipng', '-o9', output]).communicate()
else:
args.append(output)
Popen(args).communicate()
# END
else:
print >>stderr, 'No such file:', input
exit(2)
else:
parser.print_help()
exit(1)

The runtime options are the same as flatten.py.

Sunday, January 31, 2010

Grok

A friend of mine wrote a Python script to replace Ack (which is much faster than grep) and the resulting script turned out to be significantly faster than it. I decided then to write my own rough equivalent, called 'grok' (name from another similar program):

grok.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pcre.h>
#include <dirent.h>
#include <limits.h>
#define BLOCK_SIZE 1024
#define OFFSET_COUNT 1
struct {
char * bytes;
off_t length;
} blocks = {NULL, 0};


int search(const char * path, pcre * re) {
FILE * input = fopen(path, "r");
off_t n = 1;
int ovector[OFFSET_COUNT];
int rc;
char first_match = 1;
if(!input) {
perror(path);
return 1;
}
if(!blocks.bytes && !blocks.length) {
// Initialize blocks on first time
blocks.bytes = malloc(BLOCK_SIZE);
memset(blocks.bytes, '\0', BLOCK_SIZE);
blocks.length = BLOCK_SIZE;
}
// Search
while(!feof(input)) {
// Read a line
blocks.bytes[blocks.length - 2] = '\0'; // [blocks.length - 1] will always be '\0' due to fgets() behavior
fgets(blocks.bytes, blocks.length, input);
//printf("%lu/%lu; %d\n", strlen(blocks.bytes), blocks.length, blocks.bytes[blocks.length - 2]);
while(!feof(input) && blocks.bytes[blocks.length - 2] && blocks.bytes[blocks.length - 2] != '\n') {
// Expand blocks as necessary
blocks.length += BLOCK_SIZE;
blocks.bytes = realloc(blocks.bytes, blocks.length);
blocks.bytes[blocks.length - 2] = '\0';
fgets(blocks.bytes + strlen(blocks.bytes), BLOCK_SIZE + 1, input);
//printf("%lu/%lu; %d\n", strlen(blocks.bytes), blocks.length, blocks.bytes[blocks.length - 2]);
}
if(!(feof(input) && !*blocks.bytes)) {
n++;
rc = pcre_exec(re, NULL, blocks.bytes, strlen(blocks.bytes), 0, 0, ovector, OFFSET_COUNT);
if(rc < 0) {
switch(rc) {
case PCRE_ERROR_NOMATCH:
break;
case PCRE_ERROR_BADUTF8:
fprintf(stderr, "Bad UTF-8 at line %lu in %s\nSkipping file (try running with -U option to disable Unicode).\n", n, path);
fclose(input);
return 1;
break;
default:
fprintf(stderr, "Error: %d\n", rc);
break;
}
blocks.bytes[0] = '\0';
continue;
}
if(first_match) {
first_match = 0;
printf("%s:\n", path);
}
printf("%6lu:%s", n, blocks.bytes);
blocks.bytes[0] = '\0';
}
}
// Cleanup
fclose(input);
return 0;
}

int recursive_search(const char * path, pcre * re) {
DIR * dirinfo;
struct dirent * file;
struct stat info;
char fullpath[PATH_MAX], * filepart;
if(!stat(path, &info)) {
if(S_ISREG(info.st_mode)) {
// Regular files
if(search(path, re) == -1)
return -1;
}
else if(S_ISDIR(info.st_mode)) {
// Directories
strcpy(fullpath, path);
strcat(fullpath, "/");
filepart = fullpath + strlen(fullpath);
dirinfo = opendir(path);
while((file = readdir(dirinfo)) != NULL) {
if(*file->d_name != '.') {
strcpy(filepart, file->d_name);
if(recursive_search(fullpath, re) == -1)
return -1;
}
}
closedir(dirinfo);
}
}
else
perror(path);
return 0;
}


int main(int argc, const char * argv[]) {
// Defaults
const char * default_dirs[] = {"."};
const char * progname = *argv;
// General Variables
const char ** dirs;
int erroroffset;
int options = PCRE_UTF8;
off_t i, dirs_length;
const char * error;
pcre * re;
// Initialization
argc--; argv++;
// Parse flags
while(argc && (*argv)[0] == '-' && (*argv)[1] != '-') {
switch((*argv)[1]) {
case 'i':
options |= PCRE_CASELESS;
case 'U':
options &= ~PCRE_UTF8;
case '\0': break;
default:
fprintf(stderr, "Invalid option: %s", *argv);
return -1;
break;
}
argc--; argv++;
}
// Parse arguments
if(argc) {
re = pcre_compile(*argv, options, &error, &erroroffset, NULL);
if(argc > 1) {
dirs = argv + 1;
dirs_length = argc - 1;
}
else {
dirs = default_dirs;
dirs_length = 1;
}
}
else {
fprintf(stderr, "Usage: %s [ -i ] [ -u ] expr [ path1 .. pathN ]\n", progname);
return 1;
}
if(!re) {
fprintf(stderr, "PCRE compilation error at offset %d: %s\n", erroroffset, error);
return 2;
}
// Recursive search
for(i = 0; i < dirs_length; i++) {
if(recursive_search(dirs[i], re) == -1) {
fputs("Ran out of memory.", stderr);
return 128;
}
}
// Cleanup
if(blocks.bytes && blocks.length) {
free(blocks.bytes);
blocks.bytes = NULL;
blocks.length = 0;
}
pcre_free(re);
return 0;
}

As it turns out, my program is able to run twice as fast as his on a given directory tree (small to large).

Wednesday, December 16, 2009

Hamming(7, 4)

It's a pain to find any easy-to-understand explanations on how to do Hamming(7, 4), so here's the most useful information from my reference on how to do it.

NOTE: You can substitute addition (+) with XOR (^).

Encoding

Let's say you have four data bits: d1, d2, d3, d4. To create the parity bits, you use the following formulae:

  1. p1 = d2 + d3 + d4
  2. p2 = d1 + d3 + d4
  3. p3 = d1 + d2 + d4

The bits sent across the wire are: d1, d2, d3, p1, d4, p2, p3

Decoding

Now that we have the bits sent across the wire (d1, d2, d3, p1, d4, p2, p3), we can detect appropriate errors.

Error Detection

First, we calculate:

  1. p1* = d2 + d3 + d4
  2. p2* = d1 + d3 + d4
  3. p3* = d1 + d2 + d4

If any of these parity bits don't match the parity bits sent over the wire, then there was an error.

Error Correction

Now this information was the most difficult to find.

With the bits sent across the wire (d1, d2, d3, p1, d4, p2, p3), we must first calculate:

  1. c1 = d1 + d3 + d4 + p3
  2. c2 = d1 + d2 + d4 + p2
  3. c3 = d1 + d2 + d3 + p1

NOTE: You can detect errors by checking to see if any of c1, c2, or c3 are true (nonzero).

With these calculated, now we can find which bit we need to flip to correct the error:

  1. bit = ((c3 ? 4 : 0) | (c2 ? 2 : 0) | (c1 ? 1 : 0)) - 1
  1. If bit = 6, then flip d1.
  2. If bit = 5, then flip d2.
  3. If bit = 4, then flip d3.
  4. If bit = 2, then flip d4.
  5. In all other cases, there are more than one bit errors and we can't correct them.

Alternatively, it could be thought of this way: bit is the index of the flipped bit from the end of the string (where p3 is) with zero-indexing.

Wednesday, November 25, 2009

Restoration of the Old Kingdom

It starts off with a boy escaping punishment from his mother via a secret passage to a cavern...

Years later, when the boy is a young man, his mother is making them move for away. As he packs up his belongings, he is distracted by a rabbit bounding off towards the village. Once there, he is confronted by a group looking to go on an short adventure, led by a wiseman . Hoping to make his last day in his hometown a good one, he accompanies them.

They make their way to a market house at the end of a valley, where the young man had been employed previously, but they must make their way past the valley, and the wiseman discovers that it's blocked off only by a wall of the market. Unfortunately for the market owner, one of them barrels through rows of stock, then breaks through the wall. Not wanting to be stopped, they ran through.

The group happens upon a cave, and enter it as directed by the wiseman. The journey here becomes quite dangerous, with the final section requiring them to walk across the top of stalagmites that project upward out of a searing-hot spring.

Once in the final room of the cave, they discover a door at the top, much to their surprise. The young man stands, almost in a trance, at the entrance to the final room as memories from his late father fill his mind. He begins to manipulate hidden switches throughout the room, causing fire to rise from all sides, finally resulting in a major quake.

Outside, light begins to fill the area around the hill containing the cave, and the quake causes much of it to collapse. After the dust clears, a castle is revealed, and the song familiar to everyone who remembers the old kingdom that resided in the area is played from the bell towers. They exclaim, "The king has returned!" and run to the castle to greet him, only to come upon the young man. After an awkward pause, someone familiar to the old king says, "You look just like him... You must be his son!" The people rejoice, as the old kingdom can now be restored.

Once sat upon the throne, the young man realizes that this cavern of his youth was the throne room of the old castle. He also found out his father's death led to the collapse of the old kingdom, and his that mother wanted to keep him isolated from anything involving it.