⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 acs.cpp

📁 VC下的蚁群算法
💻 CPP
字号:
/*
ANT-CYCLE ALGORITHM FOR TSP
File:    acs.c
Author:  ehui928
Purpose: implementation of acs.h
Date:		2007-01-18
Reference:  Dorigo M --"The Ant System: Optimization by  a colony of cooperating agents"  IEEE 1996
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <memory.h>
#include "acs.h"

#include <assert.h>

Acs::Acs()
{
	int i,j;
	seed = 21345678;	/* seed to generate random number */
	alpha = 1;			/* intensity of trail */
	beta = 4.5;		/* visibility of trail */
	rho = 0.5;		/* 1-rho is the evaporate rate */
	tao0 = 1e-6;		/* initial pheromone */
	//tao=0会更好
	Q = 	100;		/* const used to update pheromone */
	q_0 = 0.25;		/* used to decide which transition rule to be choosed */


	memset(distances,10000,(CITY_NUM+1)*(CITY_NUM+1)*sizeof(double));
	for(i=0;i<CITY_NUM+1;i++)
	{	
		for(j=0;j<CITY_NUM+1;j++) distances[i][j]=10000.0;
		DataPoints[i].x=0;
		DataPoints[i].y=0;
	}
	for(i=0;i<NC_MAX;i++)
	{	
		bestPerCircle[i]=0.0;
	}
	gLog.SetFileName("result.log");
	if ( (f_out = fopen("result.txt", "w+")) == NULL)
	{
		fprintf(stderr, "can not create file result.txt\n");
		exit(2);
	}
}
Acs::~Acs()
{
	gLog.Close();
	fclose(f_out);
}

