The Geeks Shall Inherit the Earth

Personal Ramblings of the Techhouse Admin

Skip to: Content | Sidebar | Footer

Iterative Deepening Finished

11 May, 2010 (19:43) | Erlang | By: Brian

I’ve completed the iterative deepening blind search algorithm and it works pretty well. The final solution is here:

%%Problem 5
%% iterative deepening blind search
iterative_deepening_search(Problem) ->
 ids_recursive(Problem, 1).

ids_recursive(Problem, Limit) ->
 case depth_limited_search(Problem, Limit) of
 {found, FoundState} ->
 print_solution_path(Problem, FoundState),
 {found, FoundState};
 _Other ->
 io:format("Solution not found at depth ~w, iterating~n", [Limit]),
 ids_recursive(Problem, Limit + 1)
 end.

%% depth limited search
%% starts a depth limited search, prints solution if found
depth_limited_search(Problem, Limit) ->
 case dls_recursive(Problem, new_solution(Problem), Limit) of
 {found, FoundState} ->
 {found, FoundState};
 Other ->
 Other
 end.

%first try to match the goal state
dls_recursive(
 #problem{goal_state = Goal},
 #solution_state{state = Goal} = SState,
 _Limit) ->
 %io:format("Goals match: ~w~n", [Goal] ),
 {found, SState};
