├── .gitignore ├── DiffErr.h ├── LICENSE ├── Makefile ├── Matrix.h ├── README.md ├── RandomAccessSequence.h ├── lcs.h └── test ├── Makefile ├── lcs.cpp ├── lisp.txt ├── lisp1.txt ├── lisp_lcs.txt ├── speedtest1.txt ├── speedtest2.txt └── test_diff.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.la 2 | *.a 3 | *.o 4 | *.d 5 | *.lo 6 | *~ 7 | gmon.out 8 | *.prof 9 | test/lcs 10 | test/test_diff 11 | -------------------------------------------------------------------------------- /DiffErr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 Allen Lee 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | 9 | #ifdef DEBUG 10 | #define debugOut std::cout 11 | #else 12 | #define debugOut if (false) std::cout 13 | #endif 14 | 15 | 16 | template 18 | void dprintMatrix(_RandomAccessSequence1Ty Orig, 19 | _RandomAccessSequence2Ty New) { 20 | #ifdef DEBUG_MATRIX 21 | printf(" "); 22 | for (unsigned int x = 0; x < New.size(); ++x) 23 | printf ("%2c ", New[x]); 24 | printf ("\n"); 25 | for (unsigned int y = 0; y < Orig.size(); ++y){ 26 | printf ("%2c ", Orig[y]); 27 | for (unsigned int x = 0; x < New.size(); ++x) 28 | printf(" . "); 29 | printf ("\n"); 30 | } 31 | #else 32 | #ifdef DEBUG 33 | printf("New: "); 34 | for (unsigned int x = 0; x < New.size(); ++x) 35 | printf ("%c", New[x]); 36 | printf ("\nOrig: "); 37 | for (unsigned int y = 0; y < Orig.size(); ++y) 38 | printf ("%c", Orig[y]); 39 | printf ("\n"); 40 | #endif 41 | #endif 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Allen Lee 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for the diff-cpp template library 2 | 3 | ABOUT = Diff-cpp is a template library. To use it include the "lcs.h" header file. 4 | 5 | 6 | all: 7 | @echo $(ABOUT) 8 | 9 | check: 10 | $(MAKE) -C test 11 | 12 | clean: 13 | @$(MAKE) -C test clean 14 | -------------------------------------------------------------------------------- /Matrix.h: -------------------------------------------------------------------------------- 1 | #ifndef MATRIX_H 2 | #define MATRIX_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | typedef unsigned int u_int; 10 | 11 | using std::vector; 12 | // Static 2D Vector class using a 1D array as the backing store. 13 | template 14 | class Matrix 15 | { 16 | uint16_t ColLen; 17 | uint16_t Rows; 18 | T * _matrix; 19 | 20 | public: 21 | Matrix(T rows, T cols): 22 | Rows(rows) {_matrix = new T[Rows*cols];} 23 | ~Matrix() {delete[] _matrix;} 24 | void DebugPrint(); 25 | // Returning a pointer here allows the double array index [][] to 26 | // work correctly 27 | inline T* operator[](size_t row) {return _matrix + (row*Rows); } 28 | }; 29 | 30 | template 31 | void Matrix::DebugPrint() 32 | { 33 | #ifdef DEBUG_MATRIX 34 | u_int i,j; 35 | printf (" "); 36 | for (j = 0; j < ColLen; ++j) 37 | printf ("%2d ", j); 38 | printf ("\n"); 39 | for (i = 0; i < Rows; ++i){ 40 | printf ("%2d ", i); 41 | for (j = 0; j < ColLen; ++j) 42 | printf("%2.2d ", (*this)[i][j]); 43 | printf("\n"); 44 | } 45 | #endif 46 | } 47 | 48 | // 2D vector class that supports negative column indexes used to 49 | // translate Myers Algorithm. The number of columns in this matrix is 50 | // 2 times larger than the max column. IE the range of the column 51 | // indexes is [-MAXCOL, MAXCOL-1] 52 | template 53 | class NegIndexVector 54 | { 55 | size_t MaxNegIndex; 56 | size_t MaxPosIndex; 57 | size_t size; 58 | T* _vector; 59 | public: 60 | NegIndexVector() {} 61 | NegIndexVector(size_t MaxNegIndex, size_t MaxPosIndex): 62 | MaxNegIndex(MaxNegIndex), MaxPosIndex(MaxPosIndex), 63 | size(MaxNegIndex + MaxPosIndex +1), 64 | _vector(new T[size]()){} 65 | ~NegIndexVector() { delete[] _vector; } 66 | inline T& operator[] (int index) { 67 | assert((index + (int)MaxNegIndex >= 0) && (index + MaxNegIndex < size)); 68 | return _vector[index + MaxNegIndex]; 69 | } 70 | }; 71 | 72 | template 73 | class NegColMatrix 74 | { 75 | typedef NegIndexVector NegVector; 76 | uint16_t Rows; 77 | vector _matrix; 78 | 79 | public: 80 | NegColMatrix(): 81 | Rows(1), _matrix(vector (1, NegVector(1, 1))){} 82 | 83 | void NewRow() { 84 | Rows++; 85 | _matrix.push_back(NegVector(Rows, Rows)); 86 | 87 | for (int i = -Rows +1; i < Rows-1; i++) 88 | _matrix[Rows-1][i] = _matrix[Rows-2][i]; 89 | } 90 | inline NegVector& operator[](size_t row) { 91 | // cout << "Accessed _matrix " << row << "\n"; 92 | assert (row < Rows); 93 | return _matrix[row]; 94 | } 95 | void DebugPrint(); 96 | }; 97 | 98 | template 99 | void NegColMatrix::DebugPrint() 100 | { 101 | #ifdef DEBUG_MATRIX 102 | int j; 103 | printf (" "); 104 | for (j = -Rows; j < Rows; ++j) 105 | printf ("%3.2d", j); 106 | printf ("\n"); 107 | for (int i = 0; i < Rows; ++i){ 108 | printf ("%2d ", i); 109 | for (j = -Rows; j < Rows; ++j){ 110 | if (j < -(i+1)) 111 | printf (" "); 112 | else if (j > i+1) 113 | printf (" "); 114 | else 115 | printf("%2.2d ", (*this)[i][j]); 116 | } 117 | printf("\n"); 118 | } 119 | #endif 120 | } 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | diff-cpp is a template library for computing the longest common subsequence. 2 | 3 | # Usage 4 | 5 | template < typename RandomAccessIterator, typename OutputIterator > 6 | OutputIterator 7 | lcs (RandomAccessIterator begin1, RandomAccessIterator end1, 8 | RandomAccessIterator begin2, RandomAccessIterator end2, 9 | OutputIterator output); 10 | 11 | 12 | diff-cpp follows the calling convention similar to STL . 13 | The two sequences must be accessible through a Random Access Iterator, 14 | and the longest common subsequence is copied into the Output Iterator 15 | output. The return value is the iterator pointing past the last 16 | element. 17 | 18 | 19 | # Example 20 | 21 | #include "lcs.h" 22 | 23 | template < typename T > 24 | void run_lcs(vector &o, vector &n) 25 | { 26 | vector LCS(n.size()); 27 | typename vector::iterator end = lcs(o.begin(), o.end(), 28 | n.begin(), n.end(), 29 | LCS.begin()); 30 | LCS.resize(end-LCS.begin()); 31 | } 32 | 33 | # Algorithm 34 | 35 | diff-cpp implements the Longest Common Subsequence algorithm described 36 | by Eugene Myers[1] with the divide and conquer linear space refinement 37 | described by Hirshberg[2], and optimizations from Neil Fraser's 38 | diff-patch-match library[3]. The final algorithm is highly performant - 39 | with sequence lengths near 10,000 and SES length around 10%, this 40 | algorithm typically finishes under 10ms my test system (1.8Ghz Core2 41 | Duo). 42 | 43 | [1] An O(ND) Difference Algorithm and Its Variations. Eugene 44 | Myers. Algorithmica 1986 45 | 46 | [2] A Linear Space Algorithm for Computing Maximal Common 47 | Subsequences. Dan S. Hirshberg. Communications of the ACM. 1975 48 | Vol. 18 No. 6 49 | 50 | [3] Google-diff-patch-match. https://code.google.com/p/google-diff-match-patch/ 51 | -------------------------------------------------------------------------------- /RandomAccessSequence.h: -------------------------------------------------------------------------------- 1 | #ifndef RANDOMACCESSSEQUENCE_H 2 | #define RANDOMACCESSSEQUENCE_H 3 | 4 | /** 5 | A generic random access sequence type whose values are stored externally 6 | */ 7 | template < typename _RandomAccessInputIterator > 8 | class RandomAccessSequence { 9 | _RandomAccessInputIterator _begin; 10 | _RandomAccessInputIterator _end; 11 | size_t _len; 12 | public: 13 | typedef typename std::iterator_traits<_RandomAccessInputIterator>::value_type ElemTy; 14 | RandomAccessSequence() {} 15 | RandomAccessSequence(_RandomAccessInputIterator b, 16 | _RandomAccessInputIterator e): 17 | _begin(b), _end(e), _len(e-b) {} 18 | ~RandomAccessSequence() {} 19 | inline _RandomAccessInputIterator begin() { return _begin; } 20 | inline _RandomAccessInputIterator end() { return _end; } 21 | inline ElemTy pop_front() { ElemTy tmp = *_begin; ++_begin; --_len; return tmp; } 22 | inline ElemTy pop_back() { ElemTy tmp = *(_end-1); --_end; --_len; return tmp; } 23 | inline size_t size() const { return _len; } 24 | inline ElemTy operator[] (size_t index) const {assert(index < _len); return *(_begin + index); } 25 | bool contains(ElemTy elem) { 26 | for (_RandomAccessInputIterator i = _begin; i < _end; ++i) if (*i == elem) return true; 27 | return false; 28 | } 29 | void split(size_t index, RandomAccessSequence &left, RandomAccessSequence &right) { 30 | left = RandomAccessSequence(_begin, _begin + index); 31 | right = RandomAccessSequence(_begin + index, _end); 32 | } 33 | }; 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /lcs.h: -------------------------------------------------------------------------------- 1 | #ifndef LCH_H 2 | #define LCS_H 3 | 4 | #include "Matrix.h" 5 | #include "RandomAccessSequence.h" 6 | #include "DiffErr.h" 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | //TODO get rid of these 13 | #define max(N,M) ((N)>(M)? N : M) 14 | #define min(N,M) ((N)<(M)? N : M) 15 | 16 | typedef NegIndexVector Vector; 17 | 18 | /** 19 | This class encapsulates operations used on (col, row) positions 20 | in the matrix that's used to trace the D-Path 21 | */ 22 | 23 | class Position { 24 | public: 25 | u_int x; 26 | u_int y; 27 | Position(){} 28 | Position(u_int col, u_int row): 29 | x(col), y(row){} 30 | inline bool operator==(Position RHS) 31 | { return y==RHS.y && x == RHS.x; } 32 | inline bool operator!=(Position RHS) 33 | { return !(*this == RHS); } 34 | 35 | inline Position operator--(){ 36 | --y; --x; 37 | return *this; 38 | } 39 | inline Position operator++(){ 40 | ++y; ++x; 41 | return *this; 42 | } 43 | friend std::ostream &operator << (std::ostream &out, Position &p) { 44 | return out << "(" << p.x << "," << p.y << ")"; 45 | } 46 | }; 47 | 48 | /* Hirshberg's linear space refinement relies on being able to run 49 | * the same algorithm in the forward and reverse direction. When the 50 | * direction is FORWARD, the algorithm starts at (0, 0) and searches 51 | * forward. When the direction is REVERSE, the algorithm stars at 52 | * (Orig.size(), New.size()) and searches backward. */ 53 | typedef enum {FORWARD, REVERSE} Direction; 54 | 55 | template < Direction dir, 56 | typename _RandomAccessSequenceTy > 57 | class MyersAlgorithm { 58 | 59 | typedef std::list LCSList; 60 | 61 | _RandomAccessSequenceTy Orig; 62 | _RandomAccessSequenceTy New; 63 | int size_delta; 64 | 65 | unsigned D; 66 | Vector V; 67 | 68 | /** Takes a position that would be an offset from the beginning of the 69 | seqence in the forward direction and mirrors it so that it's an 70 | offset from the end of the sequence. 71 | */ 72 | inline Position normalize(Position p){ 73 | if(dir == REVERSE) 74 | return Position(New.size() - p.x, Orig.size() - p.y); 75 | else 76 | return p; 77 | } 78 | 79 | /** Extends the longest possible snake from position front, 80 | returning the last position of the snake 81 | 82 | @param Front the first position 83 | */ 84 | inline Position snake(Position front) { 85 | 86 | Position norm = normalize(front); 87 | 88 | debugOut << " snake: front=" << front << " normalized=" << norm << std::endl; 89 | 90 | assert(front.y <= Orig.size() && front.x <= New.size()); 91 | while (front.y < Orig.size() && front.x < New.size() && 92 | (dir==FORWARD ? 93 | Orig[norm.y] == New[norm.x] : Orig[norm.y-1] == New[norm.x-1])) { 94 | ++front; 95 | norm = normalize(front); 96 | } 97 | return front; 98 | 99 | } 100 | 101 | /** 102 | * Computes the starting diagonal for Myer's algorithm 103 | * 104 | */ 105 | int k_begin() { 106 | 107 | // if D has grown larger than Orig.size(), set the k to the first 108 | // starting diagonal within the matrix 109 | 110 | if (D >= Orig.size()) { 111 | // Since diagonals are increased with steps of 2, set the 112 | // starting diagonal depending on whether the delta of D and 113 | // Orig.size is even or odd. 114 | const int delta = D - Orig.size(); 115 | 116 | if (delta % 2 == 0){ 117 | return -(Orig.size()-2); 118 | } else { 119 | return -(Orig.size()-1); 120 | } 121 | } 122 | else return -D; 123 | } 124 | 125 | /** 126 | * Computes the stopping diagonal for Myer's algorithm 127 | * 128 | * 129 | */ 130 | int k_end(){ 131 | 132 | // if D has grown larger than New.size(), set the end to the last 133 | // diagonal within the matrix 134 | 135 | if (D >= New.size()){ 136 | // Since diagonals are increased with steps of 2, set the 137 | // ending diagonal depending on whether the delta of D and 138 | // New.size is even or odd. 139 | const int delta = D - New.size(); 140 | if (delta % 2 == 0){ 141 | return (New.size()-2); 142 | } else { 143 | return (New.size()-1); 144 | } 145 | } 146 | else return D; 147 | } 148 | 149 | 150 | public: 151 | 152 | /** 153 | * Computes the furthest reaching D-paths. 154 | * 155 | * This function makes one "step", computing the furthest reaching D 156 | * path for all diagonals from k_begin() to k_end() 157 | */ 158 | bool trace_D_path() { 159 | if(dir==FORWARD) {debugOut<< "Forward: \n";} else debugOut<< "Reverse: \n"; 160 | debugOut << " trace_D_path: "; 161 | 162 | int kBegin = k_begin(); 163 | int kEnd = k_end(); 164 | 165 | debugOut << "D=" << D << " k=" << kBegin << " to " << kEnd << "\n"; 166 | 167 | assert(D < INT_MAX); //TODO make this an error case? 168 | 169 | // For each diagonal k 170 | for (int k = kBegin; k <= kEnd; k+=2) { 171 | unsigned row, col; 172 | 173 | if ((k == -(int)D) || 174 | (k != (int)D && V[k-1] < V[k+1])) 175 | col = V[k+1]; 176 | else 177 | col = V[k-1] + 1; 178 | row = col - k; 179 | 180 | debugOut << " x=" << col << " y=" << row << std::endl; 181 | 182 | if (row > Orig.size() || col > New.size()) { 183 | debugOut << " Outside Matrix col=" << col << " row=" < Position 224 | Position reversePos = Position(V[k], V[k] - k); 225 | Position forwardPos = Position(forward[k_r], forward[k_r] - k_r); 226 | 227 | reversePos = normalize(reversePos); 228 | 229 | debugOut << " k=" << k << " forwardPos=" << forwardPos 230 | << " reversePos=" << reversePos << std::endl; 231 | 232 | if (forwardPos.x >= reversePos.x){ 233 | bisect = forwardPos; 234 | return true; 235 | } 236 | } 237 | return false; 238 | } 239 | 240 | MyersAlgorithm(_RandomAccessSequenceTy O, 241 | _RandomAccessSequenceTy N) 242 | :Orig(O), New(N), size_delta(New.size() - Orig.size()), 243 | D(0), V(Orig.size(), New.size()) 244 | { 245 | if(dir==FORWARD) { debugOut<< "Forward: \n"; } else debugOut<< "Reverse: \n"; 246 | 247 | } 248 | 249 | Vector & getV() {return V;} 250 | void incr_D() { ++D; } 251 | }; 252 | 253 | 254 | template 255 | class Diff { 256 | typedef std::list LCSList; 257 | 258 | //The Longest Common Subsequence for the two sequences 259 | LCSList _LCS; 260 | 261 | //Eat up common elements at the beginning of both sequences 262 | inline void eatPrefix(_RandomAccessSequenceTy &Orig, 263 | _RandomAccessSequenceTy &New, 264 | LCSList &prefix) { 265 | 266 | while ((Orig.size() != 0 && New.size() != 0) && 267 | (*Orig.begin() == *New.begin())) { 268 | 269 | debugOut << "Added " << *Orig.begin() <<"\n"; 270 | //Append the common element to the LCS 271 | prefix.push_back(New.pop_front()); 272 | //Remove it from both sequences 273 | Orig.pop_front(); 274 | 275 | } 276 | } 277 | 278 | //Eat up common elements at the end of both sequences 279 | inline void eatSuffix(_RandomAccessSequenceTy &Orig, 280 | _RandomAccessSequenceTy &New, 281 | LCSList &suffix) { 282 | 283 | while ((Orig.size() != 0 && New.size() != 0) && 284 | (*(Orig.end()-1) == *(New.end()-1))) { 285 | 286 | debugOut << "Added " << *(Orig.end()-1)<< "\n"; 287 | //Append the common element to the LCS 288 | suffix.push_front(New.pop_back()); 289 | //Remove it from both sequences 290 | Orig.pop_back(); 291 | 292 | } 293 | } 294 | 295 | void do_diff(_RandomAccessSequenceTy Orig, 296 | _RandomAccessSequenceTy New, 297 | LCSList &LCS) { 298 | 299 | debugOut << "do_diff Orig.size=" << Orig.size() 300 | << " New.size=" << New.size() << std::endl; 301 | 302 | dprintMatrix(Orig, New); 303 | 304 | LCSList prefix, suffix; 305 | //Eat up common elements at the beginning and end of the sequence 306 | eatPrefix(Orig, New, prefix); 307 | eatSuffix(Orig, New, suffix); 308 | 309 | //If the problem is trivial, solve it 310 | if (Orig.size() == 0 || New.size() == 0){ 311 | //lcs is empty do nothing 312 | } 313 | else if (Orig.size() == 1){ 314 | if (New.contains(Orig[0])) 315 | LCS.push_front(Orig[0]); 316 | } 317 | else if (New.size() == 1) { 318 | if (Orig.contains(New[0])) 319 | LCS.push_front(New[0]); 320 | 321 | //Otherwise find the bisection point, and compute the diff of the left and right part 322 | } else { 323 | _RandomAccessSequenceTy origLeft, origRight, newLeft, newRight; 324 | // Get the bisection point 325 | Position bisection = bisect(Orig, New); 326 | 327 | Orig.split(bisection.y, origLeft, origRight); 328 | New.split(bisection.x, newLeft, newRight); 329 | 330 | // Compute the diffs of the left and right part 331 | LCSList left, right; 332 | do_diff(origLeft, newLeft, left); 333 | do_diff(origRight, newRight, right); 334 | 335 | // Join the results 336 | LCS.splice(LCS.begin(), right); 337 | LCS.splice(LCS.begin(), left); 338 | 339 | } 340 | 341 | //Add the prefix and suffix back; 342 | if (!prefix.empty()) LCS.splice(LCS.begin(), prefix); 343 | if (!suffix.empty()) LCS.splice(LCS.end(), suffix); 344 | } 345 | 346 | Position bisect( _RandomAccessSequenceTy Orig, 347 | _RandomAccessSequenceTy New ) { 348 | 349 | MyersAlgorithm forward(Orig, New); 350 | MyersAlgorithm reverse(Orig, New); 351 | 352 | bool overlap = false; 353 | Position bisection; 354 | 355 | // D is the length of the Shortest Edit Script. 356 | // Search D-paths until the end of each string is reached 357 | while (!overlap) { 358 | 359 | forward.trace_D_path(); 360 | reverse.trace_D_path(); 361 | 362 | overlap = reverse.is_overlapped(forward.getV(), bisection); 363 | 364 | forward.incr_D(); reverse.incr_D(); 365 | } 366 | 367 | return bisection; 368 | } 369 | 370 | public: 371 | Diff(_RandomAccessSequenceTy Orig, 372 | _RandomAccessSequenceTy New) 373 | { 374 | do_diff(Orig, New, _LCS); 375 | } 376 | 377 | inline LCSList & LCS() { 378 | return _LCS; 379 | } 380 | }; 381 | 382 | 383 | template < typename RandomAccessIterator, 384 | typename OutputIterator > 385 | OutputIterator 386 | lcs (RandomAccessIterator begin1, RandomAccessIterator end1, 387 | RandomAccessIterator begin2, RandomAccessIterator end2, 388 | OutputIterator output){ 389 | 390 | typedef RandomAccessSequence RandAccSeqTy; 391 | 392 | RandAccSeqTy Orig(begin1, end1); 393 | RandAccSeqTy New(begin2, end2); 394 | 395 | 396 | Diff Instance(Orig, New); 397 | 398 | return std::copy(Instance.LCS().begin(), Instance.LCS().end(), output); 399 | } 400 | 401 | 402 | #endif 403 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for the libdiff template library 2 | 3 | #Set compiler to g++ if not already set 4 | CXX ?= g++ 5 | 6 | CXXFLAGS += -Wall -pedantic -foptimize-sibling-calls 7 | 8 | OBJS = test_diff.o lcs.o 9 | 10 | INCLUDE = -I ../ 11 | 12 | check: all 13 | 14 | all: test_diff lcs 15 | ./test_diff 16 | 17 | lcs: lcs.o 18 | $(CXX) $(CXXFLAGS) $(INCLUDE) $+ -o $@ 19 | 20 | test_diff: test_diff.o 21 | $(CXX) $(CXXFLAGS) $(INCLUDE) $+ -o $@ 22 | 23 | # pull in dependency info for existing .o files 24 | -include $(OBJS:.o=.d) 25 | 26 | # compile and generate dependency info 27 | %.o: %.cpp 28 | $(CXX) -c $(CXXFLAGS) $(INCLUDE) $< -o $@ 29 | $(CXX) -MM $(CXXFLAGS) $(INCLUDE) $< > $*.d 30 | 31 | clean: 32 | @rm -f test_diff lcs $(OBJS) *.d > /dev/null 33 | 34 | ifdef DEBUG 35 | CXXFLAGS += -g 36 | else 37 | CXXFLAGS += -O3 -DNDEBUG 38 | endif 39 | 40 | ifdef VERBOSE 41 | CXXFLAGS += -DDEBUG 42 | endif 43 | 44 | ifdef VERBOSE_MATRIX 45 | CXXFLAGS += -DDEBUG_MATRIX 46 | endif 47 | 48 | ifdef VERBOSE_LINE 49 | CXXFLAGS += -DDEBUG_LINE 50 | endif 51 | 52 | ifdef PROFILE 53 | CXXFLAGS += -pg 54 | endif 55 | -------------------------------------------------------------------------------- /test/lcs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "lcs.h" 9 | 10 | const char* usage = "Usage:\n lcs \n"; 11 | 12 | using namespace std; 13 | 14 | template < typename T > 15 | void run_lcs(vector &o, vector &n) 16 | { 17 | clock_t start_time = clock(); 18 | 19 | vector LCS(n.size()); 20 | typename vector::iterator end = lcs(o.begin(), o.end(), 21 | n.begin(), n.end(), 22 | LCS.begin()); 23 | clock_t end_time = clock(); 24 | 25 | LCS.resize(end-LCS.begin()); 26 | 27 | cout << string(LCS.begin(), LCS.end()); 28 | 29 | double cpu_time_secs = ((end_time - start_time)/(double)CLOCKS_PER_SEC)*1000; 30 | cerr << " Time spent = " << cpu_time_secs <<" ms\n"; 31 | } 32 | 33 | vector * read_ascii_file (string name) 34 | { 35 | FILE * f = fopen (name.c_str(), "r"); 36 | if (f == NULL) perror("fopen"); 37 | int err = fseek(f, 0, SEEK_END) != 0; 38 | if (err) perror("fseek"); 39 | int fSize=ftell(f); 40 | if (fSize < 0) perror("ftell"); 41 | rewind(f); 42 | vector *bufferp=new vector; 43 | bufferp->resize(fSize); 44 | err = fread (&((*bufferp)[0]), 1, fSize, f); 45 | 46 | if (err < 0) perror ("fread"); 47 | 48 | fclose (f); 49 | return bufferp; 50 | } 51 | 52 | int main(int argc, char* argv[]) { 53 | 54 | if (argc < 3){ 55 | fprintf(stderr, "%s", usage); 56 | exit(-1); 57 | } 58 | 59 | vector * lisp = read_ascii_file(argv[1]); 60 | vector * lisp1 = read_ascii_file(argv[2]); 61 | 62 | run_lcs(*lisp, *lisp1); 63 | delete lisp; 64 | delete lisp1; 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /test/lisp.txt: -------------------------------------------------------------------------------- 1 | #Introduction 2 | 3 | A programming system called LISP (for LISt Processor) has been 4 | developed for the IBM 704 computer by the Artificial Intelligence 5 | group at M.I.T. The system was designed to facilitate experiments with 6 | a proposed system called the Advice Taker, whereby a machine could be 7 | instructed to handle declarative as well as imperative sentences and 8 | could exhibit ``common sense'' in carrying out its instructions. The 9 | original proposal [1] for the Advice Taker was made in November 10 | 1958. The main requirement was a programming system for manipulating 11 | expressions representing formalized declarative and imperative 12 | sentences so that the Advice Taker system could make deductions. 13 | 14 | In the course of its development the LISP system went through several 15 | stages of simplification and eventually came to be based on a scheme 16 | for representing the partial recursive functions of a certain class of 17 | symbolic expressions. This representation is independent of the IBM 18 | 704 computer, or of any other electronic computer, and it now seems 19 | expedient to expound the system by starting with the class of 20 | expressions called S-expressions and the functions called S-functions. 21 | 22 | In this article, we first describe a formalism for defining functions 23 | recursively. We believe this formalism has advantages both as a 24 | programming language and as a vehicle for developing a theory of 25 | computation. Next, we describe S-expressions and S-functions, give 26 | some examples, and then describe the universal S-function $apply$ 27 | which plays the theoretical role of a universal Turing machine and the 28 | practical role of an interpreter. Then we describe the representation 29 | of S-expressions in the memory of the IBM 704 by list structures 30 | similar to those used by Newell, Shaw and Simon [2], and the 31 | representation of S-functions by program. Then we mention the main 32 | features of the LISP programming system for the IBM 704. Next comes 33 | another way of describing computations with symbolic expressions, and 34 | finally we give a recursive function interpretation of flow charts. 35 | 36 | We hope to describe some of the symbolic computations for which LISP 37 | has been used in another paper, and also to give elsewhere some 38 | applications of our recursive function formalism to mathematical logic 39 | and to the problem of mechanical theorem proving.') 40 | 41 | # Functions and Function Definitions We shall need a number of 42 | mathematical ideas and notations concerning functions in general. Most 43 | of the ideas are well known, but the notion of conditional expression 44 | is believed to be new2, and the use of conditional expressions permits 45 | functions to be defined recursively in a new and convenient way. 46 | a. Partial Functions. A partial function is a function that is defined 47 | only on part of its domain. Partial functions necessarily arise when 48 | functions are defined by computations because for some values of the 49 | arguments the computation defining the value of the function may not 50 | terminate. However, some of our elementary functions will be defined 51 | as partial functions. b. Propositional Expressions and Predicates. A 52 | propositional expression is an expression whose possible values are 53 | $T$ (for truth) and $F$ (for falsity). We shall assume that the reader 54 | is familiar with the propositional connectives $\land$ (``and''', 55 | $\lor$ (``or''', and $\lnot$ (``not'''. Typical propositional 56 | expressions are: 57 | 58 | 59 | 60 | \begin{displaymath}x < y\end{displaymath} 61 | 62 | 63 | \begin{displaymath}(x < y) \land (b = c)\end{displaymath} 64 | 65 | x is prime 66 | 67 | A predicate is a function whose range consists of the truth values T 68 | and F. c. Conditional Expressions. The dependence of truth values on 69 | the values of quantities of other kinds is expressed in mathematics by 70 | predicates, and the dependence of truth values on other truth values 71 | by logical connectives. However, the notations for expressing 72 | symbolically the dependence of quantities of other kinds on truth 73 | values is inadequate, so that English words and phrases are generally 74 | used for expressing these dependences in texts that describe other 75 | dependences symbolically. For example, the function $\vert$x$\vert$ is 76 | usually defined in words. Conditional expressions are a device for 77 | expressing the dependence of quantities on propositional quantities. A 78 | conditional expression has the form 79 | 80 | 81 | 82 | \begin{displaymath}(p_1 \rightarrow e_1,\cdots,p_n \rightarrow 83 | e_n)\end{displaymath} 84 | 85 | 86 | where the $p$'s are propositional expressions and the $e$'s are 87 | expressions of any kind. It may be read, ``If $p_1$ then $e_1$ 88 | otherwise if $p_2$ then $e_2$, $\cdots$ , otherwise if $p_n$ then 89 | $e_n$,'' or ``$p_1$ yields $e_1, \cdots , p_n$ yields $e_n$.'' 3 90 | 91 | We now give the rules for determining whether the value of 92 | 93 | \begin{displaymath}(p_1 \rightarrow e_1,\cdots,p_n \rightarrow 94 | e_n)\end{displaymath} 95 | 96 | is defined, and if so what its value is. Examine the $p$'s from left 97 | to right. If a $p$ whose value is $T$ is encountered before any p 98 | whose value is undefined is encountered then the value of the 99 | conditional expression is the value of the corresponding $e$ (if this 100 | is defined). If any undefined $p$ is encountered before a true $p$, or 101 | if all $p$'s are false, or if the $e$ corresponding to the first true 102 | $p$ is undefined, then the value of the conditional expression is 103 | undefined. We now give examples. 104 | 105 | 106 | \begin{displaymath}(1 < 2 \rightarrow 4, 1 > 2 \rightarrow 3) = 107 | 4\end{displaymath} 108 | 109 | 110 | 111 | \begin{displaymath}(2 < 1 \rightarrow 4, 2 > 1 \rightarrow 3, 2 > 1 112 | \rightarrow 2) = 3\end{displaymath} 113 | 114 | 115 | 116 | \begin{displaymath}(2 < 1 \rightarrow 4, T \rightarrow 3) = 117 | 3\end{displaymath} 118 | 119 | 120 | 121 | \begin{displaymath}(2 < 1 \rightarrow {0 \over 0}, T \rightarrow 3) = 122 | 3\end{displaymath} 123 | 124 | 125 | 126 | \begin{displaymath}(2 < 1 \rightarrow 3, T \rightarrow {0 \over 0} 127 | )\mbox{ is undefined}\end{displaymath} 128 | 129 | 130 | 131 | \begin{displaymath}(2 < 1 \rightarrow 3, 4 < 1 \rightarrow 4) \mbox{ 132 | is undefined}\end{displaymath} 133 | 134 | Some of the simplest applications of conditional expressions are in 135 | giving such definitions as 136 | 137 | 138 | 139 | \begin{displaymath}\vert x\vert = (x < 0 \rightarrow - x, T 140 | \rightarrow x)\end{displaymath} 141 | 142 | 143 | 144 | \begin{displaymath}\delta_{ij} = (i = j \rightarrow 1, T \rightarrow 145 | 0)\end{displaymath} 146 | 147 | 148 | 149 | \begin{displaymath}sgn(x) = (x < 0 \rightarrow - 1, x = 0 \rightarrow 150 | 0, T \rightarrow 1)\end{displaymath} 151 | 152 | 153 | d. Recursive Function Definitions. By using conditional expressions we 154 | can, without circularity, define functions by formulas in which the 155 | defined function occurs. For example, we write 156 | 157 | 158 | 159 | \begin{displaymath}n! = (n = 0 \rightarrow 1, T \rightarrow n \cdot(n 160 | - 1)!)\end{displaymath} 161 | 162 | When we use this formula to evaluate 0! we get the answer 1; because 163 | of the way in which the value of a conditional expression was defined, 164 | the meaningless expression 0 $\cdot$ (0 - 1)! does not arise. The 165 | evaluation of 2! according to this definition proceeds as follows: 166 | \begin{eqnarray*} 2! &=& (2 = 0 \rightarrow 1, T \rightarrow 2 \cdot 167 | (2 - 1)!)\\... ...arrow 1, T \rightarrow 0\cdot(0-1)!)\\ 168 | &=&2\cdot1\cdot1\\ &=&2 \end{eqnarray*} 169 | 170 | We now give two other applications of recursive function 171 | definitions. The greatest common divisor, gcd(m,n), of two positive 172 | integers m and n is computed by means of the Euclidean algorithm. This 173 | algorithm is expressed by the recursive function definition: 174 | 175 | 176 | 177 | \begin{displaymath}gcd(m,n) = (m > n \rightarrow gcd(n,m), rem(n,m) = 178 | 0 \rightarrow m, T \rightarrow gcd(rem(n,m),m))\end{displaymath} 179 | 180 | where $rem(n, m)$ denotes the remainder left when $n$ is divided by 181 | $m$. The Newtonian algorithm for obtaining an approximate square root 182 | of a number $a$, starting with an initial approximation $x$ and 183 | requiring that an acceptable approximation $y$ satisfy $\vert y^2 - a 184 | \vert < \epsilon,$ may be written as 185 | 186 | 187 | sqrt(a, x, $\epsilon$) 188 | 189 | 190 | 191 | = ($\vert x^2 - a\vert < \epsilon \rightarrow$ x,T $\rightarrow$ sqrt 192 | (a, ${1 \over 2} (x + {a \over x}), \epsilon))$ The simultaneous 193 | recursive definition of several functions is also possible, and we 194 | shall use such definitions if they are required. 195 | 196 | There is no guarantee that the computation determined by a recursive 197 | definition will ever terminate and, for example, an attempt to compute 198 | n! from our definition will only succeed if $n$ is a non-negative 199 | integer. If the computation does not terminate, the function must be 200 | regarded as undefined for the given arguments. 201 | 202 | The propositional connectives themselves can be defined by conditional 203 | expressions. We write 204 | 205 | \begin{eqnarray*} p \wedge q &=& (p \rightarrow q, T \rightarrow F)\\ 206 | p \vee q ... ...htarrow T)\\ p \supset q &=& (p \rightarrow q, T 207 | \rightarrow T) \end{eqnarray*} 208 | 209 | It is readily seen that the right-hand sides of the equations have the 210 | correct truth tables. If we consider situations in which $p$ or $q$ 211 | may be undefined, the connectives $\wedge$ and $\vee$ are seen to be 212 | noncommutative. For example if $p$ is false and $q$ is undefined, we 213 | see that according to the definitions given above $p \wedge q$ is 214 | false, but $q \wedge p$ is undefined. For our applications this 215 | noncommutativity is desirable, since $p \wedge q$ is computed by first 216 | computing $p$, and if $p$ is false $q$ is not computed. If the 217 | computation for $p$ does not terminate, we never get around to 218 | computing $q$. We shall use propositional connectives in this sense 219 | hereafter. e. Functions and Forms. It is usual in 220 | mathematics--outside of mathematical logic--to use the word 221 | ``function'' imprecisely and to apply it to forms such as $y^2 + 222 | x$. Because we shall later compute with expressions for functions, we 223 | need a distinction between functions and forms and a notation for 224 | expressing this distinction. This distinction and a notation for 225 | describing it, from which we deviate trivially, is given by Church 226 | [3]. 227 | 228 | Let $f$ be an expression that stands for a function of two integer 229 | variables. It should make sense to write $f(3, 4)$ and the value of 230 | this expression should be determined. The expression $y^2 + x$ does 231 | not meet this requirement; $y^2 + x(3, 4)$ is not a conventional 232 | notation, and if we attempted to define it we would be uncertain 233 | whether its value would turn out to be 13 or 19. Church calls an 234 | expression like $y^2 + x$, a form. A form can be converted into a 235 | function if we can determine the correspondence between the variables 236 | occurring in the form and the ordered list of arguments of the desired 237 | function. This is accomplished by Church's $\lambda$-notation. 238 | 239 | If $\cal E$ is a form in variables $x_1, \cdots, x_n,$ then 240 | $\lambda((x_1, \cdots, x_n),\cal E)$ will be taken to be the function 241 | of $n$ variables whose value is determined by substituting the 242 | arguments for the variables $x_1, \cdots, x_n$ in that order in $\cal 243 | E$ and evaluating the resulting expression. For example, 244 | $\lambda((x,y),y^2 +x)$ is a function of two variables, and 245 | $\lambda((x,y),y^2 +x)(3,4) = 19$. 246 | 247 | The variables occurring in the list of variables of a 248 | $\lambda$-expression are dummy or bound, like variables of integration 249 | in a definite integral. That is, we may change the names of the bound 250 | variables in a function expression without changing the value of the 251 | expression, provided that we make the same change for each occurrence 252 | of the variable and do not make two variables the same that previously 253 | were different. Thus $\lambda((x,y),y^2+x),\lambda((u,v), v^2+u)$ and 254 | $\lambda((y,x),x^2+y)$ denote the same function. 255 | 256 | We shall frequently use expressions in which some of the variables are 257 | bound by $\lambda$'s and others are not. Such an expression may be 258 | regarded as defining a function with parameters. The unbound variables 259 | are called free variables. 260 | 261 | An adequate notation that distinguishes functions from forms allows an 262 | unambiguous treatment of functions of functions. It would involve too 263 | much of a digression to give examples here, but we shall use functions 264 | with functions as arguments later in this report. 265 | 266 | Difficulties arise in combining functions described by 267 | $\lambda$-expressions, or by any other notation involving variables, 268 | because different bound variables may be represented by the same 269 | symbol. This is called collision of bound variables. There is a 270 | notation involving operators that are called combinators for combining 271 | functions without the use of variables. Unfortunately, the combinatory 272 | expressions for interesting combinations of functions tend to be 273 | lengthy and unreadable. f. Expressions for Recursive Functions. The 274 | $\lambda$-notation is inadequate for naming functions defined 275 | recursively. For example, using $\lambda$'s, we can convert the 276 | definition 277 | 278 | 279 | 280 | \begin{displaymath}{\rm sqrt}(a,x,\epsilon) = (\vert x^2 - a\vert < 281 | \epsilon \r... ...ightarrow {\rm sqrt}(a, {1 \over 2}(x + {a \over 282 | x}),\epsilon))\end{displaymath} 283 | 284 | into 285 | 286 | 287 | 288 | \begin{displaymath}{\rm sqrt} = \lambda((a,x,\epsilon),(\vert x^2 - 289 | a\vert < \ep... ...tarrow {\rm sqrt} (a,{1 \over 2}(x + {a \over x}), 290 | \epsilon))),\end{displaymath} 291 | 292 | but the right-hand side cannot serve as an expression for the function 293 | because there would be nothing to indicate that the reference to 294 | $sqrt$ within the expression stood for the expression as a whole. In 295 | order to be able to write expressions for recursive functions, we 296 | introduce another notation. $label(a,\cal E)$ denotes the expression 297 | $\cal E$, provided that occurrences of $a$ within $\cal E$ are to be 298 | interpreted as referring to the expression as a whole. Thus we can 299 | write 300 | 301 | label(sqrt, $\lambda((a,x,\epsilon),(\vert x^2 - a\vert < \epsilon 302 | \rightarrow x, T \rightarrow {\rm sqrt} (a, {1 \over 2}(x + {a \over 303 | x}),\epsilon))))$ 304 | 305 | as a name for our sqrt function. The symbol $a$ in label ($a,\cal E$) 306 | is also bound, that is, it may be altered systematically without 307 | changing the meaning of the expression. It behaves differently from a 308 | variable bound by a $\lambda$, however. 309 | -------------------------------------------------------------------------------- /test/lisp1.txt: -------------------------------------------------------------------------------- 1 | #introduction 2 | 3 | a programming system called lisp (for list processor) has been 4 | developed for the ibm 704 computer by the artificial intelligence 5 | group at m.i.t. the system was designed to facilitate experiments with 6 | a proposed system called the advice taker, whereby a machine could be 7 | instructed to handle declarative as well as imperative sentences and 8 | could exhibit ``common sense'' in carrying out its instructions. the 9 | original proposal [1] for the advice taker was made in november 10 | 1958. the main requirement was a programming system for manipulating 11 | expressions representing formalized declarative and imperative 12 | sentences so that the advice taker system could make deductions. 13 | 14 | in this article, we first describe a formalism for defining functions 15 | recursively. we believe this formalism has advantages both as a 16 | programming language and as a vehicle for developing a theory of 17 | computation. next, we describe s-expressions and s-functions, give 18 | some examples, and then describe the universal s-function $apply$ 19 | which plays the theoretical role of a universal turing machine and the 20 | practical role of an interpreter. then we describe the representation 21 | of s-expressions in the memory of the ibm 704 by list structures 22 | similar to those used by newell, shaw and simon [2], and the 23 | representation of s-functions by program. then we mention the main 24 | features of the lisp programming system for the ibm 704. next comes 25 | another way of describing computations with symbolic expressions, and 26 | finally we give a recursive function interpretation of flow charts. 27 | 28 | ADDED THIS LINE 29 | 30 | we hope to describe some of the symbolic computations for which lisp 31 | has been used in another paper, and also to give elsewhere some 32 | applications of our recursive function formalism to mathematical logic 33 | and to the problem of mechanical theorem proving.') 34 | 35 | THIS LINE IS ALSO ADDITIONAL 36 | 37 | # functions and function definitions we shall need a number of 38 | mathematical ideas and notations concerning functions in general. most 39 | of the ideas are well known, but the notion of conditional expression 40 | is believed to be new2, and the use of conditional expressions permits 41 | functions to be defined recursively in a new and convenient way. 42 | a. partial functions. a partial function is a function that is defined 43 | only on part of its domain. partial functions necessarily arise when 44 | functions are defined by computations because for some values of the 45 | arguments the computation defining the value of the function may not 46 | terminate. however, some of our elementary functions will be defined 47 | as partial functions. b. propositional expressions and predicates. a 48 | propositional expression is an expression whose possible values are 49 | $t$ (for truth) and $f$ (for falsity). we shall assume that the reader 50 | is familiar with the propositional connectives $\land$ (``and''', 51 | $\lor$ (``or''', and $\lnot$ (``not'''. typical propositional 52 | expressions are: 53 | 54 | 55 | 56 | \begin{displaymath}x < y\end{displaymath} 57 | 58 | 59 | \begin{displaymath}(x < y) \land (b = c)\end{displaymath} 60 | 61 | x is prime 62 | 63 | a predicate is a function whose range consists of the truth values t 64 | and f. c. conditional expressions. the dependence of truth values on 65 | the values of quantities of other kinds is expressed in mathematics by 66 | predicates, and the dependence of truth values on other truth values 67 | by logical connectives. however, the notations for expressing 68 | symbolically the dependence of quantities of other kinds on truth 69 | values is inadequate, so that english words and phrases are generally 70 | used for expressing these dependences in texts that describe other 71 | dependences symbolically. for example, the function $\vert$x$\vert$ is 72 | usually defined in words. conditional expressions are a device for 73 | expressing the dependence of quantities on propositional quantities. a 74 | conditional expression has the form 75 | 76 | 77 | 78 | \begin{displaymath}(p_1 \rightarrow e_1,\cdots,p_n \rightarrow 79 | e_n)\end{displaymath} 80 | 81 | 82 | where the $p$'s are propositional expressions and the $e$'s are 83 | expressions of any kind. it may be read, ``if $p_1$ then $e_1$ 84 | otherwise if $p_2$ then $e_2$, $\cdots$ , otherwise if $p_n$ then 85 | $e_n$,'' or ``$p_1$ yields $e_1, \cdots , p_n$ yields $e_n$.'' 3 86 | 87 | we now give the rules for determining whether the value of 88 | 89 | \begin{displaymath}(p_1 \rightarrow e_1,\cdots,p_n \rightarrow 90 | e_n)\end{displaymath} 91 | 92 | is defined, and if so what its value is. examine the $p$'s from left 93 | to right. if a $p$ whose value is $t$ is encountered before any p 94 | whose value is undefined is encountered then the value of the 95 | conditional expression is the value of the corresponding $e$ (if this 96 | is defined). if any undefined $p$ is encountered before a true $p$, or 97 | if all $p$'s are false, or if the $e$ corresponding to the first true 98 | $p$ is undefined, then the value of the conditional expression is 99 | undefined. we now give examples. 100 | 101 | 102 | \begin{displaymath}(1 < 2 \rightarrow 4, 1 > 2 \rightarrow 3) = 103 | 4\end{displaymath} 104 | 105 | 106 | 107 | \begin{displaymath}(2 < 1 \rightarrow 4, 2 > 1 \rightarrow 3, 2 > 1 108 | \rightarrow 2) = 3\end{displaymath} 109 | 110 | 111 | 112 | \begin{displaymath}(2 < 1 \rightarrow 4, t \rightarrow 3) = 113 | 3\end{displaymath} 114 | 115 | 116 | 117 | \begin{displaymath}(2 < 1 \rightarrow {0 \over 0}, t \rightarrow 3) = 118 | 3\end{displaymath} 119 | 120 | 121 | 122 | \begin{displaymath}(2 < 1 \rightarrow 3, t \rightarrow {0 \over 0} 123 | )\mbox{ is undefined}\end{displaymath} 124 | 125 | 126 | 127 | \begin{displaymath}(2 < 1 \rightarrow 3, 4 < 1 \rightarrow 4) \mbox{ 128 | is undefined}\end{displaymath} 129 | 130 | some of the simplest applications of conditional expressions are in 131 | giving such definitions as 132 | 133 | 134 | 135 | \begin{displaymath}\vert x\vert = (x < 0 \rightarrow - x, t 136 | \rightarrow x)\end{displaymath} 137 | 138 | 139 | 140 | \begin{displaymath}\delta_{ij} = (i = j \rightarrow 1, t \rightarrow 141 | 0)\end{displaymath} 142 | 143 | 144 | 145 | \begin{displaymath}sgn(x) = (x < 0 \rightarrow - 1, x = 0 \rightarrow 146 | 0, t \rightarrow 1)\end{displaymath} 147 | 148 | 149 | d. recursive function definitions. by using conditional expressions we 150 | can, without circularity, define functions by formulas in which the 151 | defined function occurs. for example, we write 152 | 153 | 154 | 155 | \begin{displaymath}n! = (n = 0 \rightarrow 1, t \rightarrow n \cdot(n 156 | - 1)!)\end{displaymath} 157 | 158 | when we use this formula to evaluate 0! we get the answer 1; because 159 | of the way in which the value of a conditional expression was defined, 160 | the meaningless expression 0 $\cdot$ (0 - 1)! does not arise. the 161 | evaluation of 2! according to this definition proceeds as follows: 162 | \begin{eqnarray*} 2! &=& (2 = 0 \rightarrow 1, t \rightarrow 2 \cdot 163 | (2 - 1)!)\\... ...arrow 1, t \rightarrow 0\cdot(0-1)!)\\ 164 | &=&2\cdot1\cdot1\\ &=&2 \end{eqnarray*} 165 | 166 | we now give two other applications of recursive function 167 | definitions. the greatest common divisor, gcd(m,n), of two positive 168 | integers m and n is computed by means of the euclidean algorithm. this 169 | algorithm is expressed by the recursive function definition: 170 | 171 | 172 | 173 | \begin{displaymath}gcd(m,n) = (m > n \rightarrow gcd(n,m), rem(n,m) = 174 | 0 \rightarrow m, t \rightarrow gcd(rem(n,m),m))\end{displaymath} 175 | 176 | where $rem(n, m)$ denotes the remainder left when $n$ is divided by 177 | $m$. the newtonian algorithm for obtaining an approximate square root 178 | of a number $a$, starting with an initial approximation $x$ and 179 | requiring that an acceptable approximation $y$ satisfy $\vert y^2 - a 180 | \vert < \epsilon,$ may be written as 181 | 182 | 183 | sqrt(a, x, $\epsilon$) 184 | 185 | 186 | 187 | = ($\vert x^2 - a\vert < \epsilon \rightarrow$ x,t $\rightarrow$ sqrt 188 | (a, ${1 \over 2} (x + {a \over x}), \epsilon))$ the simultaneous 189 | recursive definition of several functions is also possible, and we 190 | shall use such definitions if they are required. 191 | 192 | there is no guarantee that the computation determined by a recursive 193 | definition will ever terminate and, for example, an attempt to compute 194 | n! from our definition will only succeed if $n$ is a non-negative 195 | integer. if the computation does not terminate, the function must be 196 | regarded as undefined for the given arguments. 197 | 198 | the propositional connectives themselves can be defined by conditional 199 | expressions. we write 200 | 201 | \begin{eqnarray*} p \wedge q &=& (p \rightarrow q, t \rightarrow f)\\ 202 | p \vee q ... ...htarrow t)\\ p \supset q &=& (p \rightarrow q, t 203 | \rightarrow t) \end{eqnarray*} 204 | 205 | it is readily seen that the right-hand sides of the equations have the 206 | correct truth tables. if we consider situations in which $p$ or $q$ 207 | may be undefined, the connectives $\wedge$ and $\vee$ are seen to be 208 | noncommutative. for example if $p$ is false and $q$ is undefined, we 209 | see that according to the definitions given above $p \wedge q$ is 210 | false, but $q \wedge p$ is undefined. for our applications this 211 | noncommutativity is desirable, since $p \wedge q$ is computed by first 212 | computing $p$, and if $p$ is false $q$ is not computed. if the 213 | computation for $p$ does not terminate, we never get around to 214 | computing $q$. we shall use propositional connectives in this sense 215 | hereafter. e. functions and forms. it is usual in 216 | mathematics--outside of mathematical logic--to use the word 217 | ``function'' imprecisely and to apply it to forms such as $y^2 + 218 | x$. because we shall later compute with expressions for functions, we 219 | need a distinction between functions and forms and a notation for 220 | expressing this distinction. this distinction and a notation for 221 | describing it, from which we deviate trivially, is given by church 222 | [3]. 223 | 224 | let $f$ be an expression that stands for a function of two integer 225 | variables. it should make sense to write $f(3, 4)$ and the value of 226 | this expression should be determined. the expression $y^2 + x$ does 227 | not meet this requirement; $y^2 + x(3, 4)$ is not a conventional 228 | notation, and if we attempted to define it we would be uncertain 229 | whether its value would turn out to be 13 or 19. church calls an 230 | expression like $y^2 + x$, a form. a form can be converted into a 231 | function if we can determine the correspondence between the variables 232 | occurring in the form and the ordered list of arguments of the desired 233 | function. this is accomplished by church's $\lambda$-notation. 234 | 235 | if $\cal e$ is a form in variables $x_1, \cdots, x_n,$ then 236 | $\lambda((x_1, \cdots, x_n),\cal e)$ will be taken to be the function 237 | of $n$ variables whose value is determined by substituting the 238 | arguments for the variables $x_1, \cdots, x_n$ in that order in $\cal 239 | e$ and evaluating the resulting expression. for example, 240 | $\lambda((x,y),y^2 +x)$ is a function of two variables, and 241 | $\lambda((x,y),y^2 +x)(3,4) = 19$. 242 | 243 | the variables occurring in the list of variables of a 244 | $\lambda$-expression are dummy or bound, like variables of integration 245 | in a definite integral. that is, we may change the names of the bound 246 | variables in a function expression without changing the value of the 247 | expression, provided that we make the same change for each occurrence 248 | of the variable and do not make two variables the same that previously 249 | were different. thus $\lambda((x,y),y^2+x),\lambda((u,v), v^2+u)$ and 250 | $\lambda((y,x),x^2+y)$ denote the same function. 251 | 252 | we shall frequently use expressions in which some of the variables are 253 | bound by $\lambda$'s and others are not. such an expression may be 254 | regarded as defining a function with parameters. the unbound variables 255 | are called free variables. 256 | 257 | an adequate notation that distinguishes functions from forms allows an 258 | unambiguous treatment of functions of functions. it would involve too 259 | much of a digression to give examples here, but we shall use functions 260 | with functions as arguments later in this report. 261 | 262 | difficulties arise in combining functions described by 263 | $\lambda$-expressions, or by any other notation involving variables, 264 | because different bound variables may be represented by the same 265 | symbol. this is called collision of bound variables. there is a 266 | notation involving operators that are called combinators for combining 267 | functions without the use of variables. unfortunately, the combinatory 268 | expressions for interesting combinations of functions tend to be 269 | lengthy and unreadable. f. expressions for recursive functions. the 270 | $\lambda$-notation is inadequate for naming functions defined 271 | recursively. for example, using $\lambda$'s, we can convert the 272 | definition 273 | 274 | 275 | 276 | \begin{displaymath}{\rm sqrt}(a,x,\epsilon) = (\vert x^2 - a\vert < 277 | \epsilon \r... ...ightarrow {\rm sqrt}(a, {1 \over 2}(x + {a \over 278 | x}),\epsilon))\end{displaymath} 279 | 280 | into 281 | 282 | 283 | 284 | \begin{displaymath}{\rm sqrt} = \lambda((a,x,\epsilon),(\vert x^2 - 285 | a\vert < \ep... ...tarrow {\rm sqrt} (a,{1 \over 2}(x + {a \over x}), 286 | \epsilon))),\end{displaymath} 287 | 288 | but the right-hand side cannot serve as an expression for the function 289 | because there would be nothing to indicate that the reference to 290 | $sqrt$ within the expression stood for the expression as a whole. in 291 | order to be able to write expressions for recursive functions, we 292 | introduce another notation. $label(a,\cal e)$ denotes the expression 293 | $\cal e$, provided that occurrences of $a$ within $\cal e$ are to be 294 | interpreted as referring to the expression as a whole. thus we can 295 | write 296 | 297 | label(sqrt, $\lambda((a,x,\epsilon),(\vert x^2 - a\vert < \epsilon 298 | \rightarrow x, t \rightarrow {\rm sqrt} (a, {1 \over 2}(x + {a \over 299 | x}),\epsilon))))$ 300 | 301 | as a name for our sqrt function. the symbol $a$ in label ($a,\cal e$) 302 | is also bound, that is, it may be altered systematically without 303 | changing the meaning of the expression. it behaves differently from a 304 | variable bound by a $\lambda$, however. 305 | -------------------------------------------------------------------------------- /test/lisp_lcs.txt: -------------------------------------------------------------------------------- 1 | #ntroduction 2 | 3 | programming system called (for t rocessor) has been 4 | developed for the 704 computer by the rtificial ntelligence 5 | group at ... he system was designed to facilitate experiments with 6 | a proposed system called the dvice aker, whereby a machine could be 7 | instructed to handle declarative as well as imperative sentences and 8 | could exhibit ``common sense'' in carrying out its instructions. he 9 | original proposal [1] for the dvice aker was made in ovember 10 | 1958. he main requirement was a programming system for manipulating 11 | expressions representing formalized declarative and imperative 12 | sentences so that the dvice aker system could make deductions. 13 | 14 | in this article, we first describe a formalism for defining functions 15 | recursively. e believe this formalism has advantages both as a 16 | programming language and as a vehicle for developing a theory of 17 | computation. ext, we describe -expressions and -functions, give 18 | some examples, and then describe the universal -function $apply$ 19 | which plays the theoretical role of a universal uring machine and the 20 | practical role of an interpreter. hen we describe the representation 21 | of -expressions in the memory of the 704 by list structures 22 | similar to those used by ewell, haw and imon [2], and the 23 | representation of -functions by program. hen we mention the main 24 | features of the programming system for the 704. ext comes 25 | another way of describing computations with symbolic expressions, and 26 | finally we give a recursive function interpretation of flow charts. 27 | 28 | e hope to describe some of the symbolic computations for which 29 | has been used in another paper, and also to give elsewhere some 30 | applications of our recursive function formalism to mathematical logic 31 | and to the problem of mechanical theorem proving.') 32 | 33 | # unctions and unction efinitions e shall need a number of 34 | mathematical ideas and notations concerning functions in general. ost 35 | of the ideas are well known, but the notion of conditional expression 36 | is believed to be new2, and the use of conditional expressions permits 37 | functions to be defined recursively in a new and convenient way. 38 | a. artial unctions. partial function is a function that is defined 39 | only on part of its domain. artial functions necessarily arise when 40 | functions are defined by computations because for some values of the 41 | arguments the computation defining the value of the function may not 42 | terminate. owever, some of our elementary functions will be defined 43 | as partial functions. b. ropositional xpressions and redicates. 44 | propositional expression is an expression whose possible values are 45 | $$ (for truth) and $$ (for falsity). e shall assume that the reader 46 | is familiar with the propositional connectives $\land$ (``and''', 47 | $\lor$ (``or''', and $\lnot$ (``not'''. ypical propositional 48 | expressions are: 49 | 50 | 51 | 52 | \begin{displaymath}x < y\end{displaymath} 53 | 54 | 55 | \begin{displaymath}(x < y) \land (b = c)\end{displaymath} 56 | 57 | x is prime 58 | 59 | predicate is a function whose range consists of the truth values 60 | and . c. onditional xpressions. he dependence of truth values on 61 | the values of quantities of other kinds is expressed in mathematics by 62 | predicates, and the dependence of truth values on other truth values 63 | by logical connectives. owever, the notations for expressing 64 | symbolically the dependence of quantities of other kinds on truth 65 | values is inadequate, so that nglish words and phrases are generally 66 | used for expressing these dependences in texts that describe other 67 | dependences symbolically. or example, the function $\vert$x$\vert$ is 68 | usually defined in words. onditional expressions are a device for 69 | expressing the dependence of quantities on propositional quantities. 70 | conditional expression has the form 71 | 72 | 73 | 74 | \begin{displaymath}(p_1 \rightarrow e_1,\cdots,p_n \rightarrow 75 | e_n)\end{displaymath} 76 | 77 | 78 | where the $p$'s are propositional expressions and the $e$'s are 79 | expressions of any kind. t may be read, ``f $p_1$ then $e_1$ 80 | otherwise if $p_2$ then $e_2$, $\cdots$ , otherwise if $p_n$ then 81 | $e_n$,'' or ``$p_1$ yields $e_1, \cdots , p_n$ yields $e_n$.'' 3 82 | 83 | e now give the rules for determining whether the value of 84 | 85 | \begin{displaymath}(p_1 \rightarrow e_1,\cdots,p_n \rightarrow 86 | e_n)\end{displaymath} 87 | 88 | is defined, and if so what its value is. xamine the $p$'s from left 89 | to right. f a $p$ whose value is $$ is encountered before any p 90 | whose value is undefined is encountered then the value of the 91 | conditional expression is the value of the corresponding $e$ (if this 92 | is defined). f any undefined $p$ is encountered before a true $p$, or 93 | if all $p$'s are false, or if the $e$ corresponding to the first true 94 | $p$ is undefined, then the value of the conditional expression is 95 | undefined. e now give examples. 96 | 97 | 98 | \begin{displaymath}(1 < 2 \rightarrow 4, 1 > 2 \rightarrow 3) = 99 | 4\end{displaymath} 100 | 101 | 102 | 103 | \begin{displaymath}(2 < 1 \rightarrow 4, 2 > 1 \rightarrow 3, 2 > 1 104 | \rightarrow 2) = 3\end{displaymath} 105 | 106 | 107 | 108 | \begin{displaymath}(2 < 1 \rightarrow 4, \rightarrow 3) = 109 | 3\end{displaymath} 110 | 111 | 112 | 113 | \begin{displaymath}(2 < 1 \rightarrow {0 \over 0}, \rightarrow 3) = 114 | 3\end{displaymath} 115 | 116 | 117 | 118 | \begin{displaymath}(2 < 1 \rightarrow 3, \rightarrow {0 \over 0} 119 | )\mbox{ is undefined}\end{displaymath} 120 | 121 | 122 | 123 | \begin{displaymath}(2 < 1 \rightarrow 3, 4 < 1 \rightarrow 4) \mbox{ 124 | is undefined}\end{displaymath} 125 | 126 | ome of the simplest applications of conditional expressions are in 127 | giving such definitions as 128 | 129 | 130 | 131 | \begin{displaymath}\vert x\vert = (x < 0 \rightarrow - x, 132 | \rightarrow x)\end{displaymath} 133 | 134 | 135 | 136 | \begin{displaymath}\delta_{ij} = (i = j \rightarrow 1, \rightarrow 137 | 0)\end{displaymath} 138 | 139 | 140 | 141 | \begin{displaymath}sgn(x) = (x < 0 \rightarrow - 1, x = 0 \rightarrow 142 | 0, \rightarrow 1)\end{displaymath} 143 | 144 | 145 | d. ecursive unction efinitions. y using conditional expressions we 146 | can, without circularity, define functions by formulas in which the 147 | defined function occurs. or example, we write 148 | 149 | 150 | 151 | \begin{displaymath}n! = (n = 0 \rightarrow 1, \rightarrow n \cdot(n 152 | - 1)!)\end{displaymath} 153 | 154 | hen we use this formula to evaluate 0! we get the answer 1; because 155 | of the way in which the value of a conditional expression was defined, 156 | the meaningless expression 0 $\cdot$ (0 - 1)! does not arise. he 157 | evaluation of 2! according to this definition proceeds as follows: 158 | \begin{eqnarray*} 2! &=& (2 = 0 \rightarrow 1, \rightarrow 2 \cdot 159 | (2 - 1)!)\\... ...arrow 1, \rightarrow 0\cdot(0-1)!)\\ 160 | &=&2\cdot1\cdot1\\ &=&2 \end{eqnarray*} 161 | 162 | e now give two other applications of recursive function 163 | definitions. he greatest common divisor, gcd(m,n), of two positive 164 | integers m and n is computed by means of the uclidean algorithm. his 165 | algorithm is expressed by the recursive function definition: 166 | 167 | 168 | 169 | \begin{displaymath}gcd(m,n) = (m > n \rightarrow gcd(n,m), rem(n,m) = 170 | 0 \rightarrow m, \rightarrow gcd(rem(n,m),m))\end{displaymath} 171 | 172 | where $rem(n, m)$ denotes the remainder left when $n$ is divided by 173 | $m$. he ewtonian algorithm for obtaining an approximate square root 174 | of a number $a$, starting with an initial approximation $x$ and 175 | requiring that an acceptable approximation $y$ satisfy $\vert y^2 - a 176 | \vert < \epsilon,$ may be written as 177 | 178 | 179 | sqrt(a, x, $\epsilon$) 180 | 181 | 182 | 183 | = ($\vert x^2 - a\vert < \epsilon \rightarrow$ x, $\rightarrow$ sqrt 184 | (a, ${1 \over 2} (x + {a \over x}), \epsilon))$ he simultaneous 185 | recursive definition of several functions is also possible, and we 186 | shall use such definitions if they are required. 187 | 188 | here is no guarantee that the computation determined by a recursive 189 | definition will ever terminate and, for example, an attempt to compute 190 | n! from our definition will only succeed if $n$ is a non-negative 191 | integer. f the computation does not terminate, the function must be 192 | regarded as undefined for the given arguments. 193 | 194 | he propositional connectives themselves can be defined by conditional 195 | expressions. e write 196 | 197 | \begin{eqnarray*} p \wedge q &=& (p \rightarrow q, \rightarrow )\\ 198 | p \vee q ... ...htarrow )\\ p \supset q &=& (p \rightarrow q, 199 | \rightarrow ) \end{eqnarray*} 200 | 201 | t is readily seen that the right-hand sides of the equations have the 202 | correct truth tables. f we consider situations in which $p$ or $q$ 203 | may be undefined, the connectives $\wedge$ and $\vee$ are seen to be 204 | noncommutative. or example if $p$ is false and $q$ is undefined, we 205 | see that according to the definitions given above $p \wedge q$ is 206 | false, but $q \wedge p$ is undefined. or our applications this 207 | noncommutativity is desirable, since $p \wedge q$ is computed by first 208 | computing $p$, and if $p$ is false $q$ is not computed. f the 209 | computation for $p$ does not terminate, we never get around to 210 | computing $q$. e shall use propositional connectives in this sense 211 | hereafter. e. unctions and orms. t is usual in 212 | mathematics--outside of mathematical logic--to use the word 213 | ``function'' imprecisely and to apply it to forms such as $y^2 + 214 | x$. ecause we shall later compute with expressions for functions, we 215 | need a distinction between functions and forms and a notation for 216 | expressing this distinction. his distinction and a notation for 217 | describing it, from which we deviate trivially, is given by hurch 218 | [3]. 219 | 220 | et $f$ be an expression that stands for a function of two integer 221 | variables. t should make sense to write $f(3, 4)$ and the value of 222 | this expression should be determined. he expression $y^2 + x$ does 223 | not meet this requirement; $y^2 + x(3, 4)$ is not a conventional 224 | notation, and if we attempted to define it we would be uncertain 225 | whether its value would turn out to be 13 or 19. hurch calls an 226 | expression like $y^2 + x$, a form. form can be converted into a 227 | function if we can determine the correspondence between the variables 228 | occurring in the form and the ordered list of arguments of the desired 229 | function. his is accomplished by hurch's $\lambda$-notation. 230 | 231 | f $\cal $ is a form in variables $x_1, \cdots, x_n,$ then 232 | $\lambda((x_1, \cdots, x_n),\cal )$ will be taken to be the function 233 | of $n$ variables whose value is determined by substituting the 234 | arguments for the variables $x_1, \cdots, x_n$ in that order in $\cal 235 | $ and evaluating the resulting expression. or example, 236 | $\lambda((x,y),y^2 +x)$ is a function of two variables, and 237 | $\lambda((x,y),y^2 +x)(3,4) = 19$. 238 | 239 | he variables occurring in the list of variables of a 240 | $\lambda$-expression are dummy or bound, like variables of integration 241 | in a definite integral. hat is, we may change the names of the bound 242 | variables in a function expression without changing the value of the 243 | expression, provided that we make the same change for each occurrence 244 | of the variable and do not make two variables the same that previously 245 | were different. hus $\lambda((x,y),y^2+x),\lambda((u,v), v^2+u)$ and 246 | $\lambda((y,x),x^2+y)$ denote the same function. 247 | 248 | e shall frequently use expressions in which some of the variables are 249 | bound by $\lambda$'s and others are not. uch an expression may be 250 | regarded as defining a function with parameters. he unbound variables 251 | are called free variables. 252 | 253 | n adequate notation that distinguishes functions from forms allows an 254 | unambiguous treatment of functions of functions. t would involve too 255 | much of a digression to give examples here, but we shall use functions 256 | with functions as arguments later in this report. 257 | 258 | ifficulties arise in combining functions described by 259 | $\lambda$-expressions, or by any other notation involving variables, 260 | because different bound variables may be represented by the same 261 | symbol. his is called collision of bound variables. here is a 262 | notation involving operators that are called combinators for combining 263 | functions without the use of variables. nfortunately, the combinatory 264 | expressions for interesting combinations of functions tend to be 265 | lengthy and unreadable. f. xpressions for ecursive unctions. he 266 | $\lambda$-notation is inadequate for naming functions defined 267 | recursively. or example, using $\lambda$'s, we can convert the 268 | definition 269 | 270 | 271 | 272 | \begin{displaymath}{\rm sqrt}(a,x,\epsilon) = (\vert x^2 - a\vert < 273 | \epsilon \r... ...ightarrow {\rm sqrt}(a, {1 \over 2}(x + {a \over 274 | x}),\epsilon))\end{displaymath} 275 | 276 | into 277 | 278 | 279 | 280 | \begin{displaymath}{\rm sqrt} = \lambda((a,x,\epsilon),(\vert x^2 - 281 | a\vert < \ep... ...tarrow {\rm sqrt} (a,{1 \over 2}(x + {a \over x}), 282 | \epsilon))),\end{displaymath} 283 | 284 | but the right-hand side cannot serve as an expression for the function 285 | because there would be nothing to indicate that the reference to 286 | $sqrt$ within the expression stood for the expression as a whole. n 287 | order to be able to write expressions for recursive functions, we 288 | introduce another notation. $label(a,\cal )$ denotes the expression 289 | $\cal $, provided that occurrences of $a$ within $\cal $ are to be 290 | interpreted as referring to the expression as a whole. hus we can 291 | write 292 | 293 | label(sqrt, $\lambda((a,x,\epsilon),(\vert x^2 - a\vert < \epsilon 294 | \rightarrow x, \rightarrow {\rm sqrt} (a, {1 \over 2}(x + {a \over 295 | x}),\epsilon))))$ 296 | 297 | as a name for our sqrt function. he symbol $a$ in label ($a,\cal $) 298 | is also bound, that is, it may be altered systematically without 299 | changing the meaning of the expression. t behaves differently from a 300 | variable bound by a $\lambda$, however. 301 | -------------------------------------------------------------------------------- /test/speedtest1.txt: -------------------------------------------------------------------------------- 1 | This is a '''list of newspapers published by [[Journal Register Company]]'''. 2 | 3 | The company owns daily and weekly newspapers, other print media properties and newspaper-affiliated local Websites in the [[U.S.]] states of [[Connecticut]], [[Michigan]], [[New York]], [[Ohio]] and [[Pennsylvania]], organized in six geographic "clusters":[http://www.journalregister.com/newspapers.html Journal Register Company: Our Newspapers], accessed February 10, 2008. 4 | 5 | == Capital-Saratoga == 6 | Three dailies, associated weeklies and [[pennysaver]]s in greater [[Albany, New York]]; also [http://www.capitalcentral.com capitalcentral.com] and [http://www.jobsinnewyork.com JobsInNewYork.com]. 7 | 8 | * ''The Oneida Daily Dispatch'' {{WS|oneidadispatch.com}} of [[Oneida, New York]] 9 | * ''[[The Record (Troy)|The Record]]'' {{WS|troyrecord.com}} of [[Troy, New York]] 10 | * ''[[The Saratogian]]'' {{WS|saratogian.com}} of [[Saratoga Springs, New York]] 11 | * Weeklies: 12 | ** ''Community News'' {{WS|cnweekly.com}} weekly of [[Clifton Park, New York]] 13 | ** ''Rome Observer'' of [[Rome, New York]] 14 | ** ''Life & Times of Utica'' of [[Utica, New York]] 15 | 16 | == Connecticut == 17 | Five dailies, associated weeklies and [[pennysaver]]s in the state of [[Connecticut]]; also [http://www.ctcentral.com CTcentral.com], [http://www.ctcarsandtrucks.com CTCarsAndTrucks.com] and [http://www.jobsinct.com JobsInCT.com]. 18 | 19 | * ''The Middletown Press'' {{WS|middletownpress.com}} of [[Middletown, Connecticut|Middletown]] 20 | * ''[[New Haven Register]]'' {{WS|newhavenregister.com}} of [[New Haven, Connecticut|New Haven]] 21 | * ''The Register Citizen'' {{WS|registercitizen.com}} of [[Torrington, Connecticut|Torrington]] 22 | 23 | * [[New Haven Register#Competitors|Elm City Newspapers]] {{WS|ctcentral.com}} 24 | ** ''The Advertiser'' of [[East Haven, Connecticut|East Haven]] 25 | ** ''Hamden Chronicle'' of [[Hamden, Connecticut|Hamden]] 26 | ** ''Milford Weekly'' of [[Milford, Connecticut|Milford]] 27 | ** ''The Orange Bulletin'' of [[Orange, Connecticut|Orange]] 28 | ** ''The Post'' of [[North Haven, Connecticut|North Haven]] 29 | ** ''Shelton Weekly'' of [[Shelton, Connecticut|Shelton]] 30 | ** ''The Stratford Bard'' of [[Stratford, Connecticut|Stratford]] 31 | ** ''Wallingford Voice'' of [[Wallingford, Connecticut|Wallingford]] 32 | ** ''West Haven News'' of [[West Haven, Connecticut|West Haven]] 33 | * Housatonic Publications 34 | ** ''The New Milford Times'' {{WS|newmilfordtimes.com}} of [[New Milford, Connecticut|New Milford]] 35 | ** ''The Brookfield Journal'' of [[Brookfield, Connecticut|Brookfield]] 36 | ** ''The Kent Good Times Dispatch'' of [[Kent, Connecticut|Kent]] 37 | ** ''The Bethel Beacon'' of [[Bethel, Connecticut|Bethel]] 38 | ** ''The Litchfield Enquirer'' of [[Litchfield, Connecticut|Litchfield]] 39 | ** ''Litchfield County Times'' of [[Litchfield, Connecticut|Litchfield]] 40 | * Imprint Newspapers {{WS|imprintnewspapers.com}} 41 | ** ''West Hartford News'' of [[West Hartford, Connecticut|West Hartford]] 42 | ** ''Windsor Journal'' of [[Windsor, Connecticut|Windsor]] 43 | ** ''Windsor Locks Journal'' of [[Windsor Locks, Connecticut|Windsor Locks]] 44 | ** ''Avon Post'' of [[Avon, Connecticut|Avon]] 45 | ** ''Farmington Post'' of [[Farmington, Connecticut|Farmington]] 46 | ** ''Simsbury Post'' of [[Simsbury, Connecticut|Simsbury]] 47 | ** ''Tri-Town Post'' of [[Burlington, Connecticut|Burlington]], [[Canton, Connecticut|Canton]] and [[Harwinton, Connecticut|Harwinton]] 48 | * Minuteman Publications 49 | ** ''[[Fairfield Minuteman]]'' of [[Fairfield, Connecticut|Fairfield]] 50 | ** ''The Westport Minuteman'' {{WS|westportminuteman.com}} of [[Westport, Connecticut|Westport]] 51 | * Shoreline Newspapers weeklies: 52 | ** ''Branford Review'' of [[Branford, Connecticut|Branford]] 53 | ** ''Clinton Recorder'' of [[Clinton, Connecticut|Clinton]] 54 | ** ''The Dolphin'' of [[Naval Submarine Base New London]] in [[New London, Connecticut|New London]] 55 | ** ''Main Street News'' {{WS|ctmainstreetnews.com}} of [[Essex, Connecticut|Essex]] 56 | ** ''Pictorial Gazette'' of [[Old Saybrook, Connecticut|Old Saybrook]] 57 | ** ''Regional Express'' of [[Colchester, Connecticut|Colchester]] 58 | ** ''Regional Standard'' of [[Colchester, Connecticut|Colchester]] 59 | ** ''Shoreline Times'' {{WS|shorelinetimes.com}} of [[Guilford, Connecticut|Guilford]] 60 | ** ''Shore View East'' of [[Madison, Connecticut|Madison]] 61 | ** ''Shore View West'' of [[Guilford, Connecticut|Guilford]] 62 | * Other weeklies: 63 | ** ''Registro'' {{WS|registroct.com}} of [[New Haven, Connecticut|New Haven]] 64 | ** ''Thomaston Express'' {{WS|thomastownexpress.com}} of [[Thomaston, Connecticut|Thomaston]] 65 | ** ''Foothills Traders'' {{WS|foothillstrader.com}} of Torrington, Bristol, Canton 66 | 67 | == Michigan == 68 | Four dailies, associated weeklies and [[pennysaver]]s in the state of [[Michigan]]; also [http://www.micentralhomes.com MIcentralhomes.com] and [http://www.micentralautos.com MIcentralautos.com] 69 | * ''[[Oakland Press]]'' {{WS|theoaklandpress.com}} of [[Oakland, Michigan|Oakland]] 70 | * ''Daily Tribune'' {{WS|dailytribune.com}} of [[Royal Oak, Michigan|Royal Oak]] 71 | * ''Macomb Daily'' {{WS|macombdaily.com}} of [[Mt. Clemens, Michigan|Mt. Clemens]] 72 | * ''[[Morning Sun]]'' {{WS|themorningsun.com}} of [[Mount Pleasant, Michigan|Mount Pleasant]] 73 | * Heritage Newspapers {{WS|heritage.com}} 74 | ** ''Belleville View'' 75 | ** ''Ile Camera'' 76 | ** ''Monroe Guardian'' 77 | ** ''Ypsilanti Courier'' 78 | ** ''News-Herald'' 79 | ** ''Press & Guide'' 80 | ** ''Chelsea Standard & Dexter Leader'' 81 | ** ''Manchester Enterprise'' 82 | ** ''Milan News-Leader'' 83 | ** ''Saline Reporter'' 84 | * Independent Newspapers {{WS|sourcenewspapers.com}} 85 | ** ''Advisor'' 86 | ** ''Source'' 87 | * Morning Star {{WS|morningstarpublishing.com}} 88 | ** ''Alma Reminder'' 89 | ** ''Alpena Star'' 90 | ** ''Antrim County News'' 91 | ** ''Carson City Reminder'' 92 | ** ''The Leader & Kalkaskian'' 93 | ** ''Ogemaw/Oscoda County Star'' 94 | ** ''Petoskey/Charlevoix Star'' 95 | ** ''Presque Isle Star'' 96 | ** ''Preview Community Weekly'' 97 | ** ''Roscommon County Star'' 98 | ** ''St. Johns Reminder'' 99 | ** ''Straits Area Star'' 100 | ** ''The (Edmore) Advertiser'' 101 | * Voice Newspapers {{WS|voicenews.com}} 102 | ** ''Armada Times'' 103 | ** ''Bay Voice'' 104 | ** ''Blue Water Voice'' 105 | ** ''Downriver Voice'' 106 | ** ''Macomb Township Voice'' 107 | ** ''North Macomb Voice'' 108 | ** ''Weekend Voice'' 109 | ** ''Suburban Lifestyles'' {{WS|suburbanlifestyles.com}} 110 | 111 | == Mid-Hudson == 112 | One daily, associated magazines in the [[Hudson River Valley]] of [[New York]]; also [http://www.midhudsoncentral.com MidHudsonCentral.com] and [http://www.jobsinnewyork.com JobsInNewYork.com]. 113 | 114 | * ''[[Daily Freeman]]'' {{WS|dailyfreeman.com}} of [[Kingston, New York]] 115 | 116 | == Ohio == 117 | Two dailies, associated magazines and three shared Websites, all in the state of [[Ohio]]: [http://www.allaroundcleveland.com AllAroundCleveland.com], [http://www.allaroundclevelandcars.com AllAroundClevelandCars.com] and [http://www.allaroundclevelandjobs.com AllAroundClevelandJobs.com]. 118 | 119 | * ''[[The News-Herald (Ohio)|The News-Herald]]'' {{WS|news-herald.com}} of [[Willoughby, Ohio|Willoughby]] 120 | * ''[[The Morning Journal]]'' {{WS|morningjournal.com}} of [[Lorain, Ohio|Lorain]] 121 | 122 | == Philadelphia area == 123 | Seven dailies and associated weeklies and magazines in [[Pennsylvania]] and [[New Jersey]], and associated Websites: [http://www.allaroundphilly.com AllAroundPhilly.com], [http://www.jobsinnj.com JobsInNJ.com], [http://www.jobsinpa.com JobsInPA.com], and [http://www.phillycarsearch.com PhillyCarSearch.com]. 124 | 125 | * ''The Daily Local'' {{WS|dailylocal.com}} of [[West Chester, Pennsylvania|West Chester]] 126 | * ''[[Delaware County Daily and Sunday Times]] {{WS|delcotimes.com}} of Primos 127 | * ''[[The Mercury (Pennsylvania)|The Mercury]]'' {{WS|pottstownmercury.com}} of [[Pottstown, Pennsylvania|Pottstown]] 128 | * ''The Phoenix'' {{WS|phoenixvillenews.com}} of [[Phoenixville, Pennsylvania|Phoenixville]] 129 | * ''[[The Reporter (Lansdale)|The Reporter]]'' {{WS|thereporteronline.com}} of [[Lansdale, Pennsylvania|Lansdale]] 130 | * ''The Times Herald'' {{WS|timesherald.com}} of [[Norristown, Pennsylvania|Norristown]] 131 | * ''[[The Trentonian]]'' {{WS|trentonian.com}} of [[Trenton, New Jersey]] 132 | 133 | * Weeklies 134 | ** ''El Latino Expreso'' of [[Trenton, New Jersey]] 135 | ** ''La Voz'' of [[Norristown, Pennsylvania]] 136 | ** ''The Village News'' of [[Downingtown, Pennsylvania]] 137 | ** ''The Times Record'' of [[Kennett Square, Pennsylvania]] 138 | ** ''The Tri-County Record'' {{WS|tricountyrecord.com}} of [[Morgantown, Pennsylvania]] 139 | ** ''News of Delaware County'' {{WS|newsofdelawarecounty.com}}of [[Havertown, Pennsylvania]] 140 | ** ''Main Line Times'' {{WS|mainlinetimes.com}}of [[Ardmore, Pennsylvania]] 141 | ** ''Penny Pincher'' of [[Pottstown, Pennsylvania]] 142 | ** ''Town Talk'' {{WS|towntalknews.com}} of [[Ridley, Pennsylvania]] 143 | * Chesapeake Publishing {{WS|pa8newsgroup.com}} 144 | ** ''Solanco Sun Ledger'' of [[Quarryville, Pennsylvania]] 145 | ** ''Columbia Ledger'' of [[Columbia, Pennsylvania]] 146 | ** ''Coatesville Ledger'' of [[Downingtown, Pennsylvania]] 147 | ** ''Parkesburg Post Ledger'' of [[Quarryville, Pennsylvania]] 148 | ** ''Downingtown Ledger'' of [[Downingtown, Pennsylvania]] 149 | ** ''The Kennett Paper'' of [[Kennett Square, Pennsylvania]] 150 | ** ''Avon Grove Sun'' of [[West Grove, Pennsylvania]] 151 | ** ''Oxford Tribune'' of [[Oxford, Pennsylvania]] 152 | ** ''Elizabethtown Chronicle'' of [[Elizabethtown, Pennsylvania]] 153 | ** ''Donegal Ledger'' of [[Donegal, Pennsylvania]] 154 | ** ''Chadds Ford Post'' of [[Chadds Ford, Pennsylvania]] 155 | ** ''The Central Record'' of [[Medford, New Jersey]] 156 | ** ''Maple Shade Progress'' of [[Maple Shade, New Jersey]] 157 | * Intercounty Newspapers {{WS|buckslocalnews.com}} 158 | ** ''The Review'' of Roxborough, Pennsylvania 159 | ** ''The Recorder'' of [[Conshohocken, Pennsylvania]] 160 | ** ''The Leader'' of [[Mount Airy, Pennsylvania|Mount Airy]] and West Oak Lake, Pennsylvania 161 | ** ''The Pennington Post'' of [[Pennington, New Jersey]] 162 | ** ''The Bristol Pilot'' of [[Bristol, Pennsylvania]] 163 | ** ''Yardley News'' of [[Yardley, Pennsylvania]] 164 | ** ''New Hope Gazette'' of [[New Hope, Pennsylvania]] 165 | ** ''Doylestown Patriot'' of [[Doylestown, Pennsylvania]] 166 | ** ''Newtown Advance'' of [[Newtown, Pennsylvania]] 167 | ** ''The Plain Dealer'' of [[Williamstown, New Jersey]] 168 | ** ''News Report'' of [[Sewell, New Jersey]] 169 | ** ''Record Breeze'' of [[Berlin, New Jersey]] 170 | ** ''Newsweekly'' of [[Moorestown, New Jersey]] 171 | ** ''Haddon Herald'' of [[Haddonfield, New Jersey]] 172 | ** ''New Egypt Press'' of [[New Egypt, New Jersey]] 173 | ** ''Community News'' of [[Pemberton, New Jersey]] 174 | ** ''Plymouth Meeting Journal'' of [[Plymouth Meeting, Pennsylvania]] 175 | ** ''Lafayette Hill Journal'' of [[Lafayette Hill, Pennsylvania]] 176 | * Montgomery Newspapers {{WS|montgomerynews.com}} 177 | ** ''Ambler Gazette'' of [[Ambler, Pennsylvania]] 178 | ** ''Central Bucks Life'' of [[Bucks County, Pennsylvania]] 179 | ** ''The Colonial'' of [[Plymouth Meeting, Pennsylvania]] 180 | ** ''Glenside News'' of [[Glenside, Pennsylvania]] 181 | ** ''The Globe'' of [[Lower Moreland Township, Pennsylvania]] 182 | ** ''Main Line Life'' of [[Ardmore, Pennsylvania]] 183 | ** ''Montgomery Life'' of [[Fort Washington, Pennsylvania]] 184 | ** ''North Penn Life'' of [[Lansdale, Pennsylvania]] 185 | ** ''Perkasie News Herald'' of [[Perkasie, Pennsylvania]] 186 | ** ''Public Spirit'' of [[Hatboro, Pennsylvania]] 187 | ** ''Souderton Independent'' of [[Souderton, Pennsylvania]] 188 | ** ''Springfield Sun'' of [[Springfield, Pennsylvania]] 189 | ** ''Spring-Ford Reporter'' of [[Royersford, Pennsylvania]] 190 | ** ''Times Chronicle'' of [[Jenkintown, Pennsylvania]] 191 | ** ''Valley Item'' of [[Perkiomenville, Pennsylvania]] 192 | ** ''Willow Grove Guide'' of [[Willow Grove, Pennsylvania]] 193 | * News Gleaner Publications (closed December 2008) {{WS|newsgleaner.com}} 194 | ** ''Life Newspapers'' of [[Philadelphia, Pennsylvania]] 195 | * Suburban Publications 196 | ** ''The Suburban & Wayne Times'' {{WS|waynesuburban.com}} of [[Wayne, Pennsylvania]] 197 | ** ''The Suburban Advertiser'' of [[Exton, Pennsylvania]] 198 | ** ''The King of Prussia Courier'' of [[King of Prussia, Pennsylvania]] 199 | * Press Newspapers {{WS|countypressonline.com}} 200 | ** ''County Press'' of [[Newtown Square, Pennsylvania]] 201 | ** ''Garnet Valley Press'' of [[Glen Mills, Pennsylvania]] 202 | ** ''Haverford Press'' of [[Newtown Square, Pennsylvania]] (closed January 2009) 203 | ** ''Hometown Press'' of [[Glen Mills, Pennsylvania]] (closed January 2009) 204 | ** ''Media Press'' of [[Newtown Square, Pennsylvania]] (closed January 2009) 205 | ** ''Springfield Press'' of [[Springfield, Pennsylvania]] 206 | * Berks-Mont Newspapers {{WS|berksmontnews.com}} 207 | ** ''The Boyertown Area Times'' of [[Boyertown, Pennsylvania]] 208 | ** ''The Kutztown Area Patriot'' of [[Kutztown, Pennsylvania]] 209 | ** ''The Hamburg Area Item'' of [[Hamburg, Pennsylvania]] 210 | ** ''The Southern Berks News'' of [[Exeter Township, Berks County, Pennsylvania]] 211 | ** ''The Free Press'' of [[Quakertown, Pennsylvania]] 212 | ** ''The Saucon News'' of [[Quakertown, Pennsylvania]] 213 | ** ''Westside Weekly'' of [[Reading, Pennsylvania]] 214 | 215 | * Magazines 216 | ** ''Bucks Co. Town & Country Living'' 217 | ** ''Chester Co. Town & Country Living'' 218 | ** ''Montomgery Co. Town & Country Living'' 219 | ** ''Garden State Town & Country Living'' 220 | ** ''Montgomery Homes'' 221 | ** ''Philadelphia Golfer'' 222 | ** ''Parents Express'' 223 | ** ''Art Matters'' 224 | 225 | {{JRC}} 226 | 227 | ==References== 228 | 229 | 230 | [[Category:Journal Register publications|*]] 231 | -------------------------------------------------------------------------------- /test/speedtest2.txt: -------------------------------------------------------------------------------- 1 | This is a '''list of newspapers published by [[Journal Register Company]]'''. 2 | 3 | The company owns daily and weekly newspapers, other print media properties and newspaper-affiliated local Websites in the [[U.S.]] states of [[Connecticut]], [[Michigan]], [[New York]], [[Ohio]], [[Pennsylvania]] and [[New Jersey]], organized in six geographic "clusters":[http://www.journalregister.com/publications.html Journal Register Company: Our Publications], accessed April 21, 2010. 4 | 5 | == Capital-Saratoga == 6 | Three dailies, associated weeklies and [[pennysaver]]s in greater [[Albany, New York]]; also [http://www.capitalcentral.com capitalcentral.com] and [http://www.jobsinnewyork.com JobsInNewYork.com]. 7 | 8 | * ''The Oneida Daily Dispatch'' {{WS|oneidadispatch.com}} of [[Oneida, New York]] 9 | * ''[[The Record (Troy)|The Record]]'' {{WS|troyrecord.com}} of [[Troy, New York]] 10 | * ''[[The Saratogian]]'' {{WS|saratogian.com}} of [[Saratoga Springs, New York]] 11 | * Weeklies: 12 | ** ''Community News'' {{WS|cnweekly.com}} weekly of [[Clifton Park, New York]] 13 | ** ''Rome Observer'' {{WS|romeobserver.com}} of [[Rome, New York]] 14 | ** ''WG Life '' {{WS|saratogian.com/wglife/}} of [[Wilton, New York]] 15 | ** ''Ballston Spa Life '' {{WS|saratogian.com/bspalife}} of [[Ballston Spa, New York]] 16 | ** ''Greenbush Life'' {{WS|troyrecord.com/greenbush}} of [[Troy, New York]] 17 | ** ''Latham Life'' {{WS|troyrecord.com/latham}} of [[Latham, New York]] 18 | ** ''River Life'' {{WS|troyrecord.com/river}} of [[Troy, New York]] 19 | 20 | == Connecticut == 21 | Three dailies, associated weeklies and [[pennysaver]]s in the state of [[Connecticut]]; also [http://www.ctcentral.com CTcentral.com], [http://www.ctcarsandtrucks.com CTCarsAndTrucks.com] and [http://www.jobsinct.com JobsInCT.com]. 22 | 23 | * ''The Middletown Press'' {{WS|middletownpress.com}} of [[Middletown, Connecticut|Middletown]] 24 | * ''[[New Haven Register]]'' {{WS|newhavenregister.com}} of [[New Haven, Connecticut|New Haven]] 25 | * ''The Register Citizen'' {{WS|registercitizen.com}} of [[Torrington, Connecticut|Torrington]] 26 | 27 | * Housatonic Publications 28 | ** ''The Housatonic Times'' {{WS|housatonictimes.com}} of [[New Milford, Connecticut|New Milford]] 29 | ** ''Litchfield County Times'' {{WS|countytimes.com}} of [[Litchfield, Connecticut|Litchfield]] 30 | 31 | * Minuteman Publications 32 | ** ''[[Fairfield Minuteman]]'' {{WS|fairfieldminuteman.com}}of [[Fairfield, Connecticut|Fairfield]] 33 | ** ''The Westport Minuteman'' {{WS|westportminuteman.com}} of [[Westport, Connecticut|Westport]] 34 | 35 | * Shoreline Newspapers 36 | ** ''The Dolphin'' {{WS|dolphin-news.com}} of [[Naval Submarine Base New London]] in [[New London, Connecticut|New London]] 37 | ** ''Shoreline Times'' {{WS|shorelinetimes.com}} of [[Guilford, Connecticut|Guilford]] 38 | 39 | * Foothills Media Group {{WS|foothillsmediagroup.com}} 40 | ** ''Thomaston Express'' {{WS|thomastonexpress.com}} of [[Thomaston, Connecticut|Thomaston]] 41 | ** ''Good News About Torrington'' {{WS|goodnewsabouttorrington.com}} of [[Torrington, Connecticut|Torrington]] 42 | ** ''Granby News'' {{WS|foothillsmediagroup.com/granby}} of [[Granby, Connecticut|Granby]] 43 | ** ''Canton News'' {{WS|foothillsmediagroup.com/canton}} of [[Canton, Connecticut|Canton]] 44 | ** ''Avon News'' {{WS|foothillsmediagroup.com/avon}} of [[Avon, Connecticut|Avon]] 45 | ** ''Simsbury News'' {{WS|foothillsmediagroup.com/simsbury}} of [[Simsbury, Connecticut|Simsbury]] 46 | ** ''Litchfield News'' {{WS|foothillsmediagroup.com/litchfield}} of [[Litchfield, Connecticut|Litchfield]] 47 | ** ''Foothills Trader'' {{WS|foothillstrader.com}} of Torrington, Bristol, Canton 48 | 49 | * Other weeklies 50 | ** ''The Milford-Orange Bulletin'' {{WS|ctbulletin.com}} of [[Orange, Connecticut|Orange]] 51 | ** ''The Post-Chronicle'' {{WS|ctpostchronicle.com}} of [[North Haven, Connecticut|North Haven]] 52 | ** ''West Hartford News'' {{WS|westhartfordnews.com}} of [[West Hartford, Connecticut|West Hartford]] 53 | 54 | * Magazines 55 | ** ''The Connecticut Bride'' {{WS|connecticutmag.com}} 56 | ** ''Connecticut Magazine'' {{WS|theconnecticutbride.com}} 57 | ** ''Passport Magazine'' {{WS|passport-mag.com}} 58 | 59 | == Michigan == 60 | Four dailies, associated weeklies and [[pennysaver]]s in the state of [[Michigan]]; also [http://www.micentralhomes.com MIcentralhomes.com] and [http://www.micentralautos.com MIcentralautos.com] 61 | * ''[[Oakland Press]]'' {{WS|theoaklandpress.com}} of [[Oakland, Michigan|Oakland]] 62 | * ''Daily Tribune'' {{WS|dailytribune.com}} of [[Royal Oak, Michigan|Royal Oak]] 63 | * ''Macomb Daily'' {{WS|macombdaily.com}} of [[Mt. Clemens, Michigan|Mt. Clemens]] 64 | * ''[[Morning Sun]]'' {{WS|themorningsun.com}} of [[Mount Pleasant, Michigan|Mount Pleasant]] 65 | 66 | * Heritage Newspapers {{WS|heritage.com}} 67 | ** ''Belleville View'' {{WS|bellevilleview.com}} 68 | ** ''Ile Camera'' {{WS|thenewsherald.com/ile_camera}} 69 | ** ''Monroe Guardian'' {{WS|monreguardian.com}} 70 | ** ''Ypsilanti Courier'' {{WS|ypsilanticourier.com}} 71 | ** ''News-Herald'' {{WS|thenewsherald.com}} 72 | ** ''Press & Guide'' {{WS|pressandguide.com}} 73 | ** ''Chelsea Standard & Dexter Leader'' {{WS|chelseastandard.com}} 74 | ** ''Manchester Enterprise'' {{WS|manchesterguardian.com}} 75 | ** ''Milan News-Leader'' {{WS|milannews.com}} 76 | ** ''Saline Reporter'' {{WS|salinereporter.com}} 77 | * Independent Newspapers 78 | ** ''Advisor'' {{WS|sourcenewspapers.com}} 79 | ** ''Source'' {{WS|sourcenewspapers.com}} 80 | * Morning Star {{WS|morningstarpublishing.com}} 81 | ** ''The Leader & Kalkaskian'' {{WS|leaderandkalkaskian.com}} 82 | ** ''Grand Traverse Insider'' {{WS|grandtraverseinsider.com}} 83 | ** ''Alma Reminder'' 84 | ** ''Alpena Star'' 85 | ** ''Ogemaw/Oscoda County Star'' 86 | ** ''Presque Isle Star'' 87 | ** ''St. Johns Reminder'' 88 | 89 | * Voice Newspapers {{WS|voicenews.com}} 90 | ** ''Armada Times'' 91 | ** ''Bay Voice'' 92 | ** ''Blue Water Voice'' 93 | ** ''Downriver Voice'' 94 | ** ''Macomb Township Voice'' 95 | ** ''North Macomb Voice'' 96 | ** ''Weekend Voice'' 97 | 98 | == Mid-Hudson == 99 | One daily, associated magazines in the [[Hudson River Valley]] of [[New York]]; also [http://www.midhudsoncentral.com MidHudsonCentral.com] and [http://www.jobsinnewyork.com JobsInNewYork.com]. 100 | 101 | * ''[[Daily Freeman]]'' {{WS|dailyfreeman.com}} of [[Kingston, New York]] 102 | * ''Las Noticias'' {{WS|lasnoticiasny.com}} of [[Kingston, New York]] 103 | 104 | == Ohio == 105 | Two dailies, associated magazines and three shared Websites, all in the state of [[Ohio]]: [http://www.allaroundcleveland.com AllAroundCleveland.com], [http://www.allaroundclevelandcars.com AllAroundClevelandCars.com] and [http://www.allaroundclevelandjobs.com AllAroundClevelandJobs.com]. 106 | 107 | * ''[[The News-Herald (Ohio)|The News-Herald]]'' {{WS|news-herald.com}} of [[Willoughby, Ohio|Willoughby]] 108 | * ''[[The Morning Journal]]'' {{WS|morningjournal.com}} of [[Lorain, Ohio|Lorain]] 109 | * ''El Latino Expreso'' {{WS|lorainlatino.com}} of [[Lorain, Ohio|Lorain]] 110 | 111 | == Philadelphia area == 112 | Seven dailies and associated weeklies and magazines in [[Pennsylvania]] and [[New Jersey]], and associated Websites: [http://www.allaroundphilly.com AllAroundPhilly.com], [http://www.jobsinnj.com JobsInNJ.com], [http://www.jobsinpa.com JobsInPA.com], and [http://www.phillycarsearch.com PhillyCarSearch.com]. 113 | 114 | * ''[[The Daily Local News]]'' {{WS|dailylocal.com}} of [[West Chester, Pennsylvania|West Chester]] 115 | * ''[[Delaware County Daily and Sunday Times]] {{WS|delcotimes.com}} of Primos [[Upper Darby Township, Pennsylvania]] 116 | * ''[[The Mercury (Pennsylvania)|The Mercury]]'' {{WS|pottstownmercury.com}} of [[Pottstown, Pennsylvania|Pottstown]] 117 | * ''[[The Reporter (Lansdale)|The Reporter]]'' {{WS|thereporteronline.com}} of [[Lansdale, Pennsylvania|Lansdale]] 118 | * ''The Times Herald'' {{WS|timesherald.com}} of [[Norristown, Pennsylvania|Norristown]] 119 | * ''[[The Trentonian]]'' {{WS|trentonian.com}} of [[Trenton, New Jersey]] 120 | 121 | * Weeklies 122 | * ''The Phoenix'' {{WS|phoenixvillenews.com}} of [[Phoenixville, Pennsylvania]] 123 | ** ''El Latino Expreso'' {{WS|njexpreso.com}} of [[Trenton, New Jersey]] 124 | ** ''La Voz'' {{WS|lavozpa.com}} of [[Norristown, Pennsylvania]] 125 | ** ''The Tri County Record'' {{WS|tricountyrecord.com}} of [[Morgantown, Pennsylvania]] 126 | ** ''Penny Pincher'' {{WS|pennypincherpa.com}}of [[Pottstown, Pennsylvania]] 127 | 128 | * Chesapeake Publishing {{WS|southernchestercountyweeklies.com}} 129 | ** ''The Kennett Paper'' {{WS|kennettpaper.com}} of [[Kennett Square, Pennsylvania]] 130 | ** ''Avon Grove Sun'' {{WS|avongrovesun.com}} of [[West Grove, Pennsylvania]] 131 | ** ''The Central Record'' {{WS|medfordcentralrecord.com}} of [[Medford, New Jersey]] 132 | ** ''Maple Shade Progress'' {{WS|mapleshadeprogress.com}} of [[Maple Shade, New Jersey]] 133 | 134 | * Intercounty Newspapers {{WS|buckslocalnews.com}} {{WS|southjerseylocalnews.com}} 135 | ** ''The Pennington Post'' {{WS|penningtonpost.com}} of [[Pennington, New Jersey]] 136 | ** ''The Bristol Pilot'' {{WS|bristolpilot.com}} of [[Bristol, Pennsylvania]] 137 | ** ''Yardley News'' {{WS|yardleynews.com}} of [[Yardley, Pennsylvania]] 138 | ** ''Advance of Bucks County'' {{WS|advanceofbucks.com}} of [[Newtown, Pennsylvania]] 139 | ** ''Record Breeze'' {{WS|recordbreeze.com}} of [[Berlin, New Jersey]] 140 | ** ''Community News'' {{WS|sjcommunitynews.com}} of [[Pemberton, New Jersey]] 141 | 142 | * Montgomery Newspapers {{WS|montgomerynews.com}} 143 | ** ''Ambler Gazette'' {{WS|amblergazette.com}} of [[Ambler, Pennsylvania]] 144 | ** ''The Colonial'' {{WS|colonialnews.com}} of [[Plymouth Meeting, Pennsylvania]] 145 | ** ''Glenside News'' {{WS|glensidenews.com}} of [[Glenside, Pennsylvania]] 146 | ** ''The Globe'' {{WS|globenewspaper.com}} of [[Lower Moreland Township, Pennsylvania]] 147 | ** ''Montgomery Life'' {{WS|montgomerylife.com}} of [[Fort Washington, Pennsylvania]] 148 | ** ''North Penn Life'' {{WS|northpennlife.com}} of [[Lansdale, Pennsylvania]] 149 | ** ''Perkasie News Herald'' {{WS|perkasienewsherald.com}} of [[Perkasie, Pennsylvania]] 150 | ** ''Public Spirit'' {{WS|thepublicspirit.com}} of [[Hatboro, Pennsylvania]] 151 | ** ''Souderton Independent'' {{WS|soudertonindependent.com}} of [[Souderton, Pennsylvania]] 152 | ** ''Springfield Sun'' {{WS|springfieldsun.com}} of [[Springfield, Pennsylvania]] 153 | ** ''Spring-Ford Reporter'' {{WS|springfordreporter.com}} of [[Royersford, Pennsylvania]] 154 | ** ''Times Chronicle'' {{WS|thetimeschronicle.com}} of [[Jenkintown, Pennsylvania]] 155 | ** ''Valley Item'' {{WS|valleyitem.com}} of [[Perkiomenville, Pennsylvania]] 156 | ** ''Willow Grove Guide'' {{WS|willowgroveguide.com}} of [[Willow Grove, Pennsylvania]] 157 | ** ''The Review'' {{WS|roxreview.com}} of [[Roxborough, Philadelphia, Pennsylvania]] 158 | 159 | * Main Line Media News {{WS|mainlinemedianews.com}} 160 | ** ''Main Line Times'' {{WS|mainlinetimes.com}} of [[Ardmore, Pennsylvania]] 161 | ** ''Main Line Life'' {{WS|mainlinelife.com}} of [[Ardmore, Pennsylvania]] 162 | ** ''The King of Prussia Courier'' {{WS|kingofprussiacourier.com}} of [[King of Prussia, Pennsylvania]] 163 | 164 | * Delaware County News Network {{WS|delconewsnetwork.com}} 165 | ** ''News of Delaware County'' {{WS|newsofdelawarecounty.com}} of [[Havertown, Pennsylvania]] 166 | ** ''County Press'' {{WS|countypressonline.com}} of [[Newtown Square, Pennsylvania]] 167 | ** ''Garnet Valley Press'' {{WS|countypressonline.com}} of [[Glen Mills, Pennsylvania]] 168 | ** ''Springfield Press'' {{WS|countypressonline.com}} of [[Springfield, Pennsylvania]] 169 | ** ''Town Talk'' {{WS|towntalknews.com}} of [[Ridley, Pennsylvania]] 170 | 171 | * Berks-Mont Newspapers {{WS|berksmontnews.com}} 172 | ** ''The Boyertown Area Times'' {{WS|berksmontnews.com/boyertown_area_times}} of [[Boyertown, Pennsylvania]] 173 | ** ''The Kutztown Area Patriot'' {{WS|berksmontnews.com/kutztown_area_patriot}} of [[Kutztown, Pennsylvania]] 174 | ** ''The Hamburg Area Item'' {{WS|berksmontnews.com/hamburg_area_item}} of [[Hamburg, Pennsylvania]] 175 | ** ''The Southern Berks News'' {{WS|berksmontnews.com/southern_berks_news}} of [[Exeter Township, Berks County, Pennsylvania]] 176 | ** ''Community Connection'' {{WS|berksmontnews.com/community_connection}} of [[Boyertown, Pennsylvania]] 177 | 178 | * Magazines 179 | ** ''Bucks Co. Town & Country Living'' {{WS|buckscountymagazine.com}} 180 | ** ''Parents Express'' {{WS|parents-express.com}} 181 | ** ''Real Men, Rednecks'' {{WS|realmenredneck.com}} 182 | 183 | {{JRC}} 184 | 185 | ==References== 186 | 187 | 188 | [[Category:Journal Register publications|*]] 189 | -------------------------------------------------------------------------------- /test/test_diff.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "lcs.h" 9 | 10 | using std::vector; 11 | using std::cout; 12 | using std::endl; 13 | using std::string; 14 | 15 | const char * usage = "Prints the difference between two strings\n %s: \n"; 16 | const bool longstr = true; 17 | 18 | template < typename T > 19 | bool test_case(vector &o, vector &n, vector &ExpectedLCS, bool longstr=false) 20 | { 21 | cout << "========\n"; 22 | if (longstr){ 23 | cout << " A[0]..A["<< o.size() <<"] = "<< string(o.begin(), o.begin() + 10) << "..." 24 | << string(o.end()-10, o.end()) <<"\n" 25 | << " B[0]..B["<< n.size() <<"] = " << string(n.begin(), n.begin()+ 10) << "..." 26 | << string(n.end()-10, n.end()) <<"\n"; 27 | } else { 28 | cout << " A = "<< string(o.begin(), o.end()) 29 | << " B = " << string(n.begin(), n.end()) << "\n"; 30 | } 31 | 32 | clock_t start_time = clock(); 33 | 34 | vector LCS(n.size()); 35 | typename vector::iterator end = lcs(o.begin(), o.end(), 36 | n.begin(), n.end(), 37 | LCS.begin()); 38 | clock_t end_time = clock(); 39 | 40 | LCS.resize(end-LCS.begin()); 41 | 42 | if (longstr){ 43 | cout << " LCS(A,B) = " << string(LCS.begin(), LCS.begin()+10) << "..." 44 | << string(LCS.end()-10, LCS.end()) <<"\n"; 45 | cout << " Length = " << LCS.end() - LCS.begin() << endl; 46 | } else { 47 | cout << " LCS(A,B) = " << string(LCS.begin(), LCS.end()) << "\n"; 48 | } 49 | 50 | 51 | // Test calculating the LCS in both directions. The LCS function is 52 | // a commutative function so the result should be the same. 53 | 54 | vector LCSSwap(n.size()); 55 | typename vector::iterator endSwap = lcs(n.begin(), n.end(), 56 | o.begin(), o.end(), 57 | LCSSwap.begin()); 58 | LCSSwap.resize(endSwap-LCSSwap.begin()); 59 | 60 | if (longstr) { 61 | cout << " LCS(B,A) = " << string(LCSSwap.begin(), LCSSwap.begin()+10) << "..." 62 | << string(LCSSwap.end()-10, LCSSwap.end()) <<"\n" 63 | << " Length = " << LCSSwap.end() - LCSSwap.begin() << endl 64 | << " Expected " << string (ExpectedLCS.begin(), ExpectedLCS.begin()+10) << "..." 65 | << string(ExpectedLCS.end()-10, ExpectedLCS.end()) << endl 66 | << " Length = " << ExpectedLCS.end() - ExpectedLCS.begin() << endl; 67 | 68 | } else { 69 | cout << " LCS(B,A) = " << string(LCSSwap.begin(), LCSSwap.end()) << endl 70 | << " Expected " << string (ExpectedLCS.begin(), ExpectedLCS.end()) << endl; 71 | } 72 | double cpu_time_secs = ((end_time - start_time)/(double)CLOCKS_PER_SEC)*1000; 73 | cout << " Time spent = " << cpu_time_secs <<" ms\n"; 74 | 75 | if ((LCS == ExpectedLCS) && (LCSSwap == ExpectedLCS)) { 76 | cout << "Passed!" << endl; 77 | return true; 78 | } else { 79 | cout << "FAIL!" << endl; 80 | exit(-1); 81 | return false; 82 | } 83 | } 84 | 85 | template < typename T > 86 | bool test_speed(vector &o, vector &n, vector &ExpectedLCS, bool longstr=false) 87 | { 88 | cout << "========\n"; 89 | if (longstr){ 90 | cout << " A[0]..A["<< o.size() <<"] = "<< string(o.begin(), o.begin() + 10) << "..." 91 | << string(o.end()-10, o.end()) <<"\n" 92 | << " B[0]..B["<< n.size() <<"] = " << string(n.begin(), n.begin()+ 10) << "..." 93 | << string(n.end()-10, n.end()) <<"\n"; 94 | } else { 95 | cout << " A = "<< string(o.begin(), o.end()) 96 | << " B = " << string(n.begin(), n.end()) << "\n"; 97 | } 98 | 99 | clock_t start_time = clock(); 100 | 101 | vector LCS(n.size()); 102 | typename vector::iterator end = lcs(o.begin(), o.end(), 103 | n.begin(), n.end(), 104 | LCS.begin()); 105 | clock_t end_time = clock(); 106 | 107 | LCS.resize(end-LCS.begin()); 108 | 109 | if (longstr) { 110 | cout << " LCS(A,B) = " << string(LCS.begin(), LCS.begin()+10) << "..." 111 | << string(LCS.end()-10, LCS.end()) <<"\n" 112 | << " Length = " << LCS.end() - LCS.begin() << endl; 113 | } else { 114 | cout << " LCS(A,B) = " << string(LCS.begin(), LCS.end()) << "\n" 115 | << " Length = " << LCS.end() - LCS.begin() << endl; 116 | } 117 | 118 | double cpu_time_secs = ((end_time - start_time)/(double)CLOCKS_PER_SEC)*1000; 119 | cout << " Time spent = " << cpu_time_secs <<" ms\n"; 120 | 121 | return true; 122 | } 123 | 124 | 125 | bool test_case(string o, string n, string ExpectedLCS, bool longstr=false) 126 | { 127 | vector O(o.begin(), o.end()); 128 | vector N(n.begin(), n.end()); 129 | vector E(ExpectedLCS.begin(), ExpectedLCS.end()); 130 | 131 | return test_case(O,N,E, longstr); 132 | } 133 | 134 | vector * read_ascii_file (string name) 135 | { 136 | FILE * f = fopen (name.c_str(), "r"); 137 | if (f == NULL) perror("fopen"); 138 | int err = fseek(f, 0, SEEK_END) != 0; 139 | if (err) perror("fseek"); 140 | int fSize=ftell(f); 141 | if (fSize < 0) perror("ftell"); 142 | rewind(f); 143 | vector *bufferp=new vector; 144 | bufferp->resize(fSize); 145 | err = fread (&((*bufferp)[0]), 1, fSize, f); 146 | 147 | if (err < 0) perror ("fread"); 148 | 149 | fclose (f); 150 | return bufferp; 151 | } 152 | 153 | int main(int argc, char *argv[]) 154 | { 155 | 156 | //Trivial cases - Empty LCS 157 | test_case("", "a", ""); 158 | test_case("b", "a", ""); 159 | test_case("ab", "cd", ""); 160 | test_case("asdfghjk","qwertyiu",""); 161 | 162 | //Trivial cases - Length 1 LCS 163 | test_case("a", "a", "a"); 164 | test_case("ba", "a", "a"); 165 | test_case("ab", "a", "a"); 166 | test_case("bad", "a", "a"); 167 | test_case("ba", "ac", "a"); 168 | test_case("bad", "ac", "a"); 169 | test_case("bad", "tac", "a"); 170 | test_case("bad", "taca", "a"); 171 | test_case("bab", "atacata", "a"); 172 | test_case("bad", "atacat", "a"); 173 | 174 | //Length 2 LCS 175 | test_case("bad", "ad", "ad"); 176 | test_case("bad", "ba", "ba"); 177 | test_case("bad", "dba", "ba"); 178 | test_case("read", "ea", "ea"); 179 | test_case("34cd78w", "78z", "78"); 180 | 181 | test_case("bad", "bacad", "bad"); 182 | test_case("7890", "78a90", "7890"); 183 | test_case("7890a", "7890", "7890"); 184 | test_case("a7890", "7890", "7890"); 185 | test_case("a7890b", "e7890", "7890"); 186 | test_case("a7890b", "7890", "7890"); 187 | test_case("a7890b", "c7890d", "7890"); 188 | test_case("a7890b", "c78e90d", "7890"); 189 | test_case("a123b345c678d", "e123f345g678h", "123345678"); 190 | test_case("a78f90b", "c78e90d", "7890"); 191 | test_case("aa78f90b", "c78e90d", "7890"); 192 | test_case("a7890", "7890b", "7890"); 193 | 194 | test_case("78907890", "78a90", "7890"); 195 | test_case("78a90", "78907890", "7890"); 196 | test_case("7890", "78a907890", "7890"); 197 | test_case("7890", "7890a7890", "7890"); 198 | test_case("XMJYAUZ", "MZJAWXU", "MJAU"); 199 | 200 | test_case("x1234ab34cd78w", "y12345678z", "123478"); 201 | 202 | const char * A = "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"; 203 | const char * B = "123456789012345678901234567890a1234567890b1234567890123456789012c34567890123456789012345678901d231456789012345678901234567890123456789012345678901234567890"; 204 | test_case(A,B,A,longstr); 205 | 206 | vector * lisp = read_ascii_file("lisp.txt"); 207 | vector * lisp1 = read_ascii_file("lisp1.txt"); 208 | vector * lisp_lcs = read_ascii_file("lisp_lcs.txt"); 209 | 210 | test_case(*lisp, *lisp1, *lisp_lcs,longstr); 211 | 212 | vector * sp1 = read_ascii_file("speedtest1.txt"); 213 | vector * sp2 = read_ascii_file("speedtest2.txt"); 214 | vector * WRONG_lcs = read_ascii_file("lisp_lcs.txt"); 215 | 216 | test_speed(*sp1, *sp2, *WRONG_lcs, longstr); 217 | 218 | exit(0); 219 | } 220 | int main_sp(){ 221 | vector * lisp = read_ascii_file("lisp.txt"); 222 | vector * lisp1 = read_ascii_file("lisp1.txt"); 223 | vector * lisp_lcs = read_ascii_file("lisp_lcs.txt"); 224 | 225 | test_case(*lisp, *lisp1, *lisp_lcs); 226 | 227 | return 0; 228 | } 229 | --------------------------------------------------------------------------------