/******************************************************************************* * 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 java.util.Objects.*; import java.util.ArrayList; import java.util.Iterator; import org.eclipse.jdt.annotation.Nullable; import cern.colt.map.OpenLongObjectHashMap; import com.analog.lyric.dimple.model.core.FactorGraph; import com.analog.lyric.dimple.model.core.INode; import com.analog.lyric.dimple.schedulers.IScheduler; import com.analog.lyric.dimple.schedulers.scheduleEntry.BlockScheduleEntry; 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.dimple.schedulers.scheduleEntry.SubgraphScheduleEntry; /** * A schedule with a fixed list of schedule entries. * <p> * Schedule has a fixed update order, and does not change dynamically as the solver runs. * <p> * @author jeffb */ public class FixedSchedule extends ScheduleBase implements IGibbsSchedule { // TODO - schedule will not actually be serializable until schedule entries and nodes are serializable! private static final long serialVersionUID = 1L; /*------- * State */ protected ArrayList<IScheduleEntry> _schedule = new ArrayList<IScheduleEntry>(); /*-------------- * Construction */ /** * @deprecated instead use {@link #FixedSchedule(FactorGraph)} * * @since 0.08 */ @Deprecated public FixedSchedule() { super(null, null); } public FixedSchedule(FactorGraph fg) { super(null, fg); } public FixedSchedule(@Nullable IScheduler scheduler, FactorGraph fg) { super(scheduler, fg); } /** * @deprecated instead use {@link #FixedSchedule(FactorGraph, IScheduleEntry[])} */ @Deprecated public FixedSchedule(IScheduleEntry[] entries) { this(); add(entries); } public FixedSchedule(FactorGraph fg, IScheduleEntry[] entries) { this(fg); add(entries); } public FixedSchedule(@Nullable IScheduler scheduler, FactorGraph fg, IScheduleEntry[] entries) { super(scheduler, fg); add(entries); } public FixedSchedule(@Nullable IScheduler scheduler, FactorGraph fg, Iterable<IScheduleEntry> entries) { super(scheduler, fg); add(entries); } /** * @deprecated instead use {@link #FixedSchedule(IScheduler, FactorGraph, Iterable)} */ @Deprecated public FixedSchedule(Iterable<IScheduleEntry> entries) { this(); add(entries); } public ArrayList<IScheduleEntry> getSchedule() { return _schedule; } @Deprecated public FixedSchedule(ISchedule s) { this(); add(s); } @Override public Iterator<IScheduleEntry> iterator() { return _schedule.iterator(); } public void add(INode node) { final FactorGraph fg = node.asFactorGraph(); add(fg != null ? new SubgraphScheduleEntry(fg) : new NodeScheduleEntry(node)); } public void add(INode node, int index) { add(new EdgeScheduleEntry(node, index)); } public void add(INode ... nodes) { for (int i = 0; i < nodes.length; i++) add(nodes[i]); } /** * @deprecated this method cannot correctly handle multiple connections between the same * factor and variable. Instead use {@link #add(INode, int)} method. */ @Deprecated public void add(INode from, INode to) { add(new EdgeScheduleEntry(from,to)); } // Add one schedule entry public void add(IScheduleEntry entry) { requireNonNull(entry); _schedule.add(entry); ++_version; } // Add a series of schedule entries public void add(@Nullable IScheduleEntry[] entries) { if (entries != null) for (IScheduleEntry entry : entries) add(entry); } public void add(@Nullable Iterable<IScheduleEntry> entries) { if (entries != null) { for (IScheduleEntry entry : entries) add(entry); } } // Add a sub-schedule @Deprecated public void add(@Nullable ISchedule s) { if (s != null) { add(new com.analog.lyric.dimple.schedulers.scheduleEntry.SubScheduleEntry(s)); } } // Remove node or edge schedule entries containing a specified node private final void removeAllEntriesContaining(Iterable<? extends INode> nodes) { final OpenLongObjectHashMap nodemap = new OpenLongObjectHashMap(); for (INode node : nodes) { nodemap.put(node.getGlobalId(), node); } // Use iterator to avoid concurrent modification for (final Iterator<IScheduleEntry> iterator = _schedule.iterator(); iterator.hasNext(); ) { IScheduleEntry s = iterator.next(); switch (s.type()) { case NODE: if (nodemap.containsKey(((NodeScheduleEntry)s).getNode().getGlobalId())) { iterator.remove(); ++_version; } break; case EDGE: if (nodemap.containsKey(((EdgeScheduleEntry)s).getNode().getGlobalId())) { iterator.remove(); ++_version; } break; default: } } } // Get a particular entry by index (this is used, for example, for randomly selecting entries) public final IScheduleEntry get(int index) { return _schedule.get(index); } // For IGibbsSchedule interface... // Add a block schedule entry, which will replace individual node updates included in the block @Override public void addBlockScheduleEntry(BlockScheduleEntry blockScheduleEntry) { // Remove any node entries associated with the nodes in the block entry removeAllEntriesContaining(blockScheduleEntry.getBlock()); // Add the block entry add(blockScheduleEntry); } // Return the number of entries @Override public final int size() { return _schedule.size(); } @Override public boolean isCustom() { IScheduler scheduler = _scheduler; return scheduler == null || scheduler.isCustomScheduler(); } @Override public String toString() { StringBuilder sb = new StringBuilder("FixedSchedule "); sb.append(Integer.toString(_schedule.size())); sb.append("\n"); for(IScheduleEntry entry : _schedule) { sb.append("\t" + entry.toString() + "\n"); } return sb.toString(); } }