void LMS::fit( //fit sample float &out_m, //output line float &out_c) { inT32 index; //of median inT32 trials; //no of medians float test_m, test_c; //candidate line float test_error; //error of test line switch (samplecount) { case 0: m = 0.0f; //no info c = 0.0f; line_error = 0.0f; break; case 1: m = 0.0f; c = samples[0].y (); //horiz thru pt line_error = 0.0f; break; case 2: if (samples[0].x () != samples[1].x ()) { m = (samples[1].y () - samples[0].y ()) / (samples[1].x () - samples[0].x ()); c = samples[0].y () - m * samples[0].x (); } else { m = 0.0f; c = (samples[0].y () + samples[1].y ()) / 2; } line_error = 0.0f; break; default: pick_line(m, c); //use pts at random compute_errors(m, c); //from given line index = choose_nth_item (samplecount / 2, errors, samplecount); line_error = errors[index]; for (trials = 1; trials < lms_line_trials; trials++) { //random again pick_line(test_m, test_c); compute_errors(test_m, test_c); index = choose_nth_item (samplecount / 2, errors, samplecount); test_error = errors[index]; if (test_error < line_error) { //find least median line_error = test_error; m = test_m; c = test_c; } } } fitted = TRUE; out_m = m; out_c = c; a = 0; }
void LMS::constrained_fit( //fit sample float fixed_m, //forced gradient float &out_c) { inT32 index; //of median inT32 trials; //no of medians float test_c; //candidate line static uinT16 seeds[3] = { SEED1, SEED2, SEED3 }; //for nrand float test_error; //error of test line m = fixed_m; switch (samplecount) { case 0: c = 0.0f; line_error = 0.0f; break; case 1: //horiz thru pt c = samples[0].y () - m * samples[0].x (); line_error = 0.0f; break; case 2: c = (samples[0].y () + samples[1].y () - m * (samples[0].x () + samples[1].x ())) / 2; line_error = m * samples[0].x () + c - samples[0].y (); line_error *= line_error; break; default: index = (inT32) nrand48 (seeds) % samplecount; //compute line c = samples[index].y () - m * samples[index].x (); compute_errors(m, c); //from given line index = choose_nth_item (samplecount / 2, errors, samplecount); line_error = errors[index]; for (trials = 1; trials < lms_line_trials; trials++) { index = (inT32) nrand48 (seeds) % samplecount; test_c = samples[index].y () - m * samples[index].x (); //compute line compute_errors(m, test_c); index = choose_nth_item (samplecount / 2, errors, samplecount); test_error = errors[index]; if (test_error < line_error) { //find least median line_error = test_error; c = test_c; } } } fitted = TRUE; out_c = c; a = 0; }
// Compute all the cross product distances of the points from the line // and return the true squared upper quartile distance. double DetLineFit::ComputeErrors(const ICOORD start, const ICOORD end, int* distances) { ICOORDELT_IT it(&pt_list_); ICOORD line_vector = end; line_vector -= start; // Compute the distance of each point from the line. int pt_index = 0; for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) { ICOORD pt_vector = *it.data(); pt_vector -= start; // Compute |line_vector||pt_vector|sin(angle between) int dist = line_vector * pt_vector; if (dist < 0) dist = -dist; distances[pt_index++] = dist; } // Now get the upper quartile distance. int index = choose_nth_item(3 * pt_index / 4, distances, pt_index, sizeof(distances[0]), CompareInts); double dist = distances[index]; // The true distance is the square root of the dist squared / the // squared length of line_vector (which is the dot product with itself) // Don't bother with the square root. Just return the square distance. return dist * dist / (line_vector % line_vector); }
float LMS::compute_quadratic_errors( //fit sample float outlier_threshold, //min outlier double line_a, float line_m, //input gradient float line_c) { inT32 outlier_count; //total outliers inT32 index; //picked point inT32 error_count; //no in total double total_error; //summed squares total_error = 0; outlier_count = 0; error_count = 0; for (index = 0; index < samplecount; index++) { errors[error_count] = line_c + samples[index].x () * (line_m + samples[index].x () * line_a) - samples[index].y (); errors[error_count] *= errors[error_count]; if (errors[error_count] > outlier_threshold) { outlier_count++; errors[samplecount - outlier_count] = errors[error_count]; } else { total_error += errors[error_count++]; } } if (outlier_count * 3 < error_count) return total_error / error_count; else { index = choose_nth_item (outlier_count / 2, errors + samplecount - outlier_count, outlier_count); //median outlier return errors[samplecount - outlier_count + index]; } }
DLLSYM inT32 choose_nth_item ( //fast median inT32 index, //index to choose void *array, //array of items inT32 count, //no of items size_t size, //element size //comparator int (*compar) (const void *, const void *) ) { int result; //of compar inT32 next_sample; //next one to do inT32 next_lesser; //space for new inT32 prev_greater; //last one saved inT32 equal_count; //no of equal ones inT32 pivot; //proposed median if (count <= 1) return 0; if (count == 2) { if (compar (array, (char *) array + size) < 0) { return index >= 1 ? 1 : 0; } else { return index >= 1 ? 0 : 1; } } if (index < 0) index = 0; //ensure lergal else if (index >= count) index = count - 1; pivot = (inT32) (rand () % count); swap_entries (array, size, pivot, 0); next_lesser = 0; prev_greater = count; equal_count = 1; for (next_sample = 1; next_sample < prev_greater;) { result = compar ((char *) array + size * next_sample, (char *) array + size * next_lesser); if (result < 0) { swap_entries (array, size, next_lesser++, next_sample++); //shuffle } else if (result > 0) { prev_greater--; swap_entries(array, size, prev_greater, next_sample); } else { equal_count++; next_sample++; } } if (index < next_lesser) return choose_nth_item (index, array, next_lesser, size, compar); else if (index < prev_greater) return next_lesser; //in equal bracket else return choose_nth_item (index - prev_greater, (char *) array + size * prev_greater, count - prev_greater, size, compar) + prev_greater; }
DLLSYM inT32 choose_nth_item( //fast median inT32 index, //index to choose float *array, //array of items inT32 count //no of items ) { inT32 next_sample; //next one to do inT32 next_lesser; //space for new inT32 prev_greater; //last one saved inT32 equal_count; //no of equal ones float pivot; //proposed median float sample; //current sample if (count <= 1) return 0; if (count == 2) { if (array[0] < array[1]) { return index >= 1 ? 1 : 0; } else { return index >= 1 ? 0 : 1; } } else { if (index < 0) index = 0; //ensure lergal else if (index >= count) index = count - 1; equal_count = (inT32) (rand() % count); pivot = array[equal_count]; //fill gap array[equal_count] = array[0]; next_lesser = 0; prev_greater = count; equal_count = 1; for (next_sample = 1; next_sample < prev_greater;) { sample = array[next_sample]; if (sample < pivot) { //shuffle array[next_lesser++] = sample; next_sample++; } else if (sample > pivot) { prev_greater--; //juggle array[next_sample] = array[prev_greater]; array[prev_greater] = sample; } else { equal_count++; next_sample++; } } for (next_sample = next_lesser; next_sample < prev_greater;) array[next_sample++] = pivot; if (index < next_lesser) return choose_nth_item (index, array, next_lesser); else if (index < prev_greater) return next_lesser; //in equal bracket else return choose_nth_item (index - prev_greater, array + prev_greater, count - prev_greater) + prev_greater; } }