Пример #1
0
void
BiasSolver::simpleOptimize( SolverList *list )
{
    DEBUG_BLOCK;

    if( list->m_trackList.count() <= list->m_contextCount )
        return; // nothing to optimize. All tracks are in the context

    // first set some random tracks
    // this prevents the part bias from first fullfilling the easy conditions
    for( int i = 0; i < m_n / 2; i++ )
    {
        // choose the mutation position
        int newPos = (KRandom::random() % (list->m_trackList.count() - list->m_contextCount))
            + list->m_contextCount;

        TrackSet set = matchingTracks( newPos, list->m_trackList );
        if( !m_allowDuplicates )
            set = withoutDuplicate( newPos, list->m_trackList, set, false );

        Meta::TrackPtr newTrack;
        newTrack = getRandomTrack( set );
        if( newTrack )
            list->setTrack( newPos, newTrack );
    }

    // now go through the complete list again and try to fullfill all
    for( int newPos = list->m_contextCount; newPos < list->m_trackList.count(); newPos++ )
    {
        TrackSet set = matchingTracks( newPos, list->m_trackList );
        if( !m_allowDuplicates )
            set = withoutDuplicate( newPos, list->m_trackList, set, true );

        Meta::TrackPtr newTrack;
        newTrack = getRandomTrack( set );
        if( newTrack )
            list->setTrack( newPos, newTrack );
    }
}
Пример #2
0
QUrl FooPlaylist::getNextTrack(FooPlaybackOrder::FooPlaybackOrder order, FooPlayback::FooPlayback playback)
{
	if (shouldCurrentTrackIndex >= 0)
	{
		currentTrackIndex = shouldCurrentTrackIndex;
		shouldCurrentTrackIndex = -1;
	}

	int beforeTrackIndex = currentTrackIndex;

	QUrl newTrack;

	if (playlist.empty())
	{
		currentTrackIndex = -1;
		shouldCurrentTrackIndex = -1;
	}
	else if (order == FooPlaybackOrder::Random || playback == FooPlayback::random)
	{
		newTrack = getRandomTrack();
	}
	else if (currentTrackIndex < 0)
	{
		currentTrackIndex = 0;

		newTrack = playlist.at(currentTrackIndex).file();
	}
	else
	{
		if ((playback == FooPlayback::enque && order == FooPlaybackOrder::Default) || (playback == FooPlayback::next && (order == FooPlaybackOrder::Default || order == FooPlaybackOrder::Repeat_Track)))
		{
			++currentTrackIndex;

			if (currentTrackIndex >= playlist.size())
			{
				currentTrackIndex = -1;
			}
			else
			{
				newTrack = playlist.at(currentTrackIndex).file();
			}
		}
		else if (playback == FooPlayback::prev && (order == FooPlaybackOrder::Default || order == FooPlaybackOrder::Repeat_Track))
		{
			--currentTrackIndex;

			if (currentTrackIndex < 0)
			{
				currentTrackIndex = -1;
			}
			else
			{
				newTrack = playlist.at(currentTrackIndex).file();
			}
		}
		else if (order == FooPlaybackOrder::Repeat_Playlist && (playback == FooPlayback::enque || playback == FooPlayback::next))
		{
			++currentTrackIndex;

			if (currentTrackIndex >= playlist.size())
			{
				currentTrackIndex = 0;
			}

			newTrack = playlist.at(currentTrackIndex).file();
		}
		else if (playback == FooPlayback::prev && order == FooPlaybackOrder::Repeat_Playlist)
		{
			--currentTrackIndex;

			if (currentTrackIndex < 0)
			{
				currentTrackIndex = playlist.size() - 1;
			}

			newTrack = playlist.at(currentTrackIndex).file();
		}
		else if ((playback == FooPlayback::enque && order == FooPlaybackOrder::Repeat_Track) || playback == FooPlayback::play)
		{
			newTrack = playlist.at(currentTrackIndex).file();
		}
	}

	emit metaChanged(beforeTrackIndex);

	if (currentTrackIndex >= 0)
	{
		emit metaChanged(currentTrackIndex);
	}

	return newTrack;
}
Пример #3
0
void
BiasSolver::annealingOptimize( SolverList *list,
                               int iterationLimit,
                               bool updateStatus )
{
    DEBUG_BLOCK;

    if( list->m_trackList.count() <= list->m_contextCount )
        return; // nothing to optimize. All tracks are in the context

    SolverList originalList = *list;

    /*
     * The process used here is called "simulated annealing". The basic idea is
     * that the playlist is randomly mutated one track at a time. Mutations that
     * improve the playlist (decrease the energy) are always accepted, mutations
     * that make the playlist worse (increase the energy) are sometimes
     * accepted. The decision to accept is made randomly based on a special
     * probability curve that changes as the algorithm progresses.
     *
     * Accepting some bad mutations makes the algorithm resilient to getting
     * stuck in local minima (playlists that are not optimal but can't be
     * improved by making just one change). There is much more reading available
     * on the internet or your local library.
     */

    double T = SA_INITIAL_TEMPERATURE;
    TrackSet universeSet( m_trackCollection, true );

    double oldEnergy = 0.0;
    int giveUpCount = 0;
    while( iterationLimit-- && list->energy() >= epsilon() && !m_abortRequested )
    {
        // if the energy hasn't changed in SA_GIVE_UP_LIMIT iterations, we give
        // up and bail out.
        if( oldEnergy == list->energy() )
            giveUpCount++;
        else
        {
            oldEnergy = list->energy();
            giveUpCount = 0;
        }

        if( giveUpCount >= SA_GIVE_UP_LIMIT )
            break;

        // choose the mutation position
        int newPos = (KRandom::random() % (list->m_trackList.count() - list->m_contextCount))
            + list->m_contextCount;

        // choose a matching track or a random one. Prefere matching
        Meta::TrackPtr newTrack;
        if( iterationLimit % 4 )
        {
            TrackSet set = matchingTracks( newPos, list->m_trackList );
            if( !m_allowDuplicates )
                set = withoutDuplicate( newPos, list->m_trackList, set, false );
            newTrack = getRandomTrack( set );
        }
        else
        {
            if( !m_allowDuplicates )
                newTrack = getRandomTrack( withoutDuplicate( newPos, list->m_trackList, universeSet, false ) );
            else
                newTrack = getRandomTrack( universeSet );
        }

        if( !newTrack )
            continue;

        // debug() << "replacing"<<newPos<<list->m_trackList[newPos]->name()<<"with"<<newTrack->name();

        SolverList newList = *list;
        newList.setTrack( newPos, newTrack );

        double p = 1.0 / ( 1.0 + exp( (newList.energy() - list->energy()) / list->m_trackList.count()  / T ) );
        double r = (double)KRandom::random() / (((double)RAND_MAX) + 1.0);

        // accept the mutation ?
        if( r <= p )
            *list = newList;

        // cool the temperature
        T *= SA_COOLING_RATE;

        if( updateStatus && iterationLimit % 100 == 0 )
        {
            debug() << "SA: E = " << list->energy();
            int progress = (int)(100.0 * (1.0 - list->energy()));
            emit statusUpdate( progress >= 0 ? progress : 0 );
        }
    }

    // -- use the original list if we made it worse
    if( list->energy() > originalList.energy() )
        *list = originalList;
}