<commit_before>/*
 * Copyright (C) 2016 deipi.com LLC and contributors. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "field_parser.h"

#include <ctype.h>  // for isspace

#define COLON ':'
#define DOUBLE_QUOTE '"'
#define SINGLE_QUOTE '\''
#define SQUARE_BRACKET_LEFT '['
#define SQUARE_BRACKET_RIGHT ']'
#define COMMA ','

FieldParser::FieldParser(const std::string& p)
	: fstr(p),
	  len_field(0), off_field(nullptr),
	  len_field_colon(0), off_field_colon(nullptr),
	  len_value(0), off_value(nullptr),
	  len_double_quote_value(0), off_double_quote_value(nullptr),
	  len_single_quote_value(0), off_single_quote_value(nullptr),
	  skip_quote(false), isrange(false) { }

void
FieldParser::parse()
{
	auto currentState = FieldParser::State::INIT;
	auto oldState = currentState;
	auto currentSymbol = fstr.data();
	char quote;

	while (true) {
		switch (currentState) {
			case FieldParser::State::INIT:
				switch (*currentSymbol) {
					case SQUARE_BRACKET_LEFT:
						currentState = FieldParser::State::SQUARE_BRACKET_INIT;
						off_value = currentSymbol;
						++len_value;
						isrange = true;
						break;
					case DOUBLE_QUOTE:
						currentState = FieldParser::State::QUOTE;
						quote = DOUBLE_QUOTE;
						off_double_quote_value = currentSymbol;
						off_value = currentSymbol + 1;
						++len_double_quote_value;
						++len_value;
						break;
					case SINGLE_QUOTE:
						currentState = FieldParser::State::QUOTE;
						quote = SINGLE_QUOTE;
						off_single_quote_value = currentSymbol;
						off_value = currentSymbol + 1;
						++len_single_quote_value;
						++len_value;
						break;
					case '\0':
						currentState = FieldParser::State::END;
						break;
					default:
						switch (*currentSymbol) {
							case ' ':
							case '\r':
							case '\n':
							case '\t':
								currentState = FieldParser::State::INIT;
								break;
							default:
								if (++len_field >= 1024) {
									THROW(FieldParserError, "Syntax error in query");
								}
								++len_field_colon;
								currentState = FieldParser::State::FIELD;
								off_field = currentSymbol;
								off_field_colon = currentSymbol;
								break;
						}
						break;
				}
				break;

			case FieldParser::State::FIELD:
				switch (*currentSymbol) {
					case COLON:
						currentState = FieldParser::State::START_VALUE;
						++len_field_colon;
						break;
					case '\0':
						len_value = len_field;
						off_value = off_field;
						len_field = len_field_colon = 0;
						off_field = off_field_colon = nullptr;
						return;
					case ' ':
						break;
					default:
						++len_field;
						++len_field_colon;
						break;
				}
				break;

			case FieldParser::State::START_VALUE:
				switch (*currentSymbol) {
					case DOUBLE_QUOTE:
						currentState = FieldParser::State::QUOTE;
						quote = DOUBLE_QUOTE;
						off_double_quote_value = currentSymbol;
						off_value = off_double_quote_value + 1;
						++len_double_quote_value;
						++len_value;
						break;
					case SINGLE_QUOTE:
						currentState = FieldParser::State::QUOTE;
						quote = SINGLE_QUOTE;
						off_single_quote_value = currentSymbol;
						off_value = off_single_quote_value + 1;
						++len_single_quote_value;
						++len_value;
						break;
					case SQUARE_BRACKET_LEFT:
						currentState = FieldParser::State::SQUARE_BRACKET_INIT;
						off_value = currentSymbol;
						++len_value;
						isrange = true;
						break;
					case '\0':
						currentState = FieldParser::State::END;
						break;
					default:
						currentState = FieldParser::State::VALUE;
						off_value = currentSymbol;
						++len_value;
						break;
				}
				break;

			case FieldParser::State::QUOTE:
				switch (*currentSymbol) {
					case '\\':
						currentState = FieldParser::State::ESCAPE;
						oldState = FieldParser::State::QUOTE;
						++len_value;
						switch (quote) {
							case DOUBLE_QUOTE:
								++len_double_quote_value;
								break;
							case SINGLE_QUOTE:
								++len_single_quote_value;
								break;
						}
						break;
					case '\0':
						THROW(FieldParserError, "Expected symbol: '%c'", quote);
					default:
						if (*currentSymbol == quote) {
							currentState = FieldParser::State::COLON_OR_END;
							switch (quote) {
								case DOUBLE_QUOTE:
									++len_double_quote_value;
									--len_value;	// subtract the last quote count
									break;
								case SINGLE_QUOTE:
									++len_single_quote_value;
									--len_value;	// subtract the last quote count
									break;
							}
						} else {
							++len_value;
							switch (quote) {
								case DOUBLE_QUOTE:
									++len_double_quote_value;
									break;
								case SINGLE_QUOTE:
									++len_single_quote_value;
									break;
							}
						}
						break;
				}
				break;

			case FieldParser::State::COLON_OR_END:
				switch (*currentSymbol) {
					case '\0':
						currentState = FieldParser::State::END;
						break;

					case COLON:
						currentState = FieldParser::State::START_VALUE;
						switch (quote) {
							case SINGLE_QUOTE:
								off_field = off_value;
								len_field = len_value;
								off_value = nullptr;
								len_value = 0;
								off_single_quote_value = nullptr;
								break;

							case DOUBLE_QUOTE:
								off_field = off_value;
								len_field = len_value;
								off_value = nullptr;
								len_value = 0;
								off_double_quote_value = nullptr;
								break;
						}
						skip_quote = true;
						break;

					default:
						 THROW(FieldParserError, "Unexpected symbol: %c", *currentSymbol);
						break;
				}

				break;

			case FieldParser::State::ESCAPE:
				if (*currentSymbol != '\0') {
					currentState = oldState;
					switch(currentState) {
						case FieldParser::State::QUOTE:
							++len_value;
							if (quote == DOUBLE_QUOTE) {
								++len_double_quote_value;
							} else if (quote == SINGLE_QUOTE) {
								++len_single_quote_value;
							}
							break;
						case FieldParser::State::SQUARE_BRACKET_FIRST_QUOTE:
							start += *currentSymbol;
							++len_value;
							break;
						case FieldParser::State::SQUARE_BRACKET_SECOND_QUOTE:
							end += *currentSymbol;
							++len_value;
							break;
						default:
							break;
					}
				} else {
					THROW(FieldParserError, "Syntax error in query escaped");
				}
				break;

			case FieldParser::State::VALUE:
				if (*currentSymbol == '\0') {
					currentState = FieldParser::State::END;
				} else if (!isspace(*currentSymbol)) {
					++len_value;
				} else {
					THROW(FieldParserError, "Syntax error in query");
				}
				break;

			case FieldParser::State::SQUARE_BRACKET_INIT:
				switch (*currentSymbol) {
					case DOUBLE_QUOTE:
						currentState = FieldParser::State::SQUARE_BRACKET_FIRST_QUOTE;
						quote = DOUBLE_QUOTE;
						++len_value;
						break;
					case SINGLE_QUOTE:
						currentState = FieldParser::State::SQUARE_BRACKET_FIRST_QUOTE;
						quote = SINGLE_QUOTE;
						++len_value;
						break;
					case COMMA:
						currentState = FieldParser::State::SQUARE_BRACKET;
						++len_value;
						break;
					case SQUARE_BRACKET_RIGHT:
						currentState = FieldParser::State::END;
						++len_value;
						break;
					case '\0':
						THROW(FieldParserError, "Syntax error in query");
					default:
						start += *currentSymbol;
						++len_value;
						break;
				}
				break;

			case FieldParser::State::SQUARE_BRACKET:
				switch (*currentSymbol) {
					case DOUBLE_QUOTE:
						currentState = FieldParser::State::SQUARE_BRACKET_SECOND_QUOTE;
						quote = DOUBLE_QUOTE;
						++len_value;
						break;
					case SINGLE_QUOTE:
						currentState = FieldParser::State::SQUARE_BRACKET_SECOND_QUOTE;
						quote = SINGLE_QUOTE;
						++len_value;
						break;
					case SQUARE_BRACKET_RIGHT:
						currentState = FieldParser::State::END;
						++len_value;
						break;
					case '\0':
						THROW(FieldParserError, "Expected symbol: ']'");
					default:
						end += *currentSymbol;
						++len_value;
						break;
				}
				break;

			case FieldParser::State::SQUARE_BRACKET_FIRST_QUOTE:
				switch (*currentSymbol) {
					case '\\':
						currentState = FieldParser::State::ESCAPE;
						oldState = FieldParser::State::SQUARE_BRACKET_FIRST_QUOTE;
						++len_value;
						break;
					case '\0':
						break;
					default:
						if (*currentSymbol == quote) {
							currentState = FieldParser::State::SQUARE_BRACKET_COMMA_OR_END;
						} else {
							start += *currentSymbol;
						}
						++len_value;
						break;
				}
				break;

			case FieldParser::State::SQUARE_BRACKET_COMMA_OR_END:
					switch (*currentSymbol) {
						case COMMA:
							currentState = FieldParser::State::SQUARE_BRACKET;
							++len_value;
							break;
						case SQUARE_BRACKET_RIGHT:
							currentState = FieldParser::State::END;
							++len_value;
							break;
						default:
							THROW(FieldParserError, "Unexpected symbol: %c", *currentSymbol);
					}
				break;

			case FieldParser::State::SQUARE_BRACKET_SECOND_QUOTE:
				switch (*currentSymbol) {
					case '\\':
						currentState = FieldParser::State::ESCAPE;
						oldState = FieldParser::State::SQUARE_BRACKET_SECOND_QUOTE;
						++len_value;
						break;
					case '\0':
						break;
					default:
						if (*currentSymbol == quote) {
							currentState = FieldParser::State::SQUARE_BRACKET_END;
						} else {
							end += *currentSymbol;
						}
						++len_value;
						break;
				}
				break;

			case FieldParser::State::SQUARE_BRACKET_END:
				if (*currentSymbol == SQUARE_BRACKET_RIGHT) {
					currentState = FieldParser::State::END;
					++len_value;
				} else {
					THROW(FieldParserError, "Expected symbol: ']'");
				}
				break;

			case FieldParser::State::END: {
				return;
			}
		}

		++currentSymbol;
	}
}
<commit_msg>FieldParser: Remove unneeded nested switch<commit_after>/*
 * Copyright (C) 2016 deipi.com LLC and contributors. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "field_parser.h"

#include <ctype.h>  // for isspace

#define COLON ':'
#define DOUBLE_QUOTE '"'
#define SINGLE_QUOTE '\''
#define SQUARE_BRACKET_LEFT '['
#define SQUARE_BRACKET_RIGHT ']'
#define COMMA ','

FieldParser::FieldParser(const std::string& p)
	: fstr(p),
	  len_field(0), off_field(nullptr),
	  len_field_colon(0), off_field_colon(nullptr),
	  len_value(0), off_value(nullptr),
	  len_double_quote_value(0), off_double_quote_value(nullptr),
	  len_single_quote_value(0), off_single_quote_value(nullptr),
	  skip_quote(false), isrange(false) { }

void
FieldParser::parse()
{
	auto currentState = FieldParser::State::INIT;
	auto oldState = currentState;
	auto currentSymbol = fstr.data();
	char quote;

	while (true) {
		switch (currentState) {
			case FieldParser::State::INIT:
				switch (*currentSymbol) {
					case SQUARE_BRACKET_LEFT:
						currentState = FieldParser::State::SQUARE_BRACKET_INIT;
						off_value = currentSymbol;
						++len_value;
						isrange = true;
						break;
					case DOUBLE_QUOTE:
						currentState = FieldParser::State::QUOTE;
						quote = DOUBLE_QUOTE;
						off_double_quote_value = currentSymbol;
						off_value = currentSymbol + 1;
						++len_double_quote_value;
						++len_value;
						break;
					case SINGLE_QUOTE:
						currentState = FieldParser::State::QUOTE;
						quote = SINGLE_QUOTE;
						off_single_quote_value = currentSymbol;
						off_value = currentSymbol + 1;
						++len_single_quote_value;
						++len_value;
						break;
					case '\0':
						currentState = FieldParser::State::END;
						break;
					case ' ':
					case '\r':
					case '\n':
					case '\t':
						currentState = FieldParser::State::INIT;
						break;
					default:
						if (++len_field >= 1024) {
							THROW(FieldParserError, "Syntax error in query");
						}
						++len_field_colon;
						currentState = FieldParser::State::FIELD;
						off_field = currentSymbol;
						off_field_colon = currentSymbol;
						break;
				}
				break;

			case FieldParser::State::FIELD:
				switch (*currentSymbol) {
					case COLON:
						currentState = FieldParser::State::START_VALUE;
						++len_field_colon;
						break;
					case '\0':
						len_value = len_field;
						off_value = off_field;
						len_field = len_field_colon = 0;
						off_field = off_field_colon = nullptr;
						return;
					case ' ':
						break;
					default:
						++len_field;
						++len_field_colon;
						break;
				}
				break;

			case FieldParser::State::START_VALUE:
				switch (*currentSymbol) {
					case DOUBLE_QUOTE:
						currentState = FieldParser::State::QUOTE;
						quote = DOUBLE_QUOTE;
						off_double_quote_value = currentSymbol;
						off_value = off_double_quote_value + 1;
						++len_double_quote_value;
						++len_value;
						break;
					case SINGLE_QUOTE:
						currentState = FieldParser::State::QUOTE;
						quote = SINGLE_QUOTE;
						off_single_quote_value = currentSymbol;
						off_value = off_single_quote_value + 1;
						++len_single_quote_value;
						++len_value;
						break;
					case SQUARE_BRACKET_LEFT:
						currentState = FieldParser::State::SQUARE_BRACKET_INIT;
						off_value = currentSymbol;
						++len_value;
						isrange = true;
						break;
					case '\0':
						currentState = FieldParser::State::END;
						break;
					default:
						currentState = FieldParser::State::VALUE;
						off_value = currentSymbol;
						++len_value;
						break;
				}
				break;

			case FieldParser::State::QUOTE:
				switch (*currentSymbol) {
					case '\\':
						currentState = FieldParser::State::ESCAPE;
						oldState = FieldParser::State::QUOTE;
						++len_value;
						switch (quote) {
							case DOUBLE_QUOTE:
								++len_double_quote_value;
								break;
							case SINGLE_QUOTE:
								++len_single_quote_value;
								break;
						}
						break;
					case '\0':
						THROW(FieldParserError, "Expected symbol: '%c'", quote);
					default:
						if (*currentSymbol == quote) {
							currentState = FieldParser::State::COLON_OR_END;
							switch (quote) {
								case DOUBLE_QUOTE:
									++len_double_quote_value;
									--len_value;	// subtract the last quote count
									break;
								case SINGLE_QUOTE:
									++len_single_quote_value;
									--len_value;	// subtract the last quote count
									break;
							}
						} else {
							++len_value;
							switch (quote) {
								case DOUBLE_QUOTE:
									++len_double_quote_value;
									break;
								case SINGLE_QUOTE:
									++len_single_quote_value;
									break;
							}
						}
						break;
				}
				break;

			case FieldParser::State::COLON_OR_END:
				switch (*currentSymbol) {
					case '\0':
						currentState = FieldParser::State::END;
						break;

					case COLON:
						currentState = FieldParser::State::START_VALUE;
						switch (quote) {
							case SINGLE_QUOTE:
								off_field = off_value;
								len_field = len_value;
								off_value = nullptr;
								len_value = 0;
								off_single_quote_value = nullptr;
								break;

							case DOUBLE_QUOTE:
								off_field = off_value;
								len_field = len_value;
								off_value = nullptr;
								len_value = 0;
								off_double_quote_value = nullptr;
								break;
						}
						skip_quote = true;
						break;

					default:
						 THROW(FieldParserError, "Unexpected symbol: %c", *currentSymbol);
						break;
				}

				break;

			case FieldParser::State::ESCAPE:
				if (*currentSymbol != '\0') {
					currentState = oldState;
					switch(currentState) {
						case FieldParser::State::QUOTE:
							++len_value;
							if (quote == DOUBLE_QUOTE) {
								++len_double_quote_value;
							} else if (quote == SINGLE_QUOTE) {
								++len_single_quote_value;
							}
							break;
						case FieldParser::State::SQUARE_BRACKET_FIRST_QUOTE:
							start += *currentSymbol;
							++len_value;
							break;
						case FieldParser::State::SQUARE_BRACKET_SECOND_QUOTE:
							end += *currentSymbol;
							++len_value;
							break;
						default:
							break;
					}
				} else {
					THROW(FieldParserError, "Syntax error in query escaped");
				}
				break;

			case FieldParser::State::VALUE:
				if (*currentSymbol == '\0') {
					currentState = FieldParser::State::END;
				} else if (!isspace(*currentSymbol)) {
					++len_value;
				} else {
					THROW(FieldParserError, "Syntax error in query");
				}
				break;

			case FieldParser::State::SQUARE_BRACKET_INIT:
				switch (*currentSymbol) {
					case DOUBLE_QUOTE:
						currentState = FieldParser::State::SQUARE_BRACKET_FIRST_QUOTE;
						quote = DOUBLE_QUOTE;
						++len_value;
						break;
					case SINGLE_QUOTE:
						currentState = FieldParser::State::SQUARE_BRACKET_FIRST_QUOTE;
						quote = SINGLE_QUOTE;
						++len_value;
						break;
					case COMMA:
						currentState = FieldParser::State::SQUARE_BRACKET;
						++len_value;
						break;
					case SQUARE_BRACKET_RIGHT:
						currentState = FieldParser::State::END;
						++len_value;
						break;
					case '\0':
						THROW(FieldParserError, "Syntax error in query");
					default:
						start += *currentSymbol;
						++len_value;
						break;
				}
				break;

			case FieldParser::State::SQUARE_BRACKET:
				switch (*currentSymbol) {
					case DOUBLE_QUOTE:
						currentState = FieldParser::State::SQUARE_BRACKET_SECOND_QUOTE;
						quote = DOUBLE_QUOTE;
						++len_value;
						break;
					case SINGLE_QUOTE:
						currentState = FieldParser::State::SQUARE_BRACKET_SECOND_QUOTE;
						quote = SINGLE_QUOTE;
						++len_value;
						break;
					case SQUARE_BRACKET_RIGHT:
						currentState = FieldParser::State::END;
						++len_value;
						break;
					case '\0':
						THROW(FieldParserError, "Expected symbol: ']'");
					default:
						end += *currentSymbol;
						++len_value;
						break;
				}
				break;

			case FieldParser::State::SQUARE_BRACKET_FIRST_QUOTE:
				switch (*currentSymbol) {
					case '\\':
						currentState = FieldParser::State::ESCAPE;
						oldState = FieldParser::State::SQUARE_BRACKET_FIRST_QUOTE;
						++len_value;
						break;
					case '\0':
						break;
					default:
						if (*currentSymbol == quote) {
							currentState = FieldParser::State::SQUARE_BRACKET_COMMA_OR_END;
						} else {
							start += *currentSymbol;
						}
						++len_value;
						break;
				}
				break;

			case FieldParser::State::SQUARE_BRACKET_COMMA_OR_END:
				switch (*currentSymbol) {
					case COMMA:
						currentState = FieldParser::State::SQUARE_BRACKET;
						++len_value;
						break;
					case SQUARE_BRACKET_RIGHT:
						currentState = FieldParser::State::END;
						++len_value;
						break;
					default:
						THROW(FieldParserError, "Unexpected symbol: %c", *currentSymbol);
				}
				break;

			case FieldParser::State::SQUARE_BRACKET_SECOND_QUOTE:
				switch (*currentSymbol) {
					case '\\':
						currentState = FieldParser::State::ESCAPE;
						oldState = FieldParser::State::SQUARE_BRACKET_SECOND_QUOTE;
						++len_value;
						break;
					case '\0':
						break;
					default:
						if (*currentSymbol == quote) {
							currentState = FieldParser::State::SQUARE_BRACKET_END;
						} else {
							end += *currentSymbol;
						}
						++len_value;
						break;
				}
				break;

			case FieldParser::State::SQUARE_BRACKET_END:
				if (*currentSymbol == SQUARE_BRACKET_RIGHT) {
					currentState = FieldParser::State::END;
					++len_value;
				} else {
					THROW(FieldParserError, "Expected symbol: ']'");
				}
				break;

			case FieldParser::State::END: {
				return;
			}
		}

		++currentSymbol;
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/login/existing_user_controller.h"

#include <algorithm>
#include <functional>
#include <map>

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/message_loop.h"
#include "base/stl_util-inl.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/login_library.h"
#include "chrome/browser/chromeos/cros/network_library.h"
#include "chrome/browser/chromeos/login/authenticator.h"
#include "chrome/browser/chromeos/login/background_view.h"
#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/login_utils.h"
#include "chrome/browser/chromeos/login/message_bubble.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/wm_ipc.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/profile_manager.h"
#include "grit/theme_resources.h"
#include "views/screen.h"
#include "views/widget/widget.h"
#include "views/widget/widget_gtk.h"
#include "views/window/window.h"

namespace chromeos {

namespace {

// Max number of users we'll show. The true max is the min of this and the
// number of windows that fit on the screen.
const size_t kMaxUsers = 6;

// Used to indicate no user has been selected.
const size_t kNotSelected = -1;

// ClientLogin response parameters.
const char kError[] = "Error=";
const char kCaptchaError[] = "CaptchaRequired";
const char kCaptchaUrlParam[] = "CaptchaUrl=";
const char kCaptchaTokenParam[] = "CaptchaToken=";
const char kParamSuffix[] = "\n";

// URL prefix for CAPTCHA image.
const char kCaptchaUrlPrefix[] = "http://www.google.com/accounts/";

// Checks if display names are unique. If there are duplicates, enables
// tooltips with full emails to let users distinguish their accounts.
// Otherwise, disables the tooltips.
void EnableTooltipsIfNeeded(const std::vector<UserController*>& controllers) {
  std::map<std::string, int> visible_display_names;
  for (size_t i = 0; i + 1 < controllers.size(); ++i) {
    const std::string& display_name =
        controllers[i]->user().GetDisplayName();
    ++visible_display_names[display_name];
  }
  for (size_t i = 0; i + 1 < controllers.size(); ++i) {
    const std::string& display_name =
        controllers[i]->user().GetDisplayName();
    bool show_tooltip = visible_display_names[display_name] > 1;
    controllers[i]->EnableNameTooltip(show_tooltip);
  }
}

}  // namespace

ExistingUserController*
  ExistingUserController::delete_scheduled_instance_ = NULL;

ExistingUserController::ExistingUserController(
    const std::vector<UserManager::User>& users,
    const gfx::Rect& background_bounds)
    : background_bounds_(background_bounds),
      background_window_(NULL),
      background_view_(NULL),
      selected_view_index_(kNotSelected),
      bubble_(NULL) {
  if (delete_scheduled_instance_)
    delete_scheduled_instance_->Delete();

  // Caclulate the max number of users from available screen size.
  size_t max_users = kMaxUsers;
  int screen_width = background_bounds.width();
  if (screen_width > 0) {
    max_users = std::max(static_cast<size_t>(2), std::min(kMaxUsers,
        static_cast<size_t>((screen_width - login::kUserImageSize)
                            / (UserController::kUnselectedSize +
                               UserController::kPadding))));
  }

  size_t visible_users_count = std::min(users.size(), max_users - 1);
  for (size_t i = 0; i < visible_users_count; ++i)
    controllers_.push_back(new UserController(this, users[i]));

  // Add the view representing the guest user last.
  controllers_.push_back(new UserController(this));
}

void ExistingUserController::Init() {
  if (!background_window_) {
    background_window_ = BackgroundView::CreateWindowContainingView(
        background_bounds_,
        &background_view_);
    background_window_->Show();
  }
  for (size_t i = 0; i < controllers_.size(); ++i) {
    (controllers_[i])->Init(static_cast<int>(i),
                            static_cast<int>(controllers_.size()));
  }

  EnableTooltipsIfNeeded(controllers_);

  WmMessageListener::instance()->AddObserver(this);

  if (CrosLibrary::Get()->EnsureLoaded())
    CrosLibrary::Get()->GetLoginLibrary()->EmitLoginPromptReady();
}

void ExistingUserController::OwnBackground(
    views::Widget* background_widget,
    chromeos::BackgroundView* background_view) {
  DCHECK(!background_window_);
  background_window_ = background_widget;
  background_view_ = background_view;
}

ExistingUserController::~ExistingUserController() {
  ClearErrors();

  if (background_window_)
    background_window_->Close();

  WmMessageListener::instance()->RemoveObserver(this);

  STLDeleteElements(&controllers_);
}

void ExistingUserController::Delete() {
  delete_scheduled_instance_ = NULL;
  delete this;
}

void ExistingUserController::ProcessWmMessage(const WmIpc::Message& message,
                                              GdkWindow* window) {
  if (message.type() != WM_IPC_MESSAGE_CHROME_CREATE_GUEST_WINDOW)
    return;

  ActivateWizard(std::string());
}

void ExistingUserController::SendSetLoginState(bool is_enabled) {
  WmIpc::Message message(WM_IPC_MESSAGE_WM_SET_LOGIN_STATE);
  message.set_param(0, is_enabled);
  WmIpc::instance()->SendMessage(message);
}

void ExistingUserController::Login(UserController* source,
                                   const string16& password) {
  std::vector<UserController*>::const_iterator i =
      std::find(controllers_.begin(), controllers_.end(), source);
  DCHECK(i != controllers_.end());
  selected_view_index_ = i - controllers_.begin();

  authenticator_ = LoginUtils::Get()->CreateAuthenticator(this);
  Profile* profile = g_browser_process->profile_manager()->GetDefaultProfile();
  ChromeThread::PostTask(
      ChromeThread::UI, FROM_HERE,
      NewRunnableMethod(authenticator_.get(),
                        &Authenticator::AuthenticateToLogin,
                        profile,
                        controllers_[selected_view_index_]->user().email(),
                        UTF16ToUTF8(password),
                        login_token_,
                        login_captcha_));

  // Disable clicking on other windows.
  SendSetLoginState(false);
}

void ExistingUserController::LoginOffTheRecord() {
  authenticator_ = LoginUtils::Get()->CreateAuthenticator(this);
  ChromeThread::PostTask(
      ChromeThread::UI, FROM_HERE,
      NewRunnableMethod(authenticator_.get(),
                        &Authenticator::LoginOffTheRecord));

  // Disable clicking on other windows.
  SendSetLoginState(false);
}

void ExistingUserController::ClearErrors() {
  // bubble_ will be set to NULL in callback.
  if (bubble_)
    bubble_->Close();
}

void ExistingUserController::OnUserSelected(UserController* source) {
  std::vector<UserController*>::const_iterator i =
      std::find(controllers_.begin(), controllers_.end(), source);
  DCHECK(i != controllers_.end());
  size_t new_selected_index = i - controllers_.begin();
  if (new_selected_index != selected_view_index_ &&
      selected_view_index_ != kNotSelected) {
    controllers_[selected_view_index_]->ClearAndEnablePassword();
    ClearCaptchaState();
  }
  selected_view_index_ = new_selected_index;
}

void ExistingUserController::ActivateWizard(const std::string& screen_name) {
  // WizardController takes care of deleting itself when done.
  WizardController* controller = new WizardController();
  controller->Init(screen_name, background_bounds_);
  controller->Show();

  // Give the background window to the controller.
  controller->OwnBackground(background_window_, background_view_);
  background_window_ = NULL;

  // And schedule us for deletion. We delay for a second as the window manager
  // is doing an animation with our windows.
  DCHECK(!delete_scheduled_instance_);
  delete_scheduled_instance_ = this;
  delete_timer_.Start(base::TimeDelta::FromSeconds(1), this,
                      &ExistingUserController::Delete);
}

void ExistingUserController::RemoveUser(UserController* source) {
  ClearErrors();

  UserManager::Get()->RemoveUser(source->user().email());

  // We need to unmap entry windows, the windows will be unmapped in destructor.
  controllers_.erase(controllers_.begin() + source->user_index());
  delete source;

  EnableTooltipsIfNeeded(controllers_);
  int new_size = static_cast<int>(controllers_.size());
  for (int i = 0; i < new_size; ++i)
    controllers_[i]->UpdateUserCount(i, new_size);
}

void ExistingUserController::SelectUser(int index) {
  if (index >= 0 && index < static_cast<int>(controllers_.size()) &&
      index != static_cast<int>(selected_view_index_)) {
    WmIpc::Message message(WM_IPC_MESSAGE_WM_SELECT_LOGIN_USER);
    message.set_param(0, index);
    WmIpc::instance()->SendMessage(message);
  }
}

void ExistingUserController::OnLoginFailure(const std::string& error) {
  LOG(INFO) << "OnLoginFailure";
  ClearCaptchaState();

  // Check networking after trying to login in case user is
  // cached locally or the local admin account.
  NetworkLibrary* network = CrosLibrary::Get()->GetNetworkLibrary();
  if (!network || !CrosLibrary::Get()->EnsureLoaded()) {
    ShowError(IDS_LOGIN_ERROR_NO_NETWORK_LIBRARY, error);
  } else if (!network->Connected()) {
    ShowError(IDS_LOGIN_ERROR_OFFLINE_FAILED_NETWORK_NOT_CONNECTED, error);
  } else {
    std::string error_code = LoginUtils::ExtractClientLoginParam(error,
                                                                 kError,
                                                                 kParamSuffix);
    std::string captcha_url;
    if (error_code == kCaptchaError)
      captcha_url = LoginUtils::ExtractClientLoginParam(error,
                                                        kCaptchaUrlParam,
                                                        kParamSuffix);
    if (captcha_url.empty()) {
      ShowError(IDS_LOGIN_ERROR_AUTHENTICATING, error);
    } else {
      // Save token for next login retry.
      login_token_ = LoginUtils::ExtractClientLoginParam(error,
                                                         kCaptchaTokenParam,
                                                         kParamSuffix);
      gfx::NativeWindow parent = GTK_WINDOW(
          static_cast<views::WidgetGtk*>(background_window_)->GetNativeView());
      CaptchaView* view =
          new CaptchaView(GURL(kCaptchaUrlPrefix + captcha_url));
      view->set_delegate(this);
      views::Window* window = views::Window::CreateChromeWindow(parent,
                                                                gfx::Rect(),
                                                                view);
      window->SetIsAlwaysOnTop(true);
      window->Show();
    }
  }

  controllers_[selected_view_index_]->ClearAndEnablePassword();

  // Reenable clicking on other windows.
  SendSetLoginState(true);
}

void ExistingUserController::AppendStartUrlToCmdline() {
  if (start_url_.is_valid()) {
    CommandLine::ForCurrentProcess()->AppendLooseValue(
        UTF8ToWide(start_url_.spec()));
  }
}

void ExistingUserController::ClearCaptchaState() {
  login_token_.clear();
  login_captcha_.clear();
}

void ExistingUserController::ShowError(int error_id,
                                       const std::string& details) {
  ClearErrors();
  std::wstring error_text = l10n_util::GetString(error_id);
  if (!details.empty())
    error_text += L"\n" + ASCIIToWide(details);
  bubble_ = MessageBubble::Show(
      controllers_[selected_view_index_]->controls_window(),
      controllers_[selected_view_index_]->GetScreenBounds(),
      BubbleBorder::BOTTOM_LEFT,
      ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_WARNING),
      error_text,
      this);
}

void ExistingUserController::OnLoginSuccess(const std::string& username,
                                            const std::string& credentials) {
  AppendStartUrlToCmdline();
  if (selected_view_index_ + 1 == controllers_.size()) {
    // For new user login don't launch browser until we pass image screen.
    chromeos::LoginUtils::Get()->EnableBrowserLaunch(false);
    LoginUtils::Get()->CompleteLogin(username, credentials);
    ActivateWizard(WizardController::kUserImageScreenName);
  } else {
    // Hide the login windows now.
    STLDeleteElements(&controllers_);

    background_window_->Close();

    LoginUtils::Get()->CompleteLogin(username, credentials);
    // Delay deletion as we're on the stack.
    MessageLoop::current()->DeleteSoon(FROM_HERE, this);
  }
}

void ExistingUserController::OnOffTheRecordLoginSuccess() {
  AppendStartUrlToCmdline();
  LoginUtils::Get()->CompleteOffTheRecordLogin();
}

void ExistingUserController::OnCaptchaEntered(const std::string& captcha) {
  login_captcha_ = captcha;
}

}  // namespace chromeos
<commit_msg>Hide login entries before removing them to prevent flickering.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/login/existing_user_controller.h"

#include <algorithm>
#include <functional>
#include <map>

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/message_loop.h"
#include "base/stl_util-inl.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/login_library.h"
#include "chrome/browser/chromeos/cros/network_library.h"
#include "chrome/browser/chromeos/login/authenticator.h"
#include "chrome/browser/chromeos/login/background_view.h"
#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/login_utils.h"
#include "chrome/browser/chromeos/login/message_bubble.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/wm_ipc.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/profile_manager.h"
#include "grit/theme_resources.h"
#include "views/screen.h"
#include "views/widget/widget.h"
#include "views/widget/widget_gtk.h"
#include "views/window/window.h"

namespace chromeos {

namespace {

// Max number of users we'll show. The true max is the min of this and the
// number of windows that fit on the screen.
const size_t kMaxUsers = 6;

// Used to indicate no user has been selected.
const size_t kNotSelected = -1;

// ClientLogin response parameters.
const char kError[] = "Error=";
const char kCaptchaError[] = "CaptchaRequired";
const char kCaptchaUrlParam[] = "CaptchaUrl=";
const char kCaptchaTokenParam[] = "CaptchaToken=";
const char kParamSuffix[] = "\n";

// URL prefix for CAPTCHA image.
const char kCaptchaUrlPrefix[] = "http://www.google.com/accounts/";

// Checks if display names are unique. If there are duplicates, enables
// tooltips with full emails to let users distinguish their accounts.
// Otherwise, disables the tooltips.
void EnableTooltipsIfNeeded(const std::vector<UserController*>& controllers) {
  std::map<std::string, int> visible_display_names;
  for (size_t i = 0; i + 1 < controllers.size(); ++i) {
    const std::string& display_name =
        controllers[i]->user().GetDisplayName();
    ++visible_display_names[display_name];
  }
  for (size_t i = 0; i + 1 < controllers.size(); ++i) {
    const std::string& display_name =
        controllers[i]->user().GetDisplayName();
    bool show_tooltip = visible_display_names[display_name] > 1;
    controllers[i]->EnableNameTooltip(show_tooltip);
  }
}

}  // namespace

ExistingUserController*
  ExistingUserController::delete_scheduled_instance_ = NULL;

ExistingUserController::ExistingUserController(
    const std::vector<UserManager::User>& users,
    const gfx::Rect& background_bounds)
    : background_bounds_(background_bounds),
      background_window_(NULL),
      background_view_(NULL),
      selected_view_index_(kNotSelected),
      bubble_(NULL) {
  if (delete_scheduled_instance_)
    delete_scheduled_instance_->Delete();

  // Caclulate the max number of users from available screen size.
  size_t max_users = kMaxUsers;
  int screen_width = background_bounds.width();
  if (screen_width > 0) {
    max_users = std::max(static_cast<size_t>(2), std::min(kMaxUsers,
        static_cast<size_t>((screen_width - login::kUserImageSize)
                            / (UserController::kUnselectedSize +
                               UserController::kPadding))));
  }

  size_t visible_users_count = std::min(users.size(), max_users - 1);
  for (size_t i = 0; i < visible_users_count; ++i)
    controllers_.push_back(new UserController(this, users[i]));

  // Add the view representing the guest user last.
  controllers_.push_back(new UserController(this));
}

void ExistingUserController::Init() {
  if (!background_window_) {
    background_window_ = BackgroundView::CreateWindowContainingView(
        background_bounds_,
        &background_view_);
    background_window_->Show();
  }
  for (size_t i = 0; i < controllers_.size(); ++i) {
    (controllers_[i])->Init(static_cast<int>(i),
                            static_cast<int>(controllers_.size()));
  }

  EnableTooltipsIfNeeded(controllers_);

  WmMessageListener::instance()->AddObserver(this);

  if (CrosLibrary::Get()->EnsureLoaded())
    CrosLibrary::Get()->GetLoginLibrary()->EmitLoginPromptReady();
}

void ExistingUserController::OwnBackground(
    views::Widget* background_widget,
    chromeos::BackgroundView* background_view) {
  DCHECK(!background_window_);
  background_window_ = background_widget;
  background_view_ = background_view;
}

ExistingUserController::~ExistingUserController() {
  ClearErrors();

  if (background_window_)
    background_window_->Close();

  WmMessageListener::instance()->RemoveObserver(this);

  STLDeleteElements(&controllers_);
}

void ExistingUserController::Delete() {
  delete_scheduled_instance_ = NULL;
  delete this;
}

void ExistingUserController::ProcessWmMessage(const WmIpc::Message& message,
                                              GdkWindow* window) {
  if (message.type() != WM_IPC_MESSAGE_CHROME_CREATE_GUEST_WINDOW)
    return;

  ActivateWizard(std::string());
}

void ExistingUserController::SendSetLoginState(bool is_enabled) {
  WmIpc::Message message(WM_IPC_MESSAGE_WM_SET_LOGIN_STATE);
  message.set_param(0, is_enabled);
  WmIpc::instance()->SendMessage(message);
}

void ExistingUserController::Login(UserController* source,
                                   const string16& password) {
  std::vector<UserController*>::const_iterator i =
      std::find(controllers_.begin(), controllers_.end(), source);
  DCHECK(i != controllers_.end());
  selected_view_index_ = i - controllers_.begin();

  authenticator_ = LoginUtils::Get()->CreateAuthenticator(this);
  Profile* profile = g_browser_process->profile_manager()->GetDefaultProfile();
  ChromeThread::PostTask(
      ChromeThread::UI, FROM_HERE,
      NewRunnableMethod(authenticator_.get(),
                        &Authenticator::AuthenticateToLogin,
                        profile,
                        controllers_[selected_view_index_]->user().email(),
                        UTF16ToUTF8(password),
                        login_token_,
                        login_captcha_));

  // Disable clicking on other windows.
  SendSetLoginState(false);
}

void ExistingUserController::LoginOffTheRecord() {
  authenticator_ = LoginUtils::Get()->CreateAuthenticator(this);
  ChromeThread::PostTask(
      ChromeThread::UI, FROM_HERE,
      NewRunnableMethod(authenticator_.get(),
                        &Authenticator::LoginOffTheRecord));

  // Disable clicking on other windows.
  SendSetLoginState(false);
}

void ExistingUserController::ClearErrors() {
  // bubble_ will be set to NULL in callback.
  if (bubble_)
    bubble_->Close();
}

void ExistingUserController::OnUserSelected(UserController* source) {
  std::vector<UserController*>::const_iterator i =
      std::find(controllers_.begin(), controllers_.end(), source);
  DCHECK(i != controllers_.end());
  size_t new_selected_index = i - controllers_.begin();
  if (new_selected_index != selected_view_index_ &&
      selected_view_index_ != kNotSelected) {
    controllers_[selected_view_index_]->ClearAndEnablePassword();
    ClearCaptchaState();
  }
  selected_view_index_ = new_selected_index;
}

void ExistingUserController::ActivateWizard(const std::string& screen_name) {
  // WizardController takes care of deleting itself when done.
  WizardController* controller = new WizardController();
  controller->Init(screen_name, background_bounds_);
  controller->Show();

  // Give the background window to the controller.
  controller->OwnBackground(background_window_, background_view_);
  background_window_ = NULL;

  // And schedule us for deletion. We delay for a second as the window manager
  // is doing an animation with our windows.
  DCHECK(!delete_scheduled_instance_);
  delete_scheduled_instance_ = this;
  delete_timer_.Start(base::TimeDelta::FromSeconds(1), this,
                      &ExistingUserController::Delete);
}

void ExistingUserController::RemoveUser(UserController* source) {
  ClearErrors();

  UserManager::Get()->RemoveUser(source->user().email());

  // We need to unmap entry windows, the windows will be unmapped in destructor.
  controllers_.erase(controllers_.begin() + source->user_index());
  delete source;

  EnableTooltipsIfNeeded(controllers_);
  int new_size = static_cast<int>(controllers_.size());
  for (int i = 0; i < new_size; ++i)
    controllers_[i]->UpdateUserCount(i, new_size);
}

void ExistingUserController::SelectUser(int index) {
  if (index >= 0 && index < static_cast<int>(controllers_.size()) &&
      index != static_cast<int>(selected_view_index_)) {
    WmIpc::Message message(WM_IPC_MESSAGE_WM_SELECT_LOGIN_USER);
    message.set_param(0, index);
    WmIpc::instance()->SendMessage(message);
  }
}

void ExistingUserController::OnLoginFailure(const std::string& error) {
  LOG(INFO) << "OnLoginFailure";
  ClearCaptchaState();

  // Check networking after trying to login in case user is
  // cached locally or the local admin account.
  NetworkLibrary* network = CrosLibrary::Get()->GetNetworkLibrary();
  if (!network || !CrosLibrary::Get()->EnsureLoaded()) {
    ShowError(IDS_LOGIN_ERROR_NO_NETWORK_LIBRARY, error);
  } else if (!network->Connected()) {
    ShowError(IDS_LOGIN_ERROR_OFFLINE_FAILED_NETWORK_NOT_CONNECTED, error);
  } else {
    std::string error_code = LoginUtils::ExtractClientLoginParam(error,
                                                                 kError,
                                                                 kParamSuffix);
    std::string captcha_url;
    if (error_code == kCaptchaError)
      captcha_url = LoginUtils::ExtractClientLoginParam(error,
                                                        kCaptchaUrlParam,
                                                        kParamSuffix);
    if (captcha_url.empty()) {
      ShowError(IDS_LOGIN_ERROR_AUTHENTICATING, error);
    } else {
      // Save token for next login retry.
      login_token_ = LoginUtils::ExtractClientLoginParam(error,
                                                         kCaptchaTokenParam,
                                                         kParamSuffix);
      gfx::NativeWindow parent = GTK_WINDOW(
          static_cast<views::WidgetGtk*>(background_window_)->GetNativeView());
      CaptchaView* view =
          new CaptchaView(GURL(kCaptchaUrlPrefix + captcha_url));
      view->set_delegate(this);
      views::Window* window = views::Window::CreateChromeWindow(parent,
                                                                gfx::Rect(),
                                                                view);
      window->SetIsAlwaysOnTop(true);
      window->Show();
    }
  }

  controllers_[selected_view_index_]->ClearAndEnablePassword();

  // Reenable clicking on other windows.
  SendSetLoginState(true);
}

void ExistingUserController::AppendStartUrlToCmdline() {
  if (start_url_.is_valid()) {
    CommandLine::ForCurrentProcess()->AppendLooseValue(
        UTF8ToWide(start_url_.spec()));
  }
}

void ExistingUserController::ClearCaptchaState() {
  login_token_.clear();
  login_captcha_.clear();
}

void ExistingUserController::ShowError(int error_id,
                                       const std::string& details) {
  ClearErrors();
  std::wstring error_text = l10n_util::GetString(error_id);
  if (!details.empty())
    error_text += L"\n" + ASCIIToWide(details);
  bubble_ = MessageBubble::Show(
      controllers_[selected_view_index_]->controls_window(),
      controllers_[selected_view_index_]->GetScreenBounds(),
      BubbleBorder::BOTTOM_LEFT,
      ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_WARNING),
      error_text,
      this);
}

void ExistingUserController::OnLoginSuccess(const std::string& username,
                                            const std::string& credentials) {
  AppendStartUrlToCmdline();
  if (selected_view_index_ + 1 == controllers_.size()) {
    // For new user login don't launch browser until we pass image screen.
    chromeos::LoginUtils::Get()->EnableBrowserLaunch(false);
    LoginUtils::Get()->CompleteLogin(username, credentials);
    ActivateWizard(WizardController::kUserImageScreenName);
  } else {
    // Hide the login windows now.
    WmIpc::Message message(WM_IPC_MESSAGE_WM_HIDE_LOGIN);
    WmIpc::instance()->SendMessage(message);

    LoginUtils::Get()->CompleteLogin(username, credentials);

    // Delay deletion as we're on the stack.
    MessageLoop::current()->DeleteSoon(FROM_HERE, this);
  }
}

void ExistingUserController::OnOffTheRecordLoginSuccess() {
  AppendStartUrlToCmdline();
  LoginUtils::Get()->CompleteOffTheRecordLogin();
}

void ExistingUserController::OnCaptchaEntered(const std::string& captcha) {
  login_captcha_ = captcha;
}

}  // namespace chromeos
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_FUN_HYPERGEOMETRIC_2F1_HPP
#define STAN_MATH_PRIM_FUN_HYPERGEOMETRIC_2F1_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/fun/abs.hpp>
#include <stan/math/prim/fun/asin.hpp>
#include <stan/math/prim/fun/asinh.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/digamma.hpp>
#include <stan/math/prim/fun/exp.hpp>
#include <stan/math/prim/fun/floor.hpp>
#include <stan/math/prim/fun/inv.hpp>
#include <stan/math/prim/fun/log.hpp>
#include <stan/math/prim/fun/lgamma.hpp>
#include <stan/math/prim/fun/pow.hpp>
#include <stan/math/prim/fun/sqrt.hpp>
#include <stan/math/prim/fun/square.hpp>
#include <stan/math/prim/fun/hypergeometric_pFq.hpp>
#include <boost/optional.hpp>

namespace stan {
namespace math {
namespace internal {

/**
 * Calculate the Gauss Hypergeometric (2F1) function for special-case
 * combinations of parameters which can be calculated in closed-form. For
 * more background (and other possible special-cases), see:
 * https://functions.wolfram.com/HypergeometricFunctions/Hypergeometric2F1/03/
 *
 * The return value is wrapped in a boost::optional<> type so that a void
 * return is possible if no special-case rules are applicable
 *
 * @tparam Ta1 Type of scalar first 'a' argument
 * @tparam Ta2 Type of scalar second 'a' argument
 * @tparam Tb Type of scalar 'b' argument
 * @tparam Tz Type of scalar 'z' argument
 * @param[in] a1 First of 'a' arguments to function
 * @param[in] a2 Second of 'a' arguments to function
 * @param[in] b 'b' argument to function
 * @param[in] z Scalar z argument
 * @return Gauss hypergeometric function
 */
