Compare commits

..

6 Commits

18 changed files with 397 additions and 53 deletions

9
.gitignore vendored
View File

@@ -1,9 +1,18 @@
# out files
*.out
*.file
# Java
.class
.jar
# Perl
nytprof*
.callgrind
# Python
*.pyc
*.lprof
# Executables
*.x

View File

@@ -60,6 +60,9 @@ HTTP Server:
Calculus: Simpson's Rule for Integration
* Implements composite Simpson's Rule to integrate a function over an interval `[a,b]` using `n` approximating points
N Queens:
* Solve the N queens problem using integer arrays, with minimal object-oriented fluff.
### Programs In Progress
@@ -84,7 +87,7 @@ Arrays:
* Use a native built-in data type to store a 1D array of data
Matrix inversion:
* Gauss-Jordan elimination algorithm
* Gauss-Jordan elimination or back-substitution algorithm
Vector products:
* Given three three-dimensional vectors, compute dot/cross product, scalar/vector triple products

View File

@@ -3,15 +3,20 @@ import java.util.Arrays;
public class NQueens {
public static final int SIZE = 9;
///////////////////////////////////////////////////
// main
//
public static void main(String[] args) {
long start = System.nanoTime();
SolutionSaver s = new SolutionSaver();
Board b = new Board(8);
Board b = new Board(SIZE);
explore(b,0);
System.out.printf("Found %d solutions\n ", SolutionSaver.nSolutions() );
long end = System.nanoTime();
long duration = end - start;
System.out.printf("Found %d solutions\n ", SolutionSaver.nSolutions() );
System.out.printf("Elapsed time %03f s\n ", (duration/1E9) );
}
//
///////////////////////////////////////////////////
@@ -20,25 +25,25 @@ public class NQueens {
/// Placing queens, column-by-column; place the queen in column col.
public static void explore(Board b, int col) {
if(col >= b.size() ) {
if(col >= SIZE ) {
// We have reached the end.
// No conflicts so far means no conflicts period.
// Save solution in a static class, no instantiation overhead
String serial = b.toString();
SolutionSaver.saveSolution(serial);
SolutionSaver.saveSolution( b.toString() );
} else {
// The legalRows() method is a little bit of magic.
// It returns an array of valid rows on which to place the col^th queen.
for(Integer row : b.legalRows(col) ) { // important question: is this called each time in the loop?
// (do i need to make a copy outside the loop?)
b.choose(row,col);
explore(b,col+1);
b.unchoose(row,col);
int[] attacked = b.getDiagAttacked(col);
int[] occupied = b.getOccupied(col);
for(int row=0; row<SIZE; row++) {
if(occupied[row]!=1 && attacked[row]!=1) {
b.choose(row,col);
explore(b,col+1);
b.unchoose(row,col);
}
}
}// done with base/recursive cases
}
@@ -55,7 +60,7 @@ class Board {
int[] occupiedrows; // Array to mark occupied rows.
// This is how we check for horizontal attacks.
int board_size; // Size of our problem
public static int board_size;
public Board(int size) {
this.board_size = size;
@@ -63,11 +68,6 @@ class Board {
this.occupiedrows = new int[size];
}
/// Get board size
public int size(){
return this.board_size;
}
/**
* Get String representation of queen positions.
* This prints 8 numbers, corresponding to 8 columns.
@@ -95,52 +95,44 @@ class Board {
}
}
/// Get a list of legal rows
public LinkedList<Integer> legalRows( int col ) {
/// Get a list of occupied rows
public int[] getOccupied(int col) {
return this.occupiedrows;
}
LinkedList<Integer> legalList = new LinkedList<Integer>();
/// Get a list of attacked diagonals
public int[] getDiagAttacked( int col ) {
// 1. Mark invalid squares on diagonals of already-placed queens
// 1. Mark invalid squares on diagoonals of already-placed queens
//
// 2. For this column, loop over each row where it's legal to place a queen,
// and run backtracking on that choice. Then unmake the choice and keep going.
// Store invalid rows on other queens' diagonals
int[] diag = new int[size()];
int[] diag = new int[this.board_size];
// Loop over all of the queens already placed (col-1)
for(int k = 0; k <= (col-1); k++ ) {
// We're gonig to place the next queen on col.
// Find which squares are on diagonal of queen k,
// Find which squares are on diagonals of queen k,
// and mark them as impossible.
// Lower right diagonal
// Lower right diag
int ix1 = this.queens[k] + col - k;
if(ix1 >= 0 && ix1 < size() ) {
if(ix1 >= 0 && ix1 < this.board_size ) {
diag[ix1] = 1;
}
// Upper right diagonal
// Upper right diag
int ix2 = this.queens[k] - col + k;
if(ix2 >= 0 && ix2 < size() ) {
if(ix2 >= 0 && ix2 < this.board_size ) {
diag[ix2] = 1;
}
}
// Legal rows are non-diagonal squares and squares on non-occupied rows.
for (int row = 0; row < size(); row++) {
// If this row is legal, add it to the list
boolean legal = diag[row]==0 && this.occupiedrows[row]==0;
if(legal) {
legalList.add(row);
}
}
return legalList;
return diag;
}
}

30
java/nqueens/prof_java_hprof.sh Executable file
View File

@@ -0,0 +1,30 @@
#!/bin/sh
#
# Profile the N queens problem using Java Iteractive Profiler
# http://jiprof.sourceforge.net/
#
# Also see http://charlesreid1.com/wiki/Java/Profiling
#
# Download source and look for profile/profile.jar
export PATH2JIP="${HOME}/Downloads/jip-src-1.2"
for N in 14
do
echo "**************************************"
echo "Profiling $N queens problem with Java JIP..."
# Update N
/usr/local/bin/sed -i "s/SIZE = [0-9]\{1,\}/SIZE = ${N}/g" NQueens.java
# Compile
javac NQueens.java
java -javaagent:${PATH2JIP}/profile/profile.jar NQueens
mv profile.txt profile_jip_${N}queens.out
tail -n30 profile_${N}queens.out
done

32
java/nqueens/prof_java_jip.sh Executable file
View File

@@ -0,0 +1,32 @@
#!/bin/sh
#
# Profile the N queens problem using Java Iteractive Profiler
# http://jiprof.sourceforge.net/
#
# Also see http://charlesreid1.com/wiki/Java/Profiling
#
# Download source and look for profile/profile.jar
for N in 14
do
echo "**************************************"
echo "Profiling $N queens problem with Java HPROF..."
# Update N
/usr/local/bin/sed -i "s/SIZE = [0-9]\{1,\}/SIZE = ${N}/g" NQueens.java
# Compile
javac NQueens.java
echo " - - - - - - - - - - - - - - - - - - - - -"
echo "Profiling $N queens with HPROF..."
java -agentlib:hprof=verbose=n NQueens
#java -agentlib:hprof NQueens
#java -agentlib:hprof=cpu=samples NQueens
mv java.hprof.txt profile_hprof_${N}queens.out
tail -n30 hprof_${N}queens.out
done

26
java/nqueens/time_java.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/sh
export RIGHTNOW="`date +"%Y%m%d_%H%M%S"`"
export OUT="timeout_nqueens_java_${RIGHTNOW}.out"
touch ${OUT}
cat /dev/null > ${OUT}
for N in 8 9 10 11 12 13 14 15
do
echo "**************************************" >> ${OUT}
echo "Running $N queens problem with Java..." >> ${OUT}
# Update N
/usr/local/bin/sed -i "s/SIZE = [0-9]\{1,\}/SIZE = ${N}/g" NQueens.java
# Compile
javac Nqueens.java
# Semicolon is important here
echo "Running..."
{ time java NQueens >> ${OUT}; } 2>> ${OUT}
echo "Done."
echo "" >> ${OUT}
done

View File

@@ -1,4 +1,4 @@
#!/usr/bin/perl -w
#!/usr/local/bin/perl -w
my $verse = <<"VERSE";
100 bottles of beer on the wall,

View File

@@ -1,3 +1,3 @@
#!/usr/bin/perl
#!/usr/local/bin/perl
print 'hello world';

119
perl/nqueens/nqueens.pl Normal file
View File

@@ -0,0 +1,119 @@
#!/usr/local/bin/perl
use Time::HiRes qw(time);
use strict;
use warnings;
my $start = time;
######################################
########## N Queens Puzzle ###########
#
#
# The 8 queens problem is to place 8 queens on a chessboard
# such that no queen attacks any other queen.
#
# In 1972, Dijkstra published the first depth-first
# backtracking algorithm to solve the problem.
#
# This file implements a recursive backtracking algorithm
# to find solutions to the N queens problem.
#
# This requires a way of choosing queens,
# and a way to check if a configuration is valid (as we go).
# The backtracking algorithm recursively calls a method
# to place one queen at a time, 8 times.
# When there are no more choices left to make, it has reached a leaf,
# and it stores (or prints out) a solution.
#
# Modified and expanded from http://rosettacode.org/wiki/N-queens_problem#Perl
# Create an array to store solutions
my @solutions;
# Create an array to store where queens have been placed
my @queens;
# Mark the rows already used (useful for lookup)
my @occupied;
# Size of board
my $board_size;
# explore() implements a recursive, depth-first backtracking method
sub explore {
# Parameters:
# depth : this is the argument passed by the user
# First argument passed to the function is $depth
# (how many queens we've placed on the board),
# so use shift to pop that out of the parameters
my ($depth, @attacked) = shift;
# Explore is a recursive method,
# so we need a base case and a recursive case.
#
# The base case is, we've reached a leaf node,
# placed 8 queens, and had no problems,
# so we found a solution.
if ($depth==$board_size) {
# Here, we store the stringified version of @queens,
# which are the row numbers of prior queens.
# This is a global variable that is shared across
# instances of this recursive function.
push @solutions, "@queens\n";
return;
}
##################################
# Method 1
#
# Mark the squares that are attackable,
# so that we can cut down on the search space.
my($ix1, $ix2);
$#attacked = 2 * $board_size;
for( 0 .. $#queens) {
$ix1 = $queens[$_] + $depth - $_ ;
$attacked[ $ix1 ] = 1;
$ix2 = $queens[$_] - $depth + $_ ;
$attacked[ $ix2 ] = 1;
}
#
####################################
for my $row (0 .. $board_size-1) {
# Cut down on the search space:
# if this square is already occupied
# or will lead to an invalid solution,
# don't bother exploring it.
next if $occupied[$row] || $attacked[$row];
# Make a choice
push @queens, $row;
# Mark the square as occupied
$occupied[$row] = 1;
# Explore the consequences
explore($depth+1);
# Unmake the choice
pop @queens;
# Mark the square as unoccupied
$occupied[$row] = 0;
}
}
$board_size = 11;
explore(0);
my $duration = time - $start;
print "Found ", scalar(@solutions), " solutions\n";
printf "Execution time: %0.3f s \n",$duration;

32
perl/nqueens/prof_perl.sh Executable file
View File

@@ -0,0 +1,32 @@
#!/bin/sh
#
# Profile the N queens problem using Devel::NYTProf
#
# Install using cpanm:
# $ cpanm Devel::NYTProf
#
for N in 8 9 10 11 12
do
echo "**************************************"
echo "Profiling $N queens problem with Perl..."
# Update N
/usr/local/bin/sed -i "s/board_size = [0-9]\{1,\};/board_size = ${N};/g" nqueens.pl
echo "Running..."
/usr/local/bin/perl -d:NYTProf nqueens.pl
echo "Done."
# CSV contains interesting info
${HOME}/perl5/bin/nytprofcsv nytprof.out
## More information...
#${HOME}/perl5/bin/nytprofcg nytprof.out
#${HOME}/perl5/bin/nytprofhtml nytprof.out
mv nytprof nytprof${N}
done

23
perl/nqueens/time_perl.sh Executable file
View File

@@ -0,0 +1,23 @@
#!/bin/sh
export RIGHTNOW="`date +"%Y%m%d_%H%M%S"`"
export OUT="timeout_queens_perl_${RIGHTNOW}.out"
touch ${OUT}
cat /dev/null > ${OUT}
for N in 8 9 10 11 12 13 14 15
do
echo "**************************************" >> ${OUT}
echo "Running $N queens problem with Perl..." >> ${OUT}
# Update N
/usr/local/bin/sed -i "s/board_size = [0-9]\{1,\};/board_size = ${N};/g" nqueens.pl
# Semicolon is important here
echo "Running..."
{ time /usr/local/bin/perl nqueens.pl >> ${OUT}; } 2>> ${OUT}
echo "Done."
echo "" >> ${OUT}
done

View File

@@ -1,12 +1,14 @@
# Look ma, no modules!
# bottlenecks around 12, when the problem size starts to mushroom
board_size = 10
board_size = 11
solutions = []
queens = []
occupied = board_size*[0,]
def explore(depth):
# base case
if(depth==board_size):

View File

@@ -0,0 +1,24 @@
#!/bin/sh
#
# Profile the N queens problem using cProfile
export RIGHTNOW="`date +"%Y%m%d_%H%M%S"`"
export OUT="outfile_prof_nqueens_python_${RIGHTNOW}.out"
for N in 8 9 10 11
do
echo "**************************************" >> ${OUT}
echo "Profiling $N queens problem with Python..." >> ${OUT}
# Update N
/usr/local/bin/sed -i "s/board_size = [0-9]\{1,\}/board_size = ${N}/g" nqueens.py
rm -f *.pyc
echo "Running..."
python pycprof_nqueens.py >> ${OUT}
echo "Done."
done

View File

@@ -0,0 +1,36 @@
#!/bin/sh
#
# Profile the N queens problem using cProfile
export RIGHTNOW="`date +"%Y%m%d_%H%M%S"`"
export OUT="outfile_prof_nqueens_python_${RIGHTNOW}.out"
# Add function decorator
/usr/local/bin/sed -i "s/def explore/@profile\ndef explore/g" nqueens.py
for N in 8 9 10 11
do
echo "**************************************" >> ${OUT}
echo "Profiling $N queens problem with Python..." >> ${OUT}
# Update N
/usr/local/bin/sed -i "s/board_size = [0-9]\{1,\}/board_size = ${N}/g" nqueens.py
rm -f *.pyc
echo "Running program via kernprof..."
# runs the program
kernprof -l nqueens.py >> ${OUT}
# results are in nqueens.py.lprof
python -m line_profiler nqueens.py.lprof >> ${OUT}
echo "Done."
done
# Remove function decorator
/usr/local/bin/sed -i "s/@profile//g" nqueens.py

View File

@@ -0,0 +1,21 @@
print "*******************************"
print "cProfile:"
print "*******************************"
import pstats, StringIO
import cProfile
pr = cProfile.Profile()
pr.enable()
import nqueens
pr.disable()
## Simple
#pr.dump_stats('stats.file')
#pr.print_stats()
# Complicated
s = StringIO.StringIO()
sortby = 'time'
ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
ps.print_stats()
print s.getvalue()

View File

@@ -6,14 +6,16 @@ touch ${OUT}
cat /dev/null > ${OUT}
#for N in 8 9 10 11 12 13 14 15
#for N in 8 9 10 11 12
for N in 13 14
#for N in 12 13 14
for N in 8 9 10 11
do
echo "**************************************" >> ${OUT}
echo "Running $N queens problem with Python..." >> ${OUT}
# Update N
/usr/local/bin/sed -i "s/board_size = [0-9]\{1,\}/board_size = ${N}/g" nqueens.py
rm -f *.pyc
# Semicolon is important here
echo "Running..."

View File

@@ -1,7 +0,0 @@
import cProfile
pr = cProfile.Profile()
pr.enable()
import nqueens
pr.disable()
pr.print_stats()