void Acs::read_data(char *filename)//1.读数据
{
/*
read city corordinates i,x, y refers to each record in 
input file----(city_num, coordinate1,coordinate2) 
*/	
    int i;
    double x, y;
    int n;
    FILE *fp;
	
    if ( (fp = fopen(filename, "r")) == NULL)
    {
        fprintf(stderr, "can not open file %s\n", filename);
        exit(1);
    }	
	
    n = 1;	
    while (n < CITY_NUM+1)
    {
	/* 
	since x, y all double numbers, so here the
	format must be %lf , not %f, otherwise data reading will be error
		*/
        fscanf(fp, "%d %lf %lf", &i, &x, &y);
        DataPoints[i].x = x;
        DataPoints[i].y = y;
        n++;
    }
    fclose(fp);
}
void Acs::initAll()//初始化
{
	caculate_distances();	
}
/*
FUNCTION:		find the global best tour of TSP problem
INPUT:			none
RETURN:			the length of global best tour
SIDE EFFECTS:	print the global best tour

NC --------------------iterator time
i,j--------------------city index
k----------------------ant index
s----------------------tabu index
ants-------------------ants which used to find tours
ants[0] is not used, so as the L[0],best_tour[0] etc.
start------------------starting city
best_tour--------------best tour ever find by ANT_NUM ants
best_ant_index---------index of ant which found the best tour
L[ANT_NUM+1]-----------------tour lengths  ANT_NUM ant found
best_len---------------record best tour length all ants find one iteration
global_best_len--------global best length
converge---------------test convergence
*/
double Acs::find_best_tour()
{
    int NC = 0;
    int i, j;
    int k=1;
    int s=1;
    Ant ants[ANT_NUM+1];
    int start = 1;
    int best_tour[CITY_NUM+1];
    int best_ant_index = 1;

    double L[ANT_NUM+1];
    double best_len = 10000;
    

    int converge = 0;
    /* initialize pheromone on city edges */
    initialize_pheromone();
	memset(best_tour,0,(CITY_NUM+1)*sizeof(int));
	memset(L,0,(CITY_NUM+1)*sizeof(double));
	global_best_len = 10000;
    while (NC < NC_MAX)
    {
        s = 1;	/* tabu list index */

        /* put each ant to starting city */
        for (k = 1; k <= ANT_NUM; k++)//每次所有蚂蚁都从第一个城市出发
        {
            initial_ant(&ants[k]);
            ants[k].cur = start;
            ants[k].allow[start] = start;
            ants[k].tabu[s] = start;
        }
		/*for (k = 1; k <= ANT_NUM; k++)//蚂蚁从不同城市出发
        {
            initial_ant(&ants[k]);
            ants[k].cur = k;
            ants[k].allow[k] = 1;
            ants[k].tabu[s] = k;
        }*/

        /* CITY_NUM-1 cities to choose */
        for (i = 1; i < CITY_NUM; i++)//每一只蚂蚁走CITY_NUM-1个城市为一个循环
        {
            s++;
            for (k = 1; k <= ANT_NUM; k++)
            {
                int t;	/* save next city to move */
                //t = choose_next_city(&ants[k]);
				t = choose_next_city_LunPanDu(&ants[k]);
                ants[k].tabu[s] = t;
                ants[k].allow[t] = 1;//1为已经访问过
                ants[k].cur = t;
            }
        }

        /*
        	caculate the length of every tour that ants found,
        	and update the pheromone.
        */

        for (k = 1; k <= ANT_NUM; k++)
        {
			/* 
				print tour each ant found,just for debug
			*/
			//print_ant_tour(ants[k]);
			
            L[k] = caculate_tour_length(ants[k]);
            if (L[k] < best_len)
            {
                best_len = L[k];
                best_ant_index = k;
            }
        }
		fprintf(f_out, "%d--circle\t%f\n\n",NC+1,best_len);//显示循环周期及最小路径

        /* compute delta_tao[i][j] on every edge of cities */
        for (i = 1; i <= CITY_NUM; i++)
        {   
			for (j = 1; j <= CITY_NUM; j++)
            {
                for (k = 1; k <= ANT_NUM; k++)
                {
                    if (is_in_tour(i, j, ants[k].tabu, CITY_NUM))
                        delta_tao[i][j] += Q/L[k];
                }

            }
		}
        /* update pheromone on every edge on a tour */
        for (i = 1; i <= CITY_NUM; i++)
        { 
			for (j = 1; j <= CITY_NUM; j++)
            {
				if(i != j)	tao[i][j] = rho * tao[i][j] + delta_tao[i][j];
            }

		}
        /* check if converge to one best tour */
        if (fabs(best_len - global_best_len) < EPSLON)
        {
            converge++;
            if (converge >= COVERG_NUM)
                break;
        }
        else 
		if (best_len < global_best_len)                /* save best tour */
            {
                converge = 0;
                global_best_len = best_len;
				memcpy(best_tour,ants[best_ant_index].tabu,(CITY_NUM+1)*sizeof(int));
            }

		//if(NC<Real_CIrcle) 
			bestPerCircle[NC]=best_len;

        NC++;        
        reset_delta_tao();/* set delta_tao[i][j] to 0 */




    } /* end while */

	/* free resources that ants are occupying */
    for (k = 1; k <= ANT_NUM; k++)
        destroy_ant(&ants[k]);

    print_best_tour(best_tour, CITY_NUM,global_best_len);
    return global_best_len;
}



int Acs::is_in_tour(int i, int j, int tour[], int n)
/*
FUNCTION:	check whether edge(i,j) is in tour
INPUT:		i, j---city index
tour[]----tour an ant build
n---------size of tour[]
RETURN:		if edge(i,j) is in tour, then return 1;
otherwise return 0.
EFFECTS:	print the global best tour
*/

{
    int s;
    for (s = 1; s < n; s++)
    {
        if (i == tour[s] && j == tour[s+1])
            return 1;
    }
	
    if (i == tour[s] && j == 1)
        return 1;
	
    return 0;
}

/* test if distances were caculated correctly */
void Acs::print_distance(double distances[CITY_NUM+1][CITY_NUM+1])
{
    int i, j;
    i = 1;
    for (j = 1; j < CITY_NUM+1; j++)
        printf("d[%d][%d] = %f\n", i, j, distances[i][j]);
	
	
}