%then see if we hit bottom
dls_recursive(_Problem,
 #solution_state{depth = Depth}, Limit) when Depth >= Limit ->
 {not_found, max_depth_reached};
%else generate the next possible states and iterate through them
dls_recursive(Problem, State, Limit) ->
 %expand the solution with all possible moves and go deeper
 New_SStates = expand_solution(Problem, State),
 %try each one until it passes
 dls_recurse_with_cut_off(Problem, New_SStates, Limit).

%% expand solution
expand_solution(Problem, Solution_State) ->
 lists:map(fun(Move) -> update_solution(Solution_State, Move) end,
 possible_moves(Problem#problem.yard, Solution_State#solution_state.state) ).

%recurse over the generated states as a stack
%if we empty the stack return out of moves
dls_recurse_with_cut_off(_Problem, [], _Limit) ->
 {not_found, out_of_moves};
%take the top state of the stack, if goal return immediately
%else try the next move on the stack
dls_recurse_with_cut_off(Problem, [SState | Rest], Limit) ->
 case dls_recursive(Problem, SState, Limit) of
 {found, FoundState} ->
 {found, FoundState};
 {not_found, _Reason}    ->
 dls_recurse_with_cut_off(Problem, Rest, Limit)
 end.

And some sample runs.

trainswitch:iterative_deepening_search(trainswitch:problem3()).
Solution not found at depth 1, iterating
Solution state at depth: 2
To go from [{t1,[engine]},{t2,[a]},{t3,[b]}] to
[{t1,[engine,a,b]}]
Apply: [{left,t2,t1},{left,t3,t1}]
{found,{solution_state,[{t1,[engine,a,b]}],
 [{left,t3,t1},{left,t2,t1}],
 2}}

trainswitch:iterative_deepening_search(trainswitch:problem4()).
Solution not found at depth 1, iterating
Solution not found at depth 2, iterating
Solution not found at depth 3, iterating
Solution state at depth: 4
To go from [{t1,[engine]},{t2,[a]},{t3,[b,c]},{t4,[d]}] to
[{t1,[engine,a,b,c,d]}]
Apply: [{left,t2,t1},{left,t3,t1},{left,t3,t1},{left,t4,t1}]
{found,{solution_state,[{t1,[engine,a,b,c,d]}],
 [{left,t4,t1},{left,t3,t1},{left,t3,t1},{left,t2,t1}],
 4}}

trainswitch:iterative_deepening_search(trainswitch:problem5()).
Solution not found at depth 1, iterating
Solution not found at depth 2, iterating
Solution not found at depth 3, iterating
Solution not found at depth 4, iterating
Solution not found at depth 5, iterating
Solution state at depth: 6
To go from [{t1,[engine]},{t2,[a]},{t3,1},{t4,[d]}] to
[{t1,[engine,a,b,c,d]}]
Apply: [{left,t3,t1},{right,t1,t4},{left,t2,t1},{left,t3,t1},{left,t4,t1},{left,t4,t1}]
{found,{solution_state,[{t1,[engine,a,b,c,d]}],
 [{left,t4,t1},
 {left,t4,t1},
 {left,t3,t1},
 {left,t2,t1},
 {right,t1,t4},
 {left,t3,t1}],
 6}}

For research and testing purposes I found a simple function online that runs a call a specified number of times, measures how long those runs take and then produces some useful stats. Here is that utility:

test_avg(M, F, A, N) when N > 0 ->
 L = test_loop(M, F, A, N, []),
 Length = length(L),
 Min = lists:min(L),
 Max = lists:max(L),
 Med = lists:nth(round((Length / 2)), lists:sort(L)),
 Avg = round(lists:foldl(fun(X, Sum) -> X + Sum end, 0, L) / Length),
 io:format("Range: ~b - ~b mics~n"
 "Median: ~b mics~n"
 "Average: ~b mics~n",
 [Min, Max, Med, Avg]),
 Med.

test_loop(_M, _F, _A, 0, List) ->
 List;
test_loop(M, F, A, N, List) ->
 {T, _Result} = timer:tc(M, F, A),
 test_loop(M, F, A, N - 1, [T|List]).

This blind search solves the smaller of the really large problems, 1 and 2, in a reasonable amount of time.

Solution not found at depth 1, iterating
Solution not found at depth 2, iterating
Solution not found at depth 3, iterating
Solution not found at depth 4, iterating
Solution not found at depth 5, iterating
Solution not found at depth 6, iterating
Solution not found at depth 7, iterating
Solution not found at depth 8, iterating
Solution not found at depth 9, iterating
Solution not found at depth 10, iterating
Solution not found at depth 11, iterating
Solution not found at depth 12, iterating
Solution not found at depth 13, iterating
Solution state at depth: 14
To go from [{t1,[engine]},{t2,[d]},{t3,[b]},{t4,[a,e]},{t5,1}] to
[{t1,[engine,a,b,c,d,e]}]
Apply: [{left,t5,t1},{left,t2,t1},{right,t1,t5},{right,t1,t5},{right,t1,t2},{left,t4,t2},{left,t3,t2},{left,t4,t2},{left,t2,t1},{left,t2,t1},{left,t2,t1},{left,t5,t1},{left,t5,t1},{left,t2,t1}]
Range: 253234999 - 259874999 mics
Median: 255812999 mics
Average: 255859399 mics
255812999

This means that problem 2 takes about 255 seconds, or 4 minutes to run with this blind search. Even if we know the depth ahead of time, 14, it still takes a long time for this to run. About 50 seconds on average.

trainswitch:test_avg(trainswitch, depth_limited_search, [trainswitch:problem2(), 14], 5).
Range: 46078000 - 48249999 mics
Median: 47765999 mics
Average: 47484399 mics
47765999

The next part of this assignment is to implement an A* heuristic search of some kind on this problem. Which basically means find an algorithm that will generate a rough guess as to how close to the goal state each next step is, and choose the one that’s closest to pursue. Before going down that route, I want to explore the concurrency model in Erlang briefly. My plan is to replace the depth-limited-search algorithm with a supervisor process that spawns off processes for each next state and sends them off running. It will listen to each of its child processes for either a found state, in which case it returns that state and kills off its other workers, or all of its children have hit dead-ends and it returns a solution not found state. Each child process similarly acts as a supervisor to spawn a series of child processes that it listens to, and so on. I have no idea what sort of performance impact this will have. I know it will be somewhat random, as the different processes may run at different speeds. But that’s what the measure lots of times and average function is for.

A Quick A.I. Overview

4 May, 2010 (21:20) | Erlang | By: Brian

For my Erlang exercises, I had to review a couple of software algorithms for searching. I did a quick brush-up on the concepts so that I could understand the old code I wrote, and translate it into the new code. So a couple of quick definitions.

  • Depth-First Search: DFS is the search algorithm I mentioned in the previous post. You keep going down a path until you find what you are looking for or hit a dead-end. Then you back up to your most recent decision and try another path. It’s the opposite of Breadth-First Search, which means to generate all the next steps and check each of those first, then take one of those steps and check all of its next steps.
  • Depth-Limited-Search: A kind of depth-first search where you start with some initial limit of how many steps you want to take. If you hit that number of steps before finding a solution, you back up. This is a great way to avoid problems that can loop on themselves, like chess pieces or our train yard. But what if we don’t know how deep to look?
  • Iterative deepening depth-first search: After creating a depth-limited search, you wrap that search in a process that keeps running that depth-limited-search at increasing depths until you find a solution. So you start at depth 1, if you don’t find anything, go to depth 2, then 3, then 4, and so on, until you find something. If you know something more about your search space, you might decide to start at a higher number, or increase the change in depth by more than one. But this is the basic idea.

The assignment’s next problem is to write a blind search algorithm, (i.e. – one that doesn’t do any analyzing before deciding where to go) to solve the simpler train yards. I chose IIDFS because it’s fairly simple to write and is guaranteed to find the shortest solution, or one of the shortest solutions if there are multiple solutions at the same minimal depth. It’s also pretty good on space and time.

To do this I created a solution state structure and some helper methods for it.

%%% solution state
-record(solution_state, {state = #state{}, moves, depth}).

new_solution(Problem) ->
#solution_state{state = Problem#problem.init_state,
moves = [], depth = 0} .

update_solution(Solution_state, Move) ->
#solution_state{
state = apply_move(Move, Solution_state#solution_state.state),
moves = [Move] ++ Solution_state#solution_state.moves,
depth = Solution_state#solution_state.depth + 1} .

%%print the path of moves that lead from the initial state to the current one in this solution step
print_solution_path(Problem, Solution_state) ->
io:format("Solution state at depth: ~w~n", [Solution_state#solution_state.depth]),
io:format("To go from ~w to~n", [Problem#problem.init_state]),
io:format("~w~n", [Solution_state#solution_state.state]),

io:format("Apply: ~w~n", [lists:reverse(Solution_state#solution_state.moves)]).

And, of course, I created some tests that mostly generate some objects and print them out.

SState1 = new_solution(Yard3),
    SState2 = update_solution(SState1, {left, t2, t1}),
    SState3 = update_solution(SState2, {left, t3, t1}),
    print_solution_path(Yard3, SState3),

Here’s my current work-in-progress on the depth limited search.

%first try to match the goal state
dls_recursive(
    #problem{goal_state = Goal},
    #solution_state{state = Goal} = SState,
    _Limit) ->
    io:format("Goals match: ~w~n", [Goal] ),
    {found, SState};
%then see if we hit bottom
dls_recursive(_Problem,
    #solution_state{depth = Depth}, Limit) when Depth >= Limit ->
    {not_found, max_depth_reached};
%else generate the next possible states and iterate through them
dls_recursive(Problem,
    #solution_state{depth = Depth} = State, Limit) ->
    %expand the solution with all possible moves and go deeper
    New_SStates = expand_solution(Problem, State),
    %get possible states from here
    %try each one until it passes
    dls_recursive(Problem, State, Limit).

%% expand solution
expand_solution(Problem, Solution_State) ->
    lists:map(fun(Move) -> update_solution(Solution_State, Move) end,
        possible_moves(Problem#problem.yard, Solution_State#solution_state.state) ).

I’m still missing the vital chunk that iterates through the list of next steps. The reason that it’s not just a simple map function is that if we hit the solution we want to return that immediately, but if you get a not_found, you keep looking through the list. I’m still trying to figure out what the best way to do a short-circuit/cut-off control is in Erlang.

Iterative deepening depth-first search

A Techhouse Wedding

29 April, 2010 (22:52) | Life In General, Lynn | By: Brian

Last weekend my good friend Steve from college got married to a wonderful girl named Karen, and I had the honor of being one of his groomsmen. Lynn and I had a wonderful time dancing the night away and seeing all of techhouse together again for a great wedding. And here are some pictures!

Trainyard problems 2 and 3

29 April, 2010 (22:30) | Erlang | By: Brian

After getting the problem structure worked out, I started working on Problem 2, applying a move to a state and getting a new state. This required a couple of helper functions that came over from the lisp code. These two small functions take two track listings and perform the appropriate move. They return a pair of lists as a single Tuple, because functions can only return one term. Creating these methods taught me how to use the list concatenation operator “++.” This operator is used for combining lists in statements, “|” is used for splitting lists in matches.

%% move the first element of front to the last element of back and return both new lists
move_front_to_back([Front | Rest], Back ) ->
 {Rest, Back ++ [Front] }.

%%move the last element of front to the first element of back and return both new lists
move_back_to_front(Front, Back) ->
 {lists:sublist(Front, length(Front) - 1), [lists:last(Front)] ++ Back}.

And some test cases.

{[],[b,a]} = move_front_to_back([a], [b]),
 {[b],[a]} = move_front_to_back([a,b], []),
 {[b,c],[d,e,a]} = move_front_to_back([a,b,c], [d, e]),
 {[],[a,b]} = move_back_to_front([a], [b]),
 {[a],[b]} = move_back_to_front([a,b], []),
 {[a,b],1} = move_back_to_front([a,b,c], [d, e]),

Next I needed a new function to take the two returned lists and apply them to a state list. While working on this problem, I discovered that my track list structure of [{Trackname, Tracklist}, ...] met the definition of an Erlang key store structure. Once I figured this out and read some documentation, the data management of the track list structures became fairly simple calls the lists module’s key methods. This function takes a list of track tuples and applies them recursively to the state. Finally, it sorts the tracklist by trackname and returns the new state.

%%take a list of tuples like {t1, [a,b]} and a state, update tracks, return new state
update_tracks(State, []) ->
 %io:format("No Updates to make, returning input state: ~w~n", [State]),
 lists:keysort(1,State);
update_tracks(State, [{UpdateTrack, UpdateList} | RestUpdate]) ->
 io:format("Updating state ~w with track ~w~n", [State, {UpdateTrack, UpdateList}]),
 case UpdateList of
 [] ->
 %delete the track key and recurse
 %io:format("Deleting track ~w and recursing~n", [UpdateTrack]),
 update_tracks(lists:keydelete(UpdateTrack, 1, State ), RestUpdate);
 _CarsOnTrack ->
 %replace the track key and recurse
 %io:format("Replacing with track ~w~n", [{UpdateTrack, UpdateList}]),
 update_tracks(lists:keystore(UpdateTrack, 1, State, {UpdateTrack, UpdateList}), RestUpdate)
 end.

I also refactored one of my older utility methods to use the built-in key functions.

%%trainswitch:cars_on_track(t1, Yard1#problem.init_state).
cars_on_track(Track, TrackList) ->
 %keysearch for a {Track, Cars} tuple in the list
 case lists:keyfind(Track, 1, TrackList) of
 false -> [];
 {_Track, Cars} -> Cars %try to bind track and return its cars
 end.

Now that we can apply a list of individual track updates to a state, we just generate a list of track updates from a move and apply them.

%%Problem 2
%%apply_move: apply a move to a state and return the new state
%%trainswitch:apply_move({left, t2, t1}, Yard1#problem.init_state).
apply_move({left, Right, Left}, State) ->
 %io:format("Moving car from ~w to ~w in state: ~w~n",[Right, Left, State]),
 {NewRightList, NewLeftList} = move_front_to_back(cars_on_track(Right, State), cars_on_track(Left, State)),
 %io:format("Moved car from ~w to ~w~n",[{Right, NewRightList}, {Left, NewLeftList}]),
 update_tracks(State, [{Right, NewRightList}, {Left, NewLeftList}]); %return the new state
apply_move({right, Left, Right}, State) ->
 %io:format("Moving car from ~w to ~w in state: ~w~n",[Left, Right, State]),
 { NewLeftList, NewRightList} = move_back_to_front(cars_on_track(Left, State), cars_on_track(Right, State) ),
 %io:format("Moved car from ~w to ~w~n",[{Left, NewLeftList}, {Right, NewRightList}]),
 update_tracks(State, [{Right, NewRightList}, {Left, NewLeftList}]). %return the new state

So when we want to apply a move like {left, t2, t1}, we create an update tuple for the new state of t2, an update tuple for the new state of t1, list those updates together and pass that list to the update method.

[{t1, [engine, a]}, {t3, [b]}] = apply_move({left, t2, t1}, [{t1, [engine]}, {t2, [a]}, {t3, [b]}]),
 [{t1, [a]}, {t3, [b]}] = apply_move({left, t2, t1}, [{t2, [a]}, {t3, [b]}]),
 [{t2, [engine, a]}, {t3, [b]}] = apply_move({right, t1, t2}, [{t1, [engine]}, {t2, [a]}, {t3, [b]}]),
 [{t2, [engine]}, {t3, [b]}] = apply_move({right, t1, t2}, [{t1, [engine]}, {t3, [b]}]),

For my structures I decided to just remove empty lists. So, for example, in the last test, you won’t see {t1, []}. This is just to keep the structures smaller and leaner. The function that looks for cars on a track will just return {t1, []} if the track is not in the keystore.

Problem 3 is a fairly trivial expansion of problems 1 and 2. Take a state, generate all moves from it and return a list of all the states that would be reached by applying those moves. It’s a fairly simple map process.

%%Problem 3
%%expand: take a yard and a state and return a list of all states reachable in one step
expand(State, Yard) ->
 lists:map(fun(Move) -> apply_move(Move,State) end, possible_moves(Yard, State)).

Next I get to start on actually solving the problem. When I solved this problem before I chose iterative deepening search as the “blind search” algorithm. Iterative deepening means essentially that at each step of the solution I first generate all the next steps, take one of those steps and try to solve from there before looking at any of the other steps I generated. If I run out of moves to try, I back up and try another path. Imagine blindly trying to drive to a destination and at every fork in the road you went left. When you hit a dead-end, you backed up one fork and tried the right. If you found a dead-end there you backed up twice and tried the right from that branch, and so on. The only trouble with using this method for solving this problem is that you have to be careful to not get stuck in an endless loop of states going back and forth. If you don’t check for this, your solver could endlessly go down a path of {left, 2, 1}, {right, 1, 2}, {left, 2, 1}, {right, 1, 2} … and so on. Re-writing this algorithm will require some new data structures to represent the intermediate solving steps as well as helper methods for traversing the solution space.

Train Yard Data in Records

29 April, 2010 (20:57) | Erlang | By: Brian

I wanted to start on the second problem in the train yard assignment in Erlang. But I realized that my data structure for a yard was pretty cumbersome. I wanted to mess with the Record structure system, so I created a header file with the record and test data definitions.

%%% train yard data structures
-record(yard, {track_list}).
-record(state, {yard_state}).

%%% problem structure
-record(problem, {yard = #yard{}, init_state = #state{}, goal_state = #state{}}).

%%% problems

problem1() ->
 #problem{yard = [{t1, t2}, {t1, t3}, {t3, t5}, {t4, t5}, {t2, t6}, {t5, t6}],
 init_state = [{t1, [engine]}, {t2, [e]}, {t4, [b, c, a]}, {t6, [d]}],
 goal_state = [{t1, [engine, a, b, c, d, e]}] }.
problem2() ->
 #problem{yard = [{t1, t2}, {t2, t3}, {t2, t4}, {t1, t5}],
 init_state = [{t1, [engine]}, {t2, [d]}, {t3, [b]}, {t4, [a, e]}, {t5, 1}],
 goal_state = [{t1, [engine, a, b, c, d, e]}] } .

problem3() ->
 #problem{yard = [{t1, t2}, {t1, t3}],
 init_state = [{t1, [engine]}, {t2, [a]}, {t3, [b]}],
 goal_state = [{t1, [engine, a, b]}, {t2, []}, {t3, []}] } .

problem4() ->
 #problem{yard = [{t1, t2}, {t1, t3}, {t1, t4}],
 init_state = [{t1, [engine]}, {t2, [a]}, {t3, [b, c]}, {t4, [d]}],
 goal_state = [{t1, [engine, a, b, c, d]}, {t2, []}, {t3, []}] } .

problem5() ->
 #problem{yard = [{t1, t2}, {t1, t3}, {t1, t4}],
 init_state = [{t1, [engine]}, {t2, [a]}, {t3, 1}, {t4, [d]}], %note c and b are out of order
 goal_state = [{t1, [engine, a, b, c, d]}, {t2, []}, {t3, []}] } .

The Record system is definitely a mixed bag. While it’s great to have some kind of naming structure for organizing data together, the syntax is clumsy, and particularly annoying to work with in the shell.

151> rr(trainswitch).
[problem,state,yard]
153> TestYard = trainswitch:problem1().
#problem{yard = [{t1,t2},
 {t1,t3},
 {t3,t5},
 {t4,t5},
 {t2,t6},
 {t5,t6}],
 init_state = [{t1,[engine]},{t2,[e]},{t4,[b,c,a]},{t6,[d]}],
 goal_state = [{t1,[engine,a,b,c,d,e]}]}
154> TestState = TestYard#problem.init_state.
[{t1,[engine]},{t2,[e]},{t4,[b,c,a]},{t6,[d]}]

So that’s the structure for a problem. The object is given a yard and a start state, find the moves that bring you to the goal state. Next up are a few more sub problems that work toward that goal.

Open Sarcasm Manifesto ¡

29 April, 2010 (10:49) | Grammar | By: Brian

Open Sarcasm Manifesto ¡ Free Sarcasm Punctuation ¡ Open-Source Punctuation for Sarcasm ¡ Temherte Slaqî.

I have long felt the need for a sarcasm indicator of some kind for text communication. Today I discovered that other people have not only suffered this problem, but have also researched and discovered a solution. Apparently there is historical evidence that the upside-down exclamation point, “¡”, frequently seen in Spanish usage, has also been used to indicate sarcasm. Here is a brief usage guide and some examples. I can even use it on my new Droid Eris.

Foreign Service language courses—for free – Boing Boing

27 April, 2010 (12:46) | Links | By: Brian

Lisp Practice Updates

21 April, 2010 (16:56) | Erlang | By: Brian

After reading some more documentation and tinkering, I’ve updated the three practice functions I wrote in Erlang a little while ago. Here they are:

palinedromep(List) when is_list(List) ->
 List == lists:reverse(List);
palinedromep(_) ->
 false.

presentp(Atom, Tuple) when is_atom(Atom), is_tuple(Tuple) ->
 presentp(Atom,tuple_to_list(Tuple));
presentp(Atom, [Head | Rest]) when is_atom(Atom), is_list(Head) ->
 presentp(Atom,Head) orelse presentp(Atom, Rest);
presentp(Atom, [Head | Rest]) when is_atom(Atom) ->
 Atom == Head orelse presentp(Atom, Rest);
presentp(_, _) -> false.

duplicate_entries(Thing) when not is_list(Thing) -> false;
duplicate_entries([]) -> false;
duplicate_entries([_]) -> false;
duplicate_entries([Head | Rest] ) ->
 lists:member(Head, Rest) orelse duplicate_entries(Rest).

In addition, I wrote a simple unit test method that calls each method with a bunch of different inputs and tries to match the output with an expected true or false. If the test fails it throws a mismatch error. If it succeeds, it returns an atom saying the tests passed. Simple, but effective, and I only have to call lispprac1:unit_test() to make sure I haven’t broken anything.

unit_test() ->
 true = palinedromep([]),
 true = palinedromep([a]),
 true = palinedromep([a, a]),
 true = palinedromep([a, b, a]),
 true = palinedromep([a, b, b, a]),
 false = palinedromep([a, b]),
 false = palinedromep([a, b, b]),
 false = palinedromep(a),
 false = palinedromep({a, b}),
 true = presentp(a, [a]),
 true = presentp(a, [b, a]),
 true = presentp(a, [a, b, b, c]),
 true = presentp(a, {a}),
 true = presentp(a, {b, a}),
 true = presentp(a, [b, [a]]),
 true = presentp(a, [b, [b, [b, a]]]),
 false = presentp(a, [b]),
 false = presentp(a, b),
 false = presentp(a, [b, [b, c]]),
 false = presentp(a, {b, b, c}),
 false = presentp(a, {b, {b, c}}),
 true = duplicate_entries([a, a]),
 true = duplicate_entries([a, b, a]),
 true = duplicate_entries([a, b, c, b]),
 true = duplicate_entries([[a], b, [a]]),
 true = duplicate_entries([[a, b], b, b, [a]]),
 true = duplicate_entries([[a, b], b, c, [a, b]]),
 false = duplicate_entries([a, b]),
 false = duplicate_entries([[a], b]),
 false = duplicate_entries(a),
 false = duplicate_entries({a}),
 false = duplicate_entries([a, b, c]),
 false = duplicate_entries([a]),
 tests_passed.

Next I plan to use a record data structure on the train yard problem so that the yard data is easier to work with.

Digital Photocopiers Loaded With Secrets

20 April, 2010 (08:54) | Tech | By: Brian

Digital Photocopiers Loaded With Secrets – CBS Evening News – CBS News.

Here’s a quick note of warning. If you have to throw out a copier that has any kind of memory on it, and most modern ones do, find and destroy the hard drive. Or take it to a professional.

Senators Introduce Bill in Response to EFF’s Call for New Protections Against Secret Video Surveillance

19 April, 2010 (13:18) | Tech | By: Brian

Senators Introduce Bill in Response to EFF’s Call for New Protections Against Secret Video Surveillance | Electronic Frontier Foundation.

Wow, that was fast: little more than two weeks after EFF testified to a Senate subcommittee that federal electronic privacy law needs to be updated to protect against secret video surveillance just like it regulates electronic eavesdropping, Senator Arlen Specter has responded by introducing a bill to do just that.

From the Electronic Frontier Foundation’s blog. Good news for those who equate privacy with liberty.  (For those who don’t, go watch Brazil and get back to me.) This bill is a response to a school district in Pennsylvania that was using the web-cams of the laptops they issued to students to take pictures of those students at home. This almost makes me want to move to PA, just to vote for Specter.

As long as we’re talking about policy makers and privacy I’ll give a nod to Tom Watson. He’s a UK Labour Member of Parliament, who led the fight against the Digital Economy Bill and has started his campaign for re-election. He’s working on a list of pledges for his views on internet and privacy issues. Of course it’s filled with some wishy-washy politician-speak and isn’t really as strong as I’d like, but it’s a solid start. Unfortunately most of these beliefs would be political suicide in the U.S. government.

  1. I will support and campaign for more transparency in the public and private sector.
  2. I will oppose measures that unjustly deny people’s access to the Internet.
  3. Whilst noting the acknowledged limitations, I believe people have the right to free speech on the Internet.
  4. I will support all measures that allow people access to their personal data held by others. I further support restoration of control over how personal data is gathered, managed and shared to the individual.
  5. I will use my role as an MP to support international free expression movements.
  6. The Internet shall be built and operated openly and without discrimination.
  7. I will support all measures to bring non-personal public data into the public domain.
  8. I will support all proposals that lead to greater numbers joining the digital world and oppose measures that reduce it.
  9. I believe that copyright and software patent laws should be reformed to reflect the needs of citizens in the Internet age.