Beispiel #1
0
void
DefaultCandidateSetScorer::Score(Model *model,
                                 CandidateSet &candidates, bool training) {
  // N.B.: We assume there is at least one candidate!
  CandidateSet::iterator it = candidates.begin();

  // Score first candidate, which is perforce the best candidate so far.
  model->ScoreCandidate(*(*it), training);

  CandidateSet::iterator best_it = it;
  CandidateSet::iterator gold_it = it;
  ++it;

  // Score any and all remaining candidates.
  for ( ; it != candidates.end(); ++it) {
    Candidate &candidate = *(*it);
    model->ScoreCandidate(candidate, training);
    if (model->score_comparator()->Compare(*model, candidate, **best_it) > 0) {
      best_it = it;
    }
    if (model->gold_comparator()->Compare(*model, candidate, **gold_it) > 0) {
      gold_it = it;
    }
  }
  candidates.set_best_scoring_index((*best_it)->index());
  candidates.set_gold_index((*gold_it)->index());
}
Beispiel #2
0
CandidateSet CandidateSet::getCandidateTrees(double score) {
    CandidateSet res;
    for (CandidateSet::iterator it = begin(); it != end(); it++) {
        if (abs(it->first - score) < 0.1) {
            res.insert(*it);
        }
    }
    return res;
}
Beispiel #3
0
CandidateSet CandidateSet::getBestCandidateTrees(int numTrees) {
    CandidateSet res;
    if (numTrees >= size() || numTrees == 0)
        numTrees = (int) size();

    for (reverse_iterator rit = rbegin(); rit != rend() && numTrees > 0; rit++, numTrees--) {
        res.insert(*rit);
    }
    return res;
}
Beispiel #4
0
StepCode EliminateNakedPairsStep::runOnHouse(House &cell_list) {
  bool modified = false;
  std::set<Mask> found_masks;
  std::set<Mask> duplicate_masks;
  for (const Cell *cell : cell_list) {
    if (cell->candidates.none()) {
      return {true, modified};
    }
    if (cell->candidates.count() != 2) {
      continue;
    }

    const Mask mask = cell->candidates.to_ulong();

    if (found_masks.count(mask)) {
      duplicate_masks.insert(cell->candidates.to_ulong());
    }

    found_masks.insert(mask);
  }

  for (auto &mask : duplicate_masks) {
    for (Cell *cell : cell_list) {
      if (cell->isFixed()) {
        continue;
      }

      CandidateSet *candidates = &cell->candidates;
      if (candidates->to_ulong() == mask) {
        continue;
      }

      auto new_cands = CandidateSet(candidates->to_ulong() & ~mask);
      if (*candidates == new_cands) {
        continue;
      }

      if (DEBUG) {
        const Mask intersection = candidates->to_ulong() & mask;
        dbgs() << "Naked Pair " << printCandidateString(mask) << " removes "
               << printCandidateString(intersection) << " from " << cell->coord
               << "\n";
      }

      modified = true;
      changed.insert(cell);
      *candidates = new_cands;
    }
  }

  return {false, modified};
}
Beispiel #5
0
void
PerceptronModel::ComputeFeaturesToUpdate(const CandidateSet &example,
                                         unordered_set<int> &
                                         gold_features_to_update,
                                         unordered_set<int> &
                                         best_scoring_features_to_update)
    const {
  // Collect gold features that are not in best-scoring candidate.
  const FeatureVector<int,double> &gold_features =
      example.GetGold().features();
  const FeatureVector<int,double> &best_scoring_features =
      example.GetBestScoring().features();

  if (DEBUG >= 2) {
    cerr << "Gold index: " << example.gold_index()
         << "; best scoring index: " << example.best_scoring_index()
         << endl;
    cerr << "Original gold features: " << gold_features << endl
         << "Original best scoring features: " << best_scoring_features << endl;
  }

  gold_features.GetNonZeroFeatures(gold_features_to_update);
  best_scoring_features.RemoveEqualFeatures(gold_features,
                                            gold_features_to_update);

  if (DEBUG >= 2) {
    cerr << "Time:" << time_.to_string() << ": new gold features: [";
    for (unordered_set<int>::const_iterator it =
             gold_features_to_update.begin();
         it != gold_features_to_update.end();
         ++it) {
      cerr << " " << *it;
    }
    cerr << "]" << endl;
  }

  best_scoring_features.GetNonZeroFeatures(best_scoring_features_to_update);
  gold_features.RemoveEqualFeatures(best_scoring_features,
                                    best_scoring_features_to_update);
  if (DEBUG >= 2) {
    cerr << "Time:" << time_.to_string() << ": new best scoring features: [";
    for (unordered_set<int>::const_iterator it =
             best_scoring_features_to_update.begin();
         it != best_scoring_features_to_update.end();
         ++it) {
      cerr << " " << *it;
    }
    cerr << "]" << endl;
  }

}
//Print the message followed by all the entries in the CandidateTally, in
//  the order specified by has_higher_priority: i is printed before j, if
//  has_higher_priority(i,j) returns true: sometimes alphabetically by candidate,
//  other times by decreasing votes for the candidate.
//Use a "->" to separate the candidate name from the number of votes they
//  received.
void print_tally(std::string message, const CandidateTally& tally, bool (*has_higher_priority)(const TallyEntry& i,const TallyEntry& j)) {
	CandidateSet candidateSet;
	for (const auto& kv : tally) {
		candidateSet.insert(kv.first);
	}
	TallyEntryPQ tallyPQ(*has_higher_priority);
	tallyPQ.enqueue_all(tally);
	std::cout << message << ": still in election = " << candidateSet << std::endl;

	for (const TallyEntry& tallyEntry : tallyPQ) {
		std::cout << "  " << tallyEntry.first << " -> " << tallyEntry.second << std::endl;
	}
	std::cout << std::endl;
}
//Prompt the user for a file, create a voter preference Map, and print it.
//Determine the Set of all the candidates in the election, from this Map.
//Repeatedly evaluate the ballot based on the candidates (still) in the
//  election, printing the vote count (tally) two ways: with the candidates
//  (a) shown alphabetically increasing and (b) shown with the vote count
//  decreasing (candidates with equal vote counts are shown alphabetically
//  increasing); from this tally, compute which candidates remain in the
//  election: all candidates receiving more than the minimum number of votes;
//  continue this process until there are less than 2 candidates.
//Print the final result: there may 1 candidate left (the winner) or 0 left
//   (no winner).
int main() {
  try {
	  std::ifstream text_file;
	  ics::safe_open(text_file,"Enter the name of a file with voter preferences","votepref1.txt");
	  std::cout << std::endl;

	  const Preferences prefs = read_voter_preferences(text_file);
	  print_voter_preferences(prefs);
	  std::cout << std::endl;

	  CandidateSet candidateSet;
	  for (const auto& kv : prefs) {
		  for (const std::string& candidate : kv.second) {
			  candidateSet.insert(candidate);
		  }
	  }

	  CandidateTally tally = evaluate_ballot(prefs, candidateSet);
	  int ballot = 1;

	  while (candidateSet.size() > 1) {
		  std::stringstream ss;
		  ss << ballot++;
		  print_tally("Vote count on ballot #" + ss.str() +
				  " with candidates in alphabetical order", tally, alphabetic_gt);
		  print_tally("Vote count on ballot #" + ss.str() +
				  " with candidates in numerical order", tally, numeric_gt);

		  candidateSet = remaining_candidates(tally);
		  tally = evaluate_ballot(prefs, candidateSet);
	  }

	  if (candidateSet.size() == 0) {
		  std::cout << "No winner" << std::endl;
	  } else {
		  std::string winner;
		  for (const std::string& candidate : candidateSet) {
			  winner += candidate + " and ";
		  }
		  std::cout << "Winner is " << winner.substr(0, winner.length()-5) << std::endl;
	  }

  } catch (ics::IcsError& e) {
    std::cout << e.what() << std::endl;
  }
  return 0;
}
Beispiel #8
0
void
PerceptronModel::DefaultUpdater::Update(Model *m, CandidateSet &example) {
  PerceptronModel *model = dynamic_cast<PerceptronModel *>(m);
  ++(model->num_updates_);
  unordered_set<int> gold_features;
  unordered_set<int> best_scoring_features;
  model->ComputeFeaturesToUpdate(example, gold_features, best_scoring_features);

  model->models_.UpdateGoldAndCandidateFeatureAverages(model->time_,
                                                       gold_features,
                                                       best_scoring_features);
  double step_size =
      model->ComputeStepSize(gold_features, best_scoring_features, example);

  // Finally, update perceptrons.

  if (DEBUG >= 2) {
    cerr << "Updating weights for gold features [";
    for (unordered_set<int>::const_iterator it = gold_features.begin();
         it != gold_features.end(); ++it) {
      cerr << " " << *it;
    }
    cerr << "] from\n\t" << example.GetGold() << endl;

    cerr << "Updating weights for best scoring features [";
    for (unordered_set<int>::const_iterator it = best_scoring_features.begin();
         it != best_scoring_features.end(); ++it) {
      cerr << " " << *it;
    }
    cerr << "] from\n\t" << example.GetBestScoring() << endl;

  }

  double positive_step = step_size;
  model->models_.UpdateWeights(model->time_, gold_features,
                               example.GetGold().features(), positive_step);
  double negative_step = -step_size;
  model->models_.UpdateWeights(model->time_, best_scoring_features,
                        example.GetBestScoring().features(), negative_step);

  if (DEBUG >=2) {
    cerr << "Raw model: " << model->models_.GetModel(true) << endl;
    cerr << "Avg model: " << model->models_.GetModel(false) << endl;
  }
}
//Return the Set of candidates who are still in the election, based on the
//  tally of votes: compute the minimum number of votes and return a Set of
//  all candidates receiving more than that minimum; if all candidates
//  receive the same number of votes (that would be the minimum), the empty
//  Set is returned.
CandidateSet remaining_candidates(const CandidateTally& tally) {
	CandidateSet result;
	if (!tally.empty()) {
		int min = -1;

		for (const TallyEntry& entry : tally) {
				if (min == -1 || entry.second < min) {
					min = entry.second;
				}
		}
		for (const TallyEntry& entry : tally) {
			if (entry.second > min) {
				result.insert(entry.first);
			}
		}
	}
	return result;
}
Beispiel #10
0
void
RandomPairCandidateSetScorer::Score(Model *model,
                                    CandidateSet &candidates, bool training) {
  // First, pick two candidate indices at random.
  size_t idx1 = GetRandomIndex(candidates.size());
  size_t idx2 = GetRandomIndex(candidates.size());
  Candidate &c1 = candidates.Get(idx1);
  Candidate &c2 = candidates.Get(idx2);

  // Next, just score those two candidates.
  model->ScoreCandidate(c1, training);
  model->ScoreCandidate(c2, training);

  // Finally, set indices of best scoring and gold amongst just those two.
  int score_cmp = model->score_comparator()->Compare(*model, c1, c2);
  candidates.set_best_scoring_index(score_cmp > 0 ? c1.index() : c2.index());

  int gold_cmp = model->gold_comparator()->Compare(*model, c1, c2);
  candidates.set_gold_index(gold_cmp > 0 ? c1.index() : c2.index());
}
//Return the CandidateTally: a Map of candidates (as keys) and the number of
//  votes they received, based on the unchanging Preferences (read from the
//  file) and the candidates who are currently still in the election (which changes).
//Every possible candidate should appear as a key in the resulting tally.
//Each voter should tally one vote: for their highest-ranked candidate who is
//  still in the the election.
CandidateTally evaluate_ballot(const Preferences& preferences, const CandidateSet& candidates) {
	CandidateTally tally;
	for (const PreferencesEntry& entry : preferences) {
		for (const std::string& candidate : entry.second) {
			if (candidates.contains(candidate)) {
				++tally[candidate];
				break;
			}
		}
	}
	return tally;
}
Beispiel #12
0
void
PerceptronModel::TrainOnExample(CandidateSet &example) {
  time_.Tick();

  if (symbols_ != NULL) {
    example.CompileFeatures(symbols_);
  }

  bool training = true;
  ScoreCandidates(example, training);

  if (NeedToUpdate(example)) {
    if (DEBUG >= 2) {
      cerr << "Time:" << time_.to_string() << ": need to update because "
           << "best scoring index " << example.best_scoring_index()
           << " is not equal to gold index " << example.gold_index() << endl;
    }
    ++(*num_training_errors_per_epoch_.rbegin());
    ++num_training_errors_;
    Update(example);
  }
}
Beispiel #13
0
bool
PerceptronModel::DefaultUpdatePredicate::NeedToUpdate(Model *model,
                                                      CandidateSet &example) {
  return example.best_scoring_index() != example.gold_index();
}
Beispiel #14
0
StepCode EliminateNakedTriplesStep::runOnHouse(House &house) {
  bool modified = false;

  if (house.size() <= 3) {
    return {false, modified};
  }

  std::vector<std::pair<Mask, std::vector<const Cell *>>> found_masks;
  for (const Cell *cell : house) {
    std::size_t num_candidates = cell->candidates.count();
    if (num_candidates == 0) {
      return {true, modified};
    }
    if (num_candidates != 2 && num_candidates != 3) {
      continue;
    }

    const Mask mask = cell->candidates.to_ulong();

    bool found_match = false;
    for (unsigned i = 0; i < found_masks.size(); ++i) {
      const Mask m = found_masks[i].first;

      // ORing the two masks together will switch on all candidates found in
      // both masks. If it's less than three, then we're still a triple
      // candidate.
      // TODO: If the current mask is size 2 and the OR of the two is 3, then
      // we should create two masks: one for the two and one for the OR.
      // Otherwise you could get 1/2 match with 1/2/3 and 1/2/4.
      // For now, only accept found masks of size 3. Easy naked triples.
      if (bitCount(m) == 3 && bitCount(mask | m) == 3) {
        found_match = true;
        found_masks[i].second.push_back(cell);
      }
    }

    if (!found_match) {
      std::pair<Mask, std::vector<const Cell *>> pair;
      pair.first = mask;
      pair.second.push_back(cell);
      found_masks.push_back(pair);
    }
  }

  for (auto &pair : found_masks) {
    if (pair.second.size() != 3) {
      continue;
    }

    auto &matches = pair.second;
    const Mask mask = pair.first;

    for (Cell *cell : house) {
      if (cell->isFixed()) {
        continue;
      }

      if (std::find(matches.begin(), matches.end(), cell) != matches.end()) {
        continue;
      }

      CandidateSet *candidates = &cell->candidates;
      if (candidates->to_ulong() == mask) {
        continue;
      }
      auto new_cands = CandidateSet(candidates->to_ulong() & ~mask);
      if (*candidates == new_cands) {
        continue;
      }

      if (DEBUG) {
        const Mask intersection = candidates->to_ulong() & mask;
        dbgs() << "Naked Triple " << printCandidateString(mask) << " removes "
               << printCandidateString(intersection) << " from " << cell->coord
               << "\n";
      }

      modified = true;
      changed.insert(cell);
      *candidates = new_cands;
    }
  }

  return {false, modified};
}