2016-02-28 91 views
0

我在恢復我6個月前寫的optaplanner代碼,並試圖找出爲什麼我的一些硬約束被破壞,我發現我寫的過濾器這是應該過濾掉非法移動沒有被引用。我在移動工廠的所有方法中放置了斷點,移動方法和過濾器,而且都沒有被調用。我很確定,在我更新到最新版本之前,情況並非如此,但我可能是錯的。Optaplanner自定義MoveFactory沒有被使用

更新:當我在我的測試用例中運行optaplanner而不是在生產中時使用了該工廠,所以我想這不是由於我的配置而是這個場景,但我不知道可能會對它產生什麼影響正在使用或不

我的求解器的配置:

<?xml version="1.0" encoding="UTF-8"?> 
<solver> 
<environmentMode>FULL_ASSERT</environmentMode> 

<!-- Domain model configuration --> 
<solutionClass>com.rdthree.plenty.services.activities.planner.ActivitySolution</solutionClass> 
<entityClass>com.rdthree.plenty.services.activities.helpers.dtos.TaskPlannerDto</entityClass> 
<entityClass>com.rdthree.plenty.services.activities.helpers.dtos.TaskResourceAllocationPlannerDto</entityClass> 

<!-- Score configuration --> 
<scoreDirectorFactory> 
    <scoreDefinitionType>HARD_SOFT</scoreDefinitionType> 
    <scoreDrl>com/rdthree/plenty/services/activities/planner/activity-scoring.drl</scoreDrl> 
    <initializingScoreTrend>ONLY_DOWN</initializingScoreTrend> 
</scoreDirectorFactory> 

<!-- Optimization algorithms configuration --> 
<termination> 
    <terminationCompositionStyle>OR</terminationCompositionStyle> 
    <bestScoreLimit>0hard/0soft</bestScoreLimit> 
    <secondsSpentLimit>60</secondsSpentLimit> 
</termination> 

<constructionHeuristic> 
    <queuedEntityPlacer> 
     <entitySelector id="resourceAllocationSelector"> 
      <entityClass>com.rdthree.plenty.services.activities.helpers.dtos.TaskResourceAllocationPlannerDto</entityClass> 
      <cacheType>PHASE</cacheType> 
      <selectionOrder>SORTED</selectionOrder> 
      <sorterManner>DECREASING_DIFFICULTY_IF_AVAILABLE</sorterManner> 
     </entitySelector> 
     <changeMoveSelector> 
      <entitySelector mimicSelectorRef="resourceAllocationSelector" /> 
      <valueSelector> 
       <variableName>resource</variableName> 
       <cacheType>PHASE</cacheType> 
      </valueSelector> 
     </changeMoveSelector> 
    </queuedEntityPlacer> 
</constructionHeuristic> 

<constructionHeuristic> 
    <queuedEntityPlacer> 
     <entitySelector id="taskSelector"> 
      <entityClass>com.rdthree.plenty.services.activities.helpers.dtos.TaskPlannerDto</entityClass> 
      <cacheType>PHASE</cacheType> 
      <selectionOrder>SORTED</selectionOrder> 
      <sorterManner>DECREASING_DIFFICULTY_IF_AVAILABLE</sorterManner> 
     </entitySelector> 
     <changeMoveSelector> 
      <entitySelector mimicSelectorRef="taskSelector" /> 
      <filterClass>com.rdthree.plenty.services.activities.planner.filters.TaskLengthChnageFilter</filterClass> 
      <valueSelector> 
       <variableName>interval</variableName> 
       <cacheType>PHASE</cacheType> 
      </valueSelector> 
     </changeMoveSelector> 
    </queuedEntityPlacer> 
</constructionHeuristic> 

<localSearch> 
    <unionMoveSelector> 
     <moveListFactory> 
      <moveListFactoryClass>com.rdthree.plenty.services.activities.planner.MoveResourceAllocationMoveFactory</moveListFactoryClass> 
     </moveListFactory> 
     <changeMoveSelector> 
      <fixedProbabilityWeight>1.0</fixedProbabilityWeight> 
      <filterClass>com.rdthree.plenty.services.activities.planner.filters.TaskLengthChnageFilter</filterClass> 
      <entitySelector id="taskMoveSelector"> 
       <entityClass>com.rdthree.plenty.services.activities.helpers.dtos.TaskPlannerDto</entityClass> 
      </entitySelector> 
      <valueSelector> 
       <variableName>interval</variableName> 
      </valueSelector> 
     </changeMoveSelector> 
    </unionMoveSelector> 

    <acceptor> 
     <valueTabuSize>7</valueTabuSize> 
    </acceptor> 
    <forager> 
     <acceptedCountLimit>2000</acceptedCountLimit> 
    </forager> 
</localSearch> 

我自定義的移動工廠:

public class MoveResourceAllocationMoveFactory implements MoveListFactory<ActivitySolution> { 

@Override 
public List<? extends Move> createMoveList(ActivitySolution solution) { 
    List<Move> moveList = new ArrayList<Move>(); 
    for (TaskResourceAllocationPlannerDto allocation : solution.getResourceAllocations()) { 
     for (TaskResourcePlannerDto resource : solution.getResources()) { 
      moveList.add(new MoveResourceAllocations(allocation, resource)); 
     } 
    } 
    return moveList; 
} 

} 

我自招:

