Commit 1ae96e20 authored by Ladislav Láska's avatar Ladislav Láska

aim-life: zivy klon aim-kitu

parent 8c246e53
# Compilation settings:
CFLAGS=-Wall -Wextra -std=gnu99 -I/usr/include/netpbm $(MYCFLAGS) -pthread
LDFLAGS=-lm -lnetpbm $(MYLDFLAGS)
OPTCFLAGS=$(CFLAGS) -O3 -march=native -DNDEBUG
DBGCFLAGS=$(CFLAGS) -ggdb3
######
.PHONY: all clean asm
all: aim-opt aim-dbg
aim-opt: aim-run.c exercise.c
$(CC) $(OPTCFLAGS) -o $@ $^ $(LDFLAGS)
aim-dbg: aim-run.c exercise.c
$(CC) $(DBGCFLAGS) -o $@ $^ $(LDFLAGS)
exercise-opt.s: exercise.c
$(CC) $(OPTCFLAGS) -fverbose-asm -S $< -o $@
exercise-dbg.s: exercise.c
$(CC) $(DBGCFLAGS) -fverbose-asm -S $< -o $@
asm: exercise-dbg.s exercise-opt.s
clean:
rm -f *.o *.s aim-opt aim-dbg output.pbm
If you need test data, take a look into the 'worlds' directory.
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <pbm.h>
#include <string.h>
#include "aim.h"
#if CHAR_BIT != 8
#error char size larger than 8 is not supported
#endif
static struct image *
image_init(int cols, int rows)
{
struct image *img = malloc(sizeof(*img));
img->cols = cols, img->rows = rows;
img->bitmap = malloc(img->rows * image_rowbytes(img));
return img;
}
static struct image *
image_load(char *filename)
{
FILE *f = fopen(filename, "rb");
if (!f) { perror("load"); exit(EXIT_FAILURE); }
int cols, rows, fmt;
pbm_readpbminit(f, &cols, &rows, &fmt);
struct image *img = image_init(cols, rows);
for (unsigned int i = 0; i < img->rows; i++)
pbm_readpbmrow_packed(f, img->bitmap + i * image_rowbytes(img),
img->cols, fmt);
fclose(f);
return img;
}
void
image_clear(struct image *image) {
memset(image->bitmap, 0, image->rows * image_rowbytes(image));
}
struct image *
image_clone(struct image *image) {
struct image *clone = image_init(image->cols, image->rows);
memcpy(clone->bitmap, image->bitmap, image->rows * image_rowbytes(image));
return clone;
}
static void
image_save(char *filename, struct image *img)
{
FILE *f = fopen(filename, "wb");
if (!f) { perror("save"); exit(EXIT_FAILURE); }
pbm_writepbminit(f, img->cols, img->rows, 0);
for (unsigned int i = 0; i < img->rows; i++)
pbm_writepbmrow_packed(f, img->bitmap + i * image_rowbytes(img),
img->cols, 0);
fclose(f);
}
static void
image_free(struct image *img)
{
free(img->bitmap);
free(img);
}
typedef int_fast64_t timestamp_t;
static timestamp_t
get_timer(void)
{
struct timeval t;
gettimeofday(&t, NULL);
return 1000000*t.tv_sec + t.tv_usec;
}
int
main(int argc, char *argv[])
{
if (argc != 5) {
fprintf(stderr, "%s ITERATIONS GENERATIONS SRCIMAGE.pbm DSTIMAGE.pbm\n", argv[0]);
return EXIT_FAILURE;
}
struct image *img_in = image_load(argv[3]);
int iters = atoi(argv[1]);
int gens = atoi(argv[2]);
/* Copy the image for iterations */
struct image **clones = malloc(sizeof(struct image*)*iters);
for (int i = 0; i < iters; i++)
clones[i] = image_clone(img_in);
timestamp_t t0 = get_timer();
/* Pre-warm the CPU! Neccessary for benchmarking w/ dynamic
* cpufreq policy. */
while (get_timer() - t0 < 500000);
t0 = get_timer();
for (int j = 0; j < iters; j++) {
exercise(&clones[j], gens);
}
t0 = get_timer() - t0;
// time spent:
printf("%.3f\n", (double) t0/1e6);
image_save(argv[4], clones[iters-1]);
image_free(img_in);
return EXIT_SUCCESS;
}
#ifndef AIM__AIM_H
#define AIM__AIM_H
#include <stdbool.h>
struct image {
unsigned int cols, rows;
/* Black-white image, one _BIT_ per pixel. Rows-oriented,
* rows are rounded to whole bytes. */
unsigned char *bitmap;
};
static unsigned int image_rowbytes(struct image *img);
static bool image_getpixel(struct image *img, unsigned int x, unsigned int y);
static void image_putpixel(struct image *img, unsigned int x, unsigned int y, bool pixel);
void exercise(struct image ** life, unsigned int gens);
/** Implementation: */
static inline unsigned int
image_rowbytes(struct image *img)
{
return (img->cols + 7) / 8;
}
static inline bool
image_getpixel(struct image *img, unsigned int x, unsigned int y)
{
if ((x >= img->cols) || y >= img->rows) return 0;
return (img->bitmap[image_rowbytes(img) * y + x / 8] >> (7 - x % 8)) & 1;
}
static inline void
image_putpixel(struct image *img, unsigned int x, unsigned int y, bool pixel)
{
(img->bitmap[image_rowbytes(img) * y + x / 8] &= ~(1 << (7 - x % 8)));
(img->bitmap[image_rowbytes(img) * y + x / 8] |= pixel << (7 - x % 8));
}
struct image *
image_clone(struct image *image);
void
image_clear(struct image *image);
#endif
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "aim.h"
struct coord {
int x;
int y;
};
static struct coord around[] = {
{ -1, -1 },
{ 0, -1 },
{ 1, -1 },
{ 1, 0 },
{ 1, 1 },
{ 0, 1 },
{ -1, 1 },
{ -1, 0 }
};
void
display(struct image * life) {
for (size_t j = 0; j < life->rows; j++) {
for (size_t i = 0; i < life->cols; i++) {
putchar(".x"[image_getpixel(life, i, j)]);
}
putchar('\n');
}
putchar('\n');
}
void
exercise(struct image ** life_p, unsigned int gens) {
struct image * life = *life_p;
struct image * tmp = image_clone(life);
//display(life);
for (unsigned int gen = 0; gen < gens; gen++) {
for (size_t i = 0; i < life->cols; i++) {
for (size_t j = 0; j < life->rows; j++) {
size_t sum = 0;
for (size_t k = 0; k < sizeof around / sizeof *around; k ++)
if (image_getpixel(life, i + around[k].x, j + around[k].y))
sum ++;
if (sum == 3)
image_putpixel(tmp, i, j, 1);
else if (sum == 2 && image_getpixel(life, i, j))
image_putpixel(tmp, i, j, 1);
else
image_putpixel(tmp, i, j, 0);
}
}
struct image * _t = tmp; tmp = life; life = _t;
//display(life);
}
life_p = &life;
}
# We will compute the mean and standard deviation of the numbers on stdin.
# We can interpret the standard deviation [*] like this:
#
# With probability 68%, the actual mean time M is within one S.D. s
# around the measured mean m: M \in (m-s,m+s)
#
# [*] We assume the numbers (time taken) are approximately normally
# distributed around the measured mean.
BEGIN {
sum = 0
sqsum = 0
}
{
sum = sum + $1
sqsum = sqsum + $1*$1
}
END {
n = NR
mean = sum / n
# Exercise: This method of variance computation might be
# sub-optimal. Try to find out why and implement a better
# method.
var = (n * sqsum - sum * sum) / (n * (n-1))
sd = sqrt(var)
print mean, mean - sd, mean + sd, sd
}
all: meth.pbm
./pbm-compose.pl
clean:
rm meth*pbm
%.pbm : %.rle
./rle2pbm.pl $< > $@
.PHONY: clean all
#C 18-cell 40514-generation methuselah
#C based on Richard Wobus' 15-cell marvel
x = 78, y = 54, rule = B3/S23
77bo$77bo$77bo21$3o20$3bo$3bo$3bo5$20b3o$9b3o10bo$22bo$21bo!
#!/usr/bin/perl
use common::sense;
use Data::Dumper;
############################################
## This script eats memory for breakfast! ##
############################################
#Image size is X = width, Y = height. That is $img->[$y]->[$x];
sub image_size {
my ($img) = @_;
return (scalar @{$img->[0]}, scalar @$img);
}
sub image_print {
my ($img, $fh) = @_;
$fh ||= \*STDOUT;
my ($x, $y) = image_size($img);
print $fh "P1\n$x $y\n";
for my $line (@$img) {
print $fh join(" ", @$line)."\n";
}
}
sub image_init {
my ($x, $y, $prefill) = @_;
$prefill ||= 0;
my @img;
for (my $j = 0; $j < $y; $j++) {
my @line = ($prefill) x $x;
push @img, \@line;
}
return \@img;
}
sub image_copy {
my ($dst, $src, $offx, $offy) = @_;
my ($sizex, $sizey) = image_size($src);
for (my $x = 0; $x < $sizex; $x++) {
for (my $y = 0; $y < $sizey; $y++) {
$dst->[$offy+$y]->[$offx+$x] = $src->[$y]->[$x];
}
}
}
sub image_border {
my ($img, $sizex, $sizey, $fill) = @_;
$sizey ||= $sizex;
$fill ||= 0;
for my $line (@$img) {
for (my $i = 0; $i < $sizex; $i++) {
push @$line, $fill;
unshift @$line, $fill;
}
}
my $lw = scalar @{$img->[0]};
for (my $i = 0; $i < $sizey; $i++) {
my @l1 = ($fill) x $lw;
my @l2 = ($fill) x $lw;
push @$img, \@l1;
unshift @$img, \@l2;
}
}
sub image_load {
my ($file) = @_;
open( my $fh, "<", $file) or die "Could not open file '$file'";
my $format = <$fh>;
chomp $format;
die "Unsupported format $format." unless $format eq "P1";
my ($x,$y) = split /\s+/, scalar <$fh>;
my @img = ();
while (<$fh>) {
my @line = split /\s+/;
die "Image line is not wide enough!" unless ($x == scalar @line);
push @img, \@line;
}
die "Image not high enough!" unless ($y == scalar @img);
printf STDERR "Found image $x,$y\n";
return \@img;
}
sub image_store {
my ($image, $file) = @_;
open( my $fh, ">", $file) or die "Could not open file '$file' for writing";
image_print($image, $fh);
close($fh);
}
sub image_tile {
my ($img, $nx, $ny) = @_;
my ($x, $y) = image_size($img);
my $out = image_init($nx*$x, $ny*$y);
for (my $xp = 0; $xp < $nx; $xp++) {
for (my $yp = 0; $yp < $ny; $yp++) {
image_copy($out, $img, $xp*$x, $yp*$y);
}
}
return $out;
}
my $image = image_load("meth.pbm");
image_border($image, 10);
my $out = image_tile($image, 10, 10);
image_border($image, 10);
image_store($out, "meth-big.pbm");
# Chessboard
#my $image = image_init(5,5,1);
#my $big = image_init(10, 10, 0);
#image_copy($big, $image, 0, 0);
#image_copy($big, $image, 5, 5);
#my $extra = image_tile($big, 4, 4);
#image_border($extra, 1, 1, 1);
#image_border($extra, 10);
#image_print($extra);
#!/usr/bin/perl
use common::sense;
##C 18-cell 40514-generation methuselah
##C based on Richard Wobus' 15-cell marvel
#x = 78, y = 54, rule = B3/S23
#77bo$77bo$77bo21$3o20$3bo$3bo$3bo5$20b3o$9b3o10bo$22bo$21bo!
my $format = 1;
my $header = <>;
while ($header =~ m/^#/) { $header = <>; }
chomp $header;
$header =~ m/x\s*=\s([0-9]*)\s*,\s*y\s*=\s*([0-9]*)\s*,\s*rule\s*=\s*([^ ]*)/;
my ($x, $y, $rule) = ($1, $2, $3);
print STDERR "Have header: $x, $y, $rule\n";
print STDERR "Warning: rule '$rule' is lost in this conversion.\n" unless $rule eq "B3/S23";
my $rows_printed = 0;
my $image;
while (<>) {
next if (m/^#/);
chomp;
my $source = $_;
$source =~ s {(\d+)(.)} {$2 x $1}gse;
my @lines = split /\$/,$source;
for my $line (@lines) {
$line =~ s/!//;
$line =~ y/bo/01/;
$image .= $line."0" x ($x-length $line)."\n";
$rows_printed++;
}
}
for (;$rows_printed < $y;$rows_printed) {
$\ = "\n";
$image .= "b" x ($x);
}
if ($format == 1) {
$image =~ s/(.)/\1 /g;
$image =~ s/ $//g;
print "P1\n$x $y\n$image";
} else {
print "Format $format not supported.";
}
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
int main(int argc, char **argv) {
if (argc != 2) { fprintf(stderr, "Usage: %s count\n", argv[0]); exit(1); }
int count = atoi(argv[1]);
if (count <= 0) {
fprintf(stderr, "Invalid count given: %i\n", count);
exit(2);
}
printf("%i\n", count);
for (int i = 0; i < count; i++) {
printf("%i\n", rand());
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment