/******************************************************************************* * Copyright 2012 Analog Devices, Inc. * * 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. ********************************************************************************/ package com.analog.lyric.dimple.schedulers.schedule; import static com.analog.lyric.dimple.environment.DimpleEnvironment.*; import java.util.ArrayList; import java.util.Iterator; import java.util.Objects; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import com.analog.lyric.dimple.model.core.EdgeState; import com.analog.lyric.dimple.model.core.FactorGraph; import com.analog.lyric.dimple.model.factors.Factor; import com.analog.lyric.dimple.model.factors.FactorList; import com.analog.lyric.dimple.schedulers.IScheduler; import com.analog.lyric.dimple.schedulers.scheduleEntry.EdgeScheduleEntry; import com.analog.lyric.dimple.schedulers.scheduleEntry.IScheduleEntry; import com.analog.lyric.dimple.schedulers.scheduleEntry.NodeScheduleEntry; import com.analog.lyric.math.DimpleRandom; /** * @author jeffb * * This is a dynamic schedule, which updates factors in a randomly * chosen sequence with replacement. Prior to each factor update, the * corresponding edges of the connected variables are updated. The * number of factors updated per iteration is equal to the total number * of factors in the graph. However, since the factors are chosen * randomly with replacement, not all factors are necessarily updated in * a single iteration. * * WARNING: This schedule DOES NOT respect any existing sub-graph * scheduler associations. That is, if any sub-graph already has an * associated scheduler, that scheduler is ignored in creating this * schedule. */ public class RandomWithReplacementSchedule extends ScheduleBase { private static final long serialVersionUID = 1L; /*------- * State */ protected FactorList _factors; protected int _numFactors; /*-------------- * Construction */ public RandomWithReplacementSchedule(FactorGraph factorGraph) { this(null, factorGraph); } @SuppressWarnings("null") public RandomWithReplacementSchedule(@Nullable IScheduler scheduler, FactorGraph factorGraph) { super(scheduler, factorGraph); initialize(); } /*------------------- * ISchedule methods */ @Override public void attach(FactorGraph factorGraph) { super.attach(factorGraph); initialize(); } protected void initialize() { _factors = getFactorGraph().getNonGraphFactors(); _numFactors = _factors.size(); ++_version; } @Override public @NonNull FactorGraph getFactorGraph() { return Objects.requireNonNull(_factorGraph); } @Override public Iterator<IScheduleEntry> iterator() { final DimpleRandom rand = activeRandom(); ArrayList<IScheduleEntry> updateList = new ArrayList<IScheduleEntry>(); // One iteration consists of the number of factor updates equaling the total number of factors, even though not all factors will necessarily be updated for (int iFactor = 0; iFactor < _numFactors; iFactor++) { final int factorIndex = rand.nextInt(_numFactors); final Factor f = ((ArrayList<Factor>)_factors.values()).get(factorIndex); final FactorGraph fg = f.requireParentGraph(); for (EdgeState edge : f.getSiblingEdgeState()) { updateList.add(new EdgeScheduleEntry(edge.getVariable(fg), edge.getVariableToFactorEdgeNumber())); } updateList.add(new NodeScheduleEntry(f)); } return updateList.iterator(); } }