public class MoveResourceAllocations extends AbstractMove { 

private TaskResourceAllocationPlannerDto allocation; 

private TaskResourcePlannerDto newResource; 

@Getter 
@Setter 
boolean doMove; 

public MoveResourceAllocations(TaskResourceAllocationPlannerDto allocation, TaskResourcePlannerDto newResource) { 
    super(); 
    this.allocation = allocation; 
    this.newResource = newResource; 
} 

@Override 
public boolean isMoveDoable(ScoreDirector scoreDirector) { 
    if (allocation.getResource().equals(newResource)) { 
     return false; 
    } 
    return new ResourceTypeMismatchFilter().acceptCustomMove(scoreDirector, this); 
} 

@Override 
public Move createUndoMove(ScoreDirector scoreDirector) { 
    return new MoveResourceAllocations(allocation, allocation.getResource()); 
} 

@Override 
public void doMoveOnGenuineVariables(ScoreDirector scoreDirector) { 
    scoreDirector.beforeVariableChanged(allocation, "resource"); 

    updateOnHandAmounts(scoreDirector); 

    allocation.setResource(newResource); 

    scoreDirector.afterVariableChanged(allocation, "resource"); 
} 


private void updateOnHandAmounts(ScoreDirector scoreDirector) { 
    ActivitySolution solution = (ActivitySolution) scoreDirector.getWorkingSolution(); 
    List<OnHandForProduct> onHandForProducts = solution.getOnHandForProducts(); 
    List<ProductInventoryTransactionPlannerDto> transactions = solution.getTransactions(); 
    boolean transactionFoundForTask = false; 
    if ((newResource.getClass().getSimpleName().contains(Product.class.getSimpleName())) 
      && allocation.getResourceClass().equals(Product.class)) { 
     // find the transaction caused by the task and product in question and replace the product in the 
     // transaction with the newly assigned product and revert this for an undo move 
     for (ProductInventoryTransactionPlannerDto transaction : transactions) { 
      if (transaction.getCauseId().equals(allocation.getTaskId()) 
        && transaction.getProductId() == (allocation.getResource().getId()) 
        && transaction.getTransactionTypeName().equals(InventoryTransactionType.SUBTRACT)) { 
       transaction.setProductId(newResource.getId()); 
       transactionFoundForTask = true; 
       break; 
      } 
     } 
     if (!transactionFoundForTask) { 
      throw new EmptyResultDataAccessException(
        "Internal scheduler fail: no product transaction found for the product-requiring task with id: " 
          + allocation.getTaskId() + " for product : " + allocation.getResource(), 1); 
     } 
     TaskPlannerDto thisTask = null; 
     for (TaskPlannerDto task : solution.getTasks()) { 
      if (task.getId().equals(allocation.getTaskId())) { 
       thisTask = task; 
      } 
     } 
     Long oldProductId = allocation.getResource().getId(); 
     Long newProductId = newResource.getId(); 
     for (OnHandForProduct onHandForProduct : onHandForProducts) { 
      if (onHandForProduct.getProductId().equals(oldProductId) 
        && onHandForProduct.getDate().isAfter(
          thisTask.getInterval().getStart().withTimeAtStartOfDay() 
            .plusDays(0/* - GeneralPrefs.PRODUCT_PRESENCE_SAFETY_BUFFER*/))) { 
       onHandForProduct.setAmount(onHandForProduct.getAmount() + allocation.getAmount()); 
      } 
      if (onHandForProduct.getProductId().equals(newProductId) 
        && onHandForProduct.getDate().isAfter(
          thisTask.getInterval().getStart().withTimeAtStartOfDay() 
          .plusDays(0/* - GeneralPrefs.PRODUCT_PRESENCE_SAFETY_BUFFER*/))) { 
       onHandForProduct.setAmount(onHandForProduct.getAmount() - allocation.getAmount()); 
      } 
     } 
    } 
} 

@Override 
public Collection<? extends Object> getPlanningEntities() { 
    return Collections.singletonList(allocation); 
} 

@Override 
public Collection<? extends Object> getPlanningValues() { 
    return Collections.singletonList(newResource); 
} 

@Override 
public String toString() { 
    return "replacing resource " + allocation.getResource() + " for task with id " + allocation.getId() + " with " 
      + newResource; 
} 

@Override 
public int hashCode() { 
    final int prime = 31; 
    int result = 1; 
    result = prime * result + ((allocation == null) ? 0 : allocation.hashCode()); 
    result = prime * result + ((newResource == null) ? 0 : newResource.hashCode()); 
    return result; 
} 

@Override 
public boolean equals(Object obj) { 
    if (this == obj) 
     return true; 
    if (obj == null) 
     return false; 
    if (getClass() != obj.getClass()) 
     return false; 
    MoveResourceAllocations other = (MoveResourceAllocations) obj; 
    if (allocation == null) { 
     if (other.allocation != null) 
      return false; 
    } else if (!allocation.equals(other.allocation)) 
     return false; 
    if (newResource == null) { 
     if (other.newResource != null) 
      return false; 
    } else if (!newResource.equals(other.newResource)) 
     return false; 
    return true; 
} 

} 

回答

1

的配置看起來不錯。

1)也許2構建啓發式階段永遠不會完成。 打開INFO日誌記錄(或更好的DEBUG)。它將在2個構造啓發式法結束時記錄。

2)也許本地搜索以ChangeMoveSelector開始(這是一個聯合,所以2個選擇器中的任何一個都可以先去),並且它以某種方式掛在過濾器中。打開TRACE日誌記錄以查看選定的移動。

相關問題