template <typename Ta1, typename Ta2, typename Tb, typename Tz,
          typename RtnT = boost::optional<return_type_t<Ta1, Ta1, Tb, Tz>>,
          require_all_arithmetic_t<Ta1, Ta2, Tb, Tz>* = nullptr>
inline RtnT hyper_2F1_special_cases(const Ta1& a1, const Ta2& a2, const Tb& b,
                                    const Tz& z) {
  // https://functions.wolfram.com/HypergeometricFunctions/Hypergeometric2F1/03/01/
  // // NOLINT
  if (z == 0.0) {
    return 1.0;
  }

  // https://functions.wolfram.com/HypergeometricFunctions/Hypergeometric2F1/03/06/01/0001/
  // // NOLINT
  if (a1 == b) {
    return inv(pow(1.0 - z, a2));
  }

  // https://functions.wolfram.com/HypergeometricFunctions/Hypergeometric2F1/03/06/01/0003/
  // // NOLINT
  if (b == (a2 - 1.0)) {
    return (pow((1.0 - z), -a1 - 1.0) * (a2 + z * (a1 - a2 + 1.0) - 1.0))
           / (a2 - 1);
  }

  if (a1 == a2) {
    // https://www.wolframalpha.com/input?i=Hypergeometric2F1%281%2C+1%2C+2%2C+-z%29
    // // NOLINT
    if (a1 == 1.0 && b == 2.0 && z < 0) {
      auto pos_z = abs(z);
      return log1p(pos_z) / pos_z;
    }

    if (a1 == 0.5 && b == 1.5 && z < 1.0) {
      auto sqrt_z = sqrt(abs(z));
      auto numerator = (z > 0.0)
                           // https://www.wolframalpha.com/input?i=Hypergeometric2F1%281%2F2%2C+1%2F2%2C+3%2F2%2C+z%29
                           // // NOLINT
                           ? asin(sqrt_z)
                           // https://www.wolframalpha.com/input?i=Hypergeometric2F1%281%2F2%2C+1%2F2%2C+3%2F2%2C+-z%29
                           // // NOLINT
                           : asinh(sqrt_z);
      return numerator / sqrt_z;
    }

    // https://functions.wolfram.com/HypergeometricFunctions/Hypergeometric2F1/03/04/03/
    // // NOLINT
    if (b == (a1 + 1) && z == 0.5) {
      return pow(2, a1 - 1) * a1
             * (digamma((a1 + 1) / 2.0) - digamma(a1 / 2.0));
    }
  }

  if (z == 1.0) {
    // https://www.wolframalpha.com/input?i=Hypergeometric2F1%28a1%2C+a2%2C+a1+%2B+a2+%2B+2%2C+1%29
    // // NOLINT
    if (b == (a1 + a2 + 2)) {
      auto log_2f1 = lgamma(b) - (lgamma(a1 + 2) + lgamma(a2 + 2));
      return exp(log_2f1);
      // https://functions.wolfram.com/HypergeometricFunctions/Hypergeometric2F1/03/02/0001/
      // // NOLINT
    } else if (b > (a1 + a2)) {
      auto log_2f1 = (lgamma(b) + lgamma(b - a1 - a2))
                     - (lgamma(b - a1) + lgamma(b - a2));
      return exp(log_2f1);
    }
  }

  // https://www.wolframalpha.com/input?i=Hypergeometric2F1%283%2F2%2C+2%2C+3%2C+-z%29
  // // NOLINT
  if (a1 == 1.5 && a2 == 2.0 && b == 3.0 && z < 0.0) {
    auto abs_z = abs(z);
    auto sqrt_1pz = sqrt(1 + abs_z);
    return -4 * (2 * sqrt_1pz + z - 2) / (sqrt_1pz * square(z));
  }

  return {};
}
}  // namespace internal

