本文整理汇总了C++中SizeOptions::propagation方法的典型用法代码示例。如果您正苦于以下问题:C++ SizeOptions::propagation方法的具体用法?C++ SizeOptions::propagation怎么用?C++ SizeOptions::propagation使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类SizeOptions
的用法示例。
在下文中一共展示了SizeOptions::propagation方法的7个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: Queens
/// The actual problem
Queens(const SizeOptions& opt)
: q(*this,opt.size(),0,opt.size()-1) {
const int n = q.size();
switch (opt.propagation()) {
case PROP_BINARY:
for (int i = 0; i<n; i++)
for (int j = i+1; j<n; j++) {
rel(*this, q[i] != q[j]);
rel(*this, q[i]+i != q[j]+j);
rel(*this, q[i]-i != q[j]-j);
}
break;
case PROP_MIXED:
for (int i = 0; i<n; i++)
for (int j = i+1; j<n; j++) {
rel(*this, q[i]+i != q[j]+j);
rel(*this, q[i]-i != q[j]-j);
}
distinct(*this, q, opt.icl());
break;
case PROP_DISTINCT:
distinct(*this, IntArgs::create(n,0,1), q, opt.icl());
distinct(*this, IntArgs::create(n,0,-1), q, opt.icl());
distinct(*this, q, opt.icl());
break;
}
switch(opt.branching()) {
case BRANCH_MIN:
branch(*this, q, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
break;
case BRANCH_MID:
branch(*this, q, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
break;
case BRANCH_MAX_MAX:
branch(*this, q, INT_VAR_SIZE_MAX(), INT_VAL_MIN());
break;
case BRANCH_KNIGHT_MOVE:
branch(*this, q, INT_VAR_MIN_MIN(), INT_VAL_MED());
break;
}
}
示例2: r_a
SUSHI_EQUATION(const SizeOptions& opt)
: n_x(*this, 1, wordlength),
n_y(*this, 1, wordlength),
n_z(*this, 1, wordlength),
n_t(*this, opt.size()+1, opt.size()+1),
X(*this, wordlength , val_dom_min, val_dom_max),
Y(*this, wordlength , val_dom_min, val_dom_max),
Z(*this, wordlength , val_dom_min, val_dom_max),
T(*this, opt.size()+1 , val_dom_min, val_dom_max){
int n = opt.size();
gecode_find_solution = false;
REG r_a(1);
REG r_b(2);
REG dum(dummy_sym);
REG reg_z = r_b(n,n) + r_a + r_b(n,n);
if (opt.propagation() == PROP_PAD) {
reg_z += (*dum);
}
DFA myDFA_z(reg_z);
// T = "a" . Y[0,n]
rel(*this, T[0]==1);
for (int i = 0; (i < n) && (i+1 < T.size()); i++){
T[i+1] = Y[i];
}
rel(*this, n_y >= n);
switch(opt.propagation()){
case PROP_OPEN:
extensional(*this, Z, myDFA_z, n_z);
//concat(*this, X, n_x, T, n_t, Z, n_z, ICL_BND);
rel(*this, n_z == (n_x+n_t));
for(int i=0; i<wordlength; i++)
{
rel(*this, (i<n_x) >> (X[i]==Z[i]));
BoolVar b = expr(*this, i==n_x);
for(int j=0; (i+j)<wordlength; j++)
{
rel(*this, (b&&(j<n_t)) >> (T[j]==Z[i+j]));
}
}
break;
case PROP_CLOSED:
extensional(*this, Z, myDFA_z);
rel(*this, n_z == (n_x+n_t));
rel(*this, n_y == wordlength);
for(int i=0; i<wordlength; i++)
{
rel(*this, (i<n_x) >> (X[i]==Z[i]));
BoolVar b = expr(*this, i==n_x);
for(int j=0; (j < T.size()) && ((i+j)<wordlength); j++)
{
rel(*this, (b&&(j<n_t)) >> (T[j]==Z[i+j]));
}
}
break;
case PROP_PAD:
extensional(*this, Z, myDFA_z);
for(int i=0; i<wordlength; i++)
{
rel(*this, (Z[i]==dummy_sym) == (n_z<=i));
rel(*this, (Y[i]==dummy_sym) == (n_y<=i));
rel(*this, (X[i]==dummy_sym) == (n_x<=i));
}
rel(*this, n_z == (n_x+n_t));
for(int i=0; i<wordlength; i++)
{
rel(*this, (i<n_x) >> (X[i]==Z[i]));
BoolVar b = expr(*this, i==n_x);
for(int j=0; (j < T.size()) && ((i+j)<wordlength); j++)
{
rel(*this, (b&&(j<n_t)) >> (T[j]==Z[i+j]));
}
}
break;
}
IntVarArgs lengths;
lengths << n_z << n_x << n_y;
switch(opt.branching()){
case BRANCH_N_A:
branch(*this, lengths, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
branch(*this, Z, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
branch(*this, X, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
branch(*this, Y, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
break;
//.........这里部分代码省略.........
示例3: sa
/// Actual model
PerfectSquare(const SizeOptions& opt)
: x(*this,specs[opt.size()][0],0,specs[opt.size()][1]-1),
y(*this,specs[opt.size()][0],0,specs[opt.size()][1]-1) {
const int* s = specs[opt.size()];
int n = *s++;
int w = *s++;
// Restrict position according to square size
for (int i=n; i--; ) {
rel(*this, x[i], IRT_LQ, w-s[i]);
rel(*this, y[i], IRT_LQ, w-s[i]);
}
IntArgs sa(n,s);
// Squares do not overlap
nooverlap(*this, x, sa, y, sa);
/*
* Capacity constraints
*
*/
switch (opt.propagation()) {
case PROP_REIFIED:
{
for (int cx=0; cx<w; cx++) {
BoolVarArgs bx(*this,n,0,1);
for (int i=0; i<n; i++)
dom(*this, x[i], cx-s[i]+1, cx, bx[i]);
linear(*this, sa, bx, IRT_EQ, w);
}
for (int cy=0; cy<w; cy++) {
BoolVarArgs by(*this,n,0,1);
for (int i=0; i<n; i++)
dom(*this, y[i], cy-s[i]+1, cy, by[i]);
linear(*this, sa, by, IRT_EQ, w);
}
}
break;
case PROP_CUMULATIVES:
{
IntArgs m(n), dh(n);
for (int i = n; i--; ) {
m[i]=0; dh[i]=s[i];
}
IntArgs limit(1, w);
{
// x-direction
IntVarArgs e(n);
for (int i=n; i--;)
e[i]=expr(*this, x[i]+dh[i]);
cumulatives(*this, m, x, dh, e, dh, limit, true);
cumulatives(*this, m, x, dh, e, dh, limit, false);
}
{
// y-direction
IntVarArgs e(n);
for (int i=n; i--;)
e[i]=expr(*this, y[i]+dh[i]);
cumulatives(*this, m, y, dh, e, dh, limit, true);
cumulatives(*this, m, y, dh, e, dh, limit, false);
}
}
break;
default:
GECODE_NEVER;
}
branch(*this, x, INT_VAR_MIN_MIN(), INT_VAL_MIN());
branch(*this, y, INT_VAR_MIN_MIN(), INT_VAL_MIN());
}
示例4: expr
KaluzaExample(const SizeOptions& opt)
: var_0xINPUT_9_n(*this,1,wordlength),
T0_2_n(*this,1,wordlength),
T1_2_n(*this,1,wordlength),
PCTEMP_LHS_1_idx_0_n(*this,1,wordlength),
T2_2_n(*this,1,wordlength),
PCTEMP_LHS_1_group_1_n(*this,1,wordlength),
PCTEMP_LHS_1_len_0(*this,1,wordlength),
var_0xINPUT_9(*this,wordlength,val_dom_min,val_dom_max),
T0_2(*this,wordlength,val_dom_min,val_dom_max),
T1_2(*this,wordlength,val_dom_min,val_dom_max),
PCTEMP_LHS_1_idx_0(*this,wordlength,val_dom_min,val_dom_max),
T2_2(*this,wordlength,val_dom_min,val_dom_max),
PCTEMP_LHS_1_group_1(*this,wordlength,val_dom_min,val_dom_max){
// PCTEMP_LHS_1_len_0 == Len(PCTEMP_LHS_1_idx_0);
rel(*this, PCTEMP_LHS_1_len_0==PCTEMP_LHS_1_idx_0_n);
// PCTEMP_LHS_1_len_0 < 15;
rel(*this, PCTEMP_LHS_1_len_0 < 15);
switch(opt.propagation()){
case PROP_PAD:
{
PAD_INVARIANT(*this,var_0xINPUT_9, var_0xINPUT_9_n);
PAD_INVARIANT(*this,T0_2, T0_2_n);
PAD_INVARIANT(*this,T1_2, T1_2_n);
PAD_INVARIANT(*this,PCTEMP_LHS_1_idx_0, PCTEMP_LHS_1_idx_0_n);
PAD_INVARIANT(*this,T2_2, T2_2_n);
PAD_INVARIANT(*this,PCTEMP_LHS_1_group_1, PCTEMP_LHS_1_group_1_n);
//var_0xINPUT_9 := T0_2 . T1_2;
rel(*this, var_0xINPUT_9_n == (T0_2_n+T1_2_n)); // Zn=Xn+Yn
for(int i=0; i<wordlength; i++)
{
rel(*this, (i<T0_2_n) >> (T0_2[i]==var_0xINPUT_9[i])); // i<Xn --> X[i]=Z[i]
BoolVar b = expr(*this, i==T0_2_n); // b <-> i=Xn
for(int j=0; (i+j)<wordlength; j++) //(i+j)<|Z|&j<|Y|
rel(*this, (b&&(j<T1_2_n)) >> (T1_2[j]==var_0xINPUT_9[i+j])); // b&(j<Yn) --> Y[i]=Z[i]
}
//T1_2 := PCTEMP_LHS_1_idx_0 . T2_2;
rel(*this, T1_2_n == (PCTEMP_LHS_1_idx_0_n+T2_2_n)); // Zn=Xn+Yn
for(int i=0; i<wordlength; i++)
{
rel(*this, (i<PCTEMP_LHS_1_idx_0_n) >> (PCTEMP_LHS_1_idx_0[i]==T1_2[i])); // i<Xn --> X[i]=Z[i]
BoolVar b = expr(*this, i==PCTEMP_LHS_1_idx_0_n); // b <-> i=Xn
for(int j=0; (i+j)<wordlength; j++) //(i+j)<|Z|&j<|Y|
rel(*this, (b&&(j<T2_2_n)) >> (T2_2[j]==T1_2[i+j])); // b&(j<Yn) --> Y[i]=Z[i]
}
//PCTEMP_LHS_1_group_1 == PCTEMP_LHS_1_idx_0;
PAD_EQUAL(*this, PCTEMP_LHS_1_group_1, PCTEMP_LHS_1_group_1_n, PCTEMP_LHS_1_idx_0, PCTEMP_LHS_1_idx_0_n);
// PCTEMP_LHS_1_idx_0 \in CapturedBrack(/john/,0);
Gecode::DFA::Transition tp[] = {{0,75,1},{1,80,2},{2,73,3},{3,79,4},{4,dummy_sym,4},{-1,0,0}};
int fp1[] = {4,-1};
john = DFA(0,tp,fp1);
extensional(*this, PCTEMP_LHS_1_idx_0, john);
// T0_2 \notin CapturedBrack(/john/, 0);
int fp2[] = {0,1,2,3,5,-1};
notjohn = DFA(0,bigp,fp2);
extensional(*this, T0_2, notjohn);
break;
}
case PROP_OPEN:
{
open_invariant(*this,var_0xINPUT_9, var_0xINPUT_9_n);
open_invariant(*this,T0_2, T0_2_n);
open_invariant(*this,T1_2, T1_2_n);
open_invariant(*this,PCTEMP_LHS_1_idx_0, PCTEMP_LHS_1_idx_0_n);
open_invariant(*this,T2_2, T2_2_n);
open_invariant(*this,PCTEMP_LHS_1_group_1, PCTEMP_LHS_1_group_1_n);
//var_0xINPUT_9 := T0_2 . T1_2;
open_concat(*this, T0_2, T0_2_n, T1_2, T1_2_n, var_0xINPUT_9, var_0xINPUT_9_n);
//T1_2 := PCTEMP_LHS_1_idx_0 . T2_2;
open_concat(*this, PCTEMP_LHS_1_idx_0, PCTEMP_LHS_1_idx_0_n, T2_2, T2_2_n, T1_2, T1_2_n);
//PCTEMP_LHS_1_group_1 == PCTEMP_LHS_1_idx_0;
open_equal(*this, PCTEMP_LHS_1_group_1, PCTEMP_LHS_1_group_1_n, PCTEMP_LHS_1_idx_0, PCTEMP_LHS_1_idx_0_n);
// PCTEMP_LHS_1_idx_0 \in CapturedBrack(/john/,0);
Gecode::DFA::Transition tp[] = {{0,75,1},{1,80,2},{2,73,3},{3,79,4},{4,dummy_sym,4},{-1,0,0}};
int fp1[] = {4,-1};
john = DFA(0,tp,fp1);
extensional(*this, PCTEMP_LHS_1_idx_0, john);
// T0_2 \notin CapturedBrack(/john/, 0);
int fp2[] = {0,1,2,3,5,-1};
notjohn = DFA(0,bigp,fp2);
extensional(*this, T0_2, notjohn);
// // PCTEMP_LHS_1_idx_0 \in CapturedBrack(/john/,0);
// Gecode::DFA::Transition t[] = {{0,75,1},{1,80,2},{2,73,3},{3,79,4},{-1,0,0}};
// int f1[] = {4,-1};
// john = DFA(0,t,f1);
// extensional(*this, PCTEMP_LHS_1_idx_0, john, PCTEMP_LHS_1_idx_0_n);
// // T0_2 \notin CapturedBrack(/john/, 0);
// int f2[] = {0,1,2,3,5,-1};
// notjohn = DFA(0,big,f2);
// extensional(*this, T0_2, notjohn, T0_2_n);
break;
}
//.........这里部分代码省略.........
示例5: board
/// Actual model
Domino(const SizeOptions& opt)
: spec(specs[opt.size()]),
width(spec[0]), height(spec[1]),
x(*this, (width+1)*height, 0, 28) {
spec+=2; // skip board size information
// Copy spec information to the board
IntArgs board((width+1)*height);
for (int i=0; i<width; i++)
for (int j=0; j<height; j++)
board[j*(width+1)+i] = spec[j*width+i];
// Initialize the separator column in the board
for (int i=0; i<height; i++) {
board[i*(width+1)+8] = -1;
rel(*this, x[i*(width+1)+8]==28);
}
// Variables representing the coordinates of the first
// and second half of a domino piece
IntVarArgs p1(*this, 28, 0, (width+1)*height-1);
IntVarArgs p2(*this, 28, 0, (width+1)*height-1);
if (opt.propagation() == PROP_ELEMENT) {
int dominoCount = 0;
int possibleDiffsA[] = {1, width+1};
IntSet possibleDiffs(possibleDiffsA, 2);
for (int i=0; i<=6; i++)
for (int j=i; j<=6; j++) {
// The two coordinates must be adjacent.
// I.e., they may differ by 1 or by the width.
// The separator column makes sure that a field
// at the right border is not adjacent to the first field
// in the next row.
IntVar diff(*this, possibleDiffs);
abs(*this, expr(*this, p1[dominoCount]-p2[dominoCount]),
diff, ICL_DOM);
// If the piece is symmetrical, order the locations
if (i == j)
rel(*this, p1[dominoCount], IRT_LE, p2[dominoCount]);
// Link the current piece to the board
element(*this, board, p1[dominoCount], i);
element(*this, board, p2[dominoCount], j);
// Link the current piece to the array where its
// number is stored.
element(*this, x, p1[dominoCount], dominoCount);
element(*this, x, p2[dominoCount], dominoCount);
dominoCount++;
}
} else {
int dominoCount = 0;
for (int i=0; i<=6; i++)
for (int j=i; j<=6; j++) {
// Find valid placements for piece i-j
// Extensional is used as a table-constraint listing all valid
// tuples.
// Note that when i == j, only one of the orientations are used.
REG valids;
for (int pos = 0; pos < (width+1)*height; ++pos) {
if ((pos+1) % (width+1) != 0) { // not end-col
if (board[pos] == i && board[pos+1] == j)
valids |= REG(pos) + REG(pos+1);
if (board[pos] == j && board[pos+1] == i && i != j)
valids |= REG(pos+1) + REG(pos);
}
if (pos/(width+1) < height-1) { // not end-row
if (board[pos] == i && board[pos+width+1] == j)
valids |= REG(pos) + REG(pos+width+1);
if (board[pos] == j && board[pos+width+1] == i && i != j)
valids |= REG(pos+width+1) + REG(pos);
}
}
IntVarArgs piece(2);
piece[0] = p1[dominoCount];
piece[1] = p2[dominoCount];
extensional(*this, piece, valids);
// Link the current piece to the array where its
// number is stored.
element(*this, x, p1[dominoCount], dominoCount);
element(*this, x, p2[dominoCount], dominoCount);
dominoCount++;
}
}
// Branch by piece
IntVarArgs ps(28*2);
for (int i=0; i<28; i++) {
ps[2*i] = p1[i];
ps[2*i+1] = p2[i];
//.........这里部分代码省略.........
示例6: mark
/// Construction of the model.
Pentominoes(const SizeOptions& opt)
: spec(examples[opt.size()]),
width(spec[0].width+1), // Add one for extra row at end.
height(spec[0].height),
filled(spec[0].amount),
nspecs(examples_size[opt.size()]-1),
ntiles(compute_number_of_tiles(spec+1, nspecs)),
board(*this, width*height, filled,ntiles+1) {
spec += 1; // No need for the specification-part any longer
// Set end-of-line markers
for (int h = 0; h < height; ++h) {
for (int w = 0; w < width-1; ++w)
rel(*this, board[h*width + w], IRT_NQ, ntiles+1);
rel(*this, board[h*width + width - 1], IRT_EQ, ntiles+1);
}
// Post constraints
if (opt.propagation() == PROPAGATION_INT) {
int tile = 0;
for (int i = 0; i < nspecs; ++i) {
for (int j = 0; j < spec[i].amount; ++j) {
// Color
int col = tile+1;
// Expression for color col
REG mark(col);
// Build expression for complement to color col
REG other;
bool first = true;
for (int j = filled; j <= ntiles; ++j) {
if (j == col) continue;
if (first) {
other = REG(j);
first = false;
} else {
other |= REG(j);
}
}
// End of line marker
REG eol(ntiles+1);
extensional(*this, board, get_constraint(i, mark, other, eol));
++tile;
}
}
} else { // opt.propagation() == PROPAGATION_BOOLEAN
int ncolors = ntiles + 2;
// Boolean variables for channeling
BoolVarArgs p(*this,ncolors * board.size(),0,1);
// Post channel constraints
for (int i=board.size(); i--; ) {
BoolVarArgs c(ncolors);
for (int j=ncolors; j--; )
c[j]=p[i*ncolors+j];
channel(*this, c, board[i]);
}
// For placing tile i, we construct the expression over
// 0/1-variables and apply it to the projection of
// the board on the color for the tile.
REG other(0), mark(1);
int tile = 0;
for (int i = 0; i < nspecs; ++i) {
for (int j = 0; j < spec[i].amount; ++j) {
int col = tile+1;
// Projection for color col
BoolVarArgs c(board.size());
for (int k = board.size(); k--; ) {
c[k] = p[k*ncolors+col];
}
extensional(*this, c, get_constraint(i, mark, other, other));
++tile;
}
}
}
if (opt.symmetry() == SYMMETRY_FULL) {
// Remove symmetrical boards
IntVarArgs orig(board.size()-height), symm(board.size()-height);
int pos = 0;
for (int i = 0; i < board.size(); ++i) {
if ((i+1)%width==0) continue;
orig[pos++] = board[i];
}
int w2, h2;
bsymmfunc syms[] = {flipx, flipy, flipd1, flipd2, rot90, rot180, rot270};
int symscnt = sizeof(syms)/sizeof(bsymmfunc);
for (int i = 0; i < symscnt; ++i) {
syms[i](orig, width-1, height, symm, w2, h2);
if (width-1 == w2 && height == h2)
rel(*this, orig, IRT_LQ, symm);
}
}
// Install branching
branch(*this, board, INT_VAR_NONE, INT_VAL_MIN);
//.........这里部分代码省略.........
示例7: b
/// The model of the problem
CrowdedChess(const SizeOptions& opt)
: n(opt.size()),
s(*this, n*n, 0, PMAX-1),
queens(*this, n, 0, n-1),
rooks(*this, n, 0, n-1),
knights(*this, n*n, 0, 1) {
const int nkval = sizeof(kval)/sizeof(int);
const int nn = n*n, q = n, r = n, b = (2*n)-2,
k = n <= nkval ? kval[n-1] : kval[nkval-1];
const int e = nn - (q + r + b + k);
assert(nn == (e + q + r + b + k));
Matrix<IntVarArray> m(s, n);
// ***********************
// Basic model
// ***********************
count(*this, s, E, IRT_EQ, e, opt.icl());
count(*this, s, Q, IRT_EQ, q, opt.icl());
count(*this, s, R, IRT_EQ, r, opt.icl());
count(*this, s, B, IRT_EQ, b, opt.icl());
count(*this, s, K, IRT_EQ, k, opt.icl());
// Collect rows and columns for handling rooks and queens
for (int i = 0; i < n; ++i) {
IntVarArgs aa = m.row(i), bb = m.col(i);
count(*this, aa, Q, IRT_EQ, 1, opt.icl());
count(*this, bb, Q, IRT_EQ, 1, opt.icl());
count(*this, aa, R, IRT_EQ, 1, opt.icl());
count(*this, bb, R, IRT_EQ, 1, opt.icl());
// Connect (queens|rooks)[i] to the row it is in
element(*this, aa, queens[i], Q, ICL_DOM);
element(*this, aa, rooks[i], R, ICL_DOM);
}
// N-queens constraints
distinct(*this, queens, ICL_DOM);
distinct(*this, IntArgs::create(n,0,1), queens, ICL_DOM);
distinct(*this, IntArgs::create(n,0,-1), queens, ICL_DOM);
// N-rooks constraints
distinct(*this, rooks, ICL_DOM);
// Collect diagonals for handling queens and bishops
for (int l = n; l--; ) {
const int il = (n-1) - l;
IntVarArgs d1(l+1), d2(l+1), d3(l+1), d4(l+1);
for (int i = 0; i <= l; ++i) {
d1[i] = m(i+il, i);
d2[i] = m(i, i+il);
d3[i] = m((n-1)-i-il, i);
d4[i] = m((n-1)-i, i+il);
}
count(*this, d1, Q, IRT_LQ, 1, opt.icl());
count(*this, d2, Q, IRT_LQ, 1, opt.icl());
count(*this, d3, Q, IRT_LQ, 1, opt.icl());
count(*this, d4, Q, IRT_LQ, 1, opt.icl());
if (opt.propagation() == PROP_DECOMPOSE) {
count(*this, d1, B, IRT_LQ, 1, opt.icl());
count(*this, d2, B, IRT_LQ, 1, opt.icl());
count(*this, d3, B, IRT_LQ, 1, opt.icl());
count(*this, d4, B, IRT_LQ, 1, opt.icl());
}
}
if (opt.propagation() == PROP_TUPLE_SET) {
IntVarArgs b(s.size());
for (int i = s.size(); i--; )
b[i] = channel(*this, expr(*this, (s[i] == B)));
extensional(*this, b, bishops, EPK_DEF, opt.icl());
}
// Handle knigths
// Connect knigths to board
for(int i = n*n; i--; )
knights[i] = expr(*this, (s[i] == K));
knight_constraints();
// ***********************
// Redundant constraints
// ***********************
// Queens and rooks not in the same place
// Faster than going through the channelled board-connection
for (int i = n; i--; )
rel(*this, queens[i], IRT_NQ, rooks[i]);
// Place bishops in two corners (from Schimpf and Hansens solution)
// Avoids some symmetries of the problem
rel(*this, m(n-1, 0), IRT_EQ, B);
rel(*this, m(n-1, n-1), IRT_EQ, B);
// ***********************
//.........这里部分代码省略.........