void Acs::print_best_tour(int tour[], int n,double global_best_len)
/*
FUNCTION:	print global best tour
INPUT:		tour[]----global best tour
n---------size of tour[]
RETURN:		none
EFFECTS:	print the global best tour
*/
{
    int i,index=0;
	char buf[1000];

    printf("Find best tour:");
    for (i = 1; i <= n; i++)
	{
        printf("%d-", tour[i]);
		index+=sprintf(&buf[index], "%d-", tour[i]);
	}
	
    printf("%d\r%f\n", tour[1],global_best_len);
	index+=sprintf(&buf[index], "%d\r\nFind best tour: %f", tour[1],global_best_len);
	this->gLog.Log(buf,index+1);
}

double Acs::Euclid_distance(Point p1, Point p2)
{
    double a = p1.x - p2.x;
    double b = p1.y - p2.y;
	
    return (double)sqrt(a * a + b * b);
}

void Acs::caculate_distances()
{
    int i, j;	
    for (i = 1; i <= CITY_NUM; i++)
        for (j = 1; j <= CITY_NUM; j++)
        {
            if (i != j)
                distances[i][j] = Euclid_distance(DataPoints[i], DataPoints[j]);
        }
}

/* function to test if data has been read correctly */
void Acs::print_coordinates(Point *p)
{
    int i;
    printf("Cities Coordinates:\n");
    for (i = 1; i < CITY_NUM+1; i++)
        printf("%d	%f	%f\n", i, p[i].x, p[i].y);
}

void Acs::initial_ant(Ant *pant)
{
    pant->cur = 0;
    pant->length = 10000.0;
    pant->tabu = (int *) malloc(sizeof(int) * (CITY_NUM+1));
    pant->allow = (int *) malloc(sizeof(int) * (CITY_NUM+1));
    memset(pant->tabu, 0, sizeof(int) * (CITY_NUM+1));
    memset(pant->allow, 0, sizeof(int) * (CITY_NUM+1));
	
	/*  if you want the seed changes every time when the 
	program runs, then uncomment the following line
	*/
		//seed = (long int)time(NULL); 
}



/*
FUNCTION:		choose the next city according to transition rule
INPUT:			the poiter to Ant---pant
RETURN:			next city been choosed
*/
int Acs::choose_next_city(Ant *pant)
{
    int i;//city index
    int j;//next city to choose 
    int k = 1;//index of f_tmp
    int s = 1;//index of prob[]
	int n;//actual size of candidate
	int candidate[CITY_NUM+1];//candidate cities can be chosen
    
    double tmp[CITY_NUM+1];//record the values of  tao
	double max = -10000.0;//max values of tmp
    double sum = 0;//sum of tmp	
	
	double prob[CITY_NUM+1];//probabilities of each candidate city to be choosen	
	double q;	/* random generate q to decide using which transition rule */

	for(i=0;i<= CITY_NUM; i++)
	{
		candidate[i]=0;
		tmp[i]=0.0;
		prob[i]=0.0;
	}
    for (i = 1; i <= CITY_NUM; i++)
    {
        if (!pant->allow[i])
        {
            /* city i is not visited */
			assert( pant->cur >0 && pant->cur <= CITY_NUM );
			assert(distances[pant->cur][i] >=0);
			candidate[s++] = i;
            tmp[k] = pow(tao[pant->cur][i], alpha) * pow(1/distances[pant->cur][i], beta);
			
            if (tmp[k] >= max)
            {
                max = tmp[k];
                j = i;
            }
            sum += tmp[k];
            k++;
        }
    }
		n = k - 1;

	assert(sum > 0);
	for (i = 1; i <= n; i++)
	{
		assert(tmp[i] > 0);
		prob[i] = tmp[i] / sum;
	}

		/* generate a random double number between [0,1] */
		q = ran01( &seed );


	if ( (q_0 > 0.0) && (q < q_0)  )
		/* 
			choose next city according to 
			pheromone maximum multiply heuristic values
		*/
	{
		return j;
	}

	else
		/* choose a random city  according to probabilities */
	{
		double rnd;
		double partial_sum;
		rnd = ran01( &seed );

		i = 1;

		partial_sum = prob[i];
		while ( partial_sum <= rnd ) 
		{
			//assert(i <= CITY_NUM);
			i++;
			partial_sum += prob[i];
		}

		return candidate[i];
	}

	
}
int Acs::choose_next_city_LunPanDu(Ant* pant)//2 使用轮盘赌法找下一个城市
{
	int i;
    int k = 1;
    int s = 1;
	int n;
	int candidate[CITY_NUM+1];

    
    double tmp[CITY_NUM+1];
    double sum = 0;
	
	double prob[CITY_NUM+1] = {0};
	double obj[CITY_NUM+1] = {0};
	
    for (i = 1; i <= CITY_NUM; i++)
    {
        if (!pant->allow[i])
        {
            /* city i is not visited */
			candidate[s++] = i;
            tmp[k] = pow(tao[pant->cur][i], alpha) * pow(1/distances[pant->cur][i], beta);
			
            sum += tmp[k];
            k++;
        }
    }
		n = k - 1;
/*             轮盘赌选择
tmp[]原始数组,选择概率如{10,30,20,40} 此时sum=100
prob[]规格数据到【0,1】内{0.1,0.3,0.2,0.4}
obj[]概率的长度表示{0.1,0.4,0.6,1}
*/
	for (i = 1; i <= n; i++)
	{
		prob[i] = tmp[i] / sum;
		obj[i]=prob[i];
	}
	for (i = 2; i <= n; i++)
	{
		obj[i] += obj[i-1];
	}

	double rnd=0;
	rnd = ((double)(rand()%1000))/1000.0;

	for(i=1;i<=CITY_NUM;i++)
	{
		if(rnd < obj[i]) break;
	}

	return candidate[i];
}
void Acs::destroy_ant(Ant *pant)
{
    free(pant->tabu);
    free(pant->allow);
}
double Acs::caculate_tour_length(Ant ant)
{
    int i;
    double len = 0.0;
	
    for (i = 1; i < CITY_NUM; i++)
        len += distances[ant.tabu[i]][ant.tabu[i+1]];
	
    len += distances[ant.tabu[CITY_NUM]][ant.tabu[1]];
	
    return len;
}