/**
 * Returns the Gauss hypergeometric function applied to the
 * input arguments:
 * \f$_2F_1(a_1,a_2;b;z)\f$
 *
 * If the input parameters do not meet convergence criteria, then Euler's
 * transformation is applied to resolve this:
 * https://mathworld.wolfram.com/EulerTransform.html
 *
 * For some special-case combinations of parameters the series is calculated
 * in closed form, see the internal::hyper_2F1_special_cases function for more
 * details.
 *
 * See 'grad_2F1.hpp' for the derivatives wrt each parameter
 *
 * @tparam Ta1 Type of scalar first 'a' argument
 * @tparam Ta2 Type of scalar second 'a' argument
 * @tparam Tb Type of scalar 'b' argument
 * @tparam Tz Type of scalar 'z' argument
 * @param[in] a1 First of 'a' arguments to function
 * @param[in] a2 Second of 'a' arguments to function
 * @param[in] b 'b' argument to function
 * @param[in] z Scalar z argument
 * @return Gauss hypergeometric function
 */
template <typename Ta1, typename Ta2, typename Tb, typename Tz,
          typename ScalarT = return_type_t<Ta1, Ta1, Tb, Tz>,
          typename OptT = boost::optional<ScalarT>,
          require_all_arithmetic_t<Ta1, Ta2, Tb, Tz>* = nullptr>
inline return_type_t<Ta1, Ta1, Tb, Tz> hypergeometric_2F1(const Ta1& a1,
                                                          const Ta2& a2,
                                                          const Tb& b,
                                                          const Tz& z) {
  check_finite("hypergeometric_2F1", "a1", a1);
  check_finite("hypergeometric_2F1", "a2", a2);
  check_finite("hypergeometric_2F1", "b", b);
  check_finite("hypergeometric_2F1", "z", z);

  check_not_nan("hypergeometric_2F1", "a1", a1);
  check_not_nan("hypergeometric_2F1", "a2", a2);
  check_not_nan("hypergeometric_2F1", "b", b);
  check_not_nan("hypergeometric_2F1", "z", z);

  // Check whether value can be calculated by any special-case rules
  // before estimating infinite sum
  OptT special_case_a1a2 = internal::hyper_2F1_special_cases(a1, a2, b, z);
  if (special_case_a1a2.is_initialized()) {
    return special_case_a1a2.get();
  }

  // Check whether any special case rules apply with 'a' arguments reversed
  // as 2F1(a1, a2, b, z) = 2F1(a2, a1, b, z)
  OptT special_case_a2a1 = internal::hyper_2F1_special_cases(a2, a1, b, z);
  if (special_case_a2a1.is_initialized()) {
    return special_case_a2a1.get();
  }

  Eigen::VectorXd a_args(2);
  Eigen::VectorXd b_args(1);

  try {
    check_2F1_converges("hypergeometric_2F1", a1, a2, b, z);

    a_args << a1, a2;
    b_args << b;
    return hypergeometric_pFq(a_args, b_args, z);
  } catch (...) {
    // Apply Euler's hypergeometric transformation if function
    // will not converge with current arguments
    ScalarT a1_t = b - a1;
    ScalarT a2_t = a2;
    ScalarT b_t = b;
    ScalarT z_t = z / (z - 1);

    check_2F1_converges("hypergeometric_2F1", a1_t, a2_t, b_t, z_t);

    a_args << a1_t, a2_t;
    b_args << b_t;
    return hypergeometric_pFq(a_args, b_args, z_t) / pow(1 - z, a2);
  }
}
}  // namespace math
}  // namespace stan
#endif
<commit_msg>[Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1<commit_after>#ifndef STAN_MATH_PRIM_FUN_HYPERGEOMETRIC_2F1_HPP
#define STAN_MATH_PRIM_FUN_HYPERGEOMETRIC_2F1_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/fun/abs.hpp>
#include <stan/math/prim/fun/asin.hpp>
#include <stan/math/prim/fun/asinh.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/digamma.hpp>
#include <stan/math/prim/fun/exp.hpp>
#include <stan/math/prim/fun/floor.hpp>
#include <stan/math/prim/fun/inv.hpp>
#include <stan/math/prim/fun/log.hpp>
#include <stan/math/prim/fun/lgamma.hpp>
#include <stan/math/prim/fun/pow.hpp>
#include <stan/math/prim/fun/sqrt.hpp>
#include <stan/math/prim/fun/square.hpp>
#include <stan/math/prim/fun/hypergeometric_pFq.hpp>
#include <boost/optional.hpp>

namespace stan {
namespace math {
namespace internal {

/**
 * Calculate the Gauss Hypergeometric (2F1) function for special-case
 * combinations of parameters which can be calculated in closed-form. For
 * more background (and other possible special-cases), see:
 * https://functions.wolfram.com/HypergeometricFunctions/Hypergeometric2F1/03/
 *
 * The return value is wrapped in a boost::optional<> type so that a void
 * return is possible if no special-case rules are applicable
 *
 * @tparam Ta1 Type of scalar first 'a' argument
 * @tparam Ta2 Type of scalar second 'a' argument
 * @tparam Tb Type of scalar 'b' argument
 * @tparam Tz Type of scalar 'z' argument
 * @param[in] a1 First of 'a' arguments to function
 * @param[in] a2 Second of 'a' arguments to function
 * @param[in] b 'b' argument to function
 * @param[in] z Scalar z argument
 * @return Gauss hypergeometric function
 */
template <typename Ta1, typename Ta2, typename Tb, typename Tz,
          typename RtnT = boost::optional<return_type_t<Ta1, Ta1, Tb, Tz>>,
          require_all_arithmetic_t<Ta1, Ta2, Tb, Tz>* = nullptr>
inline RtnT hyper_2F1_special_cases(const Ta1& a1, const Ta2& a2, const Tb& b,
                                    const Tz& z) {
  // https://functions.wolfram.com/HypergeometricFunctions/Hypergeometric2F1/03/01/
  // // NOLINT
  if (z == 0.0) {
    return 1.0;
  }

  // https://functions.wolfram.com/HypergeometricFunctions/Hypergeometric2F1/03/06/01/0001/
  // // NOLINT
  if (a1 == b) {
    return inv(pow(1.0 - z, a2));
  }

  // https://functions.wolfram.com/HypergeometricFunctions/Hypergeometric2F1/03/06/01/0003/
  // // NOLINT
  if (b == (a2 - 1.0)) {
    return (pow((1.0 - z), -a1 - 1.0) * (a2 + z * (a1 - a2 + 1.0) - 1.0))
           / (a2 - 1);
  }

  if (a1 == a2) {
    // https://www.wolframalpha.com/input?i=Hypergeometric2F1%281%2C+1%2C+2%2C+-z%29
    // // NOLINT
    if (a1 == 1.0 && b == 2.0 && z < 0) {
      auto pos_z = abs(z);
      return log1p(pos_z) / pos_z;
    }

    if (a1 == 0.5 && b == 1.5 && z < 1.0) {
      auto sqrt_z = sqrt(abs(z));
      auto numerator
          = (z > 0.0)
                // https://www.wolframalpha.com/input?i=Hypergeometric2F1%281%2F2%2C+1%2F2%2C+3%2F2%2C+z%29
                // // NOLINT
                ? asin(sqrt_z)
                // https://www.wolframalpha.com/input?i=Hypergeometric2F1%281%2F2%2C+1%2F2%2C+3%2F2%2C+-z%29
                // // NOLINT
                : asinh(sqrt_z);
      return numerator / sqrt_z;
    }

    // https://functions.wolfram.com/HypergeometricFunctions/Hypergeometric2F1/03/04/03/
    // // NOLINT
    if (b == (a1 + 1) && z == 0.5) {
      return pow(2, a1 - 1) * a1
             * (digamma((a1 + 1) / 2.0) - digamma(a1 / 2.0));
    }
  }

  if (z == 1.0) {
    // https://www.wolframalpha.com/input?i=Hypergeometric2F1%28a1%2C+a2%2C+a1+%2B+a2+%2B+2%2C+1%29
    // // NOLINT
    if (b == (a1 + a2 + 2)) {
      auto log_2f1 = lgamma(b) - (lgamma(a1 + 2) + lgamma(a2 + 2));
      return exp(log_2f1);
      // https://functions.wolfram.com/HypergeometricFunctions/Hypergeometric2F1/03/02/0001/
      // // NOLINT
    } else if (b > (a1 + a2)) {
      auto log_2f1 = (lgamma(b) + lgamma(b - a1 - a2))
                     - (lgamma(b - a1) + lgamma(b - a2));
      return exp(log_2f1);
    }
  }

  // https://www.wolframalpha.com/input?i=Hypergeometric2F1%283%2F2%2C+2%2C+3%2C+-z%29
  // // NOLINT
  if (a1 == 1.5 && a2 == 2.0 && b == 3.0 && z < 0.0) {
    auto abs_z = abs(z);
    auto sqrt_1pz = sqrt(1 + abs_z);
    return -4 * (2 * sqrt_1pz + z - 2) / (sqrt_1pz * square(z));
  }

  return {};
}
}  // namespace internal

/**
 * Returns the Gauss hypergeometric function applied to the
 * input arguments:
 * \f$_2F_1(a_1,a_2;b;z)\f$
 *
 * If the input parameters do not meet convergence criteria, then Euler's
 * transformation is applied to resolve this:
 * https://mathworld.wolfram.com/EulerTransform.html
 *
 * For some special-case combinations of parameters the series is calculated
 * in closed form, see the internal::hyper_2F1_special_cases function for more
 * details.
 *
 * See 'grad_2F1.hpp' for the derivatives wrt each parameter
 *
 * @tparam Ta1 Type of scalar first 'a' argument
 * @tparam Ta2 Type of scalar second 'a' argument
 * @tparam Tb Type of scalar 'b' argument
 * @tparam Tz Type of scalar 'z' argument
 * @param[in] a1 First of 'a' arguments to function
 * @param[in] a2 Second of 'a' arguments to function
 * @param[in] b 'b' argument to function
 * @param[in] z Scalar z argument
 * @return Gauss hypergeometric function
 */
template <typename Ta1, typename Ta2, typename Tb, typename Tz,
          typename ScalarT = return_type_t<Ta1, Ta1, Tb, Tz>,
          typename OptT = boost::optional<ScalarT>,
          require_all_arithmetic_t<Ta1, Ta2, Tb, Tz>* = nullptr>
inline return_type_t<Ta1, Ta1, Tb, Tz> hypergeometric_2F1(const Ta1& a1,
                                                          const Ta2& a2,
                                                          const Tb& b,
                                                          const Tz& z) {
  check_finite("hypergeometric_2F1", "a1", a1);
  check_finite("hypergeometric_2F1", "a2", a2);
  check_finite("hypergeometric_2F1", "b", b);
  check_finite("hypergeometric_2F1", "z", z);

  check_not_nan("hypergeometric_2F1", "a1", a1);
  check_not_nan("hypergeometric_2F1", "a2", a2);
  check_not_nan("hypergeometric_2F1", "b", b);
  check_not_nan("hypergeometric_2F1", "z", z);

  // Check whether value can be calculated by any special-case rules
  // before estimating infinite sum
  OptT special_case_a1a2 = internal::hyper_2F1_special_cases(a1, a2, b, z);
  if (special_case_a1a2.is_initialized()) {
    return special_case_a1a2.get();
  }

  // Check whether any special case rules apply with 'a' arguments reversed
  // as 2F1(a1, a2, b, z) = 2F1(a2, a1, b, z)
  OptT special_case_a2a1 = internal::hyper_2F1_special_cases(a2, a1, b, z);
  if (special_case_a2a1.is_initialized()) {
    return special_case_a2a1.get();
  }

  Eigen::VectorXd a_args(2);
  Eigen::VectorXd b_args(1);

  try {
    check_2F1_converges("hypergeometric_2F1", a1, a2, b, z);

    a_args << a1, a2;
    b_args << b;
    return hypergeometric_pFq(a_args, b_args, z);
  } catch (...) {
    // Apply Euler's hypergeometric transformation if function
    // will not converge with current arguments
    ScalarT a1_t = b - a1;
    ScalarT a2_t = a2;
    ScalarT b_t = b;
    ScalarT z_t = z / (z - 1);

    check_2F1_converges("hypergeometric_2F1", a1_t, a2_t, b_t, z_t);

    a_args << a1_t, a2_t;
    b_args << b_t;
    return hypergeometric_pFq(a_args, b_args, z_t) / pow(1 - z, a2);
  }
}
}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>
/**
 * \file
 * \brief Main file for printstrings tool
 * \date 8-8-2012
 * \author Gonzalo Iglesias
 */

#include <main.custom_assert.hpp>
#include <main.logger.hpp>
#include <main.printstrings.hpp>

typedef std::tr1::unordered_map<std::size_t, std::string> labelmap_t;
typedef labelmap_t::iterator labelmap_iterator_t;
labelmap_t vmap;
bool printweight = false;
bool sparseformat = false;

using fst::Hyp;

/**
 * \brief Same as Hyp but the printing will convert integer ids to words.
 */
template<class Arc>
struct HypW: public Hyp<Arc> {

  HypW (std::basic_string<unsigned> const& h, typename Arc::Weight const& c)
    : Hyp<Arc> (h, c) {
  }
  HypW (HypW<Arc> const& h)
    : Hyp<Arc> (h) {
  }
};

/**
 * \brief Templated method that prints an arc weight. By default, reuses
 * the operator<< already defined for each weight.
 * \param weight The arc weight to be printed
 * \param os The output stream to print to
 */
template <class Arc>
void printWeight (typename Arc::Weight const& weight, std::ostream& os) {
  os << weight;
}

/**
 * \brief Template specialization of printWeight for a tropical sparse
 * tuple weight. Uses the global var sparseformat.
 * For the non sparse format, the comma separator is hard coded.
 * \param weight The arc weight to be printed
 * \param sparseformat Whether to print in sparse format or not.
 * \param os The output stream to print to
 */
template <>
void printWeight<TupleArc32> (const TupleW32& weight, std::ostream& os) {
  if (sparseformat) {
    os << weight;
  } else {
    // size of the parameter vector
    std::size_t nonSparseSize = TupleW32::Params().size();
    std::size_t counter = 1;
    std::string separator ("");
    for (fst::SparseTupleWeightIterator<fst::TropicalWeight, int> it (weight);
         !it.Done(); it.Next() ) {
      std::size_t featureIndex = it.Value().first;
      for (std::size_t featureMissingIndex = counter;
           featureMissingIndex < featureIndex; ++featureMissingIndex) {
        os << separator << "0";
        separator = ",";
        counter++;
      }
      os << separator << it.Value().second;
      separator = ",";
      counter++;
    }
    for (; counter <= nonSparseSize; ++counter) {
      os << separator << "0";
      separator = ",";
    }
  }
}

/**
 * \brief Operator<< overloading to print a hypothesis.
 */
template<class Arc>
std::ostream& operator<< (std::ostream& os, const Hyp<Arc>& obj) {
  for (unsigned k = 0; k < obj.hyp.size(); ++k) {
    if (obj.hyp[k] == OOV) continue;
    if (obj.hyp[k] == DR) continue;
    if (obj.hyp[k] == EPSILON) continue;
    if (obj.hyp[k] == SEP) continue;
    os << obj.hyp[k] << " ";
  }
  if (printweight) {
    os << "\t";
    printWeight<Arc> (obj.cost, os);
  };
  return os;
}

/**
 * \brief Operator<< overloading to print a hypothesis.
 * Integer are converted to words using the global variable wmap.
 */
template<class Arc>
std::ostream& operator<< (std::ostream& os, const HypW<Arc>& obj) {
  for (unsigned k = 0; k < obj.hyp.size(); ++k) {
    if (obj.hyp[k] == OOV) continue;
    if (obj.hyp[k] == DR) continue;
    if (obj.hyp[k] == EPSILON) continue;
    if (obj.hyp[k] == SEP) continue;
    labelmap_iterator_t itx = vmap.find (obj.hyp[k]);
    if (itx != vmap.end() )
      os << vmap[ obj.hyp[k] ] << " ";
    else {
      os << "[" << obj.hyp[k] << "] ";
      std::cerr << "\nWARNING: word map does not contain word " << obj.hyp[k] <<
                std::endl;
    }
  }
  if (printweight) {
    os << "\t";
    printWeight<Arc> (obj.cost, os);
  };
  return os;
}

template <class Arc, class HypT>
int run ( ucam::util::RegistryPO const& rg) {
  using ucam::util::oszfstream;
  using ucam::util::PatternAddress;
  PatternAddress<unsigned> input (rg.get<std::string>
                                  (HifstConstants::kInput.c_str() ) );
  PatternAddress<unsigned> output (rg.get<std::string>
                                   (HifstConstants::kOutput.c_str() ) );
  unsigned n = rg.get<unsigned> (HifstConstants::kNbest.c_str() );
  boost::scoped_ptr<oszfstream> out;
  bool unique =  rg.exists (HifstConstants::kUnique.c_str() );
  bool printOutputLabels = rg.exists(HifstConstants::kPrintOutputLabels.c_str());
  std::string old;
  for ( ucam::util::IntRangePtr ir (ucam::util::IntRangeFactory ( rg,
                                    HifstConstants::kRangeOne ) );
        !ir->done();
        ir->next() ) {
    FORCELINFO ("Processing file " << input ( ir->get() ) );
    boost::scoped_ptr<fst::VectorFst<Arc> > ifst (fst::VectorFstRead<Arc> (input (
          ir->get() ) ) );
    fst::VectorFst<Arc> nfst;
    Connect (&*ifst);
    if (old != output (ir->get() ) ) {
      out.reset (new oszfstream (output (ir->get() ) ) );
      old = output (ir->get() );
    }
    if (!ifst->NumStates() ) {
      *out << "[EMPTY]" << std::endl;
      continue;
    }
    // Projecting allows unique to work for all cases.
    if (printOutputLabels)
      fst::Project(&*ifst, PROJECT_OUTPUT);
    else
      fst::Project(&*ifst, PROJECT_INPUT);
    ShortestPath (*ifst, &nfst, n, unique );
    std::vector<HypT> hyps;
    fst::printStrings<Arc> (nfst, &hyps);
    for (unsigned k = 0; k < hyps.size(); ++k) {
      *out->getStream() << hyps[k] << std::endl;
    }
  }
};

/*
 * \brief Main function.
 * \param       argc Number of command-line program options.
 * \param       argv Actual program options.
 * \remarks
 */
int  main ( int argc, const char* argv[] ) {
  ucam::util::initLogger ( argc, argv );
  FORCELINFO ( argv[0] << " starts!" );
  ucam::util::RegistryPO rg ( argc, argv );
  FORCELINFO ( rg.dump ( "CONFIG parameters:\n=====================",
                         "=====================" ) );
  if (rg.exists (HifstConstants::kWeight) ) {
    printweight = true;
  }
  if (rg.exists (HifstConstants::kSparseFormat) ) {
    sparseformat = true;
  }
  // check that tuplearc weights are set for the tuplearc semiring
  if (rg.get<std::string> (HifstConstants::kHifstSemiring.c_str() ) ==
      HifstConstants::kHifstSemiringTupleArc) {
    const std::string& tuplearcWeights = rg.exists (
                                           HifstConstants::kTupleArcWeights)
                                         ? rg.get<std::string> (HifstConstants::kTupleArcWeights.c_str() ) : "";
    if (tuplearcWeights.empty() ) {
      LERROR ("The tuplearc.weights option needs to be specified "
              "for the tropical sparse tuple weight semiring "
              "(--semiring=tuplearc)");
      exit (EXIT_FAILURE);
    }
    TupleW32::Params() = ucam::util::ParseParamString<float> (tuplearcWeights);
  }
  std::string const& semiring = rg.get<std::string>
                                (HifstConstants::kHifstSemiring);
  if (!vmap.size() && rg.get<std::string> (HifstConstants::kLabelMap) != "" ) {
    FORCELINFO ("Loading symbol map file...");
    ucam::util::iszfstream f (rg.get<std::string> (HifstConstants::kLabelMap) );
    unsigned id;
    std::string word;
    while (f >> word >> id) {
      vmap[id] = word;
    }
    FORCELINFO ("Loaded " << vmap.size() << " symbols");
    if (semiring == HifstConstants::kHifstSemiringStdArc) {
      run<fst::StdArc, HypW<fst::StdArc> > (rg);
    } else if (semiring == HifstConstants::kHifstSemiringLexStdArc) {
      run<fst::LexStdArc, HypW<fst::LexStdArc> > (rg);
    } else if (semiring == HifstConstants::kHifstSemiringTupleArc) {
      run<TupleArc32, HypW<TupleArc32> > (rg);
    } else {
      LERROR ("Sorry, semiring option not correctly defined");
    }
    FORCELINFO ( argv[0] << " finished!" );
    exit (EXIT_SUCCESS);
  }
  if (semiring == HifstConstants::kHifstSemiringStdArc) {
    run<fst::StdArc, Hyp<fst::StdArc> > (rg);
  } else if (semiring == HifstConstants::kHifstSemiringLexStdArc) {
    run<fst::LexStdArc, Hyp<fst::LexStdArc> > (rg);
  } else if (semiring == HifstConstants::kHifstSemiringTupleArc) {
    run<TupleArc32, Hyp<TupleArc32> > (rg);
  } else {
    LERROR ("Sorry, semiring option not correctly defined");
  }
  FORCELINFO ( argv[0] << " finished!" );
}
<commit_msg>Fix bugs with sparse tuple weights  in printstrings.<commit_after>
/**
 * \file
 * \brief Main file for printstrings tool
 * \date 8-8-2012
 * \author Gonzalo Iglesias
 */

#include <main.custom_assert.hpp>
#include <main.logger.hpp>
#include <main.printstrings.hpp>

typedef std::tr1::unordered_map<std::size_t, std::string> labelmap_t;
typedef labelmap_t::iterator labelmap_iterator_t;
labelmap_t vmap;
bool printweight = false;
bool sparseformat = false;

using fst::Hyp;

/**
 * \brief Same as Hyp but the printing will convert integer ids to words.
 */
template<class Arc>
struct HypW: public Hyp<Arc> {

  HypW (std::basic_string<unsigned> const& h, typename Arc::Weight const& c)
    : Hyp<Arc> (h, c) {
  }
  HypW (HypW<Arc> const& h)
    : Hyp<Arc> (h) {
  }
};

/**
 * \brief Templated method that prints an arc weight. By default, reuses
 * the operator<< already defined for each weight.
 * \param weight The arc weight to be printed
 * \param os The output stream to print to
 */
template <class Arc>
void printWeight (typename Arc::Weight const& weight, std::ostream& os) {
  os << weight;
}

/**
 * \brief Template specialization of printWeight for a tropical sparse
 * tuple weight. Uses the global var sparseformat.
 * For the non sparse format, the comma separator is hard coded.
 * \param weight The arc weight to be printed
 * \param sparseformat Whether to print in sparse format or not.
 * \param os The output stream to print to
 */
template <>
void printWeight<TupleArc32> (const TupleW32& weight, std::ostream& os) {
  std::map<int,float> costs;
  for (fst::SparseTupleWeightIterator<fst::TropicalWeight, int> it (weight);
       !it.Done(); it.Next() ) {
    costs[it.Value().first] += it.Value().second.Value();
  }
  if (sparseformat) {
    os << "0," << costs.size() << ",";
    for (std::map<int,float>::const_iterator itx=costs.begin()
             ; itx != costs.end()
             ; ++itx) {
      os << itx->first << "," << itx->second << ",";
    }
    os << std::endl;
    return;
  }
  std::size_t nonSparseSize = TupleW32::Params().size();
  std::size_t counter = 1;
  std::string separator (",");

  for (std::map<int,float>::const_iterator itx=costs.begin()
           ; itx != costs.end()
           ; ++itx) {
    if (itx->first < 1 ) continue;
    std::size_t featureIndex = itx->first;
    for (std::size_t featureMissingIndex = counter;
         featureMissingIndex < featureIndex; ++featureMissingIndex) {
      os << "0" << separator;
    }
    os << itx->second << separator;
    counter = itx->first + 1;
  }
  for (; counter <= nonSparseSize; ++counter)
    os << "0" << separator;

  // dense format is buggy. We also want sparse format to sum contributions to the same index.
  // if (sparseformat) {
  //   os << weight;
  // } else {
  //   // size of the parameter vector
  //   std::size_t nonSparseSize = TupleW32::Params().size();
  //   std::size_t counter = 1;
  //   std::string separator ("");
  //   for (fst::SparseTupleWeightIterator<fst::TropicalWeight, int> it (weight);
  //        !it.Done(); it.Next() ) {
  //     std::size_t featureIndex = it.Value().first;
  //     for (std::size_t featureMissingIndex = counter;
  //          featureMissingIndex < featureIndex; ++featureMissingIndex) {
  //       os << separator << "0";
  //       separator = ",";
  //       counter++;
  //     }
  //     os << separator << it.Value().second;
  //     separator = ",";
  //     counter++;
  //   }
  //   for (; counter <= nonSparseSize; ++counter) {
  //     os << separator << "0";
  //     separator = ",";
  //   }
  // }
}

/**
 * \brief Operator<< overloading to print a hypothesis.
 */
template<class Arc>
std::ostream& operator<< (std::ostream& os, const Hyp<Arc>& obj) {
  for (unsigned k = 0; k < obj.hyp.size(); ++k) {
    if (obj.hyp[k] == OOV) continue;
    if (obj.hyp[k] == DR) continue;
    if (obj.hyp[k] == EPSILON) continue;
    if (obj.hyp[k] == SEP) continue;
    os << obj.hyp[k] << " ";
  }
  if (printweight) {
    os << "\t";
    printWeight<Arc> (obj.cost, os);
  };
  return os;
}

/**
 * \brief Operator<< overloading to print a hypothesis.
 * Integer are converted to words using the global variable wmap.
 */
template<class Arc>
std::ostream& operator<< (std::ostream& os, const HypW<Arc>& obj) {
  for (unsigned k = 0; k < obj.hyp.size(); ++k) {
    if (obj.hyp[k] == OOV) continue;
    if (obj.hyp[k] == DR) continue;
    if (obj.hyp[k] == EPSILON) continue;
    if (obj.hyp[k] == SEP) continue;
    labelmap_iterator_t itx = vmap.find (obj.hyp[k]);
    if (itx != vmap.end() )
      os << vmap[ obj.hyp[k] ] << " ";
    else {
      os << "[" << obj.hyp[k] << "] ";
      std::cerr << "\nWARNING: word map does not contain word " << obj.hyp[k] <<
                std::endl;
    }
  }
  if (printweight) {
    os << "\t";
    printWeight<Arc> (obj.cost, os);
  };
  return os;
}

template <class Arc, class HypT>
int run ( ucam::util::RegistryPO const& rg) {
  using ucam::util::oszfstream;
  using ucam::util::PatternAddress;
  PatternAddress<unsigned> input (rg.get<std::string>
                                  (HifstConstants::kInput.c_str() ) );
  PatternAddress<unsigned> output (rg.get<std::string>
                                   (HifstConstants::kOutput.c_str() ) );
  unsigned n = rg.get<unsigned> (HifstConstants::kNbest.c_str() );
  boost::scoped_ptr<oszfstream> out;
  bool unique =  rg.exists (HifstConstants::kUnique.c_str() );
  bool printOutputLabels = rg.exists(HifstConstants::kPrintOutputLabels.c_str());
  std::string old;
  for ( ucam::util::IntRangePtr ir (ucam::util::IntRangeFactory ( rg,
                                    HifstConstants::kRangeOne ) );
        !ir->done();
        ir->next() ) {
    FORCELINFO ("Processing file " << input ( ir->get() ) );
    boost::scoped_ptr<fst::VectorFst<Arc> > ifst (fst::VectorFstRead<Arc> (input (
          ir->get() ) ) );
    fst::VectorFst<Arc> nfst;
    Connect (&*ifst);
    if (old != output (ir->get() ) ) {
      out.reset (new oszfstream (output (ir->get() ) ) );
      old = output (ir->get() );
    }
    if (!ifst->NumStates() ) {
      *out << "[EMPTY]" << std::endl;
      continue;
    }
    // Projecting allows unique to work for all cases.
    if (printOutputLabels)
      fst::Project(&*ifst, PROJECT_OUTPUT);
    else
      fst::Project(&*ifst, PROJECT_INPUT);
    ShortestPath (*ifst, &nfst, n, unique );
    std::vector<HypT> hyps;
    fst::printStrings<Arc> (nfst, &hyps);
    for (unsigned k = 0; k < hyps.size(); ++k) {
      *out->getStream() << hyps[k] << std::endl;
    }
  }
};

/*
 * \brief Main function.
 * \param       argc Number of command-line program options.
 * \param       argv Actual program options.
 * \remarks
 */
int  main ( int argc, const char* argv[] ) {
  ucam::util::initLogger ( argc, argv );
  FORCELINFO ( argv[0] << " starts!" );
  ucam::util::RegistryPO rg ( argc, argv );
  FORCELINFO ( rg.dump ( "CONFIG parameters:\n=====================",
                         "=====================" ) );
  if (rg.exists (HifstConstants::kWeight) ) {
    printweight = true;
  }
  if (rg.exists (HifstConstants::kSparseFormat) ) {
    sparseformat = true;
  }
  // check that tuplearc weights are set for the tuplearc semiring
  if (rg.get<std::string> (HifstConstants::kHifstSemiring.c_str() ) ==
      HifstConstants::kHifstSemiringTupleArc) {
    const std::string& tuplearcWeights = rg.exists (
                                           HifstConstants::kTupleArcWeights)
                                         ? rg.get<std::string> (HifstConstants::kTupleArcWeights.c_str() ) : "";
    if (tuplearcWeights.empty() ) {
      LERROR ("The tuplearc.weights option needs to be specified "
              "for the tropical sparse tuple weight semiring "
              "(--semiring=tuplearc)");
      exit (EXIT_FAILURE);
    }
    TupleW32::Params() = ucam::util::ParseParamString<float> (tuplearcWeights);
  }
  std::string const& semiring = rg.get<std::string>
                                (HifstConstants::kHifstSemiring);
  if (!vmap.size() && rg.get<std::string> (HifstConstants::kLabelMap) != "" ) {
    FORCELINFO ("Loading symbol map file...");
    ucam::util::iszfstream f (rg.get<std::string> (HifstConstants::kLabelMap) );
    unsigned id;
    std::string word;
    while (f >> word >> id) {
      vmap[id] = word;
    }
    FORCELINFO ("Loaded " << vmap.size() << " symbols");
    if (semiring == HifstConstants::kHifstSemiringStdArc) {
      run<fst::StdArc, HypW<fst::StdArc> > (rg);
    } else if (semiring == HifstConstants::kHifstSemiringLexStdArc) {
      run<fst::LexStdArc, HypW<fst::LexStdArc> > (rg);
    } else if (semiring == HifstConstants::kHifstSemiringTupleArc) {
      run<TupleArc32, HypW<TupleArc32> > (rg);
    } else {
      LERROR ("Sorry, semiring option not correctly defined");
    }
    FORCELINFO ( argv[0] << " finished!" );
    exit (EXIT_SUCCESS);
  }
  if (semiring == HifstConstants::kHifstSemiringStdArc) {
    run<fst::StdArc, Hyp<fst::StdArc> > (rg);
  } else if (semiring == HifstConstants::kHifstSemiringLexStdArc) {
    run<fst::LexStdArc, Hyp<fst::LexStdArc> > (rg);
  } else if (semiring == HifstConstants::kHifstSemiringTupleArc) {
    run<TupleArc32, Hyp<TupleArc32> > (rg);
  } else {
    LERROR ("Sorry, semiring option not correctly defined");
  }
  FORCELINFO ( argv[0] << " finished!" );
}
<|endoftext|>


<commit_before>// Copyright 2010-2014 Google
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This is the skeleton for the official flatzinc interpreter.  Much
// of the funcionnalities are fixed (name of parameters, format of the
// input): see http://www.minizinc.org/downloads/doc-1.6/flatzinc-spec.pdf

#include <iostream>  // NOLINT
#include <string>
#include <vector>

#include "base/commandlineflags.h"
#include "base/stringprintf.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/threadpool.h"
#include "base/timer.h"
#include "flatzinc2/model.h"
#include "flatzinc2/parser.h"
#include "flatzinc2/presolve.h"
#include "flatzinc2/search.h"
#include "flatzinc2/solver.h"

DEFINE_int32(log_period, 10000000, "Search log period");
DEFINE_bool(all, false, "Search for all solutions");
DEFINE_bool(free, false, "Ignore search annotations");
DEFINE_int32(num_solutions, 0, "Number of solution to search for");
DEFINE_int32(time_limit, 0, "time limit in ms");
DEFINE_int32(workers, 0, "Number of workers");
DEFINE_bool(use_impact, false, "Use impact based search");
DEFINE_double(restart_log_size, -1, "Restart log size for impact search");
DEFINE_int32(luby_restart, -1, "Luby restart factor, <= 0 = no luby");
DEFINE_int32(heuristic_period, 100, "Period to call heuristics in free search");
DEFINE_bool(verbose_impact, false, "Verbose impact");
DEFINE_bool(verbose_mt, false, "Verbose Multi-Thread");
DEFINE_bool(presolve, true, "Use presolve.");

DECLARE_bool(fz_logging);
DECLARE_bool(log_prefix);
DECLARE_bool(use_sat);

using operations_research::ThreadPool;

namespace operations_research {
void Run(const std::string& filename, const FzSolverParameters& parameters,
         FzParallelSupportInterface* parallel_support) {
  WallTimer timer;
  timer.Start();
  std::string problem_name(filename);
  problem_name.resize(problem_name.size() - 4);
  size_t found = problem_name.find_last_of("/\\");
  if (found != std::string::npos) {
    problem_name = problem_name.substr(found + 1);
  }
  FzModel model(problem_name);
  CHECK(ParseFlatzincFile(filename, &model));
  FZLOG << "File " << filename << " parsed in " << timer.GetInMs() << " ms"
        << FZENDL;
  FzPresolver presolve;
  presolve.CleanUpModelForTheCpSolver(&model, FLAGS_use_sat);
  if (FLAGS_presolve) {
    FZLOG << "Presolve model" << FZENDL;
    timer.Reset();
    timer.Start();
    presolve.Run(&model);
    FZLOG << "  - done in " << timer.GetInMs() << " ms" << FZENDL;
  }
  FzModelStatistics stats(model);
  stats.PrintStatistics();
  FzSolver solver(model);
  CHECK(solver.Extract());
  solver.Solve(parameters, parallel_support);
}

void SequentialRun(const std::string& filename) {
  FzSolverParameters parameters;
  parameters.all_solutions = FLAGS_all;
  parameters.free_search = FLAGS_free;
  parameters.heuristic_period = FLAGS_heuristic_period;
  parameters.ignore_unknown = false;
  parameters.log_period = FLAGS_log_period;
  parameters.luby_restart = FLAGS_luby_restart;
  parameters.num_solutions = FLAGS_num_solutions;
  parameters.restart_log_size = FLAGS_restart_log_size;
  parameters.threads = FLAGS_workers;
  parameters.time_limit_in_ms = FLAGS_time_limit;
  parameters.use_log = FLAGS_fz_logging;
  parameters.verbose_impact = FLAGS_verbose_impact;
  parameters.worker_id = -1;
  parameters.search_type =
      FLAGS_use_impact ? FzSolverParameters::IBS : FzSolverParameters::DEFAULT;

  std::unique_ptr<FzParallelSupportInterface> parallel_support(
      operations_research::MakeSequentialSupport(parameters.all_solutions,
                                                 parameters.num_solutions));
  Run(filename, parameters, parallel_support.get());
}

void ParallelRun(char* const file, int worker_id,
                 FzParallelSupportInterface* parallel_support) {
  FzSolverParameters parameters;
  parameters.all_solutions = FLAGS_all;
  parameters.heuristic_period = FLAGS_heuristic_period;
  parameters.ignore_unknown = false;
  parameters.log_period = 0;
  parameters.luby_restart = -1;
  parameters.num_solutions = FLAGS_num_solutions;
  parameters.random_seed = worker_id * 10;
  parameters.threads = FLAGS_workers;
  parameters.time_limit_in_ms = FLAGS_time_limit;
  parameters.use_log = false;
  parameters.verbose_impact = false;
  parameters.worker_id = worker_id;
  switch (worker_id) {
    case 0: {
      parameters.free_search = false;
      parameters.search_type = operations_research::FzSolverParameters::DEFAULT;
      parameters.restart_log_size = -1.0;
      break;
    }
    case 1: {
      parameters.free_search = true;
      parameters.search_type =
          operations_research::FzSolverParameters::MIN_SIZE;
      parameters.restart_log_size = -1.0;
      break;
    }
    case 2: {
      parameters.free_search = true;
      parameters.search_type = operations_research::FzSolverParameters::IBS;
      parameters.restart_log_size = FLAGS_restart_log_size;
      break;
    }
    case 3: {
      parameters.free_search = true;
      parameters.search_type =
          operations_research::FzSolverParameters::FIRST_UNBOUND;
      parameters.restart_log_size = -1.0;
      parameters.heuristic_period = 10000000;
      break;
    }
    case 4: {
      parameters.free_search = true;
      parameters.search_type = operations_research::FzSolverParameters::DEFAULT;
      parameters.restart_log_size = -1.0;
      parameters.heuristic_period = 30;
      parameters.run_all_heuristics = true;
      break;
    }
    default: {
      parameters.free_search = true;
      parameters.search_type =
          worker_id % 2 == 0
              ? operations_research::FzSolverParameters::RANDOM_MIN
              : operations_research::FzSolverParameters::RANDOM_MAX;
      parameters.restart_log_size = -1.0;
      parameters.luby_restart = 250;
    }
  }
  Run(file, parameters, parallel_support);
}

void FixAndParseParameters(int* argc, char*** argv) {
  FLAGS_log_prefix = false;
  char all_param[] = "--all";
  char free_param[] = "--free";
  char workers_param[] = "--workers";
  char solutions_param[] = "--num_solutions";
  char logging_param[] = "--fz_logging";
  char verbose_param[] = "--fz_verbose";
  char debug_param[] = "--fz_debug";
  for (int i = 1; i < *argc; ++i) {
    if (strcmp((*argv)[i], "-a") == 0) {
      (*argv)[i] = all_param;
    }
    if (strcmp((*argv)[i], "-f") == 0) {
      (*argv)[i] = free_param;
    }
    if (strcmp((*argv)[i], "-p") == 0) {
      (*argv)[i] = workers_param;
    }
    if (strcmp((*argv)[i], "-n") == 0) {
      (*argv)[i] = solutions_param;
    }
    if (strcmp((*argv)[i], "-l") == 0) {
      (*argv)[i] = logging_param;
    }
    if (strcmp((*argv)[i], "-v") == 0) {
      (*argv)[i] = verbose_param;
    }
    if (strcmp((*argv)[i], "-d") == 0) {
      (*argv)[i] = debug_param;
    }
  }
  google::ParseCommandLineFlags(argc, argv, true);
  // Fix the number of solutions.
  if (FLAGS_num_solutions == 0) {  // not specified
    FLAGS_num_solutions = FLAGS_all ? kint32max : 1;
  }
}
}  // namespace operations_research

int main(int argc, char** argv) {
  operations_research::FixAndParseParameters(&argc, &argv);
  if (argc <= 1) {
    LOG(ERROR) << "Usage: " << argv[0] << " <file>";
    exit(EXIT_FAILURE);
  }
  if (FLAGS_workers == 0) {
    operations_research::SequentialRun(argv[1]);
  } else {
    std::unique_ptr<operations_research::FzParallelSupportInterface>
        parallel_support(operations_research::MakeMtSupport(
            FLAGS_all, FLAGS_num_solutions, FLAGS_verbose_mt));
    {
      ThreadPool pool("Parallel FlatZinc", FLAGS_workers);
      pool.StartWorkers();
      for (int w = 0; w < FLAGS_workers; ++w) {
        pool.Add(NewCallback(&operations_research::ParallelRun, argv[1], w,
                             parallel_support.get()));
      }
    }
  }
  return 0;
}
<commit_msg>revisit fz2's implementation of parallelism<commit_after>// Copyright 2010-2014 Google
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This is the skeleton for the official flatzinc interpreter.  Much
// of the funcionnalities are fixed (name of parameters, format of the
// input): see http://www.minizinc.org/downloads/doc-1.6/flatzinc-spec.pdf

#include <iostream>  // NOLINT
#include <string>
#include <vector>

#include "base/commandlineflags.h"
#include "base/stringprintf.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/threadpool.h"
#include "base/timer.h"
#include "flatzinc2/model.h"
#include "flatzinc2/parser.h"
#include "flatzinc2/presolve.h"
#include "flatzinc2/search.h"
#include "flatzinc2/solver.h"

DEFINE_int32(log_period, 10000000, "Search log period");
DEFINE_bool(all, false, "Search for all solutions");
DEFINE_bool(free, false, "Ignore search annotations");
DEFINE_int32(num_solutions, 0, "Number of solution to search for");
DEFINE_int32(time_limit, 0, "time limit in ms");
DEFINE_int32(workers, 0, "Number of workers");
DEFINE_bool(use_impact, false, "Use impact based search");
DEFINE_double(restart_log_size, -1, "Restart log size for impact search");
DEFINE_int32(luby_restart, -1, "Luby restart factor, <= 0 = no luby");
DEFINE_int32(heuristic_period, 100, "Period to call heuristics in free search");
DEFINE_bool(verbose_impact, false, "Verbose impact");
DEFINE_bool(verbose_mt, false, "Verbose Multi-Thread");
DEFINE_bool(presolve, true, "Use presolve.");

DECLARE_bool(fz_logging);
DECLARE_bool(log_prefix);
DECLARE_bool(use_sat);

using operations_research::ThreadPool;

namespace operations_research {
void Solve(const FzModel* const model, const FzSolverParameters& parameters,
           FzParallelSupportInterface* parallel_support) {
  FzSolver solver(*model);
  CHECK(solver.Extract());
  solver.Solve(parameters, parallel_support);
}

void SequentialRun(const FzModel* model) {
  FzSolverParameters parameters;
  parameters.all_solutions = FLAGS_all;
  parameters.free_search = FLAGS_free;
  parameters.heuristic_period = FLAGS_heuristic_period;
  parameters.ignore_unknown = false;
  parameters.log_period = FLAGS_log_period;
  parameters.luby_restart = FLAGS_luby_restart;
  parameters.num_solutions = FLAGS_num_solutions;
  parameters.restart_log_size = FLAGS_restart_log_size;
  parameters.threads = FLAGS_workers;
  parameters.time_limit_in_ms = FLAGS_time_limit;
  parameters.use_log = FLAGS_fz_logging;
  parameters.verbose_impact = FLAGS_verbose_impact;
  parameters.worker_id = -1;
  parameters.search_type =
      FLAGS_use_impact ? FzSolverParameters::IBS : FzSolverParameters::DEFAULT;

  std::unique_ptr<FzParallelSupportInterface> parallel_support(
      MakeSequentialSupport(FLAGS_all, FLAGS_num_solutions));
  Solve(model, parameters, parallel_support.get());
}

void ParallelRun(const FzModel* const model, int worker_id,
                 FzParallelSupportInterface* parallel_support) {
  FzSolverParameters parameters;
  parameters.all_solutions = FLAGS_all;
  parameters.heuristic_period = FLAGS_heuristic_period;
  parameters.ignore_unknown = false;
  parameters.log_period = 0;
  parameters.luby_restart = -1;
  parameters.num_solutions = FLAGS_num_solutions;
  parameters.random_seed = worker_id * 10;
  parameters.threads = FLAGS_workers;
  parameters.time_limit_in_ms = FLAGS_time_limit;
  parameters.use_log = false;
  parameters.verbose_impact = false;
  parameters.worker_id = worker_id;
  switch (worker_id) {
    case 0: {
      parameters.free_search = false;
      parameters.search_type = operations_research::FzSolverParameters::DEFAULT;
      parameters.restart_log_size = -1.0;
      break;
    }
    case 1: {
      parameters.free_search = true;
      parameters.search_type =
          operations_research::FzSolverParameters::MIN_SIZE;
      parameters.restart_log_size = -1.0;
      break;
    }
    case 2: {
      parameters.free_search = true;
      parameters.search_type = operations_research::FzSolverParameters::IBS;
      parameters.restart_log_size = FLAGS_restart_log_size;
      break;
    }
    case 3: {
      parameters.free_search = true;
      parameters.search_type =
          operations_research::FzSolverParameters::FIRST_UNBOUND;
      parameters.restart_log_size = -1.0;
      parameters.heuristic_period = 10000000;
      break;
    }
    case 4: {
      parameters.free_search = true;
      parameters.search_type = operations_research::FzSolverParameters::DEFAULT;
      parameters.restart_log_size = -1.0;
      parameters.heuristic_period = 30;
      parameters.run_all_heuristics = true;
      break;
    }
    default: {
      parameters.free_search = true;
      parameters.search_type =
          worker_id % 2 == 0
              ? operations_research::FzSolverParameters::RANDOM_MIN
              : operations_research::FzSolverParameters::RANDOM_MAX;
      parameters.restart_log_size = -1.0;
      parameters.luby_restart = 250;
    }
  }
  Solve(model, parameters, parallel_support);
}

void FixAndParseParameters(int* argc, char*** argv) {
  FLAGS_log_prefix = false;
  char all_param[] = "--all";
  char free_param[] = "--free";
  char workers_param[] = "--workers";
  char solutions_param[] = "--num_solutions";
  char logging_param[] = "--fz_logging";
  char verbose_param[] = "--fz_verbose";
  char debug_param[] = "--fz_debug";
  for (int i = 1; i < *argc; ++i) {
    if (strcmp((*argv)[i], "-a") == 0) {
      (*argv)[i] = all_param;
    }
    if (strcmp((*argv)[i], "-f") == 0) {
      (*argv)[i] = free_param;
    }
    if (strcmp((*argv)[i], "-p") == 0) {
      (*argv)[i] = workers_param;
    }
    if (strcmp((*argv)[i], "-n") == 0) {
      (*argv)[i] = solutions_param;
    }
    if (strcmp((*argv)[i], "-l") == 0) {
      (*argv)[i] = logging_param;
    }
    if (strcmp((*argv)[i], "-v") == 0) {
      (*argv)[i] = verbose_param;
    }
    if (strcmp((*argv)[i], "-d") == 0) {
      (*argv)[i] = debug_param;
    }
  }
  google::ParseCommandLineFlags(argc, argv, true);
  // Fix the number of solutions.
  if (FLAGS_num_solutions == 0) {  // not specified
    FLAGS_num_solutions = FLAGS_all ? kint32max : 1;
  }
}

void ParseAndRun(const std::string& filename, int num_workers) {
  WallTimer timer;
  timer.Start();
  std::string problem_name(filename);
  problem_name.resize(problem_name.size() - 4);
  size_t found = problem_name.find_last_of("/\\");
  if (found != std::string::npos) {
    problem_name = problem_name.substr(found + 1);
  }
  FzModel model(problem_name);
  CHECK(ParseFlatzincFile(filename, &model));
  FZLOG << "File " << filename << " parsed in " << timer.GetInMs() << " ms"
        << FZENDL;
  FzPresolver presolve;
  presolve.CleanUpModelForTheCpSolver(&model, FLAGS_use_sat);
  if (FLAGS_presolve) {
    FZLOG << "Presolve model" << FZENDL;
    timer.Reset();
    timer.Start();
    presolve.Run(&model);
    FZLOG << "  - done in " << timer.GetInMs() << " ms" << FZENDL;
  }
  FzModelStatistics stats(model);
  stats.PrintStatistics();

  if (num_workers == 0) {
    operations_research::SequentialRun(&model);
  } else {
    std::unique_ptr<operations_research::FzParallelSupportInterface>
        parallel_support(operations_research::MakeMtSupport(
            FLAGS_all, FLAGS_num_solutions, FLAGS_verbose_mt));
    {
      ThreadPool pool("Parallel FlatZinc", num_workers);
      for (int w = 0; w < num_workers; ++w) {
        pool.Add(NewCallback(ParallelRun, &model, w, parallel_support.get()));
      }
      pool.StartWorkers();
    }
  }
}
}  // namespace operations_research

int main(int argc, char** argv) {
  operations_research::FixAndParseParameters(&argc, &argv);
  if (argc <= 1) {
    LOG(ERROR) << "Usage: " << argv[0] << " <file>";
    exit(EXIT_FAILURE);
  }
  operations_research::ParseAndRun(argv[1], FLAGS_workers);
  return 0;
}
<|endoftext|>