void Acs::print_ant_tour(Ant ant)
/*
FUNCTION:		print a tour an ant found
INPUT:			Ant ant
RETURN:			none
*/
{

	int i;
    for (i = 1; i < CITY_NUM+1; i++)
		fprintf(f_out, "%d-", ant.tabu[i]);
	fprintf(f_out, "%d\n", ant.tabu[1]);
	/*int i,index=0;
	char buf[1000];
	
    for (i = 1; i < CITY_NUM+1; i++)
	{
		index+=sprintf(&buf[index], "%d-", ant.tabu[i]);
		fprintf(f_out, "%d-", ant.tabu[i]);
	}
    index+=sprintf(&buf[index], "%d", ant.tabu[1]);
	//this->gLog.Log(buf,index+1);
	fprintf(f_out, "%d\n", ant.tabu[1]);*/
}

void Acs::initialize_pheromone()
/*
	FUNCTION:		initial pheromone on all edge(i,j) to tao0
	INPUT:			none
	RETURN:			none
*/
{
    int i, j;
    for (i = 1; i < CITY_NUM+1; i++)
        for (j = 1; j < CITY_NUM+1; j++)            
		{
			tao[i][j] = tao0;
			delta_tao[i][j]=0.0;
		}
}


/* 
constants for a random number generator, 
for details see numerical recipes in C 
*/



double Acs::ran01( long *idum )
/*    
FUNCTION:       generate a random number that is uniformly distributed in [0,1]
INPUT:          pointer to variable with the current seed
OUTPUT:         random number uniformly distributed in [0,1]
(SIDE)EFFECTS:  random number seed is modified (important, this has to be done!)
ORIGIN:         numerical recipes in C
*/
{
#define IA 16807
#define IM 2147483647
#define AM (1.0/IM)
#define IQ 127773
#define IR 2836
	
	
	long k;
	double ans;
	
	k =(*idum)/IQ;
	*idum = IA * (*idum - k * IQ) - IR * k;
	if (*idum < 0 ) *idum += IM;
	ans = AM * (*idum);
  return ans;
}
//FUNCTION:		clear the delta_tao matrix, set it all to 0
void Acs::reset_delta_tao()
{
    int i, j;
    for (i = 1; i < CITY_NUM+1; i++)
        for (j = 1; j < CITY_NUM+1; j++)
            delta_tao[i][j] = 0.0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -